Merge branches 'sh/pci-express-integration', 'sh/rsk-updates', 'sh/platform-updates...
authorPaul Mundt <lethal@linux-sh.org>
Wed, 17 Jun 2009 07:37:26 +0000 (16:37 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Wed, 17 Jun 2009 07:37:26 +0000 (16:37 +0900)
1342 files changed:
Documentation/DocBook/debugobjects.tmpl
Documentation/accounting/getdelays.c
Documentation/atomic_ops.txt
Documentation/cdrom/packet-writing.txt
Documentation/driver-model/device.txt
Documentation/dvb/get_dvb_firmware
Documentation/fault-injection/fault-injection.txt
Documentation/fb/vesafb.txt
Documentation/filesystems/proc.txt
Documentation/filesystems/vfat.txt
Documentation/firmware_class/README
Documentation/hwmon/f71882fg
Documentation/hwmon/ibmaem
Documentation/hwmon/sysfs-interface
Documentation/hwmon/tmp401 [new file with mode: 0644]
Documentation/hwmon/w83627ehf
Documentation/i2c/busses/i2c-viapro
Documentation/kernel-parameters.txt
Documentation/kmemcheck.txt [new file with mode: 0644]
Documentation/kprobes.txt
Documentation/sysctl/vm.txt
Documentation/trace/ftrace.txt
Documentation/trace/mmiotrace.txt
Documentation/video4linux/CARDLIST.cx23885
Documentation/video4linux/CARDLIST.cx88
Documentation/video4linux/CARDLIST.em28xx
Documentation/video4linux/CARDLIST.saa7134
Documentation/video4linux/CARDLIST.tuner
Documentation/video4linux/gspca.txt
Documentation/video4linux/pxa_camera.txt
Documentation/video4linux/v4l2-framework.txt
Documentation/vm/Makefile
Documentation/vm/balance
Documentation/vm/page-types.c [new file with mode: 0644]
Documentation/vm/pagemap.txt
MAINTAINERS
arch/alpha/include/asm/8253pit.h
arch/alpha/include/asm/kmap_types.h
arch/alpha/kernel/init_task.c
arch/alpha/kernel/irq_alpha.c
arch/alpha/kernel/irq_i8259.c
arch/alpha/kernel/irq_impl.h
arch/alpha/kernel/irq_pyxis.c
arch/alpha/kernel/irq_srm.c
arch/alpha/kernel/setup.c
arch/alpha/kernel/sys_alcor.c
arch/alpha/kernel/sys_cabriolet.c
arch/alpha/kernel/sys_dp264.c
arch/alpha/kernel/sys_eb64p.c
arch/alpha/kernel/sys_eiger.c
arch/alpha/kernel/sys_jensen.c
arch/alpha/kernel/sys_marvel.c
arch/alpha/kernel/sys_mikasa.c
arch/alpha/kernel/sys_noritake.c
arch/alpha/kernel/sys_rawhide.c
arch/alpha/kernel/sys_ruffian.c
arch/alpha/kernel/sys_rx164.c
arch/alpha/kernel/sys_sable.c
arch/alpha/kernel/sys_takara.c
arch/alpha/kernel/sys_titan.c
arch/alpha/kernel/sys_wildfire.c
arch/alpha/mm/numa.c
arch/arm/kernel/init_task.c
arch/arm/mach-pxa/pcm990-baseboard.c
arch/arm/plat-s3c/include/plat/regs-usb-hsotg-phy.h [new file with mode: 0644]
arch/arm/plat-s3c/include/plat/regs-usb-hsotg.h [new file with mode: 0644]
arch/avr32/kernel/init_task.c
arch/blackfin/Kconfig
arch/blackfin/Makefile
arch/blackfin/boot/.gitignore
arch/blackfin/boot/Makefile
arch/blackfin/include/asm/atomic.h
arch/blackfin/include/asm/bfin-global.h
arch/blackfin/include/asm/bitops.h
arch/blackfin/include/asm/bug.h
arch/blackfin/include/asm/cache.h
arch/blackfin/include/asm/cacheflush.h
arch/blackfin/include/asm/cpu.h
arch/blackfin/include/asm/ftrace.h
arch/blackfin/include/asm/ipipe.h
arch/blackfin/include/asm/irq.h
arch/blackfin/include/asm/irqflags.h [new file with mode: 0644]
arch/blackfin/include/asm/kmap_types.h
arch/blackfin/include/asm/mutex-dec.h [deleted file]
arch/blackfin/include/asm/sections.h
arch/blackfin/include/asm/system.h
arch/blackfin/include/asm/unistd.h
arch/blackfin/kernel/Makefile
arch/blackfin/kernel/bfin_dma_5xx.c
arch/blackfin/kernel/bfin_ksyms.c
arch/blackfin/kernel/cplb-mpu/cplbmgr.c
arch/blackfin/kernel/cplb-nompu/cplbmgr.c
arch/blackfin/kernel/early_printk.c
arch/blackfin/kernel/ftrace-entry.S [new file with mode: 0644]
arch/blackfin/kernel/ftrace.c [new file with mode: 0644]
arch/blackfin/kernel/init_task.c
arch/blackfin/kernel/ipipe.c
arch/blackfin/kernel/setup.c
arch/blackfin/kernel/stacktrace.c [new file with mode: 0644]
arch/blackfin/kernel/traps.c
arch/blackfin/kernel/vmlinux.lds.S
arch/blackfin/lib/checksum.c
arch/blackfin/mach-bf518/boards/ezbrd.c
arch/blackfin/mach-bf527/boards/cm_bf527.c
arch/blackfin/mach-bf527/boards/ezbrd.c
arch/blackfin/mach-bf527/boards/ezkit.c
arch/blackfin/mach-bf533/boards/H8606.c
arch/blackfin/mach-bf533/boards/blackstamp.c
arch/blackfin/mach-bf533/boards/cm_bf533.c
arch/blackfin/mach-bf533/boards/ezkit.c
arch/blackfin/mach-bf533/boards/stamp.c
arch/blackfin/mach-bf537/boards/cm_bf537.c
arch/blackfin/mach-bf537/boards/minotaur.c
arch/blackfin/mach-bf537/boards/pnav10.c
arch/blackfin/mach-bf537/boards/stamp.c
arch/blackfin/mach-bf537/boards/tcm_bf537.c
arch/blackfin/mach-bf538/boards/ezkit.c
arch/blackfin/mach-bf548/boards/cm_bf548.c
arch/blackfin/mach-bf548/boards/ezkit.c
arch/blackfin/mach-bf561/boards/cm_bf561.c
arch/blackfin/mach-bf561/boards/ezkit.c
arch/blackfin/mach-common/cache-c.c
arch/blackfin/mach-common/entry.S
arch/blackfin/mach-common/smp.c
arch/cris/include/asm/kmap_types.h
arch/cris/kernel/process.c
arch/frv/kernel/init_task.c
arch/h8300/include/asm/kmap_types.h
arch/h8300/kernel/init_task.c
arch/ia64/hp/common/sba_iommu.c
arch/ia64/include/asm/kmap_types.h
arch/ia64/kernel/init_task.c
arch/ia64/kernel/mca.c
arch/ia64/kernel/perfmon.c
arch/ia64/kernel/uncached.c
arch/ia64/sn/pci/pci_dma.c
arch/m32r/include/asm/kmap_types.h
arch/m32r/kernel/init_task.c
arch/m32r/mm/discontig.c
arch/m32r/platforms/m32104ut/setup.c
arch/m32r/platforms/m32700ut/setup.c
arch/m32r/platforms/mappi/setup.c
arch/m32r/platforms/mappi2/setup.c
arch/m32r/platforms/mappi3/setup.c
arch/m32r/platforms/oaks32r/setup.c
arch/m32r/platforms/opsput/setup.c
arch/m32r/platforms/usrv/setup.c
arch/m68k/include/asm/kmap_types.h
arch/m68k/kernel/process.c
arch/m68knommu/kernel/init_task.c
arch/microblaze/include/asm/kmap_types.h
arch/mips/configs/bigsur_defconfig
arch/mips/configs/mtx1_defconfig
arch/mips/include/asm/i8253.h
arch/mips/include/asm/kmap_types.h
arch/mips/kernel/init_task.c
arch/mips/sni/eisa.c
arch/mn10300/include/asm/kmap_types.h
arch/mn10300/kernel/init_task.c
arch/parisc/include/asm/kmap_types.h
arch/parisc/kernel/init_task.c
arch/powerpc/Kconfig
arch/powerpc/boot/install.sh
arch/powerpc/configs/ppc6xx_defconfig
arch/powerpc/include/asm/8253pit.h
arch/powerpc/include/asm/atomic.h
arch/powerpc/include/asm/hw_irq.h
arch/powerpc/include/asm/iommu.h
arch/powerpc/include/asm/ps3.h
arch/powerpc/include/asm/ps3gpu.h [new file with mode: 0644]
arch/powerpc/include/asm/reg.h
arch/powerpc/include/asm/systbl.h
arch/powerpc/include/asm/unistd.h
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/init_task.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/setup_64.c
arch/powerpc/kernel/time.c
arch/powerpc/platforms/cell/axon_msi.c
arch/powerpc/platforms/cell/iommu.c
arch/powerpc/platforms/cell/ras.c
arch/powerpc/platforms/cell/spu_base.c
arch/powerpc/platforms/iseries/dt.c
arch/powerpc/platforms/iseries/mf.c
arch/powerpc/platforms/ps3/mm.c
arch/powerpc/platforms/ps3/os-area.c
arch/powerpc/platforms/ps3/platform.h
arch/powerpc/platforms/ps3/setup.c
arch/powerpc/platforms/ps3/system-bus.c
arch/s390/Kconfig
arch/s390/Makefile
arch/s390/appldata/appldata_base.c
arch/s390/include/asm/ccwdev.h
arch/s390/include/asm/ccwgroup.h
arch/s390/include/asm/kmap_types.h
arch/s390/include/asm/suspend.h [new file with mode: 0644]
arch/s390/include/asm/system.h
arch/s390/kernel/early.c
arch/s390/kernel/init_task.c
arch/s390/kernel/mem_detect.c
arch/s390/kernel/smp.c
arch/s390/mm/pgtable.c
arch/s390/power/Makefile [new file with mode: 0644]
arch/s390/power/suspend.c [new file with mode: 0644]
arch/s390/power/swsusp.c [new file with mode: 0644]
arch/s390/power/swsusp_64.c [new file with mode: 0644]
arch/s390/power/swsusp_asm64.S [new file with mode: 0644]
arch/sh/Kconfig
arch/sh/Kconfig.debug
arch/sh/boards/board-ap325rxa.c
arch/sh/boards/board-sh7785lcr.c
arch/sh/boards/board-urquell.c
arch/sh/boards/mach-highlander/setup.c
arch/sh/boards/mach-migor/setup.c
arch/sh/boards/mach-se/7780/irq.c
arch/sh/boards/mach-x3proto/setup.c
arch/sh/configs/r7780mp_defconfig
arch/sh/drivers/pci/Makefile
arch/sh/drivers/pci/ops-dreamcast.c
arch/sh/drivers/pci/ops-sh7786.c [new file with mode: 0644]
arch/sh/drivers/pci/pci.c
arch/sh/drivers/pci/pcie-sh7786.h [new file with mode: 0644]
arch/sh/include/asm/atomic-irq.h
arch/sh/include/asm/atomic.h
arch/sh/include/asm/checksum.h
arch/sh/include/asm/checksum_64.h [deleted file]
arch/sh/include/asm/current.h
arch/sh/include/asm/dma.h
arch/sh/include/asm/ipcbuf.h
arch/sh/include/asm/irq.h
arch/sh/include/asm/kmap_types.h
arch/sh/include/asm/mman.h
arch/sh/include/asm/mmu_context.h
arch/sh/include/asm/module.h
arch/sh/include/asm/msgbuf.h
arch/sh/include/asm/param.h
arch/sh/include/asm/parport.h
arch/sh/include/asm/perf_counter.h [new file with mode: 0644]
arch/sh/include/asm/posix_types_32.h
arch/sh/include/asm/posix_types_64.h
arch/sh/include/asm/scatterlist.h
arch/sh/include/asm/sembuf.h
arch/sh/include/asm/serial.h
arch/sh/include/asm/setup.h
arch/sh/include/asm/shmbuf.h
arch/sh/include/asm/signal.h
arch/sh/include/asm/smp.h
arch/sh/include/asm/socket.h
arch/sh/include/asm/swab.h
arch/sh/include/asm/termbits.h
arch/sh/include/asm/termios.h
arch/sh/include/asm/timex.h
arch/sh/include/asm/topology.h
arch/sh/include/asm/types.h
arch/sh/include/asm/ucontext.h
arch/sh/include/asm/unaligned.h
arch/sh/include/asm/unistd_32.h
arch/sh/include/asm/unistd_64.h
arch/sh/include/mach-common/mach/highlander.h
arch/sh/kernel/cpu/clock-cpg.c
arch/sh/kernel/cpu/sh4a/setup-sh7366.c
arch/sh/kernel/cpu/sh4a/setup-sh7723.c
arch/sh/kernel/cpu/sh4a/smp-shx3.c
arch/sh/kernel/ftrace.c
arch/sh/kernel/init_task.c
arch/sh/kernel/sh_ksyms_64.c
arch/sh/kernel/smp.c
arch/sh/kernel/syscalls_32.S
arch/sh/kernel/syscalls_64.S
arch/sh/kernel/time.c
arch/sh/kernel/traps.c
arch/sh/lib64/Makefile
arch/sh/lib64/c-checksum.c [deleted file]
arch/sparc/Kconfig
arch/sparc/configs/sparc64_defconfig
arch/sparc/include/asm/cpudata_64.h
arch/sparc/include/asm/dma-mapping.h
arch/sparc/include/asm/dma-mapping_32.h [deleted file]
arch/sparc/include/asm/dma-mapping_64.h [deleted file]
arch/sparc/include/asm/ftrace.h
arch/sparc/include/asm/kmap_types.h
arch/sparc/include/asm/mdesc.h
arch/sparc/include/asm/percpu_64.h
arch/sparc/include/asm/prom.h
arch/sparc/include/asm/trap_block.h [new file with mode: 0644]
arch/sparc/include/asm/unistd.h
arch/sparc/kernel/Makefile
arch/sparc/kernel/cpumap.c [new file with mode: 0644]
arch/sparc/kernel/cpumap.h [new file with mode: 0644]
arch/sparc/kernel/dma.c
arch/sparc/kernel/ds.c
arch/sparc/kernel/ftrace.c
arch/sparc/kernel/head_64.S
arch/sparc/kernel/init_task.c
arch/sparc/kernel/iommu.c
arch/sparc/kernel/irq_64.c
arch/sparc/kernel/mdesc.c
arch/sparc/kernel/of_device_32.c
arch/sparc/kernel/of_device_64.c
arch/sparc/kernel/of_device_common.c [new file with mode: 0644]
arch/sparc/kernel/of_device_common.h [new file with mode: 0644]
arch/sparc/kernel/pci_sun4v.c
arch/sparc/kernel/prom.h
arch/sparc/kernel/prom_64.c
arch/sparc/kernel/prom_common.c
arch/sparc/kernel/smp_64.c
arch/sparc/kernel/systbls_32.S
arch/sparc/kernel/systbls_64.S
arch/sparc/kernel/traps_64.c
arch/sparc/mm/init_32.c
arch/sparc/mm/init_64.c
arch/sparc/mm/srmmu.c
arch/um/drivers/net_kern.c
arch/um/drivers/ubd_kern.c
arch/um/include/shared/init.h
arch/um/include/shared/net_user.h
arch/um/kernel/init_task.c
arch/um/kernel/irq.c
arch/um/sys-i386/stub.S
arch/um/sys-x86_64/asm/elf.h
arch/um/sys-x86_64/stub.S
arch/x86/Kconfig
arch/x86/Makefile
arch/x86/include/asm/dma-mapping.h
arch/x86/include/asm/kmap_types.h
arch/x86/include/asm/kmemcheck.h [new file with mode: 0644]
arch/x86/include/asm/pgtable.h
arch/x86/include/asm/pgtable_types.h
arch/x86/include/asm/string_32.h
arch/x86/include/asm/string_64.h
arch/x86/include/asm/thread_info.h
arch/x86/include/asm/timex.h
arch/x86/include/asm/xor.h
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/cpuid.c
arch/x86/kernel/i8253.c
arch/x86/kernel/init_task.c
arch/x86/kernel/microcode_core.c
arch/x86/kernel/msr.c
arch/x86/kernel/process.c
arch/x86/kernel/stacktrace.c
arch/x86/kernel/traps.c
arch/x86/kernel/tsc.c
arch/x86/kvm/vmx.c
arch/x86/mm/Makefile
arch/x86/mm/fault.c
arch/x86/mm/init.c
arch/x86/mm/init_32.c
arch/x86/mm/init_64.c
arch/x86/mm/kmemcheck/Makefile [new file with mode: 0644]
arch/x86/mm/kmemcheck/error.c [new file with mode: 0644]
arch/x86/mm/kmemcheck/error.h [new file with mode: 0644]
arch/x86/mm/kmemcheck/kmemcheck.c [new file with mode: 0644]
arch/x86/mm/kmemcheck/opcode.c [new file with mode: 0644]
arch/x86/mm/kmemcheck/opcode.h [new file with mode: 0644]
arch/x86/mm/kmemcheck/pte.c [new file with mode: 0644]
arch/x86/mm/kmemcheck/pte.h [new file with mode: 0644]
arch/x86/mm/kmemcheck/selftest.c [new file with mode: 0644]
arch/x86/mm/kmemcheck/selftest.h [new file with mode: 0644]
arch/x86/mm/kmemcheck/shadow.c [new file with mode: 0644]
arch/x86/mm/kmemcheck/shadow.h [new file with mode: 0644]
arch/x86/mm/pageattr.c
arch/x86/mm/pgtable.c
arch/xtensa/include/asm/kmap_types.h
arch/xtensa/kernel/init_task.c
block/blk-core.c
block/blk-settings.c
block/bsg.c
block/cfq-iosched.c
block/genhd.c
crypto/xor.c
drivers/Kconfig
drivers/Makefile
drivers/acpi/acpica/acevents.h
drivers/acpi/acpica/acglobal.h
drivers/acpi/acpica/aclocal.h
drivers/acpi/acpica/acnamesp.h
drivers/acpi/acpica/amlcode.h
drivers/acpi/acpica/dsobject.c
drivers/acpi/acpica/dsopcode.c
drivers/acpi/acpica/dswstate.c
drivers/acpi/acpica/evregion.c
drivers/acpi/acpica/evxfevnt.c
drivers/acpi/acpica/exconfig.c
drivers/acpi/acpica/excreate.c
drivers/acpi/acpica/exdump.c
drivers/acpi/acpica/exfldio.c
drivers/acpi/acpica/exmutex.c
drivers/acpi/acpica/exstore.c
drivers/acpi/acpica/hwregs.c
drivers/acpi/acpica/nsalloc.c
drivers/acpi/acpica/nsnames.c
drivers/acpi/acpica/nsobject.c
drivers/acpi/acpica/nspredef.c
drivers/acpi/acpica/nssearch.c
drivers/acpi/acpica/nswalk.c
drivers/acpi/acpica/nsxfname.c
drivers/acpi/acpica/nsxfobj.c
drivers/acpi/acpica/rscalc.c
drivers/acpi/acpica/rsxface.c
drivers/acpi/acpica/tbfadt.c
drivers/acpi/acpica/tbinstal.c
drivers/acpi/acpica/utcopy.c
drivers/acpi/acpica/utdebug.c
drivers/acpi/acpica/utdelete.c
drivers/acpi/acpica/utmisc.c
drivers/acpi/acpica/utmutex.c
drivers/base/core.c
drivers/base/dd.c
drivers/base/firmware_class.c
drivers/base/node.c
drivers/base/platform.c
drivers/base/sys.c
drivers/block/aoe/aoechr.c
drivers/block/cciss.c
drivers/block/mg_disk.c
drivers/block/pktcdvd.c
drivers/block/ps3disk.c
drivers/block/ps3vram.c
drivers/block/xen-blkfront.c
drivers/char/hvc_iucv.c
drivers/char/hvcs.c
drivers/char/hw_random/core.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/misc.c
drivers/char/ps3flash.c
drivers/char/pty.c
drivers/char/raw.c
drivers/char/tty_io.c
drivers/char/tty_ioctl.c
drivers/char/tty_ldisc.c
drivers/char/vt.c
drivers/clocksource/acpi_pm.c
drivers/clocksource/sh_cmt.c
drivers/clocksource/sh_mtu2.c
drivers/clocksource/sh_tmu.c
drivers/eisa/eisa.ids
drivers/eisa/pci_eisa.c
drivers/eisa/virtual_root.c
drivers/firewire/Makefile
drivers/firewire/core-card.c [moved from drivers/firewire/fw-card.c with 97% similarity]
drivers/firewire/core-cdev.c [moved from drivers/firewire/fw-cdev.c with 99% similarity]
drivers/firewire/core-device.c [moved from drivers/firewire/fw-device.c with 88% similarity]
drivers/firewire/core-iso.c [moved from drivers/firewire/fw-iso.c with 99% similarity]
drivers/firewire/core-topology.c [moved from drivers/firewire/fw-topology.c with 97% similarity]
drivers/firewire/core-transaction.c [moved from drivers/firewire/fw-transaction.c with 97% similarity]
drivers/firewire/core.h [new file with mode: 0644]
drivers/firewire/fw-device.h [deleted file]
drivers/firewire/fw-topology.h [deleted file]
drivers/firewire/fw-transaction.h [deleted file]
drivers/firewire/ohci.c [moved from drivers/firewire/fw-ohci.c with 99% similarity]
drivers/firewire/ohci.h [moved from drivers/firewire/fw-ohci.h with 98% similarity]
drivers/firewire/sbp2.c [moved from drivers/firewire/fw-sbp2.c with 96% similarity]
drivers/firmware/memmap.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/Makefile
drivers/gpu/drm/drm_debugfs.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_mm.c
drivers/gpu/drm/drm_stub.c
drivers/gpu/drm/drm_sysfs.c
drivers/gpu/drm/i915/intel_fb.c
drivers/gpu/drm/radeon/Kconfig [new file with mode: 0644]
drivers/gpu/drm/radeon/Makefile
drivers/gpu/drm/radeon/ObjectID.h [new file with mode: 0644]
drivers/gpu/drm/radeon/atom-bits.h [new file with mode: 0644]
drivers/gpu/drm/radeon/atom-names.h [new file with mode: 0644]
drivers/gpu/drm/radeon/atom-types.h [new file with mode: 0644]
drivers/gpu/drm/radeon/atom.c [new file with mode: 0644]
drivers/gpu/drm/radeon/atom.h [new file with mode: 0644]
drivers/gpu/drm/radeon/atombios.h [new file with mode: 0644]
drivers/gpu/drm/radeon/atombios_crtc.c [new file with mode: 0644]
drivers/gpu/drm/radeon/r100.c [new file with mode: 0644]
drivers/gpu/drm/radeon/r300.c [new file with mode: 0644]
drivers/gpu/drm/radeon/r300_reg.h
drivers/gpu/drm/radeon/r420.c [new file with mode: 0644]
drivers/gpu/drm/radeon/r500_reg.h [new file with mode: 0644]
drivers/gpu/drm/radeon/r520.c [new file with mode: 0644]
drivers/gpu/drm/radeon/r600.c [new file with mode: 0644]
drivers/gpu/drm/radeon/r600_reg.h [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon.h [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_agp.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_asic.h [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_atombios.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_benchmark.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_bios.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_clocks.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_combios.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_connectors.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_cs.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_cursor.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_device.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_display.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_encoders.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_fb.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_fence.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_fixed.h [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_gart.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_gem.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_i2c.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_irq_kms.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_kms.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_legacy_crtc.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_legacy_encoders.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_mode.h [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_object.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_object.h [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_reg.h [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_ring.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_ttm.c [new file with mode: 0644]
drivers/gpu/drm/radeon/rs400.c [new file with mode: 0644]
drivers/gpu/drm/radeon/rs600.c [new file with mode: 0644]
drivers/gpu/drm/radeon/rs690.c [new file with mode: 0644]
drivers/gpu/drm/radeon/rs780.c [new file with mode: 0644]
drivers/gpu/drm/radeon/rv515.c [new file with mode: 0644]
drivers/gpu/drm/radeon/rv770.c [new file with mode: 0644]
drivers/gpu/drm/ttm/Makefile [new file with mode: 0644]
drivers/gpu/drm/ttm/ttm_agp_backend.c [new file with mode: 0644]
drivers/gpu/drm/ttm/ttm_bo.c [new file with mode: 0644]
drivers/gpu/drm/ttm/ttm_bo_util.c [new file with mode: 0644]
drivers/gpu/drm/ttm/ttm_bo_vm.c [new file with mode: 0644]
drivers/gpu/drm/ttm/ttm_global.c [new file with mode: 0644]
drivers/gpu/drm/ttm/ttm_memory.c [new file with mode: 0644]
drivers/gpu/drm/ttm/ttm_module.c [new file with mode: 0644]
drivers/gpu/drm/ttm/ttm_tt.c [new file with mode: 0644]
drivers/hid/usbhid/hiddev.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/f71882fg.c
drivers/hwmon/hp_accel.c
drivers/hwmon/hwmon.c
drivers/hwmon/ibmaem.c
drivers/hwmon/lis3lv02d.c
drivers/hwmon/lis3lv02d.h
drivers/hwmon/lis3lv02d_spi.c
drivers/hwmon/max6650.c
drivers/hwmon/sht15.c
drivers/hwmon/tmp401.c [new file with mode: 0644]
drivers/hwmon/w83627ehf.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-at91.c
drivers/i2c/busses/i2c-au1550.c
drivers/i2c/busses/i2c-bfin-twi.c
drivers/i2c/busses/i2c-highlander.c
drivers/i2c/busses/i2c-mv64xxx.c
drivers/i2c/busses/i2c-ocores.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/busses/i2c-pca-platform.c
drivers/i2c/busses/i2c-pmcmsp.c
drivers/i2c/busses/i2c-pxa.c
drivers/i2c/busses/i2c-s3c2410.c
drivers/i2c/busses/i2c-stu300.c [new file with mode: 0644]
drivers/i2c/busses/i2c-versatile.c
drivers/i2c/busses/i2c-viapro.c
drivers/i2c/busses/i2c-voodoo3.c
drivers/i2c/chips/Kconfig
drivers/i2c/chips/Makefile
drivers/i2c/i2c-core.c
drivers/ide/ide-pm.c
drivers/ide/ide-probe.c
drivers/ide/ide_platform.c
drivers/ieee1394/csr1212.c
drivers/ieee1394/eth1394.c
drivers/ieee1394/nodemgr.c
drivers/ieee1394/sbp2.c
drivers/infiniband/core/sysfs.c
drivers/infiniband/hw/ehca/ehca_main.c
drivers/input/input.c
drivers/input/joystick/analog.c
drivers/input/misc/pcspkr.c
drivers/input/touchscreen/wm97xx-core.c
drivers/input/xen-kbdfront.c
drivers/macintosh/therm_adt746x.c
drivers/macintosh/therm_pm72.c
drivers/macintosh/therm_windtunnel.c
drivers/macintosh/windfarm_lm75_sensor.c
drivers/macintosh/windfarm_max6690_sensor.c
drivers/macintosh/windfarm_smu_sat.c
drivers/md/dm-ioctl.c
drivers/md/dm.c
drivers/media/Kconfig
drivers/media/common/tuners/tuner-simple.c
drivers/media/common/tuners/tuner-types.c
drivers/media/common/tuners/tuner-xc2028.c
drivers/media/common/tuners/xc5000.c
drivers/media/dvb/b2c2/flexcop-common.h
drivers/media/dvb/b2c2/flexcop-fe-tuner.c
drivers/media/dvb/b2c2/flexcop-i2c.c
drivers/media/dvb/b2c2/flexcop-misc.c
drivers/media/dvb/bt8xx/bt878.c
drivers/media/dvb/dm1105/dm1105.c
drivers/media/dvb/dvb-core/dmxdev.c
drivers/media/dvb/dvb-core/dvb_demux.c
drivers/media/dvb/dvb-core/dvb_demux.h
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvbdev.c
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/dvb/dvb-usb/af9015.c
drivers/media/dvb/dvb-usb/dib0700_devices.c
drivers/media/dvb/dvb-usb/dibusb-common.c
drivers/media/dvb/dvb-usb/dvb-usb-ids.h
drivers/media/dvb/dvb-usb/dvb-usb.h
drivers/media/dvb/dvb-usb/dw2102.c
drivers/media/dvb/dvb-usb/dw2102.h
drivers/media/dvb/dvb-usb/gp8psk.c
drivers/media/dvb/firewire/firedtv-1394.c
drivers/media/dvb/firewire/firedtv-dvb.c
drivers/media/dvb/firewire/firedtv-rc.c
drivers/media/dvb/frontends/Kconfig
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/frontends/af9013.c
drivers/media/dvb/frontends/au8522_dig.c
drivers/media/dvb/frontends/cx24116.c
drivers/media/dvb/frontends/drx397xD.c
drivers/media/dvb/frontends/isl6423.c [new file with mode: 0644]
drivers/media/dvb/frontends/isl6423.h [new file with mode: 0644]
drivers/media/dvb/frontends/lgdt3305.c
drivers/media/dvb/frontends/lgs8gxx.c
drivers/media/dvb/frontends/lnbp21.c
drivers/media/dvb/frontends/mt312.c
drivers/media/dvb/frontends/nxt200x.c
drivers/media/dvb/frontends/or51132.c
drivers/media/dvb/frontends/stv0900_priv.h
drivers/media/dvb/frontends/stv090x.c [new file with mode: 0644]
drivers/media/dvb/frontends/stv090x.h [new file with mode: 0644]
drivers/media/dvb/frontends/stv090x_priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/stv090x_reg.h [new file with mode: 0644]
drivers/media/dvb/frontends/stv6110x.c [new file with mode: 0644]
drivers/media/dvb/frontends/stv6110x.h [new file with mode: 0644]
drivers/media/dvb/frontends/stv6110x_priv.h [new file with mode: 0644]
drivers/media/dvb/frontends/stv6110x_reg.h [new file with mode: 0644]
drivers/media/dvb/frontends/tda10048.c
drivers/media/dvb/frontends/tda10048.h
drivers/media/dvb/siano/Makefile
drivers/media/dvb/siano/sms-cards.c
drivers/media/dvb/siano/sms-cards.h
drivers/media/dvb/siano/smscoreapi.c
drivers/media/dvb/siano/smscoreapi.h
drivers/media/dvb/siano/smsdvb.c
drivers/media/dvb/siano/smsendian.c [new file with mode: 0644]
drivers/media/dvb/siano/smsendian.h [new file with mode: 0644]
drivers/media/dvb/siano/smsir.c [new file with mode: 0644]
drivers/media/dvb/siano/smsir.h [new file with mode: 0644]
drivers/media/dvb/siano/smssdio.c [new file with mode: 0644]
drivers/media/dvb/siano/smsusb.c
drivers/media/dvb/ttpci/av7110_av.c
drivers/media/dvb/ttpci/av7110_hw.c
drivers/media/dvb/ttpci/av7110_v4l.c
drivers/media/dvb/ttpci/budget-av.c
drivers/media/dvb/ttpci/budget.c
drivers/media/radio/dsbr100.c
drivers/media/radio/radio-mr800.c
drivers/media/radio/radio-sf16fmi.c
drivers/media/radio/radio-sf16fmr2.c
drivers/media/radio/radio-si470x.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/adv7343.c [new file with mode: 0644]
drivers/media/video/adv7343_regs.h [new file with mode: 0644]
drivers/media/video/au0828/au0828-cards.c
drivers/media/video/au0828/au0828-core.c
drivers/media/video/au0828/au0828-video.c
drivers/media/video/bt8xx/bttv-driver.c
drivers/media/video/bt8xx/bttv-i2c.c
drivers/media/video/cpia2/cpia2_v4l.c
drivers/media/video/cx18/cx18-audio.c
drivers/media/video/cx18/cx18-av-core.c
drivers/media/video/cx18/cx18-av-firmware.c
drivers/media/video/cx18/cx18-av-vbi.c
drivers/media/video/cx18/cx18-cards.c
drivers/media/video/cx18/cx18-controls.c
drivers/media/video/cx18/cx18-driver.c
drivers/media/video/cx18/cx18-driver.h
drivers/media/video/cx18/cx18-dvb.c
drivers/media/video/cx18/cx18-fileops.c
drivers/media/video/cx18/cx18-mailbox.c
drivers/media/video/cx18/cx18-mailbox.h
drivers/media/video/cx18/cx18-queue.c
drivers/media/video/cx18/cx18-streams.c
drivers/media/video/cx18/cx18-streams.h
drivers/media/video/cx18/cx18-version.h
drivers/media/video/cx231xx/cx231xx-avcore.c
drivers/media/video/cx231xx/cx231xx-cards.c
drivers/media/video/cx231xx/cx231xx-i2c.c
drivers/media/video/cx231xx/cx231xx-input.c
drivers/media/video/cx231xx/cx231xx-vbi.c
drivers/media/video/cx231xx/cx231xx.h
drivers/media/video/cx23885/cimax2.c
drivers/media/video/cx23885/cx23885-417.c
drivers/media/video/cx23885/cx23885-cards.c
drivers/media/video/cx23885/cx23885-core.c
drivers/media/video/cx23885/cx23885-dvb.c
drivers/media/video/cx23885/cx23885-i2c.c
drivers/media/video/cx23885/cx23885-video.c
drivers/media/video/cx23885/cx23885.h
drivers/media/video/cx88/Makefile
drivers/media/video/cx88/cx88-alsa.c
drivers/media/video/cx88/cx88-cards.c
drivers/media/video/cx88/cx88-core.c
drivers/media/video/cx88/cx88-dsp.c [new file with mode: 0644]
drivers/media/video/cx88/cx88-dvb.c
drivers/media/video/cx88/cx88-i2c.c
drivers/media/video/cx88/cx88-input.c
drivers/media/video/cx88/cx88-tvaudio.c
drivers/media/video/cx88/cx88-video.c
drivers/media/video/cx88/cx88.h
drivers/media/video/dabusb.c
drivers/media/video/em28xx/em28xx-audio.c
drivers/media/video/em28xx/em28xx-cards.c
drivers/media/video/em28xx/em28xx-core.c
drivers/media/video/em28xx/em28xx-dvb.c
drivers/media/video/em28xx/em28xx-i2c.c
drivers/media/video/em28xx/em28xx-input.c
drivers/media/video/em28xx/em28xx-reg.h
drivers/media/video/em28xx/em28xx.h
drivers/media/video/gspca/finepix.c
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/gspca.h
drivers/media/video/gspca/m5602/Makefile
drivers/media/video/gspca/m5602/m5602_bridge.h
drivers/media/video/gspca/m5602/m5602_core.c
drivers/media/video/gspca/m5602/m5602_mt9m111.c
drivers/media/video/gspca/m5602/m5602_mt9m111.h
drivers/media/video/gspca/m5602/m5602_ov7660.c [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_ov7660.h [new file with mode: 0644]
drivers/media/video/gspca/m5602/m5602_ov9650.c
drivers/media/video/gspca/m5602/m5602_ov9650.h
drivers/media/video/gspca/m5602/m5602_po1030.c
drivers/media/video/gspca/m5602/m5602_po1030.h
drivers/media/video/gspca/m5602/m5602_s5k4aa.c
drivers/media/video/gspca/m5602/m5602_s5k4aa.h
drivers/media/video/gspca/m5602/m5602_s5k83a.c
drivers/media/video/gspca/m5602/m5602_s5k83a.h
drivers/media/video/gspca/m5602/m5602_sensor.h
drivers/media/video/gspca/mr97310a.c
drivers/media/video/gspca/ov519.c
drivers/media/video/gspca/ov534.c
drivers/media/video/gspca/sonixb.c
drivers/media/video/gspca/sonixj.c
drivers/media/video/gspca/spca500.c
drivers/media/video/gspca/spca505.c
drivers/media/video/gspca/spca508.c
drivers/media/video/gspca/spca561.c
drivers/media/video/gspca/sq905.c
drivers/media/video/gspca/sq905c.c
drivers/media/video/gspca/stv06xx/stv06xx.c
drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
drivers/media/video/gspca/sunplus.c
drivers/media/video/gspca/t613.c
drivers/media/video/gspca/vc032x.c
drivers/media/video/gspca/zc3xx.c
drivers/media/video/hexium_gemini.c
drivers/media/video/hexium_orion.c
drivers/media/video/ir-kbd-i2c.c
drivers/media/video/ivtv/ivtv-driver.c
drivers/media/video/ivtv/ivtv-i2c.c
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/mt9m001.c
drivers/media/video/mt9m111.c
drivers/media/video/mt9t031.c
drivers/media/video/mt9v022.c
drivers/media/video/mx1_camera.c
drivers/media/video/mx3_camera.c
drivers/media/video/mxb.c
drivers/media/video/ov511.c
drivers/media/video/ov511.h
drivers/media/video/ov772x.c
drivers/media/video/pvrusb2/pvrusb2-devattr.c
drivers/media/video/pvrusb2/pvrusb2-devattr.h
drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
drivers/media/video/pvrusb2/pvrusb2-hdw.c
drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
drivers/media/video/pvrusb2/pvrusb2-sysfs.c
drivers/media/video/pvrusb2/pvrusb2-v4l2.c
drivers/media/video/pwc/pwc-if.c
drivers/media/video/pwc/pwc-v4l.c
drivers/media/video/pxa_camera.c
drivers/media/video/s2255drv.c
drivers/media/video/saa7134/Kconfig
drivers/media/video/saa7134/Makefile
drivers/media/video/saa7134/saa7134-cards.c
drivers/media/video/saa7134/saa7134-core.c
drivers/media/video/saa7134/saa7134-dvb.c
drivers/media/video/saa7134/saa7134-empress.c
drivers/media/video/saa7134/saa7134-i2c.c
drivers/media/video/saa7134/saa7134-input.c
drivers/media/video/saa7134/saa7134-ts.c
drivers/media/video/saa7134/saa7134-video.c
drivers/media/video/saa7134/saa7134.h
drivers/media/video/se401.c
drivers/media/video/se401.h
drivers/media/video/sh_mobile_ceu_camera.c
drivers/media/video/soc_camera.c
drivers/media/video/stk-webcam.c
drivers/media/video/tda7432.c
drivers/media/video/tea6415c.c
drivers/media/video/tea6420.c
drivers/media/video/ths7303.c [new file with mode: 0644]
drivers/media/video/tuner-core.c
drivers/media/video/tveeprom.c
drivers/media/video/tvp514x.c
drivers/media/video/tw9910.c
drivers/media/video/usbvideo/konicawc.c
drivers/media/video/usbvideo/quickcam_messenger.c
drivers/media/video/usbvision/usbvision-core.c
drivers/media/video/usbvision/usbvision-video.c
drivers/media/video/uvc/uvc_ctrl.c
drivers/media/video/uvc/uvc_driver.c
drivers/media/video/uvc/uvc_queue.c
drivers/media/video/uvc/uvc_status.c
drivers/media/video/uvc/uvc_v4l2.c
drivers/media/video/uvc/uvc_video.c
drivers/media/video/uvc/uvcvideo.h
drivers/media/video/v4l2-common.c
drivers/media/video/v4l2-device.c
drivers/media/video/videobuf-core.c
drivers/media/video/videobuf-dma-contig.c
drivers/media/video/videobuf-dma-sg.c
drivers/media/video/vino.c
drivers/media/video/zoran/zoran_card.c
drivers/media/video/zr364xx.c
drivers/mfd/htc-pasic3.c
drivers/mfd/pcf50633-core.c
drivers/mfd/wm8400-core.c
drivers/misc/c2port/core.c
drivers/misc/eeprom/Kconfig
drivers/misc/eeprom/Makefile
drivers/misc/eeprom/max6875.c [moved from drivers/i2c/chips/max6875.c with 99% similarity]
drivers/misc/sgi-gru/grufile.c
drivers/misc/sgi-xp/xpc_uv.c
drivers/net/Kconfig
drivers/net/ps3_gelic_net.c
drivers/net/tun.c
drivers/net/wimax/i2400m/i2400m.h
drivers/net/wireless/ath/ath5k/Kconfig
drivers/net/wireless/libertas/README
drivers/net/wireless/libertas/if_spi.c
drivers/net/wireless/libertas/if_spi.h
drivers/net/wireless/libertas/if_usb.c
drivers/net/xen-netfront.c
drivers/parisc/eisa.c
drivers/parisc/sba_iommu.c
drivers/parport/parport_gsc.c
drivers/pci/pci.c
drivers/pci/pcie/portdrv_core.c
drivers/pcmcia/ds.c
drivers/pcmcia/pcmcia_ioctl.c
drivers/ps3/ps3-sys-manager.c
drivers/ps3/ps3av.c
drivers/ps3/ps3av_cmd.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_devmap.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_fba.c
drivers/s390/block/dasd_int.h
drivers/s390/block/dcssblk.c
drivers/s390/block/xpram.c
drivers/s390/char/con3215.c
drivers/s390/char/con3270.c
drivers/s390/char/fs3270.c
drivers/s390/char/monreader.c
drivers/s390/char/monwriter.c
drivers/s390/char/raw3270.c
drivers/s390/char/raw3270.h
drivers/s390/char/sclp.c
drivers/s390/char/sclp.h
drivers/s390/char/sclp_cmd.c
drivers/s390/char/sclp_con.c
drivers/s390/char/sclp_rw.c
drivers/s390/char/sclp_rw.h
drivers/s390/char/sclp_vt220.c
drivers/s390/char/tape.h
drivers/s390/char/tape_34xx.c
drivers/s390/char/tape_3590.c
drivers/s390/char/tape_core.c
drivers/s390/char/vmlogrdr.c
drivers/s390/char/vmur.c
drivers/s390/char/vmwatchdog.c
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/chsc.c
drivers/s390/cio/chsc.h
drivers/s390/cio/chsc_sch.c
drivers/s390/cio/cmf.c
drivers/s390/cio/css.c
drivers/s390/cio/css.h
drivers/s390/cio/device.c
drivers/s390/cio/device.h
drivers/s390/cio/device_fsm.c
drivers/s390/cio/device_ops.c
drivers/s390/cio/io_sch.h
drivers/s390/net/claw.c
drivers/s390/net/ctcm_main.c
drivers/s390/net/lcs.c
drivers/s390/net/lcs.h
drivers/s390/net/netiucv.c
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3_main.c
drivers/s390/net/smsgiucv.c
drivers/s390/scsi/zfcp_ccw.c
drivers/sbus/char/openprom.c
drivers/scsi/aha1740.c
drivers/scsi/ibmvscsi/ibmvscsi.c
drivers/scsi/ibmvscsi/ibmvstgt.c
drivers/scsi/libsrp.c
drivers/scsi/lpfc/lpfc_debugfs.c
drivers/serial/atmel_serial.c
drivers/serial/imx.c
drivers/serial/of_serial.c
drivers/serial/sh-sci.c
drivers/sh/intc.c
drivers/spi/spi_bfin5xx.c
drivers/spi/spi_mpc83xx.c
drivers/staging/Kconfig
drivers/staging/uc2322/aten2011.c
drivers/thermal/thermal_sys.c
drivers/usb/Kconfig
drivers/usb/Makefile
drivers/usb/atm/ueagle-atm.c
drivers/usb/class/cdc-acm.c
drivers/usb/class/cdc-acm.h
drivers/usb/class/usblp.c
drivers/usb/class/usbtmc.c
drivers/usb/core/Kconfig
drivers/usb/core/Makefile
drivers/usb/core/config.c
drivers/usb/core/driver.c
drivers/usb/core/endpoint.c
drivers/usb/core/file.c
drivers/usb/core/hcd-pci.c
drivers/usb/core/hcd.c
drivers/usb/core/hcd.h
drivers/usb/core/hub.c
drivers/usb/core/hub.h
drivers/usb/core/message.c
drivers/usb/core/sysfs.c
drivers/usb/core/urb.c
drivers/usb/core/usb.c
drivers/usb/core/usb.h
drivers/usb/gadget/Kconfig
drivers/usb/gadget/Makefile
drivers/usb/gadget/at91_udc.c
drivers/usb/gadget/atmel_usba_udc.c
drivers/usb/gadget/audio.c [new file with mode: 0644]
drivers/usb/gadget/ci13xxx_udc.c
drivers/usb/gadget/f_audio.c [new file with mode: 0644]
drivers/usb/gadget/f_rndis.c
drivers/usb/gadget/file_storage.c
drivers/usb/gadget/fsl_mx3_udc.c [new file with mode: 0644]
drivers/usb/gadget/fsl_udc_core.c [moved from drivers/usb/gadget/fsl_usb2_udc.c with 99% similarity]
drivers/usb/gadget/fsl_usb2_udc.h
drivers/usb/gadget/gadget_chips.h
drivers/usb/gadget/goku_udc.c
drivers/usb/gadget/imx_udc.c
drivers/usb/gadget/inode.c
drivers/usb/gadget/langwell_udc.c [new file with mode: 0644]
drivers/usb/gadget/langwell_udc.h [new file with mode: 0644]
drivers/usb/gadget/pxa27x_udc.c
drivers/usb/gadget/pxa27x_udc.h
drivers/usb/gadget/s3c-hsotg.c [new file with mode: 0644]
drivers/usb/gadget/u_audio.c [new file with mode: 0644]
drivers/usb/gadget/u_audio.h [new file with mode: 0644]
drivers/usb/gadget/u_serial.c
drivers/usb/host/Kconfig
drivers/usb/host/Makefile
drivers/usb/host/ehci-au1xxx.c
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/ehci-ixp4xx.c
drivers/usb/host/ehci-orion.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-ppc-of.c
drivers/usb/host/ehci-ps3.c
drivers/usb/host/ehci-q.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/ehci.h
drivers/usb/host/fhci-dbg.c
drivers/usb/host/hwa-hc.c
drivers/usb/host/ohci-dbg.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-pci.c
drivers/usb/host/ohci-ps3.c
drivers/usb/host/pci-quirks.c
drivers/usb/host/r8a66597-hcd.c
drivers/usb/host/r8a66597.h
drivers/usb/host/uhci-hcd.c
drivers/usb/host/uhci-q.c
drivers/usb/host/xhci-dbg.c [new file with mode: 0644]
drivers/usb/host/xhci-ext-caps.h [new file with mode: 0644]
drivers/usb/host/xhci-hcd.c [new file with mode: 0644]
drivers/usb/host/xhci-hub.c [new file with mode: 0644]
drivers/usb/host/xhci-mem.c [new file with mode: 0644]
drivers/usb/host/xhci-pci.c [new file with mode: 0644]
drivers/usb/host/xhci-ring.c [new file with mode: 0644]
drivers/usb/host/xhci.h [new file with mode: 0644]
drivers/usb/misc/iowarrior.c
drivers/usb/misc/legousbtower.c
drivers/usb/misc/sisusbvga/Kconfig
drivers/usb/misc/usbtest.c
drivers/usb/mon/mon_text.c
drivers/usb/musb/Kconfig
drivers/usb/musb/blackfin.c
drivers/usb/musb/cppi_dma.c
drivers/usb/musb/cppi_dma.h
drivers/usb/musb/davinci.c
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_core.h
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/musb_gadget_ep0.c
drivers/usb/musb/musb_host.c
drivers/usb/musb/musb_host.h
drivers/usb/musb/musb_virthub.c
drivers/usb/musb/omap2430.c
drivers/usb/musb/tusb6010.c
drivers/usb/otg/Kconfig
drivers/usb/otg/Makefile
drivers/usb/otg/langwell_otg.c [new file with mode: 0644]
drivers/usb/otg/nop-usb-xceiv.c
drivers/usb/otg/twl4030-usb.c
drivers/usb/serial/aircable.c
drivers/usb/serial/belkin_sa.c
drivers/usb/serial/bus.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/cyberjack.c
drivers/usb/serial/cypress_m8.c
drivers/usb/serial/digi_acceleport.c
drivers/usb/serial/empeg.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio.h
drivers/usb/serial/garmin_gps.c
drivers/usb/serial/generic.c
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/io_tables.h
drivers/usb/serial/io_ti.c
drivers/usb/serial/ipaq.c
drivers/usb/serial/iuu_phoenix.c
drivers/usb/serial/keyspan.c
drivers/usb/serial/keyspan.h
drivers/usb/serial/keyspan_pda.c
drivers/usb/serial/kl5kusb105.c
drivers/usb/serial/kobil_sct.c
drivers/usb/serial/mct_u232.c
drivers/usb/serial/mos7720.c
drivers/usb/serial/mos7840.c
drivers/usb/serial/omninet.c
drivers/usb/serial/opticon.c
drivers/usb/serial/option.c
drivers/usb/serial/oti6858.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/sierra.c
drivers/usb/serial/spcp8x5.c
drivers/usb/serial/symbolserial.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/usb_debug.c
drivers/usb/serial/visor.c
drivers/usb/serial/whiteheat.c
drivers/usb/storage/initializers.c
drivers/usb/storage/option_ms.c
drivers/usb/storage/sierra_ms.c
drivers/usb/storage/unusual_devs.h
drivers/video/Kconfig
drivers/video/acornfb.c
drivers/video/atmel_lcdfb.c
drivers/video/aty/radeon_pm.c
drivers/video/bf54x-lq043fb.c
drivers/video/bfin-t350mcqb-fb.c
drivers/video/bw2.c
drivers/video/carminefb.c
drivers/video/cg14.c
drivers/video/cg3.c
drivers/video/cg6.c
drivers/video/chipsfb.c
drivers/video/efifb.c
drivers/video/fbmem.c
drivers/video/igafb.c
drivers/video/intelfb/intelfbdrv.c
drivers/video/leo.c
drivers/video/logo/Makefile
drivers/video/logo/logo.c
drivers/video/mb862xx/mb862xxfb.c
drivers/video/modedb.c
drivers/video/offb.c
drivers/video/p9100.c
drivers/video/pm2fb.c
drivers/video/ps3fb.c
drivers/video/s1d13xxxfb.c
drivers/video/s3c-fb.c
drivers/video/s3c2410fb.c
drivers/video/s3c2410fb.h
drivers/video/sis/sis_main.c
drivers/video/stifb.c
drivers/video/tcx.c
drivers/video/tdfxfb.c
drivers/video/vesafb.c
drivers/video/xen-fbfront.c
drivers/vlynq/Kconfig [new file with mode: 0644]
drivers/vlynq/Makefile [new file with mode: 0644]
drivers/vlynq/vlynq.c [new file with mode: 0644]
fs/Kconfig
fs/afs/misc.c
fs/afs/vlocation.c
fs/befs/linuxvfs.c
fs/bio.c
fs/btrfs/disk-io.c
fs/btrfs/transaction.c
fs/debugfs/file.c
fs/debugfs/inode.c
fs/drop_caches.c
fs/fat/cache.c
fs/fat/dir.c
fs/fat/fat.h
fs/fat/fatent.c
fs/fat/file.c
fs/fat/inode.c
fs/fat/misc.c
fs/fat/namei_msdos.c
fs/fat/namei_vfat.c
fs/fcntl.c
fs/fs-writeback.c
fs/isofs/joliet.c
fs/jfs/jfs_extent.c
fs/ncpfs/ncplib_kernel.c
fs/nfs/iostat.h
fs/nls/nls_base.c
fs/nls/nls_utf8.c
fs/ntfs/inode.c
fs/ntfs/logfile.c
fs/ocfs2/alloc.c
fs/ocfs2/blockcheck.c
fs/ocfs2/blockcheck.h
fs/ocfs2/cluster/masklog.h
fs/ocfs2/cluster/tcp.c
fs/ocfs2/dir.c
fs/ocfs2/dlmglue.c
fs/ocfs2/dlmglue.h
fs/ocfs2/file.c
fs/ocfs2/journal.c
fs/ocfs2/journal.h
fs/ocfs2/ocfs2.h
fs/ocfs2/ocfs2_lockid.h
fs/ocfs2/quota_global.c
fs/ocfs2/quota_local.c
fs/ocfs2/super.c
fs/ocfs2/xattr.c
fs/proc/base.c
fs/proc/meminfo.c
fs/proc/page.c
fs/select.c
fs/sysfs/symlink.c
fs/ubifs/super.c
include/acpi/acpixf.h
include/acpi/actypes.h
include/acpi/platform/acgcc.h
include/acpi/platform/aclinux.h
include/asm-generic/atomic64.h [new file with mode: 0644]
include/asm-generic/kmap_types.h
include/drm/drm_pciids.h
include/drm/radeon_drm.h
include/drm/ttm/ttm_bo_api.h [new file with mode: 0644]
include/drm/ttm/ttm_bo_driver.h [new file with mode: 0644]
include/drm/ttm/ttm_memory.h [new file with mode: 0644]
include/drm/ttm/ttm_module.h [new file with mode: 0644]
include/drm/ttm/ttm_placement.h [new file with mode: 0644]
include/linux/bio.h
include/linux/blkdev.h
include/linux/bug.h
include/linux/c2port.h
include/linux/cpuset.h
include/linux/device.h
include/linux/eisa.h
include/linux/fb.h
include/linux/firewire.h [new file with mode: 0644]
include/linux/firmware-map.h
include/linux/firmware.h
include/linux/fs.h
include/linux/genhd.h
include/linux/gfp.h
include/linux/highmem.h
include/linux/hugetlb.h
include/linux/init.h
include/linux/init_task.h
include/linux/interrupt.h
include/linux/kernel.h
include/linux/kmemcheck.h [new file with mode: 0644]
include/linux/linux_logo.h
include/linux/lis3lv02d.h [new file with mode: 0644]
include/linux/major.h
include/linux/memcontrol.h
include/linux/mg_disk.h [new file with mode: 0644]
include/linux/miscdevice.h
include/linux/mm.h
include/linux/mm_types.h
include/linux/mmc/sdio_ids.h
include/linux/mmzone.h
include/linux/module.h
include/linux/nls.h
include/linux/nodemask.h
include/linux/page-flags.h
include/linux/pagemap.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/platform_device.h
include/linux/poll.h
include/linux/radix-tree.h
include/linux/ring_buffer.h
include/linux/rmap.h
include/linux/sched.h
include/linux/skbuff.h
include/linux/slab.h
include/linux/slab_def.h
include/linux/smp.h
include/linux/stacktrace.h
include/linux/swap.h
include/linux/syscalls.h
include/linux/timex.h
include/linux/tracepoint.h
include/linux/usb.h
include/linux/usb/audio.h
include/linux/usb/ch9.h
include/linux/usb/composite.h
include/linux/usb/langwell_otg.h [new file with mode: 0644]
include/linux/usb/langwell_udc.h [new file with mode: 0644]
include/linux/usb/otg.h
include/linux/usb/r8a66597.h [new file with mode: 0644]
include/linux/usb/serial.h
include/linux/utsname.h
include/linux/videodev2.h
include/linux/vlynq.h [new file with mode: 0644]
include/linux/vmstat.h
include/media/adv7343.h [new file with mode: 0644]
include/media/ir-kbd-i2c.h
include/media/soc_camera.h
include/media/tuner.h
include/media/v4l2-chip-ident.h
include/media/v4l2-device.h
include/media/v4l2-subdev.h
include/net/inet_sock.h
include/net/inet_timewait_sock.h
include/net/sock.h
include/video/s1d13xxxfb.h
init/Kconfig
init/do_mounts.c
init/main.c
kernel/Makefile
kernel/cpuset.c
kernel/fork.c
kernel/groups.c [new file with mode: 0644]
kernel/kfifo.c
kernel/kthread.c
kernel/module.c
kernel/power/process.c
kernel/printk.c
kernel/profile.c
kernel/signal.c
kernel/slow-work.c
kernel/softirq.c
kernel/sys.c
kernel/sysctl.c
kernel/trace/Kconfig
kernel/trace/ring_buffer.c
kernel/trace/trace.c
kernel/user.c
lib/Kconfig
lib/Kconfig.debug
lib/Kconfig.kmemcheck [new file with mode: 0644]
lib/Makefile
lib/atomic64.c [new file with mode: 0644]
lib/dec_and_lock.c
lib/genalloc.c
lib/hexdump.c
lib/kobject.c
lib/radix-tree.c
lib/rbtree.c
mm/Kconfig
mm/Kconfig.debug
mm/Makefile
mm/bounce.c
mm/fadvise.c
mm/filemap.c
mm/highmem.c
mm/hugetlb.c
mm/init-mm.c [new file with mode: 0644]
mm/internal.h
mm/kmemcheck.c [new file with mode: 0644]
mm/madvise.c
mm/memcontrol.c
mm/memory.c
mm/memory_hotplug.c
mm/mempolicy.c
mm/migrate.c
mm/mlock.c
mm/oom_kill.c
mm/page-writeback.c
mm/page_alloc.c
mm/page_io.c
mm/readahead.c
mm/rmap.c
mm/shmem.c
mm/slab.c
mm/slob.c
mm/slub.c
mm/swap_state.c
mm/swapfile.c
mm/truncate.c
mm/util.c
mm/vmscan.c
mm/vmstat.c
net/core/skbuff.c
net/core/sock.c
net/ipv4/inet_timewait_sock.c
net/iucv/af_iucv.c
net/iucv/iucv.c
net/rxrpc/ar-connection.c
net/rxrpc/ar-connevent.c
net/sunrpc/svc.c
samples/Kconfig
samples/firmware_class/firmware_sample_driver.c [deleted file]
samples/firmware_class/firmware_sample_firmware_class.c [deleted file]
scripts/get_maintainer.pl
scripts/gfp-translate [new file with mode: 0644]
scripts/pnmtologo.c
scripts/recordmcount.pl
scripts/tracing/draw_functrace.py
sound/drivers/pcsp/pcsp.h
sound/oss/pas2_pcm.c
sound/pci/ctxfi/ctatc.c
sound/pci/ctxfi/ctatc.h
sound/pci/ctxfi/cttimer.c
sound/pci/hda/patch_realtek.c
sound/pci/intel8x0.c
sound/soc/codecs/ssm2602.c
sound/soc/codecs/wm8903.c
sound/soc/pxa/magician.c
sound/soc/soc-core.c
sound/sound_core.c
sound/usb/usbquirks.h

index 7f5f218015feb8beed681fa7742caced8ac4c76f..08ff908aa7a239732fce68cc1b06e507626f216a 100644 (file)
       number of errors are printk'ed including a full stack trace.
     </para>
     <para>
-      The statistics are available via debugfs/debug_objects/stats.
+      The statistics are available via /sys/kernel/debug/debug_objects/stats.
       They provide information about the number of warnings and the
       number of successful fixups along with information about the
       usage of the internal tracking objects and the state of the
index 7ea231172c850db1a7eed7127d0bb8a036e56364..aa73e72fd793896cbb70fa85505d5f6a7b76d80a 100644 (file)
@@ -246,7 +246,8 @@ void print_ioacct(struct taskstats *t)
 
 int main(int argc, char *argv[])
 {
-       int c, rc, rep_len, aggr_len, len2, cmd_type;
+       int c, rc, rep_len, aggr_len, len2;
+       int cmd_type = TASKSTATS_CMD_ATTR_UNSPEC;
        __u16 id;
        __u32 mypid;
 
index 4ef245010457fc9301f21f6e78f2b1fc16c1d014..396bec3b74ed12ca1ddbfe980f9ffd4ca4d91308 100644 (file)
@@ -229,10 +229,10 @@ kernel.  It is the use of atomic counters to implement reference
 counting, and it works such that once the counter falls to zero it can
 be guaranteed that no other entity can be accessing the object:
 
-static void obj_list_add(struct obj *obj)
+static void obj_list_add(struct obj *obj, struct list_head *head)
 {
        obj->active = 1;
-       list_add(&obj->list);
+       list_add(&obj->list, head);
 }
 
 static void obj_list_del(struct obj *obj)
index cf1f8126991c00fe5f904631d0471821bf958515..1c407778c8b26213a69984e03a94d34a4fe16d82 100644 (file)
@@ -117,7 +117,7 @@ Using the pktcdvd debugfs interface
 
 To read pktcdvd device infos in human readable form, do:
 
-       # cat /debug/pktcdvd/pktcdvd[0-7]/info
+       # cat /sys/kernel/debug/pktcdvd/pktcdvd[0-7]/info
 
 For a description of the debugfs interface look into the file:
 
index a7cbfff40d077047f76463377381b269b5d41fc4..a124f3126b0d1f4f495c982a03df6e12f743b87b 100644 (file)
@@ -162,3 +162,35 @@ device_remove_file(dev,&dev_attr_power);
 
 The file name will be 'power' with a mode of 0644 (-rw-r--r--).
 
+Word of warning:  While the kernel allows device_create_file() and
+device_remove_file() to be called on a device at any time, userspace has
+strict expectations on when attributes get created.  When a new device is
+registered in the kernel, a uevent is generated to notify userspace (like
+udev) that a new device is available.  If attributes are added after the
+device is registered, then userspace won't get notified and userspace will
+not know about the new attributes.
+
+This is important for device driver that need to publish additional
+attributes for a device at driver probe time.  If the device driver simply
+calls device_create_file() on the device structure passed to it, then
+userspace will never be notified of the new attributes.  Instead, it should
+probably use class_create() and class->dev_attrs to set up a list of
+desired attributes in the modules_init function, and then in the .probe()
+hook, and then use device_create() to create a new device as a child
+of the probed device.  The new device will generate a new uevent and
+properly advertise the new attributes to userspace.
+
+For example, if a driver wanted to add the following attributes:
+struct device_attribute mydriver_attribs[] = {
+       __ATTR(port_count, 0444, port_count_show),
+       __ATTR(serial_number, 0444, serial_number_show),
+       NULL
+};
+
+Then in the module init function is would do:
+       mydriver_class = class_create(THIS_MODULE, "my_attrs");
+       mydriver_class.dev_attr = mydriver_attribs;
+
+And assuming 'dev' is the struct device passed into the probe hook, the driver
+probe function would do something like:
+       create_device(&mydriver_class, dev, chrdev, &private_data, "my_name");
index 2f21ecd4c205fefcefd870abe5c415b49a1b5253..a52adfc9a57fe4d7b8cfbbecfa525df6d91906e1 100644 (file)
@@ -112,7 +112,7 @@ sub tda10045 {
 
 sub tda10046 {
        my $sourcefile = "TT_PCI_2.19h_28_11_2006.zip";
-       my $url = "http://technotrend-online.com/download/software/219/$sourcefile";
+       my $url = "http://www.tt-download.com/download/updates/219/$sourcefile";
        my $hash = "6a7e1e2f2644b162ff0502367553c72d";
        my $outfile = "dvb-fe-tda10046.fw";
        my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
@@ -129,8 +129,8 @@ sub tda10046 {
 }
 
 sub tda10046lifeview {
-    my $sourcefile = "Drv_2.11.02.zip";
-    my $url = "http://www.lifeview.com.tw/drivers/pci_card/FlyDVB-T/$sourcefile";
+    my $sourcefile = "7%5Cdrv_2.11.02.zip";
+    my $url = "http://www.lifeview.hk/dbimages/document/$sourcefile";
     my $hash = "1ea24dee4eea8fe971686981f34fd2e0";
     my $outfile = "dvb-fe-tda10046.fw";
     my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
@@ -317,7 +317,7 @@ sub nxt2002 {
 
 sub nxt2004 {
     my $sourcefile = "AVerTVHD_MCE_A180_Drv_v1.2.2.16.zip";
-    my $url = "http://www.aver.com/support/Drivers/$sourcefile";
+    my $url = "http://www.avermedia-usa.com/support/Drivers/$sourcefile";
     my $hash = "111cb885b1e009188346d72acfed024c";
     my $outfile = "dvb-fe-nxt2004.fw";
     my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
index 4bc374a14345da10f666d67745aa151231c10c92..079305640790ee0436ab7ae46e49624498c333ce 100644 (file)
@@ -29,16 +29,16 @@ o debugfs entries
 fault-inject-debugfs kernel module provides some debugfs entries for runtime
 configuration of fault-injection capabilities.
 
-- /debug/fail*/probability:
+- /sys/kernel/debug/fail*/probability:
 
        likelihood of failure injection, in percent.
        Format: <percent>
 
        Note that one-failure-per-hundred is a very high error rate
        for some testcases.  Consider setting probability=100 and configure
-       /debug/fail*/interval for such testcases.
+       /sys/kernel/debug/fail*/interval for such testcases.
 
-- /debug/fail*/interval:
+- /sys/kernel/debug/fail*/interval:
 
        specifies the interval between failures, for calls to
        should_fail() that pass all the other tests.
@@ -46,18 +46,18 @@ configuration of fault-injection capabilities.
        Note that if you enable this, by setting interval>1, you will
        probably want to set probability=100.
 
-- /debug/fail*/times:
+- /sys/kernel/debug/fail*/times:
 
        specifies how many times failures may happen at most.
        A value of -1 means "no limit".
 
-- /debug/fail*/space:
+- /sys/kernel/debug/fail*/space:
 
        specifies an initial resource "budget", decremented by "size"
        on each call to should_fail(,size).  Failure injection is
        suppressed until "space" reaches zero.
 
-- /debug/fail*/verbose
+- /sys/kernel/debug/fail*/verbose
 
        Format: { 0 | 1 | 2 }
        specifies the verbosity of the messages when failure is
@@ -65,17 +65,17 @@ configuration of fault-injection capabilities.
        log line per failure; '2' will print a call trace too -- useful
        to debug the problems revealed by fault injection.
 
-- /debug/fail*/task-filter:
+- /sys/kernel/debug/fail*/task-filter:
 
        Format: { 'Y' | 'N' }
        A value of 'N' disables filtering by process (default).
        Any positive value limits failures to only processes indicated by
        /proc/<pid>/make-it-fail==1.
 
-- /debug/fail*/require-start:
-- /debug/fail*/require-end:
-- /debug/fail*/reject-start:
-- /debug/fail*/reject-end:
+- /sys/kernel/debug/fail*/require-start:
+- /sys/kernel/debug/fail*/require-end:
+- /sys/kernel/debug/fail*/reject-start:
+- /sys/kernel/debug/fail*/reject-end:
 
        specifies the range of virtual addresses tested during
        stacktrace walking.  Failure is injected only if some caller
@@ -84,26 +84,26 @@ configuration of fault-injection capabilities.
        Default required range is [0,ULONG_MAX) (whole of virtual address space).
        Default rejected range is [0,0).
 
-- /debug/fail*/stacktrace-depth:
+- /sys/kernel/debug/fail*/stacktrace-depth:
 
        specifies the maximum stacktrace depth walked during search
        for a caller within [require-start,require-end) OR
        [reject-start,reject-end).
 
-- /debug/fail_page_alloc/ignore-gfp-highmem:
+- /sys/kernel/debug/fail_page_alloc/ignore-gfp-highmem:
 
        Format: { 'Y' | 'N' }
        default is 'N', setting it to 'Y' won't inject failures into
        highmem/user allocations.
 
-- /debug/failslab/ignore-gfp-wait:
-- /debug/fail_page_alloc/ignore-gfp-wait:
+- /sys/kernel/debug/failslab/ignore-gfp-wait:
+- /sys/kernel/debug/fail_page_alloc/ignore-gfp-wait:
 
        Format: { 'Y' | 'N' }
        default is 'N', setting it to 'Y' will inject failures
        only into non-sleep allocations (GFP_ATOMIC allocations).
 
-- /debug/fail_page_alloc/min-order:
+- /sys/kernel/debug/fail_page_alloc/min-order:
 
        specifies the minimum page allocation order to be injected
        failures.
@@ -166,13 +166,13 @@ o Inject slab allocation failures into module init/exit code
 #!/bin/bash
 
 FAILTYPE=failslab
-echo Y > /debug/$FAILTYPE/task-filter
-echo 10 > /debug/$FAILTYPE/probability
-echo 100 > /debug/$FAILTYPE/interval
-echo -1 > /debug/$FAILTYPE/times
-echo 0 > /debug/$FAILTYPE/space
-echo 2 > /debug/$FAILTYPE/verbose
-echo 1 > /debug/$FAILTYPE/ignore-gfp-wait
+echo Y > /sys/kernel/debug/$FAILTYPE/task-filter
+echo 10 > /sys/kernel/debug/$FAILTYPE/probability
+echo 100 > /sys/kernel/debug/$FAILTYPE/interval
+echo -1 > /sys/kernel/debug/$FAILTYPE/times
+echo 0 > /sys/kernel/debug/$FAILTYPE/space
+echo 2 > /sys/kernel/debug/$FAILTYPE/verbose
+echo 1 > /sys/kernel/debug/$FAILTYPE/ignore-gfp-wait
 
 faulty_system()
 {
@@ -217,20 +217,20 @@ then
        exit 1
 fi
 
-cat /sys/module/$module/sections/.text > /debug/$FAILTYPE/require-start
-cat /sys/module/$module/sections/.data > /debug/$FAILTYPE/require-end
+cat /sys/module/$module/sections/.text > /sys/kernel/debug/$FAILTYPE/require-start
+cat /sys/module/$module/sections/.data > /sys/kernel/debug/$FAILTYPE/require-end
 
-echo N > /debug/$FAILTYPE/task-filter
-echo 10 > /debug/$FAILTYPE/probability
-echo 100 > /debug/$FAILTYPE/interval
-echo -1 > /debug/$FAILTYPE/times
-echo 0 > /debug/$FAILTYPE/space
-echo 2 > /debug/$FAILTYPE/verbose
-echo 1 > /debug/$FAILTYPE/ignore-gfp-wait
-echo 1 > /debug/$FAILTYPE/ignore-gfp-highmem
-echo 10 > /debug/$FAILTYPE/stacktrace-depth
+echo N > /sys/kernel/debug/$FAILTYPE/task-filter
+echo 10 > /sys/kernel/debug/$FAILTYPE/probability
+echo 100 > /sys/kernel/debug/$FAILTYPE/interval
+echo -1 > /sys/kernel/debug/$FAILTYPE/times
+echo 0 > /sys/kernel/debug/$FAILTYPE/space
+echo 2 > /sys/kernel/debug/$FAILTYPE/verbose
+echo 1 > /sys/kernel/debug/$FAILTYPE/ignore-gfp-wait
+echo 1 > /sys/kernel/debug/$FAILTYPE/ignore-gfp-highmem
+echo 10 > /sys/kernel/debug/$FAILTYPE/stacktrace-depth
 
-trap "echo 0 > /debug/$FAILTYPE/probability" SIGINT SIGTERM EXIT
+trap "echo 0 > /sys/kernel/debug/$FAILTYPE/probability" SIGINT SIGTERM EXIT
 
 echo "Injecting errors into the module $module... (interrupt to stop)"
 sleep 1000000
index ee277dd204b0f575165b02f0dfc1fcb27c8d0bf8..950d5a658cb33860e05abaf2673b19e12482d388 100644 (file)
@@ -95,7 +95,7 @@ There is no way to change the vesafb video mode and/or timings after
 booting linux.  If you are not happy with the 60 Hz refresh rate, you
 have these options:
 
- * configure and load the DOS-Tools for your the graphics board (if
+ * configure and load the DOS-Tools for the graphics board (if
    available) and boot linux with loadlin.
  * use a native driver (matroxfb/atyfb) instead if vesafb.  If none
    is available, write a new one!
index cd8717a362712fbb537bf562eaa95b0be778dd3b..ebff3c10a07fc124b865f815de5b38d65f38d1fa 100644 (file)
@@ -1003,11 +1003,13 @@ CHAPTER 3: PER-PROCESS PARAMETERS
 3.1 /proc/<pid>/oom_adj - Adjust the oom-killer score
 ------------------------------------------------------
 
-This file can be used to adjust the score used to select which processes
-should be killed in an  out-of-memory  situation.  Giving it a high score will
-increase the likelihood of this process being killed by the oom-killer.  Valid
-values are in the range -16 to +15, plus the special value -17, which disables
-oom-killing altogether for this process.
+This file can be used to adjust the score used to select which processes should
+be killed in an out-of-memory situation.  The oom_adj value is a characteristic
+of the task's mm, so all threads that share an mm with pid will have the same
+oom_adj value.  A high value will increase the likelihood of this process being
+killed by the oom-killer.  Valid values are in the range -16 to +15 as
+explained below and a special value of -17, which disables oom-killing
+altogether for threads sharing pid's mm.
 
 The process to be killed in an out-of-memory situation is selected among all others
 based on its badness score. This value equals the original memory size of the process
@@ -1021,6 +1023,9 @@ the parent's score if they do not share the same memory. Thus forking servers
 are the prime candidates to be killed. Having only one 'hungry' child will make
 parent less preferable than the child.
 
+/proc/<pid>/oom_adj cannot be changed for kthreads since they are immune from
+oom-killing already.
+
 /proc/<pid>/oom_score shows process' current badness score.
 
 The following heuristics are then applied:
index 5147be5e13cd6376c9dac99cad8ffc186a201ab1..b58b84b50fa21944ccb98b87f5a2519f34a01705 100644 (file)
@@ -132,6 +132,11 @@ rodir            -- FAT has the ATTR_RO (read-only) attribute. On Windows,
                 If you want to use ATTR_RO as read-only flag even for
                 the directory, set this option.
 
+errors=panic|continue|remount-ro
+             -- specify FAT behavior on critical errors: panic, continue
+                without doing anything or remount the partition in
+                read-only mode (default behavior).
+
 <bool>: 0,1,yes,no,true,false
 
 TODO
index c3480aa66ba8048bf46483544ed6fb3ebb7151eb..7eceaff63f5ffb8f45748d0cb1f46b864652b69a 100644 (file)
@@ -77,7 +77,8 @@
    seconds for the whole load operation.
 
  - request_firmware_nowait() is also provided for convenience in
-   non-user contexts.
+   user contexts to request firmware asynchronously, but can't be called
+   in atomic contexts.
 
 
  about in-kernel persistence:
index a8321267b5b61901757c15f347c2a753ebbd016a..bee4c30bc1e2a82caa2421c9504e031ff1658c73 100644 (file)
@@ -2,14 +2,18 @@ Kernel driver f71882fg
 ======================
 
 Supported chips:
-  * Fintek F71882FG and F71883FG
-    Prefix: 'f71882fg'
+  * Fintek F71858FG
+    Prefix: 'f71858fg'
     Addresses scanned: none, address read from Super I/O config space
     Datasheet: Available from the Fintek website
   * Fintek F71862FG and F71863FG
     Prefix: 'f71862fg'
     Addresses scanned: none, address read from Super I/O config space
     Datasheet: Available from the Fintek website
+  * Fintek F71882FG and F71883FG
+    Prefix: 'f71882fg'
+    Addresses scanned: none, address read from Super I/O config space
+    Datasheet: Available from the Fintek website
   * Fintek F8000
     Prefix: 'f8000'
     Addresses scanned: none, address read from Super I/O config space
@@ -66,13 +70,13 @@ printed when loading the driver.
 
 Three different fan control modes are supported; the mode number is written
 to the pwm#_enable file. Note that not all modes are supported on all
-chips, and some modes may only be available in RPM / PWM mode on the F8000.
+chips, and some modes may only be available in RPM / PWM mode.
 Writing an unsupported mode will result in an invalid parameter error.
 
 * 1: Manual mode
   You ask for a specific PWM duty cycle / DC voltage or a specific % of
   fan#_full_speed by writing to the pwm# file. This mode is only
-  available on the F8000 if the fan channel is in RPM mode.
+  available on the F71858FG / F8000 if the fan channel is in RPM mode.
 
 * 2: Normal auto mode
   You can define a number of temperature/fan speed trip points, which % the
index e98bdfea3467f679411f86d8f82be7ea421da491..1e0d59e000b475cafe418db3fd44fba6f08b3122 100644 (file)
@@ -7,7 +7,7 @@ henceforth as AEM.
 Supported systems:
   * Any recent IBM System X server with AEM support.
     This includes the x3350, x3550, x3650, x3655, x3755, x3850 M2,
-    x3950 M2, and certain HS2x/LS2x/QS2x blades.  The IPMI host interface
+    x3950 M2, and certain HC10/HS2x/LS2x/QS2x blades.  The IPMI host interface
     driver ("ipmi-si") needs to be loaded for this driver to do anything.
     Prefix: 'ibmaem'
     Datasheet: Not available
index 004ee161721e9b3bd1aa213c174a594174b187c8..dcbd502c8792b4e786507bc2023860c716d8fd8b 100644 (file)
@@ -70,6 +70,7 @@ are interpreted as 0! For more on how written strings are interpreted see the
 [0-*]  denotes any positive number starting from 0
 [1-*]  denotes any positive number starting from 1
 RO     read only value
+WO     write only value
 RW     read/write value
 
 Read/write values may be read-only for some chips, depending on the
@@ -295,6 +296,24 @@ temp[1-*]_label    Suggested temperature channel label.
                user-space.
                RO
 
+temp[1-*]_lowest
+               Historical minimum temperature
+               Unit: millidegree Celsius
+               RO
+
+temp[1-*]_highest
+               Historical maximum temperature
+               Unit: millidegree Celsius
+               RO
+
+temp[1-*]_reset_history
+               Reset temp_lowest and temp_highest
+               WO
+
+temp_reset_history
+               Reset temp_lowest and temp_highest for all sensors
+               WO
+
 Some chips measure temperature using external thermistors and an ADC, and
 report the temperature measurement as a voltage. Converting this voltage
 back to a temperature (or the other way around for limits) requires
diff --git a/Documentation/hwmon/tmp401 b/Documentation/hwmon/tmp401
new file mode 100644 (file)
index 0000000..9fc4472
--- /dev/null
@@ -0,0 +1,42 @@
+Kernel driver tmp401
+====================
+
+Supported chips:
+  * Texas Instruments TMP401
+    Prefix: 'tmp401'
+    Addresses scanned: I2C 0x4c
+    Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp401.html
+  * Texas Instruments TMP411
+    Prefix: 'tmp411'
+    Addresses scanned: I2C 0x4c
+    Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp411.html
+
+Authors:
+         Hans de Goede <hdegoede@redhat.com>
+        Andre Prendel <andre.prendel@gmx.de>
+
+Description
+-----------
+
+This driver implements support for Texas Instruments TMP401 and
+TMP411 chips. These chips implements one remote and one local
+temperature sensor. Temperature is measured in degrees
+Celsius. Resolution of the remote sensor is 0.0625 degree. Local
+sensor resolution can be set to 0.5, 0.25, 0.125 or 0.0625 degree (not
+supported by the driver so far, so using the default resolution of 0.5
+degree).
+
+The driver provides the common sysfs-interface for temperatures (see
+/Documentation/hwmon/sysfs-interface under Temperatures).
+
+The TMP411 chip is compatible with TMP401. It provides some additional
+features.
+
+* Minimum and Maximum temperature measured since power-on, chip-reset
+
+  Exported via sysfs attributes tempX_lowest and tempX_highest.
+
+* Reset of historical minimum/maximum temperature measurements
+
+  Exported via sysfs attribute temp_reset_history. Writing 1 to this
+  file triggers a reset.
index b6eb59384bb39c1b67d0c99a1ade601269a64d05..02b74899edaf42e5c1a266399aeb51c890fc5c5c 100644 (file)
@@ -12,6 +12,10 @@ Supported chips:
     Addresses scanned: ISA address retrieved from Super I/O registers
     Datasheet:
         http://www.nuvoton.com.tw/NR/rdonlyres/7885623D-A487-4CF9-A47F-30C5F73D6FE6/0/W83627DHG.pdf
+  * Winbond W83627DHG-P
+    Prefix: 'w83627dhg'
+    Addresses scanned: ISA address retrieved from Super I/O registers
+    Datasheet: not available
   * Winbond W83667HG
     Prefix: 'w83667hg'
     Addresses scanned: ISA address retrieved from Super I/O registers
@@ -28,8 +32,8 @@ Description
 -----------
 
 This driver implements support for the Winbond W83627EHF, W83627EHG,
-W83627DHG and W83667HG super I/O chips. We will refer to them collectively
-as Winbond chips.
+W83627DHG, W83627DHG-P and W83667HG super I/O chips. We will refer to them
+collectively as Winbond chips.
 
 The chips implement three temperature sensors, five fan rotation
 speed sensors, ten analog voltage sensors (only nine for the 627DHG), one
@@ -135,3 +139,6 @@ done in the driver for all register addresses.
 The DHG also supports PECI, where the DHG queries Intel CPU temperatures, and
 the ICH8 southbridge gets that data via PECI from the DHG, so that the
 southbridge drives the fans. And the DHG supports SST, a one-wire serial bus.
+
+The DHG-P has an additional automatic fan speed control mode named Smart Fan
+(TM) III+. This mode is not yet supported by the driver.
index 22efedf60c872869e5230eb5ccf66c166634e22c..2e758b0e94564042d14d1d763d6a11fc998c181d 100644 (file)
@@ -19,6 +19,9 @@ Supported adapters:
   * VIA Technologies, Inc. VX800/VX820
     Datasheet: available on http://linux.via.com.tw
 
+  * VIA Technologies, Inc. VX855/VX875
+    Datasheet: Availability unknown
+
 Authors:
        Kyösti Mälkki <kmalkki@cc.hut.fi>,
        Mark D. Studebaker <mdsxyz123@yahoo.com>,
@@ -53,6 +56,7 @@ Your lspci -n listing must show one of these :
  device 1106:3287   (VT8251)
  device 1106:8324   (CX700)
  device 1106:8353   (VX800/VX820)
+ device 1106:8409   (VX855/VX875)
 
 If none of these show up, you should look in the BIOS for settings like
 enable ACPI / SMBus or even USB.
index ad38006307725ff2a563d9e86e78230df0879e22..5578248c18a46837e6c88b0b1779cb2e08b436c3 100644 (file)
@@ -546,6 +546,10 @@ and is between 256 and 4096 characters. It is defined in the file
                        console=brl,ttyS0
                For now, only VisioBraille is supported.
 
+       consoleblank=   [KNL] The console blank (screen saver) timeout in
+                       seconds. Defaults to 10*60 = 10mins. A value of 0
+                       disables the blank timer.
+
        coredump_filter=
                        [KNL] Change the default value for
                        /proc/<pid>/coredump_filter.
diff --git a/Documentation/kmemcheck.txt b/Documentation/kmemcheck.txt
new file mode 100644 (file)
index 0000000..3630446
--- /dev/null
@@ -0,0 +1,773 @@
+GETTING STARTED WITH KMEMCHECK
+==============================
+
+Vegard Nossum <vegardno@ifi.uio.no>
+
+
+Contents
+========
+0. Introduction
+1. Downloading
+2. Configuring and compiling
+3. How to use
+3.1. Booting
+3.2. Run-time enable/disable
+3.3. Debugging
+3.4. Annotating false positives
+4. Reporting errors
+5. Technical description
+
+
+0. Introduction
+===============
+
+kmemcheck is a debugging feature for the Linux Kernel. More specifically, it
+is a dynamic checker that detects and warns about some uses of uninitialized
+memory.
+
+Userspace programmers might be familiar with Valgrind's memcheck. The main
+difference between memcheck and kmemcheck is that memcheck works for userspace
+programs only, and kmemcheck works for the kernel only. The implementations
+are of course vastly different. Because of this, kmemcheck is not as accurate
+as memcheck, but it turns out to be good enough in practice to discover real
+programmer errors that the compiler is not able to find through static
+analysis.
+
+Enabling kmemcheck on a kernel will probably slow it down to the extent that
+the machine will not be usable for normal workloads such as e.g. an
+interactive desktop. kmemcheck will also cause the kernel to use about twice
+as much memory as normal. For this reason, kmemcheck is strictly a debugging
+feature.
+
+
+1. Downloading
+==============
+
+kmemcheck can only be downloaded using git. If you want to write patches
+against the current code, you should use the kmemcheck development branch of
+the tip tree. It is also possible to use the linux-next tree, which also
+includes the latest version of kmemcheck.
+
+Assuming that you've already cloned the linux-2.6.git repository, all you
+have to do is add the -tip tree as a remote, like this:
+
+       $ git remote add tip git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip.git
+
+To actually download the tree, fetch the remote:
+
+       $ git fetch tip
+
+And to check out a new local branch with the kmemcheck code:
+
+       $ git checkout -b kmemcheck tip/kmemcheck
+
+General instructions for the -tip tree can be found here:
+http://people.redhat.com/mingo/tip.git/readme.txt
+
+
+2. Configuring and compiling
+============================
+
+kmemcheck only works for the x86 (both 32- and 64-bit) platform. A number of
+configuration variables must have specific settings in order for the kmemcheck
+menu to even appear in "menuconfig". These are:
+
+  o CONFIG_CC_OPTIMIZE_FOR_SIZE=n
+
+       This option is located under "General setup" / "Optimize for size".
+
+       Without this, gcc will use certain optimizations that usually lead to
+       false positive warnings from kmemcheck. An example of this is a 16-bit
+       field in a struct, where gcc may load 32 bits, then discard the upper
+       16 bits. kmemcheck sees only the 32-bit load, and may trigger a
+       warning for the upper 16 bits (if they're uninitialized).
+
+  o CONFIG_SLAB=y or CONFIG_SLUB=y
+
+       This option is located under "General setup" / "Choose SLAB
+       allocator".
+
+  o CONFIG_FUNCTION_TRACER=n
+
+       This option is located under "Kernel hacking" / "Tracers" / "Kernel
+       Function Tracer"
+
+       When function tracing is compiled in, gcc emits a call to another
+       function at the beginning of every function. This means that when the
+       page fault handler is called, the ftrace framework will be called
+       before kmemcheck has had a chance to handle the fault. If ftrace then
+       modifies memory that was tracked by kmemcheck, the result is an
+       endless recursive page fault.
+
+  o CONFIG_DEBUG_PAGEALLOC=n
+
+       This option is located under "Kernel hacking" / "Debug page memory
+       allocations".
+
+In addition, I highly recommend turning on CONFIG_DEBUG_INFO=y. This is also
+located under "Kernel hacking". With this, you will be able to get line number
+information from the kmemcheck warnings, which is extremely valuable in
+debugging a problem. This option is not mandatory, however, because it slows
+down the compilation process and produces a much bigger kernel image.
+
+Now the kmemcheck menu should be visible (under "Kernel hacking" / "kmemcheck:
+trap use of uninitialized memory"). Here follows a description of the
+kmemcheck configuration variables:
+
+  o CONFIG_KMEMCHECK
+
+       This must be enabled in order to use kmemcheck at all...
+
+  o CONFIG_KMEMCHECK_[DISABLED | ENABLED | ONESHOT]_BY_DEFAULT
+
+       This option controls the status of kmemcheck at boot-time. "Enabled"
+       will enable kmemcheck right from the start, "disabled" will boot the
+       kernel as normal (but with the kmemcheck code compiled in, so it can
+       be enabled at run-time after the kernel has booted), and "one-shot" is
+       a special mode which will turn kmemcheck off automatically after
+       detecting the first use of uninitialized memory.
+
+       If you are using kmemcheck to actively debug a problem, then you
+       probably want to choose "enabled" here.
+
+       The one-shot mode is mostly useful in automated test setups because it
+       can prevent floods of warnings and increase the chances of the machine
+       surviving in case something is really wrong. In other cases, the one-
+       shot mode could actually be counter-productive because it would turn
+       itself off at the very first error -- in the case of a false positive
+       too -- and this would come in the way of debugging the specific
+       problem you were interested in.
+
+       If you would like to use your kernel as normal, but with a chance to
+       enable kmemcheck in case of some problem, it might be a good idea to
+       choose "disabled" here. When kmemcheck is disabled, most of the run-
+       time overhead is not incurred, and the kernel will be almost as fast
+       as normal.
+
+  o CONFIG_KMEMCHECK_QUEUE_SIZE
+
+       Select the maximum number of error reports to store in an internal
+       (fixed-size) buffer. Since errors can occur virtually anywhere and in
+       any context, we need a temporary storage area which is guaranteed not
+       to generate any other page faults when accessed. The queue will be
+       emptied as soon as a tasklet may be scheduled. If the queue is full,
+       new error reports will be lost.
+
+       The default value of 64 is probably fine. If some code produces more
+       than 64 errors within an irqs-off section, then the code is likely to
+       produce many, many more, too, and these additional reports seldom give
+       any more information (the first report is usually the most valuable
+       anyway).
+
+       This number might have to be adjusted if you are not using serial
+       console or similar to capture the kernel log. If you are using the
+       "dmesg" command to save the log, then getting a lot of kmemcheck
+       warnings might overflow the kernel log itself, and the earlier reports
+       will get lost in that way instead. Try setting this to 10 or so on
+       such a setup.
+
+  o CONFIG_KMEMCHECK_SHADOW_COPY_SHIFT
+
+       Select the number of shadow bytes to save along with each entry of the
+       error-report queue. These bytes indicate what parts of an allocation
+       are initialized, uninitialized, etc. and will be displayed when an
+       error is detected to help the debugging of a particular problem.
+
+       The number entered here is actually the logarithm of the number of
+       bytes that will be saved. So if you pick for example 5 here, kmemcheck
+       will save 2^5 = 32 bytes.
+
+       The default value should be fine for debugging most problems. It also
+       fits nicely within 80 columns.
+
+  o CONFIG_KMEMCHECK_PARTIAL_OK
+
+       This option (when enabled) works around certain GCC optimizations that
+       produce 32-bit reads from 16-bit variables where the upper 16 bits are
+       thrown away afterwards.
+
+       The default value (enabled) is recommended. This may of course hide
+       some real errors, but disabling it would probably produce a lot of
+       false positives.
+
+  o CONFIG_KMEMCHECK_BITOPS_OK
+
+       This option silences warnings that would be generated for bit-field
+       accesses where not all the bits are initialized at the same time. This
+       may also hide some real bugs.
+
+       This option is probably obsolete, or it should be replaced with
+       the kmemcheck-/bitfield-annotations for the code in question. The
+       default value is therefore fine.
+
+Now compile the kernel as usual.
+
+
+3. How to use
+=============
+
+3.1. Booting
+============
+
+First some information about the command-line options. There is only one
+option specific to kmemcheck, and this is called "kmemcheck". It can be used
+to override the default mode as chosen by the CONFIG_KMEMCHECK_*_BY_DEFAULT
+option. Its possible settings are:
+
+  o kmemcheck=0 (disabled)
+  o kmemcheck=1 (enabled)
+  o kmemcheck=2 (one-shot mode)
+
+If SLUB debugging has been enabled in the kernel, it may take precedence over
+kmemcheck in such a way that the slab caches which are under SLUB debugging
+will not be tracked by kmemcheck. In order to ensure that this doesn't happen
+(even though it shouldn't by default), use SLUB's boot option "slub_debug",
+like this: slub_debug=-
+
+In fact, this option may also be used for fine-grained control over SLUB vs.
+kmemcheck. For example, if the command line includes "kmemcheck=1
+slub_debug=,dentry", then SLUB debugging will be used only for the "dentry"
+slab cache, and with kmemcheck tracking all the other caches. This is advanced
+usage, however, and is not generally recommended.
+
+
+3.2. Run-time enable/disable
+============================
+
+When the kernel has booted, it is possible to enable or disable kmemcheck at
+run-time. WARNING: This feature is still experimental and may cause false
+positive warnings to appear. Therefore, try not to use this. If you find that
+it doesn't work properly (e.g. you see an unreasonable amount of warnings), I
+will be happy to take bug reports.
+
+Use the file /proc/sys/kernel/kmemcheck for this purpose, e.g.:
+
+       $ echo 0 > /proc/sys/kernel/kmemcheck # disables kmemcheck
+
+The numbers are the same as for the kmemcheck= command-line option.
+
+
+3.3. Debugging
+==============
+
+A typical report will look something like this:
+
+WARNING: kmemcheck: Caught 32-bit read from uninitialized memory (ffff88003e4a2024)
+80000000000000000000000000000000000000000088ffff0000000000000000
+ i i i i u u u u i i i i i i i i u u u u u u u u u u u u u u u u
+         ^
+
+Pid: 1856, comm: ntpdate Not tainted 2.6.29-rc5 #264 945P-A
+RIP: 0010:[<ffffffff8104ede8>]  [<ffffffff8104ede8>] __dequeue_signal+0xc8/0x190
+RSP: 0018:ffff88003cdf7d98  EFLAGS: 00210002
+RAX: 0000000000000030 RBX: ffff88003d4ea968 RCX: 0000000000000009
+RDX: ffff88003e5d6018 RSI: ffff88003e5d6024 RDI: ffff88003cdf7e84
+RBP: ffff88003cdf7db8 R08: ffff88003e5d6000 R09: 0000000000000000
+R10: 0000000000000080 R11: 0000000000000000 R12: 000000000000000e
+R13: ffff88003cdf7e78 R14: ffff88003d530710 R15: ffff88003d5a98c8
+FS:  0000000000000000(0000) GS:ffff880001982000(0063) knlGS:00000
+CS:  0010 DS: 002b ES: 002b CR0: 0000000080050033
+CR2: ffff88003f806ea0 CR3: 000000003c036000 CR4: 00000000000006a0
+DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
+DR3: 0000000000000000 DR6: 00000000ffff4ff0 DR7: 0000000000000400
+ [<ffffffff8104f04e>] dequeue_signal+0x8e/0x170
+ [<ffffffff81050bd8>] get_signal_to_deliver+0x98/0x390
+ [<ffffffff8100b87d>] do_notify_resume+0xad/0x7d0
+ [<ffffffff8100c7b5>] int_signal+0x12/0x17
+ [<ffffffffffffffff>] 0xffffffffffffffff
+
+The single most valuable information in this report is the RIP (or EIP on 32-
+bit) value. This will help us pinpoint exactly which instruction that caused
+the warning.
+
+If your kernel was compiled with CONFIG_DEBUG_INFO=y, then all we have to do
+is give this address to the addr2line program, like this:
+
+       $ addr2line -e vmlinux -i ffffffff8104ede8
+       arch/x86/include/asm/string_64.h:12
+       include/asm-generic/siginfo.h:287
+       kernel/signal.c:380
+       kernel/signal.c:410
+
+The "-e vmlinux" tells addr2line which file to look in. IMPORTANT: This must
+be the vmlinux of the kernel that produced the warning in the first place! If
+not, the line number information will almost certainly be wrong.
+
+The "-i" tells addr2line to also print the line numbers of inlined functions.
+In this case, the flag was very important, because otherwise, it would only
+have printed the first line, which is just a call to memcpy(), which could be
+called from a thousand places in the kernel, and is therefore not very useful.
+These inlined functions would not show up in the stack trace above, simply
+because the kernel doesn't load the extra debugging information. This
+technique can of course be used with ordinary kernel oopses as well.
+
+In this case, it's the caller of memcpy() that is interesting, and it can be
+found in include/asm-generic/siginfo.h, line 287:
+
+281 static inline void copy_siginfo(struct siginfo *to, struct siginfo *from)
+282 {
+283         if (from->si_code < 0)
+284                 memcpy(to, from, sizeof(*to));
+285         else
+286                 /* _sigchld is currently the largest know union member */
+287                 memcpy(to, from, __ARCH_SI_PREAMBLE_SIZE + sizeof(from->_sifields._sigchld));
+288 }
+
+Since this was a read (kmemcheck usually warns about reads only, though it can
+warn about writes to unallocated or freed memory as well), it was probably the
+"from" argument which contained some uninitialized bytes. Following the chain
+of calls, we move upwards to see where "from" was allocated or initialized,
+kernel/signal.c, line 380:
+
+359 static void collect_signal(int sig, struct sigpending *list, siginfo_t *info)
+360 {
+...
+367         list_for_each_entry(q, &list->list, list) {
+368                 if (q->info.si_signo == sig) {
+369                         if (first)
+370                                 goto still_pending;
+371                         first = q;
+...
+377         if (first) {
+378 still_pending:
+379                 list_del_init(&first->list);
+380                 copy_siginfo(info, &first->info);
+381                 __sigqueue_free(first);
+...
+392         }
+393 }
+
+Here, it is &first->info that is being passed on to copy_siginfo(). The
+variable "first" was found on a list -- passed in as the second argument to
+collect_signal(). We  continue our journey through the stack, to figure out
+where the item on "list" was allocated or initialized. We move to line 410:
+
+395 static int __dequeue_signal(struct sigpending *pending, sigset_t *mask,
+396                         siginfo_t *info)
+397 {
+...
+410                 collect_signal(sig, pending, info);
+...
+414 }
+
+Now we need to follow the "pending" pointer, since that is being passed on to
+collect_signal() as "list". At this point, we've run out of lines from the
+"addr2line" output. Not to worry, we just paste the next addresses from the
+kmemcheck stack dump, i.e.:
+
+ [<ffffffff8104f04e>] dequeue_signal+0x8e/0x170
+ [<ffffffff81050bd8>] get_signal_to_deliver+0x98/0x390
+ [<ffffffff8100b87d>] do_notify_resume+0xad/0x7d0
+ [<ffffffff8100c7b5>] int_signal+0x12/0x17
+
+       $ addr2line -e vmlinux -i ffffffff8104f04e ffffffff81050bd8 \
+               ffffffff8100b87d ffffffff8100c7b5
+       kernel/signal.c:446
+       kernel/signal.c:1806
+       arch/x86/kernel/signal.c:805
+       arch/x86/kernel/signal.c:871
+       arch/x86/kernel/entry_64.S:694
+
+Remember that since these addresses were found on the stack and not as the
+RIP value, they actually point to the _next_ instruction (they are return
+addresses). This becomes obvious when we look at the code for line 446:
+
+422 int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
+423 {
+...
+431                 signr = __dequeue_signal(&tsk->signal->shared_pending,
+432                                          mask, info);
+433                 /*
+434                  * itimer signal ?
+435                  *
+436                  * itimers are process shared and we restart periodic
+437                  * itimers in the signal delivery path to prevent DoS
+438                  * attacks in the high resolution timer case. This is
+439                  * compliant with the old way of self restarting
+440                  * itimers, as the SIGALRM is a legacy signal and only
+441                  * queued once. Changing the restart behaviour to
+442                  * restart the timer in the signal dequeue path is
+443                  * reducing the timer noise on heavy loaded !highres
+444                  * systems too.
+445                  */
+446                 if (unlikely(signr == SIGALRM)) {
+...
+489 }
+
+So instead of looking at 446, we should be looking at 431, which is the line
+that executes just before 446. Here we see that what we are looking for is
+&tsk->signal->shared_pending.
+
+Our next task is now to figure out which function that puts items on this
+"shared_pending" list. A crude, but efficient tool, is git grep:
+
+       $ git grep -n 'shared_pending' kernel/
+       ...
+       kernel/signal.c:828:    pending = group ? &t->signal->shared_pending : &t->pending;
+       kernel/signal.c:1339:   pending = group ? &t->signal->shared_pending : &t->pending;
+       ...
+
+There were more results, but none of them were related to list operations,
+and these were the only assignments. We inspect the line numbers more closely
+and find that this is indeed where items are being added to the list:
+
+816 static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
+817                         int group)
+818 {
+...
+828         pending = group ? &t->signal->shared_pending : &t->pending;
+...
+851         q = __sigqueue_alloc(t, GFP_ATOMIC, (sig < SIGRTMIN &&
+852                                              (is_si_special(info) ||
+853                                               info->si_code >= 0)));
+854         if (q) {
+855                 list_add_tail(&q->list, &pending->list);
+...
+890 }
+
+and:
+
+1309 int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group)
+1310 {
+....
+1339         pending = group ? &t->signal->shared_pending : &t->pending;
+1340         list_add_tail(&q->list, &pending->list);
+....
+1347 }
+
+In the first case, the list element we are looking for, "q", is being returned
+from the function __sigqueue_alloc(), which looks like an allocation function.
+Let's take a look at it:
+
+187 static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags,
+188                                          int override_rlimit)
+189 {
+190         struct sigqueue *q = NULL;
+191         struct user_struct *user;
+192 
+193         /*
+194          * We won't get problems with the target's UID changing under us
+195          * because changing it requires RCU be used, and if t != current, the
+196          * caller must be holding the RCU readlock (by way of a spinlock) and
+197          * we use RCU protection here
+198          */
+199         user = get_uid(__task_cred(t)->user);
+200         atomic_inc(&user->sigpending);
+201         if (override_rlimit ||
+202             atomic_read(&user->sigpending) <=
+203                         t->signal->rlim[RLIMIT_SIGPENDING].rlim_cur)
+204                 q = kmem_cache_alloc(sigqueue_cachep, flags);
+205         if (unlikely(q == NULL)) {
+206                 atomic_dec(&user->sigpending);
+207                 free_uid(user);
+208         } else {
+209                 INIT_LIST_HEAD(&q->list);
+210                 q->flags = 0;
+211                 q->user = user;
+212         }
+213 
+214         return q;
+215 }
+
+We see that this function initializes q->list, q->flags, and q->user. It seems
+that now is the time to look at the definition of "struct sigqueue", e.g.:
+
+14 struct sigqueue {
+15         struct list_head list;
+16         int flags;
+17         siginfo_t info;
+18         struct user_struct *user;
+19 };
+
+And, you might remember, it was a memcpy() on &first->info that caused the
+warning, so this makes perfect sense. It also seems reasonable to assume that
+it is the caller of __sigqueue_alloc() that has the responsibility of filling
+out (initializing) this member.
+
+But just which fields of the struct were uninitialized? Let's look at
+kmemcheck's report again:
+
+WARNING: kmemcheck: Caught 32-bit read from uninitialized memory (ffff88003e4a2024)
+80000000000000000000000000000000000000000088ffff0000000000000000
+ i i i i u u u u i i i i i i i i u u u u u u u u u u u u u u u u
+         ^
+
+These first two lines are the memory dump of the memory object itself, and the
+shadow bytemap, respectively. The memory object itself is in this case
+&first->info. Just beware that the start of this dump is NOT the start of the
+object itself! The position of the caret (^) corresponds with the address of
+the read (ffff88003e4a2024).
+
+The shadow bytemap dump legend is as follows:
+
+  i - initialized
+  u - uninitialized
+  a - unallocated (memory has been allocated by the slab layer, but has not
+      yet been handed off to anybody)
+  f - freed (memory has been allocated by the slab layer, but has been freed
+      by the previous owner)
+
+In order to figure out where (relative to the start of the object) the
+uninitialized memory was located, we have to look at the disassembly. For
+that, we'll need the RIP address again:
+
+RIP: 0010:[<ffffffff8104ede8>]  [<ffffffff8104ede8>] __dequeue_signal+0xc8/0x190
+
+       $ objdump -d --no-show-raw-insn vmlinux | grep -C 8 ffffffff8104ede8:
+       ffffffff8104edc8:       mov    %r8,0x8(%r8)
+       ffffffff8104edcc:       test   %r10d,%r10d
+       ffffffff8104edcf:       js     ffffffff8104ee88 <__dequeue_signal+0x168>
+       ffffffff8104edd5:       mov    %rax,%rdx
+       ffffffff8104edd8:       mov    $0xc,%ecx
+       ffffffff8104eddd:       mov    %r13,%rdi
+       ffffffff8104ede0:       mov    $0x30,%eax
+       ffffffff8104ede5:       mov    %rdx,%rsi
+       ffffffff8104ede8:       rep movsl %ds:(%rsi),%es:(%rdi)
+       ffffffff8104edea:       test   $0x2,%al
+       ffffffff8104edec:       je     ffffffff8104edf0 <__dequeue_signal+0xd0>
+       ffffffff8104edee:       movsw  %ds:(%rsi),%es:(%rdi)
+       ffffffff8104edf0:       test   $0x1,%al
+       ffffffff8104edf2:       je     ffffffff8104edf5 <__dequeue_signal+0xd5>
+       ffffffff8104edf4:       movsb  %ds:(%rsi),%es:(%rdi)
+       ffffffff8104edf5:       mov    %r8,%rdi
+       ffffffff8104edf8:       callq  ffffffff8104de60 <__sigqueue_free>
+
+As expected, it's the "rep movsl" instruction from the memcpy() that causes
+the warning. We know about REP MOVSL that it uses the register RCX to count
+the number of remaining iterations. By taking a look at the register dump
+again (from the kmemcheck report), we can figure out how many bytes were left
+to copy:
+
+RAX: 0000000000000030 RBX: ffff88003d4ea968 RCX: 0000000000000009
+
+By looking at the disassembly, we also see that %ecx is being loaded with the
+value $0xc just before (ffffffff8104edd8), so we are very lucky. Keep in mind
+that this is the number of iterations, not bytes. And since this is a "long"
+operation, we need to multiply by 4 to get the number of bytes. So this means
+that the uninitialized value was encountered at 4 * (0xc - 0x9) = 12 bytes
+from the start of the object.
+
+We can now try to figure out which field of the "struct siginfo" that was not
+initialized. This is the beginning of the struct:
+
+40 typedef struct siginfo {
+41         int si_signo;
+42         int si_errno;
+43         int si_code;
+44                 
+45         union {
+..
+92         } _sifields;
+93 } siginfo_t;
+
+On 64-bit, the int is 4 bytes long, so it must the the union member that has
+not been initialized. We can verify this using gdb:
+
+       $ gdb vmlinux
+       ...
+       (gdb) p &((struct siginfo *) 0)->_sifields
+       $1 = (union {...} *) 0x10
+
+Actually, it seems that the union member is located at offset 0x10 -- which
+means that gcc has inserted 4 bytes of padding between the members si_code
+and _sifields. We can now get a fuller picture of the memory dump:
+
+         _----------------------------=> si_code
+        /        _--------------------=> (padding)
+       |        /        _------------=> _sifields(._kill._pid)
+       |       |        /        _----=> _sifields(._kill._uid)
+       |       |       |        / 
+-------|-------|-------|-------|
+80000000000000000000000000000000000000000088ffff0000000000000000
+ i i i i u u u u i i i i i i i i u u u u u u u u u u u u u u u u
+
+This allows us to realize another important fact: si_code contains the value
+0x80. Remember that x86 is little endian, so the first 4 bytes "80000000" are
+really the number 0x00000080. With a bit of research, we find that this is
+actually the constant SI_KERNEL defined in include/asm-generic/siginfo.h:
+
+144 #define SI_KERNEL       0x80            /* sent by the kernel from somewhere     */
+
+This macro is used in exactly one place in the x86 kernel: In send_signal()
+in kernel/signal.c:
+
+816 static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
+817                         int group)
+818 {
+...
+828         pending = group ? &t->signal->shared_pending : &t->pending;
+...
+851         q = __sigqueue_alloc(t, GFP_ATOMIC, (sig < SIGRTMIN &&
+852                                              (is_si_special(info) ||
+853                                               info->si_code >= 0)));
+854         if (q) {
+855                 list_add_tail(&q->list, &pending->list);
+856                 switch ((unsigned long) info) {
+...
+865                 case (unsigned long) SEND_SIG_PRIV:
+866                         q->info.si_signo = sig;
+867                         q->info.si_errno = 0;
+868                         q->info.si_code = SI_KERNEL;
+869                         q->info.si_pid = 0;
+870                         q->info.si_uid = 0;
+871                         break;
+...
+890 }
+
+Not only does this match with the .si_code member, it also matches the place
+we found earlier when looking for where siginfo_t objects are enqueued on the
+"shared_pending" list.
+
+So to sum up: It seems that it is the padding introduced by the compiler
+between two struct fields that is uninitialized, and this gets reported when
+we do a memcpy() on the struct. This means that we have identified a false
+positive warning.
+
+Normally, kmemcheck will not report uninitialized accesses in memcpy() calls
+when both the source and destination addresses are tracked. (Instead, we copy
+the shadow bytemap as well). In this case, the destination address clearly
+was not tracked. We can dig a little deeper into the stack trace from above:
+
+       arch/x86/kernel/signal.c:805
+       arch/x86/kernel/signal.c:871
+       arch/x86/kernel/entry_64.S:694
+
+And we clearly see that the destination siginfo object is located on the
+stack:
+
+782 static void do_signal(struct pt_regs *regs)
+783 {
+784         struct k_sigaction ka;
+785         siginfo_t info;
+...
+804         signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+...
+854 }
+
+And this &info is what eventually gets passed to copy_siginfo() as the
+destination argument.
+
+Now, even though we didn't find an actual error here, the example is still a
+good one, because it shows how one would go about to find out what the report
+was all about.
+
+
+3.4. Annotating false positives
+===============================
+
+There are a few different ways to make annotations in the source code that
+will keep kmemcheck from checking and reporting certain allocations. Here
+they are:
+
+  o __GFP_NOTRACK_FALSE_POSITIVE
+
+       This flag can be passed to kmalloc() or kmem_cache_alloc() (therefore
+       also to other functions that end up calling one of these) to indicate
+       that the allocation should not be tracked because it would lead to
+       a false positive report. This is a "big hammer" way of silencing
+       kmemcheck; after all, even if the false positive pertains to 
+       particular field in a struct, for example, we will now lose the
+       ability to find (real) errors in other parts of the same struct.
+
+       Example:
+
+           /* No warnings will ever trigger on accessing any part of x */
+           x = kmalloc(sizeof *x, GFP_KERNEL | __GFP_NOTRACK_FALSE_POSITIVE);
+
+  o kmemcheck_bitfield_begin(name)/kmemcheck_bitfield_end(name) and
+       kmemcheck_annotate_bitfield(ptr, name)
+
+       The first two of these three macros can be used inside struct
+       definitions to signal, respectively, the beginning and end of a
+       bitfield. Additionally, this will assign the bitfield a name, which
+       is given as an argument to the macros.
+
+       Having used these markers, one can later use
+       kmemcheck_annotate_bitfield() at the point of allocation, to indicate
+       which parts of the allocation is part of a bitfield.
+
+       Example:
+
+           struct foo {
+               int x;
+
+               kmemcheck_bitfield_begin(flags);
+               int flag_a:1;
+               int flag_b:1;
+               kmemcheck_bitfield_end(flags);
+
+               int y;
+           };
+
+           struct foo *x = kmalloc(sizeof *x);
+
+           /* No warnings will trigger on accessing the bitfield of x */
+           kmemcheck_annotate_bitfield(x, flags);
+
+       Note that kmemcheck_annotate_bitfield() can be used even before the
+       return value of kmalloc() is checked -- in other words, passing NULL
+       as the first argument is legal (and will do nothing).
+
+
+4. Reporting errors
+===================
+
+As we have seen, kmemcheck will produce false positive reports. Therefore, it
+is not very wise to blindly post kmemcheck warnings to mailing lists and
+maintainers. Instead, I encourage maintainers and developers to find errors
+in their own code. If you get a warning, you can try to work around it, try
+to figure out if it's a real error or not, or simply ignore it. Most
+developers know their own code and will quickly and efficiently determine the
+root cause of a kmemcheck report. This is therefore also the most efficient
+way to work with kmemcheck.
+
+That said, we (the kmemcheck maintainers) will always be on the lookout for
+false positives that we can annotate and silence. So whatever you find,
+please drop us a note privately! Kernel configs and steps to reproduce (if
+available) are of course a great help too.
+
+Happy hacking!
+
+
+5. Technical description
+========================
+
+kmemcheck works by marking memory pages non-present. This means that whenever
+somebody attempts to access the page, a page fault is generated. The page
+fault handler notices that the page was in fact only hidden, and so it calls
+on the kmemcheck code to make further investigations.
+
+When the investigations are completed, kmemcheck "shows" the page by marking
+it present (as it would be under normal circumstances). This way, the
+interrupted code can continue as usual.
+
+But after the instruction has been executed, we should hide the page again, so
+that we can catch the next access too! Now kmemcheck makes use of a debugging
+feature of the processor, namely single-stepping. When the processor has
+finished the one instruction that generated the memory access, a debug
+exception is raised. From here, we simply hide the page again and continue
+execution, this time with the single-stepping feature turned off.
+
+kmemcheck requires some assistance from the memory allocator in order to work.
+The memory allocator needs to
+
+  1. Tell kmemcheck about newly allocated pages and pages that are about to
+     be freed. This allows kmemcheck to set up and tear down the shadow memory
+     for the pages in question. The shadow memory stores the status of each
+     byte in the allocation proper, e.g. whether it is initialized or
+     uninitialized.
+
+  2. Tell kmemcheck which parts of memory should be marked uninitialized.
+     There are actually a few more states, such as "not yet allocated" and
+     "recently freed".
+
+If a slab cache is set up using the SLAB_NOTRACK flag, it will never return
+memory that can take page faults because of kmemcheck.
+
+If a slab cache is NOT set up using the SLAB_NOTRACK flag, callers can still
+request memory with the __GFP_NOTRACK or __GFP_NOTRACK_FALSE_POSITIVE flags.
+This does not prevent the page faults from occurring, however, but marks the
+object in question as being initialized so that no warnings will ever be
+produced for this object.
+
+Currently, the SLAB and SLUB allocators are supported by kmemcheck.
index 1e7a769a10f97354a0b3aa15229e5606723a4cd8..053037a1fe6d3b4943219c55d82dafca593c8d03 100644 (file)
@@ -507,9 +507,9 @@ http://www.linuxsymposium.org/2006/linuxsymposium_procv2.pdf (pages 101-115)
 Appendix A: The kprobes debugfs interface
 
 With recent kernels (> 2.6.20) the list of registered kprobes is visible
-under the /debug/kprobes/ directory (assuming debugfs is mounted at /debug).
+under the /sys/kernel/debug/kprobes/ directory (assuming debugfs is mounted at //sys/kernel/debug).
 
-/debug/kprobes/list: Lists all registered probes on the system
+/sys/kernel/debug/kprobes/list: Lists all registered probes on the system
 
 c015d71a  k  vfs_read+0x0
 c011a316  j  do_fork+0x0
@@ -525,7 +525,7 @@ virtual addresses that correspond to modules that've been unloaded),
 such probes are marked with [GONE]. If the probe is temporarily disabled,
 such probes are marked with [DISABLED].
 
-/debug/kprobes/enabled: Turn kprobes ON/OFF forcibly.
+/sys/kernel/debug/kprobes/enabled: Turn kprobes ON/OFF forcibly.
 
 Provides a knob to globally and forcibly turn registered kprobes ON or OFF.
 By default, all kprobes are enabled. By echoing "0" to this file, all
index 6fab2dcbb4d37f4a02accdcae64ebc8ede16cd9f..c4de6359d440e4dbf92d585e8a7e577d62d475c1 100644 (file)
@@ -233,8 +233,8 @@ These protections are added to score to judge whether this zone should be used
 for page allocation or should be reclaimed.
 
 In this example, if normal pages (index=2) are required to this DMA zone and
-pages_high is used for watermark, the kernel judges this zone should not be
-used because pages_free(1355) is smaller than watermark + protection[2]
+watermark[WMARK_HIGH] is used for watermark, the kernel judges this zone should
+not be used because pages_free(1355) is smaller than watermark + protection[2]
 (4 + 2004 = 2008). If this protection value is 0, this zone would be used for
 normal page requirement. If requirement is DMA zone(index=0), protection[0]
 (=0) is used.
@@ -280,9 +280,10 @@ The default value is 65536.
 min_free_kbytes:
 
 This is used to force the Linux VM to keep a minimum number
-of kilobytes free.  The VM uses this number to compute a pages_min
-value for each lowmem zone in the system.  Each lowmem zone gets
-a number of reserved free pages based proportionally on its size.
+of kilobytes free.  The VM uses this number to compute a
+watermark[WMARK_MIN] value for each lowmem zone in the system.
+Each lowmem zone gets a number of reserved free pages based
+proportionally on its size.
 
 Some minimal amount of memory is needed to satisfy PF_MEMALLOC
 allocations; if you set this to lower than 1024KB, your system will
@@ -314,10 +315,14 @@ min_unmapped_ratio:
 
 This is available only on NUMA kernels.
 
-A percentage of the total pages in each zone.  Zone reclaim will only
-occur if more than this percentage of pages are file backed and unmapped.
-This is to insure that a minimal amount of local pages is still available for
-file I/O even if the node is overallocated.
+This is a percentage of the total pages in each zone. Zone reclaim will
+only occur if more than this percentage of pages are in a state that
+zone_reclaim_mode allows to be reclaimed.
+
+If zone_reclaim_mode has the value 4 OR'd, then the percentage is compared
+against all file-backed unmapped pages including swapcache pages and tmpfs
+files. Otherwise, only unmapped pages backed by normal files but not tmpfs
+files and similar are considered.
 
 The default is 1 percent.
 
index 7bd27f0e288008c641c31474341a2dd84ef8bf73..a39b3c749de58c12129d80d0ffad738f9a7836f0 100644 (file)
@@ -7,7 +7,6 @@ Copyright 2008 Red Hat Inc.
                (dual licensed under the GPL v2)
 Reviewers:   Elias Oltmanns, Randy Dunlap, Andrew Morton,
             John Kacur, and David Teigland.
-
 Written for: 2.6.28-rc2
 
 Introduction
@@ -33,13 +32,26 @@ The File System
 Ftrace uses the debugfs file system to hold the control files as
 well as the files to display output.
 
-To mount the debugfs system:
+When debugfs is configured into the kernel (which selecting any ftrace
+option will do) the directory /sys/kernel/debug will be created. To mount
+this directory, you can add to your /etc/fstab file:
+
+ debugfs       /sys/kernel/debug          debugfs defaults        0       0
+
+Or you can mount it at run time with:
+
+ mount -t debugfs nodev /sys/kernel/debug
 
-  # mkdir /debug
-  # mount -t debugfs nodev /debug
+For quicker access to that directory you may want to make a soft link to
+it:
 
-( Note: it is more common to mount at /sys/kernel/debug, but for
-  simplicity this document will use /debug)
+ ln -s /sys/kernel/debug /debug
+
+Any selected ftrace option will also create a directory called tracing
+within the debugfs. The rest of the document will assume that you are in
+the ftrace directory (cd /sys/kernel/debug/tracing) and will only concentrate
+on the files within that directory and not distract from the content with
+the extended "/sys/kernel/debug/tracing" path name.
 
 That's it! (assuming that you have ftrace configured into your kernel)
 
@@ -389,18 +401,18 @@ trace_options
 The trace_options file is used to control what gets printed in
 the trace output. To see what is available, simply cat the file:
 
-  cat /debug/tracing/trace_options
+  cat trace_options
   print-parent nosym-offset nosym-addr noverbose noraw nohex nobin \
   noblock nostacktrace nosched-tree nouserstacktrace nosym-userobj
 
 To disable one of the options, echo in the option prepended with
 "no".
 
-  echo noprint-parent > /debug/tracing/trace_options
+  echo noprint-parent > trace_options
 
 To enable an option, leave off the "no".
 
-  echo sym-offset > /debug/tracing/trace_options
+  echo sym-offset > trace_options
 
 Here are the available options:
 
@@ -476,11 +488,11 @@ sched_switch
 This tracer simply records schedule switches. Here is an example
 of how to use it.
 
- # echo sched_switch > /debug/tracing/current_tracer
- # echo 1 > /debug/tracing/tracing_enabled
+ # echo sched_switch > current_tracer
+ # echo 1 > tracing_enabled
  # sleep 1
- # echo 0 > /debug/tracing/tracing_enabled
- # cat /debug/tracing/trace
+ # echo 0 > tracing_enabled
+ # cat trace
 
 # tracer: sched_switch
 #
@@ -583,13 +595,13 @@ new trace is saved.
 To reset the maximum, echo 0 into tracing_max_latency. Here is
 an example:
 
- # echo irqsoff > /debug/tracing/current_tracer
- # echo 0 > /debug/tracing/tracing_max_latency
- # echo 1 > /debug/tracing/tracing_enabled
+ # echo irqsoff > current_tracer
+ # echo 0 > tracing_max_latency
+ # echo 1 > tracing_enabled
  # ls -ltr
  [...]
- # echo 0 > /debug/tracing/tracing_enabled
- # cat /debug/tracing/latency_trace
+ # echo 0 > tracing_enabled
+ # cat latency_trace
 # tracer: irqsoff
 #
 irqsoff latency trace v1.1.5 on 2.6.26
@@ -690,13 +702,13 @@ Like the irqsoff tracer, it records the maximum latency for
 which preemption was disabled. The control of preemptoff tracer
 is much like the irqsoff tracer.
 
- # echo preemptoff > /debug/tracing/current_tracer
- # echo 0 > /debug/tracing/tracing_max_latency
- # echo 1 > /debug/tracing/tracing_enabled
+ # echo preemptoff > current_tracer
+ # echo 0 > tracing_max_latency
+ # echo 1 > tracing_enabled
  # ls -ltr
  [...]
- # echo 0 > /debug/tracing/tracing_enabled
- # cat /debug/tracing/latency_trace
+ # echo 0 > tracing_enabled
+ # cat latency_trace
 # tracer: preemptoff
 #
 preemptoff latency trace v1.1.5 on 2.6.26-rc8
@@ -837,13 +849,13 @@ tracer.
 Again, using this trace is much like the irqsoff and preemptoff
 tracers.
 
- # echo preemptirqsoff > /debug/tracing/current_tracer
- # echo 0 > /debug/tracing/tracing_max_latency
- # echo 1 > /debug/tracing/tracing_enabled
+ # echo preemptirqsoff > current_tracer
+ # echo 0 > tracing_max_latency
+ # echo 1 > tracing_enabled
  # ls -ltr
  [...]
- # echo 0 > /debug/tracing/tracing_enabled
- # cat /debug/tracing/latency_trace
+ # echo 0 > tracing_enabled
+ # cat latency_trace
 # tracer: preemptirqsoff
 #
 preemptirqsoff latency trace v1.1.5 on 2.6.26-rc8
@@ -999,12 +1011,12 @@ slightly differently than we did with the previous tracers.
 Instead of performing an 'ls', we will run 'sleep 1' under
 'chrt' which changes the priority of the task.
 
- # echo wakeup > /debug/tracing/current_tracer
- # echo 0 > /debug/tracing/tracing_max_latency
- # echo 1 > /debug/tracing/tracing_enabled
+ # echo wakeup > current_tracer
+ # echo 0 > tracing_max_latency
+ # echo 1 > tracing_enabled
  # chrt -f 5 sleep 1
- # echo 0 > /debug/tracing/tracing_enabled
- # cat /debug/tracing/latency_trace
+ # echo 0 > tracing_enabled
+ # cat latency_trace
 # tracer: wakeup
 #
 wakeup latency trace v1.1.5 on 2.6.26-rc8
@@ -1114,11 +1126,11 @@ can be done from the debug file system. Make sure the
 ftrace_enabled is set; otherwise this tracer is a nop.
 
  # sysctl kernel.ftrace_enabled=1
- # echo function > /debug/tracing/current_tracer
- # echo 1 > /debug/tracing/tracing_enabled
+ # echo function > current_tracer
+ # echo 1 > tracing_enabled
  # usleep 1
- # echo 0 > /debug/tracing/tracing_enabled
- # cat /debug/tracing/trace
+ # echo 0 > tracing_enabled
+ # cat trace
 # tracer: function
 #
 #           TASK-PID   CPU#    TIMESTAMP  FUNCTION
@@ -1155,7 +1167,7 @@ int trace_fd;
 [...]
 int main(int argc, char *argv[]) {
        [...]
-       trace_fd = open("/debug/tracing/tracing_enabled", O_WRONLY);
+       trace_fd = open(tracing_file("tracing_enabled"), O_WRONLY);
        [...]
        if (condition_hit()) {
                write(trace_fd, "0", 1);
@@ -1163,26 +1175,20 @@ int main(int argc, char *argv[]) {
        [...]
 }
 
-Note: Here we hard coded the path name. The debugfs mount is not
-guaranteed to be at /debug (and is more commonly at
-/sys/kernel/debug). For simple one time traces, the above is
-sufficent. For anything else, a search through /proc/mounts may
-be needed to find where the debugfs file-system is mounted.
-
 
 Single thread tracing
 ---------------------
 
-By writing into /debug/tracing/set_ftrace_pid you can trace a
+By writing into set_ftrace_pid you can trace a
 single thread. For example:
 
-# cat /debug/tracing/set_ftrace_pid
+# cat set_ftrace_pid
 no pid
-# echo 3111 > /debug/tracing/set_ftrace_pid
-# cat /debug/tracing/set_ftrace_pid
+# echo 3111 > set_ftrace_pid
+# cat set_ftrace_pid
 3111
-# echo function > /debug/tracing/current_tracer
-# cat /debug/tracing/trace | head
+# echo function > current_tracer
+# cat trace | head
  # tracer: function
  #
  #           TASK-PID    CPU#    TIMESTAMP  FUNCTION
@@ -1193,8 +1199,8 @@ no pid
      yum-updatesd-3111  [003]  1637.254683: lock_hrtimer_base <-hrtimer_try_to_cancel
      yum-updatesd-3111  [003]  1637.254685: fget_light <-do_sys_poll
      yum-updatesd-3111  [003]  1637.254686: pipe_poll <-do_sys_poll
-# echo -1 > /debug/tracing/set_ftrace_pid
-# cat /debug/tracing/trace |head
+# echo -1 > set_ftrace_pid
+# cat trace |head
  # tracer: function
  #
  #           TASK-PID    CPU#    TIMESTAMP  FUNCTION
@@ -1216,6 +1222,51 @@ something like this simple program:
 #include <fcntl.h>
 #include <unistd.h>
 
+#define _STR(x) #x
+#define STR(x) _STR(x)
+#define MAX_PATH 256
+
+const char *find_debugfs(void)
+{
+       static char debugfs[MAX_PATH+1];
+       static int debugfs_found;
+       char type[100];
+       FILE *fp;
+
+       if (debugfs_found)
+               return debugfs;
+
+       if ((fp = fopen("/proc/mounts","r")) == NULL) {
+               perror("/proc/mounts");
+               return NULL;
+       }
+
+       while (fscanf(fp, "%*s %"
+                     STR(MAX_PATH)
+                     "s %99s %*s %*d %*d\n",
+                     debugfs, type) == 2) {
+               if (strcmp(type, "debugfs") == 0)
+                       break;
+       }
+       fclose(fp);
+
+       if (strcmp(type, "debugfs") != 0) {
+               fprintf(stderr, "debugfs not mounted");
+               return NULL;
+       }
+
+       debugfs_found = 1;
+
+       return debugfs;
+}
+
+const char *tracing_file(const char *file_name)
+{
+       static char trace_file[MAX_PATH+1];
+       snprintf(trace_file, MAX_PATH, "%s/%s", find_debugfs(), file_name);
+       return trace_file;
+}
+
 int main (int argc, char **argv)
 {
         if (argc < 1)
@@ -1226,12 +1277,12 @@ int main (int argc, char **argv)
                 char line[64];
                 int s;
 
-                ffd = open("/debug/tracing/current_tracer", O_WRONLY);
+                ffd = open(tracing_file("current_tracer"), O_WRONLY);
                 if (ffd < 0)
                         exit(-1);
                 write(ffd, "nop", 3);
 
-                fd = open("/debug/tracing/set_ftrace_pid", O_WRONLY);
+                fd = open(tracing_file("set_ftrace_pid"), O_WRONLY);
                 s = sprintf(line, "%d\n", getpid());
                 write(fd, line, s);
 
@@ -1383,22 +1434,22 @@ want, depending on your needs.
   tracing_cpu_mask file) or you might sometimes see unordered
   function calls while cpu tracing switch.
 
-       hide: echo nofuncgraph-cpu > /debug/tracing/trace_options
-       show: echo funcgraph-cpu > /debug/tracing/trace_options
+       hide: echo nofuncgraph-cpu > trace_options
+       show: echo funcgraph-cpu > trace_options
 
 - The duration (function's time of execution) is displayed on
   the closing bracket line of a function or on the same line
   than the current function in case of a leaf one. It is default
   enabled.
 
-       hide: echo nofuncgraph-duration > /debug/tracing/trace_options
-       show: echo funcgraph-duration > /debug/tracing/trace_options
+       hide: echo nofuncgraph-duration > trace_options
+       show: echo funcgraph-duration > trace_options
 
 - The overhead field precedes the duration field in case of
   reached duration thresholds.
 
-       hide: echo nofuncgraph-overhead > /debug/tracing/trace_options
-       show: echo funcgraph-overhead > /debug/tracing/trace_options
+       hide: echo nofuncgraph-overhead > trace_options
+       show: echo funcgraph-overhead > trace_options
        depends on: funcgraph-duration
 
   ie:
@@ -1427,8 +1478,8 @@ want, depending on your needs.
 - The task/pid field displays the thread cmdline and pid which
   executed the function. It is default disabled.
 
-       hide: echo nofuncgraph-proc > /debug/tracing/trace_options
-       show: echo funcgraph-proc > /debug/tracing/trace_options
+       hide: echo nofuncgraph-proc > trace_options
+       show: echo funcgraph-proc > trace_options
 
   ie:
 
@@ -1451,8 +1502,8 @@ want, depending on your needs.
   system clock since it started. A snapshot of this time is
   given on each entry/exit of functions
 
-       hide: echo nofuncgraph-abstime > /debug/tracing/trace_options
-       show: echo funcgraph-abstime > /debug/tracing/trace_options
+       hide: echo nofuncgraph-abstime > trace_options
+       show: echo funcgraph-abstime > trace_options
 
   ie:
 
@@ -1549,7 +1600,7 @@ listed in:
 
    available_filter_functions
 
- # cat /debug/tracing/available_filter_functions
+ # cat available_filter_functions
 put_prev_task_idle
 kmem_cache_create
 pick_next_task_rt
@@ -1561,12 +1612,12 @@ mutex_lock
 If I am only interested in sys_nanosleep and hrtimer_interrupt:
 
  # echo sys_nanosleep hrtimer_interrupt \
-               > /debug/tracing/set_ftrace_filter
- # echo ftrace > /debug/tracing/current_tracer
- # echo 1 > /debug/tracing/tracing_enabled
+               > set_ftrace_filter
+ # echo ftrace > current_tracer
+ # echo 1 > tracing_enabled
  # usleep 1
- # echo 0 > /debug/tracing/tracing_enabled
- # cat /debug/tracing/trace
+ # echo 0 > tracing_enabled
+ # cat trace
 # tracer: ftrace
 #
 #           TASK-PID   CPU#    TIMESTAMP  FUNCTION
@@ -1577,7 +1628,7 @@ If I am only interested in sys_nanosleep and hrtimer_interrupt:
 
 To see which functions are being traced, you can cat the file:
 
- # cat /debug/tracing/set_ftrace_filter
+ # cat set_ftrace_filter
 hrtimer_interrupt
 sys_nanosleep
 
@@ -1597,7 +1648,7 @@ Note: It is better to use quotes to enclose the wild cards,
       otherwise the shell may expand the parameters into names
       of files in the local directory.
 
- # echo 'hrtimer_*' > /debug/tracing/set_ftrace_filter
+ # echo 'hrtimer_*' > set_ftrace_filter
 
 Produces:
 
@@ -1618,7 +1669,7 @@ Produces:
 
 Notice that we lost the sys_nanosleep.
 
- # cat /debug/tracing/set_ftrace_filter
+ # cat set_ftrace_filter
 hrtimer_run_queues
 hrtimer_run_pending
 hrtimer_init
@@ -1644,17 +1695,17 @@ To append to the filters, use '>>'
 To clear out a filter so that all functions will be recorded
 again:
 
- # echo > /debug/tracing/set_ftrace_filter
- # cat /debug/tracing/set_ftrace_filter
+ # echo > set_ftrace_filter
+ # cat set_ftrace_filter
  #
 
 Again, now we want to append.
 
- # echo sys_nanosleep > /debug/tracing/set_ftrace_filter
- # cat /debug/tracing/set_ftrace_filter
+ # echo sys_nanosleep > set_ftrace_filter
+ # cat set_ftrace_filter
 sys_nanosleep
- # echo 'hrtimer_*' >> /debug/tracing/set_ftrace_filter
- # cat /debug/tracing/set_ftrace_filter
+ # echo 'hrtimer_*' >> set_ftrace_filter
+ # cat set_ftrace_filter
 hrtimer_run_queues
 hrtimer_run_pending
 hrtimer_init
@@ -1677,7 +1728,7 @@ hrtimer_init_sleeper
 The set_ftrace_notrace prevents those functions from being
 traced.
 
- # echo '*preempt*' '*lock*' > /debug/tracing/set_ftrace_notrace
+ # echo '*preempt*' '*lock*' > set_ftrace_notrace
 
 Produces:
 
@@ -1767,13 +1818,13 @@ the effect on the tracing is different. Every read from
 trace_pipe is consumed. This means that subsequent reads will be
 different. The trace is live.
 
- # echo function > /debug/tracing/current_tracer
- # cat /debug/tracing/trace_pipe > /tmp/trace.out &
+ # echo function > current_tracer
+ # cat trace_pipe > /tmp/trace.out &
 [1] 4153
- # echo 1 > /debug/tracing/tracing_enabled
+ # echo 1 > tracing_enabled
  # usleep 1
- # echo 0 > /debug/tracing/tracing_enabled
- # cat /debug/tracing/trace
+ # echo 0 > tracing_enabled
+ # cat trace
 # tracer: function
 #
 #           TASK-PID   CPU#    TIMESTAMP  FUNCTION
@@ -1809,7 +1860,7 @@ number listed is the number of entries that can be recorded per
 CPU. To know the full size, multiply the number of possible CPUS
 with the number of entries.
 
- # cat /debug/tracing/buffer_size_kb
+ # cat buffer_size_kb
 1408 (units kilobytes)
 
 Note, to modify this, you must have tracing completely disabled.
@@ -1817,18 +1868,18 @@ To do that, echo "nop" into the current_tracer. If the
 current_tracer is not set to "nop", an EINVAL error will be
 returned.
 
- # echo nop > /debug/tracing/current_tracer
- # echo 10000 > /debug/tracing/buffer_size_kb
- # cat /debug/tracing/buffer_size_kb
+ # echo nop > current_tracer
+ # echo 10000 > buffer_size_kb
+ # cat buffer_size_kb
 10000 (units kilobytes)
 
 The number of pages which will be allocated is limited to a
 percentage of available memory. Allocating too much will produce
 an error.
 
- # echo 1000000000000 > /debug/tracing/buffer_size_kb
+ # echo 1000000000000 > buffer_size_kb
 -bash: echo: write error: Cannot allocate memory
- # cat /debug/tracing/buffer_size_kb
+ # cat buffer_size_kb
 85
 
 -----------
index 5731c67abc558f4ac91d9f54d78bf88cacb8dad6..162effbfbdec09b947a914b27cc7197cc87f1ba9 100644 (file)
@@ -32,41 +32,41 @@ is no way to automatically detect if you are losing events due to CPUs racing.
 Usage Quick Reference
 ---------------------
 
-$ mount -t debugfs debugfs /debug
-$ echo mmiotrace > /debug/tracing/current_tracer
-$ cat /debug/tracing/trace_pipe > mydump.txt &
+$ mount -t debugfs debugfs /sys/kernel/debug
+$ echo mmiotrace > /sys/kernel/debug/tracing/current_tracer
+$ cat /sys/kernel/debug/tracing/trace_pipe > mydump.txt &
 Start X or whatever.
-$ echo "X is up" > /debug/tracing/trace_marker
-$ echo nop > /debug/tracing/current_tracer
+$ echo "X is up" > /sys/kernel/debug/tracing/trace_marker
+$ echo nop > /sys/kernel/debug/tracing/current_tracer
 Check for lost events.
 
 
 Usage
 -----
 
-Make sure debugfs is mounted to /debug. If not, (requires root privileges)
-$ mount -t debugfs debugfs /debug
+Make sure debugfs is mounted to /sys/kernel/debug. If not, (requires root privileges)
+$ mount -t debugfs debugfs /sys/kernel/debug
 
 Check that the driver you are about to trace is not loaded.
 
 Activate mmiotrace (requires root privileges):
-$ echo mmiotrace > /debug/tracing/current_tracer
+$ echo mmiotrace > /sys/kernel/debug/tracing/current_tracer
 
 Start storing the trace:
-$ cat /debug/tracing/trace_pipe > mydump.txt &
+$ cat /sys/kernel/debug/tracing/trace_pipe > mydump.txt &
 The 'cat' process should stay running (sleeping) in the background.
 
 Load the driver you want to trace and use it. Mmiotrace will only catch MMIO
 accesses to areas that are ioremapped while mmiotrace is active.
 
 During tracing you can place comments (markers) into the trace by
-$ echo "X is up" > /debug/tracing/trace_marker
+$ echo "X is up" > /sys/kernel/debug/tracing/trace_marker
 This makes it easier to see which part of the (huge) trace corresponds to
 which action. It is recommended to place descriptive markers about what you
 do.
 
 Shut down mmiotrace (requires root privileges):
-$ echo nop > /debug/tracing/current_tracer
+$ echo nop > /sys/kernel/debug/tracing/current_tracer
 The 'cat' process exits. If it does not, kill it by issuing 'fg' command and
 pressing ctrl+c.
 
@@ -78,10 +78,10 @@ to view your kernel log and look for "mmiotrace has lost events" warning. If
 events were lost, the trace is incomplete. You should enlarge the buffers and
 try again. Buffers are enlarged by first seeing how large the current buffers
 are:
-$ cat /debug/tracing/buffer_size_kb
+$ cat /sys/kernel/debug/tracing/buffer_size_kb
 gives you a number. Approximately double this number and write it back, for
 instance:
-$ echo 128000 > /debug/tracing/buffer_size_kb
+$ echo 128000 > /sys/kernel/debug/tracing/buffer_size_kb
 Then start again from the top.
 
 If you are doing a trace for a driver project, e.g. Nouveau, you should also
index 91aa3c0f0dd29b47cd6fff8fbea649e523ce2e75..450b8f8c389bcb5eba41cc21515795429f0c2b5c 100644 (file)
@@ -16,3 +16,8 @@
  15 -> TeVii S470                                          [d470:9022]
  16 -> DVBWorld DVB-S2 2005                                [0001:2005]
  17 -> NetUP Dual DVB-S2 CI                                [1b55:2a2c]
+ 18 -> Hauppauge WinTV-HVR1270                             [0070:2211]
+ 19 -> Hauppauge WinTV-HVR1275                             [0070:2215]
+ 20 -> Hauppauge WinTV-HVR1255                             [0070:2251]
+ 21 -> Hauppauge WinTV-HVR1210                             [0070:2291,0070:2295]
+ 22 -> Mygica X8506 DMB-TH                                 [14f1:8651]
index 71e9db0b26f74d43ab7025caef914ec462f13707..89093f531727766639fc074dcd03cdf528abd7b2 100644 (file)
@@ -78,3 +78,5 @@
  77 -> TBS 8910 DVB-S                                      [8910:8888]
  78 -> Prof 6200 DVB-S                                     [b022:3022]
  79 -> Terratec Cinergy HT PCI MKII                        [153b:1177]
+ 80 -> Hauppauge WinTV-IR Only                             [0070:9290]
+ 81 -> Leadtek WinFast DTV1800 Hybrid                      [107d:6654]
index 78d0a6eed5715809855698d76de27e1bcbde4464..a98a688c11b8b916b0e3e26dba584985b22050e4 100644 (file)
@@ -17,7 +17,7 @@
  16 -> Hauppauge WinTV HVR 950                  (em2883)        [2040:6513,2040:6517,2040:651b]
  17 -> Pinnacle PCTV HD Pro Stick               (em2880)        [2304:0227]
  18 -> Hauppauge WinTV HVR 900 (R2)             (em2880)        [2040:6502]
- 19 -> PointNix Intra-Oral Camera               (em2860)
+ 19 -> EM2860/SAA711X Reference Design          (em2860)
  20 -> AMD ATI TV Wonder HD 600                 (em2880)        [0438:b002]
  21 -> eMPIA Technology, Inc. GrabBeeX+ Video Encoder (em2800)        [eb1a:2801]
  22 -> Unknown EM2750/EM2751 webcam grabber     (em2750)        [eb1a:2750,eb1a:2751]
@@ -61,3 +61,7 @@
  63 -> Kaiomy TVnPC U2                          (em2860)        [eb1a:e303]
  64 -> Easy Cap Capture DC-60                   (em2860)
  65 -> IO-DATA GV-MVP/SZ                        (em2820/em2840) [04bb:0515]
+ 66 -> Empire dual TV                           (em2880)
+ 67 -> Terratec Grabby                          (em2860)        [0ccd:0096]
+ 68 -> Terratec AV350                           (em2860)        [0ccd:0084]
+ 69 -> KWorld ATSC 315U HDTV TV Box             (em2882)        [eb1a:a313]
index 6dacf2825259a143de95e0d5fe15a67194b7b0ab..15562427e8a9cb51b7f7611bb38a0bc7975bfa65 100644 (file)
 123 -> Beholder BeholdTV 407                    [0000:4070]
 124 -> Beholder BeholdTV 407 FM                 [0000:4071]
 125 -> Beholder BeholdTV 409                    [0000:4090]
-126 -> Beholder BeholdTV 505 FM/RDS             [0000:5051,0000:505B,5ace:5050]
-127 -> Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM [0000:5071,0000:507B,5ace:5070,5ace:5090]
+126 -> Beholder BeholdTV 505 FM                 [5ace:5050]
+127 -> Beholder BeholdTV 507 FM / BeholdTV 509 FM [5ace:5070,5ace:5090]
 128 -> Beholder BeholdTV Columbus TVFM          [0000:5201]
-129 -> Beholder BeholdTV 607 / BeholdTV 609     [5ace:6070,5ace:6071,5ace:6072,5ace:6073,5ace:6090,5ace:6091,5ace:6092,5ace:6093]
+129 -> Beholder BeholdTV 607 FM                 [5ace:6070]
 130 -> Beholder BeholdTV M6                     [5ace:6190]
 131 -> Twinhan Hybrid DTV-DVB 3056 PCI          [1822:0022]
 132 -> Genius TVGO AM11MCE
 142 -> Beholder BeholdTV H6                     [5ace:6290]
 143 -> Beholder BeholdTV M63                    [5ace:6191]
 144 -> Beholder BeholdTV M6 Extra               [5ace:6193]
-145 -> AVerMedia MiniPCI DVB-T Hybrid M103      [1461:f636]
+145 -> AVerMedia MiniPCI DVB-T Hybrid M103      [1461:f636,1461:f736]
 146 -> ASUSTeK P7131 Analog
 147 -> Asus Tiger 3in1                          [1043:4878]
 148 -> Encore ENLTV-FM v5.3                     [1a7f:2008]
 153 -> Kworld Plus TV Analog Lite PCI           [17de:7128]
 154 -> Avermedia AVerTV GO 007 FM Plus          [1461:f31d]
 155 -> Hauppauge WinTV-HVR1120 ATSC/QAM-Hybrid  [0070:6706,0070:6708]
-156 -> Hauppauge WinTV-HVR1110r3                [0070:6707,0070:6709,0070:670a]
+156 -> Hauppauge WinTV-HVR1110r3 DVB-T/Hybrid   [0070:6707,0070:6709,0070:670a]
+157 -> Avermedia AVerTV Studio 507UA            [1461:a11b]
+158 -> AVerMedia Cardbus TV/Radio (E501R)       [1461:b7e9]
+159 -> Beholder BeholdTV 505 RDS                [0000:505B]
+160 -> Beholder BeholdTV 507 RDS                [0000:5071]
+161 -> Beholder BeholdTV 507 RDS                [0000:507B]
+162 -> Beholder BeholdTV 607 FM                 [5ace:6071]
+163 -> Beholder BeholdTV 609 FM                 [5ace:6090]
+164 -> Beholder BeholdTV 609 FM                 [5ace:6091]
+165 -> Beholder BeholdTV 607 RDS                [5ace:6072]
+166 -> Beholder BeholdTV 607 RDS                [5ace:6073]
+167 -> Beholder BeholdTV 609 RDS                [5ace:6092]
+168 -> Beholder BeholdTV 609 RDS                [5ace:6093]
index 691d2f37dc57f49267f263d89bb11e985ada7cf7..be67844074dd1f3c31430dc75a70ccc9a53be24a 100644 (file)
@@ -76,3 +76,5 @@ tuner=75 - Philips TEA5761 FM Radio
 tuner=76 - Xceive 5000 tuner
 tuner=77 - TCL tuner MF02GIP-5N-E
 tuner=78 - Philips FMD1216MEX MK3 Hybrid Tuner
+tuner=79 - Philips PAL/SECAM multi (FM1216 MK5)
+tuner=80 - Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough
index 98529e03a46e196b25f086e604bf0a39bbefceaf..2bcf78896e225a191cc58c23d8636ad92365ecd7 100644 (file)
@@ -163,10 +163,11 @@ sunplus           055f:c650       Mustek MDC5500Z
 zc3xx          055f:d003       Mustek WCam300A
 zc3xx          055f:d004       Mustek WCam300 AN
 conex          0572:0041       Creative Notebook cx11646
-ov519          05a9:0519       OmniVision
+ov519          05a9:0519       OV519 Microphone
 ov519          05a9:0530       OmniVision
-ov519          05a9:4519       OmniVision
+ov519          05a9:4519       Webcam Classic
 ov519          05a9:8519       OmniVision
+ov519          05a9:a518       D-Link DSB-C310 Webcam
 sunplus                05da:1018       Digital Dream Enigma 1.3
 stk014         05e1:0893       Syntek DV4000
 spca561                060b:a001       Maxell Compact Pc PM3
@@ -178,6 +179,7 @@ spca506             06e1:a190       ADS Instant VCD
 ov534          06f8:3002       Hercules Blog Webcam
 ov534          06f8:3003       Hercules Dualpix HD Weblog
 sonixj         06f8:3004       Hercules Classic Silver
+sonixj         06f8:3008       Hercules Deluxe Optical Glass
 spca508                0733:0110       ViewQuest VQ110
 spca508                0130:0130       Clone Digital Webcam 11043
 spca501                0733:0401       Intel Create and Share
@@ -209,6 +211,7 @@ sunplus             08ca:2050       Medion MD 41437
 sunplus                08ca:2060       Aiptek PocketDV5300
 tv8532         0923:010f       ICM532 cams
 mars           093a:050f       Mars-Semi Pc-Camera
+mr97310a       093a:010f       Sakar Digital no. 77379
 pac207         093a:2460       Qtec Webcam 100
 pac207         093a:2461       HP Webcam
 pac207         093a:2463       Philips SPC 220 NC
@@ -265,6 +268,11 @@ sonixj             0c45:60ec       SN9C105+MO4000
 sonixj         0c45:60fb       Surfer NoName
 sonixj         0c45:60fc       LG-LIC300
 sonixj         0c45:60fe       Microdia Audio
+sonixj         0c45:6100       PC Camera (SN9C128)
+sonixj         0c45:610a       PC Camera (SN9C128)
+sonixj         0c45:610b       PC Camera (SN9C128)
+sonixj         0c45:610c       PC Camera (SN9C128)
+sonixj         0c45:610e       PC Camera (SN9C128)
 sonixj         0c45:6128       Microdia/Sonix SNP325
 sonixj         0c45:612a       Avant Camera
 sonixj         0c45:612c       Typhoon Rasy Cam 1.3MPix
index b1137f9a53eb28efb64fab2a1bbcdef53380f086..4f6d0ca019564f86b4dfed75fff7b9597dbd838b 100644 (file)
@@ -26,6 +26,55 @@ Global video workflow
 
      Once the last buffer is filled in, the QCI interface stops.
 
+  c) Capture global finite state machine schema
+
+      +----+                             +---+  +----+
+      | DQ |                             | Q |  | DQ |
+      |    v                             |   v  |    v
+    +-----------+                     +------------------------+
+    |   STOP    |                     | Wait for capture start |
+    +-----------+         Q           +------------------------+
++-> | QCI: stop | ------------------> | QCI: run               | <------------+
+|   | DMA: stop |                     | DMA: stop              |              |
+|   +-----------+             +-----> +------------------------+              |
+|                            /                            |                   |
+|                           /             +---+  +----+   |                   |
+|capture list empty        /              | Q |  | DQ |   | QCI Irq EOF       |
+|                         /               |   v  |    v   v                   |
+|   +--------------------+             +----------------------+               |
+|   | DMA hotlink missed |             |    Capture running   |               |
+|   +--------------------+             +----------------------+               |
+|   | QCI: run           |     +-----> | QCI: run             | <-+           |
+|   | DMA: stop          |    /        | DMA: run             |   |           |
+|   +--------------------+   /         +----------------------+   | Other     |
+|     ^                     /DMA still            |               | channels  |
+|     | capture list       /  running             | DMA Irq End   | not       |
+|     | not empty         /                       |               | finished  |
+|     |                  /                        v               | yet       |
+|   +----------------------+           +----------------------+   |           |
+|   |  Videobuf released   |           |  Channel completed   |   |           |
+|   +----------------------+           +----------------------+   |           |
++-- | QCI: run             |           | QCI: run             | --+           |
+    | DMA: run             |           | DMA: run             |               |
+    +----------------------+           +----------------------+               |
+               ^                      /           |                           |
+               |          no overrun /            | overrun                   |
+               |                    /             v                           |
+    +--------------------+         /   +----------------------+               |
+    |  Frame completed   |        /    |     Frame overran    |               |
+    +--------------------+ <-----+     +----------------------+ restart frame |
+    | QCI: run           |             | QCI: stop            | --------------+
+    | DMA: run           |             | DMA: stop            |
+    +--------------------+             +----------------------+
+
+    Legend: - each box is a FSM state
+            - each arrow is the condition to transition to another state
+            - an arrow with a comment is a mandatory transition (no condition)
+            - arrow "Q" means : a buffer was enqueued
+            - arrow "DQ" means : a buffer was dequeued
+            - "QCI: stop" means the QCI interface is not enabled
+            - "DMA: stop" means all 3 DMA channels are stopped
+            - "DMA: run" means at least 1 DMA channel is still running
 
 DMA usage
 ---------
index 854808b67faed03f209291ae2947be5f051e8af6..d54c1e4c6a9cec5f0cb8e8a2a53517b0bac662a7 100644 (file)
@@ -89,6 +89,11 @@ from dev (driver name followed by the bus_id, to be precise). If you set it
 up before calling v4l2_device_register then it will be untouched. If dev is
 NULL, then you *must* setup v4l2_dev->name before calling v4l2_device_register.
 
+You can use v4l2_device_set_name() to set the name based on a driver name and
+a driver-global atomic_t instance. This will generate names like ivtv0, ivtv1,
+etc. If the name ends with a digit, then it will insert a dash: cx18-0,
+cx18-1, etc. This function returns the instance number.
+
 The first 'dev' argument is normally the struct device pointer of a pci_dev,
 usb_interface or platform_device. It is rare for dev to be NULL, but it happens
 with ISA devices or when one device creates multiple PCI devices, thus making
index 6f562f778b289e48f51e4b0e7b1740c89f4ff683..27479d43a9b06c53a7070d5bab1d33bb66c54caf 100644 (file)
@@ -2,7 +2,7 @@
 obj- := dummy.o
 
 # List of programs to build
-hostprogs-y := slabinfo
+hostprogs-y := slabinfo slqbinfo page-types
 
 # Tell kbuild to always build the programs
 always := $(hostprogs-y)
index bd3d31bc49150f6ec2ad7127273dc0f38e420f7f..c46e68cf93449aadb652bdce92953c53bb00ca22 100644 (file)
@@ -75,15 +75,15 @@ Page stealing from process memory and shm is done if stealing the page would
 alleviate memory pressure on any zone in the page's node that has fallen below
 its watermark.
 
-pages_min/pages_low/pages_high/low_on_memory/zone_wake_kswapd: These are 
-per-zone fields, used to determine when a zone needs to be balanced. When
-the number of pages falls below pages_min, the hysteric field low_on_memory
-gets set. This stays set till the number of free pages becomes pages_high.
-When low_on_memory is set, page allocation requests will try to free some
-pages in the zone (providing GFP_WAIT is set in the request). Orthogonal
-to this, is the decision to poke kswapd to free some zone pages. That
-decision is not hysteresis based, and is done when the number of free
-pages is below pages_low; in which case zone_wake_kswapd is also set.
+watemark[WMARK_MIN/WMARK_LOW/WMARK_HIGH]/low_on_memory/zone_wake_kswapd: These
+are per-zone fields, used to determine when a zone needs to be balanced. When
+the number of pages falls below watermark[WMARK_MIN], the hysteric field
+low_on_memory gets set. This stays set till the number of free pages becomes
+watermark[WMARK_HIGH]. When low_on_memory is set, page allocation requests will
+try to free some pages in the zone (providing GFP_WAIT is set in the request).
+Orthogonal to this, is the decision to poke kswapd to free some zone pages.
+That decision is not hysteresis based, and is done when the number of free
+pages is below watermark[WMARK_LOW]; in which case zone_wake_kswapd is also set.
 
 
 (Good) Ideas that I have heard:
diff --git a/Documentation/vm/page-types.c b/Documentation/vm/page-types.c
new file mode 100644 (file)
index 0000000..0833f44
--- /dev/null
@@ -0,0 +1,698 @@
+/*
+ * page-types: Tool for querying page flags
+ *
+ * Copyright (C) 2009 Intel corporation
+ * Copyright (C) 2009 Wu Fengguang <fengguang.wu@intel.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <getopt.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/fcntl.h>
+
+
+/*
+ * kernel page flags
+ */
+
+#define KPF_BYTES              8
+#define PROC_KPAGEFLAGS                "/proc/kpageflags"
+
+/* copied from kpageflags_read() */
+#define KPF_LOCKED             0
+#define KPF_ERROR              1
+#define KPF_REFERENCED         2
+#define KPF_UPTODATE           3
+#define KPF_DIRTY              4
+#define KPF_LRU                        5
+#define KPF_ACTIVE             6
+#define KPF_SLAB               7
+#define KPF_WRITEBACK          8
+#define KPF_RECLAIM            9
+#define KPF_BUDDY              10
+
+/* [11-20] new additions in 2.6.31 */
+#define KPF_MMAP               11
+#define KPF_ANON               12
+#define KPF_SWAPCACHE          13
+#define KPF_SWAPBACKED         14
+#define KPF_COMPOUND_HEAD      15
+#define KPF_COMPOUND_TAIL      16
+#define KPF_HUGE               17
+#define KPF_UNEVICTABLE                18
+#define KPF_NOPAGE             20
+
+/* [32-] kernel hacking assistances */
+#define KPF_RESERVED           32
+#define KPF_MLOCKED            33
+#define KPF_MAPPEDTODISK       34
+#define KPF_PRIVATE            35
+#define KPF_PRIVATE_2          36
+#define KPF_OWNER_PRIVATE      37
+#define KPF_ARCH               38
+#define KPF_UNCACHED           39
+
+/* [48-] take some arbitrary free slots for expanding overloaded flags
+ * not part of kernel API
+ */
+#define KPF_READAHEAD          48
+#define KPF_SLOB_FREE          49
+#define KPF_SLUB_FROZEN                50
+#define KPF_SLUB_DEBUG         51
+
+#define KPF_ALL_BITS           ((uint64_t)~0ULL)
+#define KPF_HACKERS_BITS       (0xffffULL << 32)
+#define KPF_OVERLOADED_BITS    (0xffffULL << 48)
+#define BIT(name)              (1ULL << KPF_##name)
+#define BITS_COMPOUND          (BIT(COMPOUND_HEAD) | BIT(COMPOUND_TAIL))
+
+static char *page_flag_names[] = {
+       [KPF_LOCKED]            = "L:locked",
+       [KPF_ERROR]             = "E:error",
+       [KPF_REFERENCED]        = "R:referenced",
+       [KPF_UPTODATE]          = "U:uptodate",
+       [KPF_DIRTY]             = "D:dirty",
+       [KPF_LRU]               = "l:lru",
+       [KPF_ACTIVE]            = "A:active",
+       [KPF_SLAB]              = "S:slab",
+       [KPF_WRITEBACK]         = "W:writeback",
+       [KPF_RECLAIM]           = "I:reclaim",
+       [KPF_BUDDY]             = "B:buddy",
+
+       [KPF_MMAP]              = "M:mmap",
+       [KPF_ANON]              = "a:anonymous",
+       [KPF_SWAPCACHE]         = "s:swapcache",
+       [KPF_SWAPBACKED]        = "b:swapbacked",
+       [KPF_COMPOUND_HEAD]     = "H:compound_head",
+       [KPF_COMPOUND_TAIL]     = "T:compound_tail",
+       [KPF_HUGE]              = "G:huge",
+       [KPF_UNEVICTABLE]       = "u:unevictable",
+       [KPF_NOPAGE]            = "n:nopage",
+
+       [KPF_RESERVED]          = "r:reserved",
+       [KPF_MLOCKED]           = "m:mlocked",
+       [KPF_MAPPEDTODISK]      = "d:mappedtodisk",
+       [KPF_PRIVATE]           = "P:private",
+       [KPF_PRIVATE_2]         = "p:private_2",
+       [KPF_OWNER_PRIVATE]     = "O:owner_private",
+       [KPF_ARCH]              = "h:arch",
+       [KPF_UNCACHED]          = "c:uncached",
+
+       [KPF_READAHEAD]         = "I:readahead",
+       [KPF_SLOB_FREE]         = "P:slob_free",
+       [KPF_SLUB_FROZEN]       = "A:slub_frozen",
+       [KPF_SLUB_DEBUG]        = "E:slub_debug",
+};
+
+
+/*
+ * data structures
+ */
+
+static int             opt_raw;        /* for kernel developers */
+static int             opt_list;       /* list pages (in ranges) */
+static int             opt_no_summary; /* don't show summary */
+static pid_t           opt_pid;        /* process to walk */
+
+#define MAX_ADDR_RANGES        1024
+static int             nr_addr_ranges;
+static unsigned long   opt_offset[MAX_ADDR_RANGES];
+static unsigned long   opt_size[MAX_ADDR_RANGES];
+
+#define MAX_BIT_FILTERS        64
+static int             nr_bit_filters;
+static uint64_t                opt_mask[MAX_BIT_FILTERS];
+static uint64_t                opt_bits[MAX_BIT_FILTERS];
+
+static int             page_size;
+
+#define PAGES_BATCH    (64 << 10)      /* 64k pages */
+static int             kpageflags_fd;
+static uint64_t                kpageflags_buf[KPF_BYTES * PAGES_BATCH];
+
+#define HASH_SHIFT     13
+#define HASH_SIZE      (1 << HASH_SHIFT)
+#define HASH_MASK      (HASH_SIZE - 1)
+#define HASH_KEY(flags)        (flags & HASH_MASK)
+
+static unsigned long   total_pages;
+static unsigned long   nr_pages[HASH_SIZE];
+static uint64_t        page_flags[HASH_SIZE];
+
+
+/*
+ * helper functions
+ */
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+#define min_t(type, x, y) ({                   \
+       type __min1 = (x);                      \
+       type __min2 = (y);                      \
+       __min1 < __min2 ? __min1 : __min2; })
+
+unsigned long pages2mb(unsigned long pages)
+{
+       return (pages * page_size) >> 20;
+}
+
+void fatal(const char *x, ...)
+{
+       va_list ap;
+
+       va_start(ap, x);
+       vfprintf(stderr, x, ap);
+       va_end(ap);
+       exit(EXIT_FAILURE);
+}
+
+
+/*
+ * page flag names
+ */
+
+char *page_flag_name(uint64_t flags)
+{
+       static char buf[65];
+       int present;
+       int i, j;
+
+       for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) {
+               present = (flags >> i) & 1;
+               if (!page_flag_names[i]) {
+                       if (present)
+                               fatal("unkown flag bit %d\n", i);
+                       continue;
+               }
+               buf[j++] = present ? page_flag_names[i][0] : '_';
+       }
+
+       return buf;
+}
+
+char *page_flag_longname(uint64_t flags)
+{
+       static char buf[1024];
+       int i, n;
+
+       for (i = 0, n = 0; i < ARRAY_SIZE(page_flag_names); i++) {
+               if (!page_flag_names[i])
+                       continue;
+               if ((flags >> i) & 1)
+                       n += snprintf(buf + n, sizeof(buf) - n, "%s,",
+                                       page_flag_names[i] + 2);
+       }
+       if (n)
+               n--;
+       buf[n] = '\0';
+
+       return buf;
+}
+
+
+/*
+ * page list and summary
+ */
+
+void show_page_range(unsigned long offset, uint64_t flags)
+{
+       static uint64_t      flags0;
+       static unsigned long index;
+       static unsigned long count;
+
+       if (flags == flags0 && offset == index + count) {
+               count++;
+               return;
+       }
+
+       if (count)
+               printf("%lu\t%lu\t%s\n",
+                               index, count, page_flag_name(flags0));
+
+       flags0 = flags;
+       index  = offset;
+       count  = 1;
+}
+
+void show_page(unsigned long offset, uint64_t flags)
+{
+       printf("%lu\t%s\n", offset, page_flag_name(flags));
+}
+
+void show_summary(void)
+{
+       int i;
+
+       printf("             flags\tpage-count       MB"
+               "  symbolic-flags\t\t\tlong-symbolic-flags\n");
+
+       for (i = 0; i < ARRAY_SIZE(nr_pages); i++) {
+               if (nr_pages[i])
+                       printf("0x%016llx\t%10lu %8lu  %s\t%s\n",
+                               (unsigned long long)page_flags[i],
+                               nr_pages[i],
+                               pages2mb(nr_pages[i]),
+                               page_flag_name(page_flags[i]),
+                               page_flag_longname(page_flags[i]));
+       }
+
+       printf("             total\t%10lu %8lu\n",
+                       total_pages, pages2mb(total_pages));
+}
+
+
+/*
+ * page flag filters
+ */
+
+int bit_mask_ok(uint64_t flags)
+{
+       int i;
+
+       for (i = 0; i < nr_bit_filters; i++) {
+               if (opt_bits[i] == KPF_ALL_BITS) {
+                       if ((flags & opt_mask[i]) == 0)
+                               return 0;
+               } else {
+                       if ((flags & opt_mask[i]) != opt_bits[i])
+                               return 0;
+               }
+       }
+
+       return 1;
+}
+
+uint64_t expand_overloaded_flags(uint64_t flags)
+{
+       /* SLOB/SLUB overload several page flags */
+       if (flags & BIT(SLAB)) {
+               if (flags & BIT(PRIVATE))
+                       flags ^= BIT(PRIVATE) | BIT(SLOB_FREE);
+               if (flags & BIT(ACTIVE))
+                       flags ^= BIT(ACTIVE) | BIT(SLUB_FROZEN);
+               if (flags & BIT(ERROR))
+                       flags ^= BIT(ERROR) | BIT(SLUB_DEBUG);
+       }
+
+       /* PG_reclaim is overloaded as PG_readahead in the read path */
+       if ((flags & (BIT(RECLAIM) | BIT(WRITEBACK))) == BIT(RECLAIM))
+               flags ^= BIT(RECLAIM) | BIT(READAHEAD);
+
+       return flags;
+}
+
+uint64_t well_known_flags(uint64_t flags)
+{
+       /* hide flags intended only for kernel hacker */
+       flags &= ~KPF_HACKERS_BITS;
+
+       /* hide non-hugeTLB compound pages */
+       if ((flags & BITS_COMPOUND) && !(flags & BIT(HUGE)))
+               flags &= ~BITS_COMPOUND;
+
+       return flags;
+}
+
+
+/*
+ * page frame walker
+ */
+
+int hash_slot(uint64_t flags)
+{
+       int k = HASH_KEY(flags);
+       int i;
+
+       /* Explicitly reserve slot 0 for flags 0: the following logic
+        * cannot distinguish an unoccupied slot from slot (flags==0).
+        */
+       if (flags == 0)
+               return 0;
+
+       /* search through the remaining (HASH_SIZE-1) slots */
+       for (i = 1; i < ARRAY_SIZE(page_flags); i++, k++) {
+               if (!k || k >= ARRAY_SIZE(page_flags))
+                       k = 1;
+               if (page_flags[k] == 0) {
+                       page_flags[k] = flags;
+                       return k;
+               }
+               if (page_flags[k] == flags)
+                       return k;
+       }
+
+       fatal("hash table full: bump up HASH_SHIFT?\n");
+       exit(EXIT_FAILURE);
+}
+
+void add_page(unsigned long offset, uint64_t flags)
+{
+       flags = expand_overloaded_flags(flags);
+
+       if (!opt_raw)
+               flags = well_known_flags(flags);
+
+       if (!bit_mask_ok(flags))
+               return;
+
+       if (opt_list == 1)
+               show_page_range(offset, flags);
+       else if (opt_list == 2)
+               show_page(offset, flags);
+
+       nr_pages[hash_slot(flags)]++;
+       total_pages++;
+}
+
+void walk_pfn(unsigned long index, unsigned long count)
+{
+       unsigned long batch;
+       unsigned long n;
+       unsigned long i;
+
+       if (index > ULONG_MAX / KPF_BYTES)
+               fatal("index overflow: %lu\n", index);
+
+       lseek(kpageflags_fd, index * KPF_BYTES, SEEK_SET);
+
+       while (count) {
+               batch = min_t(unsigned long, count, PAGES_BATCH);
+               n = read(kpageflags_fd, kpageflags_buf, batch * KPF_BYTES);
+               if (n == 0)
+                       break;
+               if (n < 0) {
+                       perror(PROC_KPAGEFLAGS);
+                       exit(EXIT_FAILURE);
+               }
+
+               if (n % KPF_BYTES != 0)
+                       fatal("partial read: %lu bytes\n", n);
+               n = n / KPF_BYTES;
+
+               for (i = 0; i < n; i++)
+                       add_page(index + i, kpageflags_buf[i]);
+
+               index += batch;
+               count -= batch;
+       }
+}
+
+void walk_addr_ranges(void)
+{
+       int i;
+
+       kpageflags_fd = open(PROC_KPAGEFLAGS, O_RDONLY);
+       if (kpageflags_fd < 0) {
+               perror(PROC_KPAGEFLAGS);
+               exit(EXIT_FAILURE);
+       }
+
+       if (!nr_addr_ranges)
+               walk_pfn(0, ULONG_MAX);
+
+       for (i = 0; i < nr_addr_ranges; i++)
+               walk_pfn(opt_offset[i], opt_size[i]);
+
+       close(kpageflags_fd);
+}
+
+
+/*
+ * user interface
+ */
+
+const char *page_flag_type(uint64_t flag)
+{
+       if (flag & KPF_HACKERS_BITS)
+               return "(r)";
+       if (flag & KPF_OVERLOADED_BITS)
+               return "(o)";
+       return "   ";
+}
+
+void usage(void)
+{
+       int i, j;
+
+       printf(
+"page-types [options]\n"
+"            -r|--raw                  Raw mode, for kernel developers\n"
+"            -a|--addr    addr-spec    Walk a range of pages\n"
+"            -b|--bits    bits-spec    Walk pages with specified bits\n"
+#if 0 /* planned features */
+"            -p|--pid     pid          Walk process address space\n"
+"            -f|--file    filename     Walk file address space\n"
+#endif
+"            -l|--list                 Show page details in ranges\n"
+"            -L|--list-each            Show page details one by one\n"
+"            -N|--no-summary           Don't show summay info\n"
+"            -h|--help                 Show this usage message\n"
+"addr-spec:\n"
+"            N                         one page at offset N (unit: pages)\n"
+"            N+M                       pages range from N to N+M-1\n"
+"            N,M                       pages range from N to M-1\n"
+"            N,                        pages range from N to end\n"
+"            ,M                        pages range from 0 to M\n"
+"bits-spec:\n"
+"            bit1,bit2                 (flags & (bit1|bit2)) != 0\n"
+"            bit1,bit2=bit1            (flags & (bit1|bit2)) == bit1\n"
+"            bit1,~bit2                (flags & (bit1|bit2)) == bit1\n"
+"            =bit1,bit2                flags == (bit1|bit2)\n"
+"bit-names:\n"
+       );
+
+       for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) {
+               if (!page_flag_names[i])
+                       continue;
+               printf("%16s%s", page_flag_names[i] + 2,
+                                page_flag_type(1ULL << i));
+               if (++j > 3) {
+                       j = 0;
+                       putchar('\n');
+               }
+       }
+       printf("\n                                   "
+               "(r) raw mode bits  (o) overloaded bits\n");
+}
+
+unsigned long long parse_number(const char *str)
+{
+       unsigned long long n;
+
+       n = strtoll(str, NULL, 0);
+
+       if (n == 0 && str[0] != '0')
+               fatal("invalid name or number: %s\n", str);
+
+       return n;
+}
+
+void parse_pid(const char *str)
+{
+       opt_pid = parse_number(str);
+}
+
+void parse_file(const char *name)
+{
+}
+
+void add_addr_range(unsigned long offset, unsigned long size)
+{
+       if (nr_addr_ranges >= MAX_ADDR_RANGES)
+               fatal("too much addr ranges\n");
+
+       opt_offset[nr_addr_ranges] = offset;
+       opt_size[nr_addr_ranges] = size;
+       nr_addr_ranges++;
+}
+
+void parse_addr_range(const char *optarg)
+{
+       unsigned long offset;
+       unsigned long size;
+       char *p;
+
+       p = strchr(optarg, ',');
+       if (!p)
+               p = strchr(optarg, '+');
+
+       if (p == optarg) {
+               offset = 0;
+               size   = parse_number(p + 1);
+       } else if (p) {
+               offset = parse_number(optarg);
+               if (p[1] == '\0')
+                       size = ULONG_MAX;
+               else {
+                       size = parse_number(p + 1);
+                       if (*p == ',') {
+                               if (size < offset)
+                                       fatal("invalid range: %lu,%lu\n",
+                                                       offset, size);
+                               size -= offset;
+                       }
+               }
+       } else {
+               offset = parse_number(optarg);
+               size   = 1;
+       }
+
+       add_addr_range(offset, size);
+}
+
+void add_bits_filter(uint64_t mask, uint64_t bits)
+{
+       if (nr_bit_filters >= MAX_BIT_FILTERS)
+               fatal("too much bit filters\n");
+
+       opt_mask[nr_bit_filters] = mask;
+       opt_bits[nr_bit_filters] = bits;
+       nr_bit_filters++;
+}
+
+uint64_t parse_flag_name(const char *str, int len)
+{
+       int i;
+
+       if (!*str || !len)
+               return 0;
+
+       if (len <= 8 && !strncmp(str, "compound", len))
+               return BITS_COMPOUND;
+
+       for (i = 0; i < ARRAY_SIZE(page_flag_names); i++) {
+               if (!page_flag_names[i])
+                       continue;
+               if (!strncmp(str, page_flag_names[i] + 2, len))
+                       return 1ULL << i;
+       }
+
+       return parse_number(str);
+}
+
+uint64_t parse_flag_names(const char *str, int all)
+{
+       const char *p    = str;
+       uint64_t   flags = 0;
+
+       while (1) {
+               if (*p == ',' || *p == '=' || *p == '\0') {
+                       if ((*str != '~') || (*str == '~' && all && *++str))
+                               flags |= parse_flag_name(str, p - str);
+                       if (*p != ',')
+                               break;
+                       str = p + 1;
+               }
+               p++;
+       }
+
+       return flags;
+}
+
+void parse_bits_mask(const char *optarg)
+{
+       uint64_t mask;
+       uint64_t bits;
+       const char *p;
+
+       p = strchr(optarg, '=');
+       if (p == optarg) {
+               mask = KPF_ALL_BITS;
+               bits = parse_flag_names(p + 1, 0);
+       } else if (p) {
+               mask = parse_flag_names(optarg, 0);
+               bits = parse_flag_names(p + 1, 0);
+       } else if (strchr(optarg, '~')) {
+               mask = parse_flag_names(optarg, 1);
+               bits = parse_flag_names(optarg, 0);
+       } else {
+               mask = parse_flag_names(optarg, 0);
+               bits = KPF_ALL_BITS;
+       }
+
+       add_bits_filter(mask, bits);
+}
+
+
+struct option opts[] = {
+       { "raw"       , 0, NULL, 'r' },
+       { "pid"       , 1, NULL, 'p' },
+       { "file"      , 1, NULL, 'f' },
+       { "addr"      , 1, NULL, 'a' },
+       { "bits"      , 1, NULL, 'b' },
+       { "list"      , 0, NULL, 'l' },
+       { "list-each" , 0, NULL, 'L' },
+       { "no-summary", 0, NULL, 'N' },
+       { "help"      , 0, NULL, 'h' },
+       { NULL        , 0, NULL, 0 }
+};
+
+int main(int argc, char *argv[])
+{
+       int c;
+
+       page_size = getpagesize();
+
+       while ((c = getopt_long(argc, argv,
+                               "rp:f:a:b:lLNh", opts, NULL)) != -1) {
+               switch (c) {
+               case 'r':
+                       opt_raw = 1;
+                       break;
+               case 'p':
+                       parse_pid(optarg);
+                       break;
+               case 'f':
+                       parse_file(optarg);
+                       break;
+               case 'a':
+                       parse_addr_range(optarg);
+                       break;
+               case 'b':
+                       parse_bits_mask(optarg);
+                       break;
+               case 'l':
+                       opt_list = 1;
+                       break;
+               case 'L':
+                       opt_list = 2;
+                       break;
+               case 'N':
+                       opt_no_summary = 1;
+                       break;
+               case 'h':
+                       usage();
+                       exit(0);
+               default:
+                       usage();
+                       exit(1);
+               }
+       }
+
+       if (opt_list == 1)
+               printf("offset\tcount\tflags\n");
+       if (opt_list == 2)
+               printf("offset\tflags\n");
+
+       walk_addr_ranges();
+
+       if (opt_list == 1)
+               show_page_range(0, 0);  /* drain the buffer */
+
+       if (opt_no_summary)
+               return 0;
+
+       if (opt_list)
+               printf("\n\n");
+
+       show_summary();
+
+       return 0;
+}
index ce72c0fe6177efaeb4afd73d2b7d01372e718727..600a304a828cb2865e63a85e031fb881f27cbbc7 100644 (file)
@@ -12,9 +12,9 @@ There are three components to pagemap:
    value for each virtual page, containing the following data (from
    fs/proc/task_mmu.c, above pagemap_read):
 
-    * Bits 0-55  page frame number (PFN) if present
+    * Bits 0-54  page frame number (PFN) if present
     * Bits 0-4   swap type if swapped
-    * Bits 5-55  swap offset if swapped
+    * Bits 5-54  swap offset if swapped
     * Bits 55-60 page shift (page size = 1<<page shift)
     * Bit  61    reserved for future use
     * Bit  62    page swapped
@@ -36,7 +36,7 @@ There are three components to pagemap:
  * /proc/kpageflags.  This file contains a 64-bit set of flags for each
    page, indexed by PFN.
 
-   The flags are (from fs/proc/proc_misc, above kpageflags_read):
+   The flags are (from fs/proc/page.c, above kpageflags_read):
 
      0. LOCKED
      1. ERROR
@@ -49,6 +49,68 @@ There are three components to pagemap:
      8. WRITEBACK
      9. RECLAIM
     10. BUDDY
+    11. MMAP
+    12. ANON
+    13. SWAPCACHE
+    14. SWAPBACKED
+    15. COMPOUND_HEAD
+    16. COMPOUND_TAIL
+    16. HUGE
+    18. UNEVICTABLE
+    20. NOPAGE
+
+Short descriptions to the page flags:
+
+ 0. LOCKED
+    page is being locked for exclusive access, eg. by undergoing read/write IO
+
+ 7. SLAB
+    page is managed by the SLAB/SLOB/SLUB/SLQB kernel memory allocator
+    When compound page is used, SLUB/SLQB will only set this flag on the head
+    page; SLOB will not flag it at all.
+
+10. BUDDY
+    a free memory block managed by the buddy system allocator
+    The buddy system organizes free memory in blocks of various orders.
+    An order N block has 2^N physically contiguous pages, with the BUDDY flag
+    set for and _only_ for the first page.
+
+15. COMPOUND_HEAD
+16. COMPOUND_TAIL
+    A compound page with order N consists of 2^N physically contiguous pages.
+    A compound page with order 2 takes the form of "HTTT", where H donates its
+    head page and T donates its tail page(s).  The major consumers of compound
+    pages are hugeTLB pages (Documentation/vm/hugetlbpage.txt), the SLUB etc.
+    memory allocators and various device drivers. However in this interface,
+    only huge/giga pages are made visible to end users.
+17. HUGE
+    this is an integral part of a HugeTLB page
+
+20. NOPAGE
+    no page frame exists at the requested address
+
+    [IO related page flags]
+ 1. ERROR     IO error occurred
+ 3. UPTODATE  page has up-to-date data
+              ie. for file backed page: (in-memory data revision >= on-disk one)
+ 4. DIRTY     page has been written to, hence contains new data
+              ie. for file backed page: (in-memory data revision >  on-disk one)
+ 8. WRITEBACK page is being synced to disk
+
+    [LRU related page flags]
+ 5. LRU         page is in one of the LRU lists
+ 6. ACTIVE      page is in the active LRU list
+18. UNEVICTABLE page is in the unevictable (non-)LRU list
+                It is somehow pinned and not a candidate for LRU page reclaims,
+               eg. ramfs pages, shmctl(SHM_LOCK) and mlock() memory segments
+ 2. REFERENCED  page has been referenced since last LRU list enqueue/requeue
+ 9. RECLAIM     page will be reclaimed soon after its pageout IO completed
+11. MMAP        a memory mapped page
+12. ANON        a memory mapped page that is not part of a file
+13. SWAPCACHE   page is mapped to swap space, ie. has an associated swap entry
+14. SWAPBACKED  page is backed by swap/RAM
+
+The page-types tool in this directory can be used to query the above flags.
 
 Using pagemap to do something useful:
 
index 2cb7566904b128a80bd507359f22031b800ff9b7..fb94addb34de463ec8c4af59d1b5861d04fd1e6b 100644 (file)
@@ -36,6 +36,12 @@ trivial patch so apply some common sense.
        (scripts/checkpatch.pl) to catch trival style violations.
        See Documentation/CodingStyle for guidance here.
 
+       PLEASE CC: the maintainers and mailing lists that are generated
+       by scripts/get_maintainer.pl.  The results returned by the
+       script will be best if you have git installed and are making
+       your changes in a branch derived from Linus' latest git tree.
+       See Documentation/SubmittingPatches for details.
+
        PLEASE try to include any credit lines you want added with the
        patch. It avoids people being missed off by mistake and makes
        it easier to know who wants adding and who doesn't.
@@ -157,9 +163,10 @@ S: Maintained
 F:     drivers/net/r8169.c
 
 8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
+P:     Alan Cox
+M:     alan@lxorguk.ukuu.org.uk
 L:     linux-serial@vger.kernel.org
 W:     http://serial.sourceforge.net
-M:     alan@lxorguk.ukuu.org.uk
 S:     Odd Fixes
 F:     drivers/serial/8250*
 F:     include/linux/serial_8250.h
@@ -488,7 +495,7 @@ AOA (Apple Onboard Audio) ALSA DRIVER
 P:     Johannes Berg
 M:     johannes@sipsolutions.net
 L:     linuxppc-dev@ozlabs.org
-L:     alsa-devel@alsa-project.org (subscribers-only)
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Maintained
 F:     sound/aoa/
 
@@ -911,7 +918,6 @@ P:  Dan Williams
 M:     dan.j.williams@intel.com
 P:     Maciej Sosnowski
 M:     maciej.sosnowski@intel.com
-L:     linux-kernel@vger.kernel.org
 W:     http://sourceforge.net/projects/xscaleiop
 S:     Supported
 F:     Documentation/crypto/async-tx-api.txt
@@ -1007,7 +1013,6 @@ F:        drivers/mmc/host/at91_mci.c
 ATMEL AT91 / AT32 SERIAL DRIVER
 P:     Haavard Skinnemoen
 M:     hskinnemoen@atmel.com
-L:     linux-kernel@vger.kernel.org
 S:     Supported
 F:     drivers/serial/atmel_serial.c
 
@@ -1063,7 +1068,6 @@ F:        kernel/audit*
 AUXILIARY DISPLAY DRIVERS
 P:     Miguel Ojeda Sandonis
 M:     miguel.ojeda.sandonis@gmail.com
-L:     linux-kernel@vger.kernel.org
 W:     http://miguelojeda.es/auxdisplay.htm
 W:     http://jair.lab.fi.uva.es/~migojed/auxdisplay.htm
 S:     Maintained
@@ -1133,7 +1137,6 @@ F:        drivers/net/hamradio/baycom*
 BEFS FILE SYSTEM
 P:     Sergey S. Kostyliov
 M:     rathamahata@php4.ru
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     Documentation/filesystems/befs.txt
 F:     fs/befs/
@@ -1141,7 +1144,6 @@ F:        fs/befs/
 BFS FILE SYSTEM
 P:     Tigran A. Aivazian
 M:     tigran@aivazian.fsnet.co.uk
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     Documentation/filesystems/bfs.txt
 F:     fs/bfs/
@@ -1198,7 +1200,6 @@ F:        drivers/i2c/busses/i2c-bfin-twi.c
 BLOCK LAYER
 P:     Jens Axboe
 M:     axboe@kernel.dk
-L:     linux-kernel@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-2.6-block.git
 S:     Maintained
 F:     block/
@@ -1325,7 +1326,6 @@ P:        Muli Ben-Yehuda
 M:     muli@il.ibm.com
 P:     Jon D. Mason
 M:     jdmason@kudzu.us
-L:     linux-kernel@vger.kernel.org
 L:     discuss@x86-64.org
 S:     Maintained
 F:     arch/x86/kernel/pci-calgary_64.c
@@ -1377,7 +1377,6 @@ F:        include/linux/usb/wusb*
 CFAG12864B LCD DRIVER
 P:     Miguel Ojeda Sandonis
 M:     miguel.ojeda.sandonis@gmail.com
-L:     linux-kernel@vger.kernel.org
 W:     http://miguelojeda.es/auxdisplay.htm
 W:     http://jair.lab.fi.uva.es/~migojed/auxdisplay.htm
 S:     Maintained
@@ -1387,7 +1386,6 @@ F:        include/linux/cfag12864b.h
 CFAG12864BFB LCD FRAMEBUFFER DRIVER
 P:     Miguel Ojeda Sandonis
 M:     miguel.ojeda.sandonis@gmail.com
-L:     linux-kernel@vger.kernel.org
 W:     http://miguelojeda.es/auxdisplay.htm
 W:     http://jair.lab.fi.uva.es/~migojed/auxdisplay.htm
 S:     Maintained
@@ -1407,7 +1405,6 @@ X:        net/wireless/wext*
 CHECKPATCH
 P:     Andy Whitcroft
 M:     apw@canonical.com
-L:     linux-kernel@vger.kernel.org
 S:     Supported
 F:     scripts/checkpatch.pl
 
@@ -1436,7 +1433,7 @@ F:        drivers/usb/host/ohci-ep93xx.c
 CIRRUS LOGIC CS4270 SOUND DRIVER
 P:     Timur Tabi
 M:     timur@freescale.com
-L:     alsa-devel@alsa-project.org
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Supported
 F:     sound/soc/codecs/cs4270*
 
@@ -1461,6 +1458,7 @@ P:        Joe Eykholt
 M:     jeykholt@cisco.com
 L:     linux-scsi@vger.kernel.org
 S:     Supported
+F:     drivers/scsi/fnic/
 
 CODA FILE SYSTEM
 P:     Jan Harkes
@@ -1533,7 +1531,6 @@ F:        drivers/usb/atm/cxacru.c
 CONFIGFS
 P:     Joel Becker
 M:     joel.becker@oracle.com
-L:     linux-kernel@vger.kernel.org
 S:     Supported
 F:     fs/configfs/
 F:     include/linux/configfs.h
@@ -1591,7 +1588,6 @@ F:        arch/x86/kernel/msr.c
 CPUSETS
 P:     Paul Menage
 M:     menage@google.com
-L:     linux-kernel@vger.kernel.org
 W:     http://www.bullopensource.org/cpuset/
 W:     http://oss.sgi.com/projects/cpusets/
 S:     Supported
@@ -1798,7 +1794,6 @@ DEVICE NUMBER REGISTRY
 P:     Torben Mathiasen
 M:     device@lanana.org
 W:     http://lanana.org/docs/device-list/index.html
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 
 DEVICE-MAPPER  (LVM)
@@ -1824,7 +1819,6 @@ F:        drivers/char/digi*
 DIRECTORY NOTIFICATION (DNOTIFY)
 P:     Eric Paris
 M:     eparis@parisplace.org
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     Documentation/filesystems/dnotify.txt
 F:     fs/notify/dnotify/
@@ -1841,7 +1835,6 @@ S:        Maintained
 DISKQUOTA
 P:     Jan Kara
 M:     jack@suse.cz
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     Documentation/filesystems/quota.txt
 F:     fs/quota/
@@ -1863,7 +1856,6 @@ P:        Maciej Sosnowski
 M:     maciej.sosnowski@intel.com
 P:     Dan Williams
 M:     dan.j.williams@intel.com
-L:     linux-kernel@vger.kernel.org
 S:     Supported
 F:     drivers/dma/
 F:     include/linux/dma*
@@ -1915,7 +1907,6 @@ F:        drivers/scsi/dpt/
 DRIVER CORE, KOBJECTS, AND SYSFS
 P:     Greg Kroah-Hartman
 M:     gregkh@suse.de
-L:     linux-kernel@vger.kernel.org
 T:     quilt kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
 S:     Supported
 F:     Documentation/kobject.txt
@@ -1981,8 +1972,8 @@ F:        net/bridge/netfilter/ebt*.c
 ECRYPT FILE SYSTEM
 P:     Tyler Hicks
 M:     tyhicks@linux.vnet.ibm.com
-M:     Dustin Kirkland
-P:     kirkland@canonical.com
+P:     Dustin Kirkland
+M:     kirkland@canonical.com
 L:     ecryptfs-devel@lists.launchpad.net
 W:     https://launchpad.net/ecryptfs
 S:     Supported
@@ -2262,7 +2253,6 @@ F:        drivers/firewire/
 F:     include/linux/firewire*.h
 
 FIRMWARE LOADER (request_firmware)
-L:     linux-kernel@vger.kernel.org
 S:     Orphan
 F:     Documentation/firmware_class/
 F:     drivers/base/firmware*.c
@@ -2299,7 +2289,6 @@ M:        leoli@freescale.com
 P:     Zhang Wei
 M:     zw@zh-kernel.org
 L:     linuxppc-dev@ozlabs.org
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     drivers/dma/fsldma.*
 
@@ -2365,7 +2354,7 @@ F:        drivers/serial/ucc_uart.c
 FREESCALE SOC SOUND DRIVERS
 P:     Timur Tabi
 M:     timur@freescale.com
-L:     alsa-devel@alsa-project.org
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 L:     linuxppc-dev@ozlabs.org
 S:     Supported
 F:     sound/soc/fsl/fsl*
@@ -2499,7 +2488,6 @@ F:        drivers/hwmon/hdaps.c
 
 HYPERVISOR VIRTUAL CONSOLE DRIVER
 L:     linuxppc-dev@ozlabs.org
-L:     linux-kernel@vger.kernel.org
 S:     Odd Fixes
 F:     drivers/char/hvc_*
 
@@ -2566,7 +2554,6 @@ F:        sound/parisc/harmony.*
 HAYES ESP SERIAL DRIVER
 P:     Andrew J. Robinson
 M:     arobinso@nyx.net
-L:     linux-kernel@vger.kernel.org
 W:     http://www.nyx.net/~arobinso
 S:     Maintained
 F:     Documentation/serial/hayes-esp.txt
@@ -2592,7 +2579,6 @@ F:        include/linux/cciss_ioctl.h
 HFS FILESYSTEM
 P:     Roman Zippel
 M:     zippel@linux-m68k.org
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     Documentation/filesystems/hfs.txt
 F:     fs/hfs/
@@ -2632,7 +2618,6 @@ F:        include/linux/hid*
 HIGH-RESOLUTION TIMERS, CLOCKEVENTS, DYNTICKS
 P:     Thomas Gleixner
 M:     tglx@linutronix.de
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     Documentation/timers/
 F:     kernel/hrtimer.c
@@ -2771,7 +2756,6 @@ F:        drivers/i2c/busses/i2c-tiny-usb.c
 i386 BOOT CODE
 P:     H. Peter Anvin
 M:     hpa@zytor.com
-L:     Linux-Kernel@vger.kernel.org
 S:     Maintained
 F:     arch/x86/boot/
 
@@ -2901,7 +2885,6 @@ P:        Robert Love
 M:     rlove@rlove.org
 P:     Eric Paris
 M:     eparis@parisplace.org
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     Documentation/filesystems/inotify.txt
 F:     fs/notify/inotify/
@@ -2949,7 +2932,6 @@ F:        arch/x86/kernel/microcode_intel.c
 INTEL I/OAT DMA DRIVER
 P:     Maciej Sosnowski
 M:     maciej.sosnowski@intel.com
-L:     linux-kernel@vger.kernel.org
 S:     Supported
 F:     drivers/dma/ioat*
 
@@ -2965,7 +2947,6 @@ F:        include/linux/intel-iommu.h
 INTEL IOP-ADMA DMA DRIVER
 P:     Dan Williams
 M:     dan.j.williams@intel.com
-L:     linux-kernel@vger.kernel.org
 S:     Supported
 F:     drivers/dma/iop-adma.c
 
@@ -3278,7 +3259,6 @@ M:        vgoyal@redhat.com
 P:     Haren Myneni
 M:     hbabu@us.ibm.com
 L:     kexec@lists.infradead.org
-L:     linux-kernel@vger.kernel.org
 W:     http://lse.sourceforge.net/kdump/
 S:     Maintained
 F:     Documentation/kdump/
@@ -3388,7 +3368,6 @@ KEXEC
 P:     Eric Biederman
 M:     ebiederm@xmission.com
 W:     http://ftp.kernel.org/pub/linux/kernel/people/horms/kexec-tools/
-L:     linux-kernel@vger.kernel.org
 L:     kexec@lists.infradead.org
 S:     Maintained
 F:     include/linux/kexec.h
@@ -3405,6 +3384,14 @@ F:       drivers/serial/kgdboc.c
 F:     include/linux/kgdb.h
 F:     kernel/kgdb.c
 
+KMEMCHECK
+P:     Vegard Nossum
+M:     vegardno@ifi.uio.no
+P      Pekka Enberg
+M:     penberg@cs.helsinki.fi
+L:     linux-kernel@vger.kernel.org
+S:     Maintained
+
 KMEMLEAK
 P:     Catalin Marinas
 M:     catalin.marinas@arm.com
@@ -3418,7 +3405,6 @@ F:        mm/kmemleak-test.c
 KMEMTRACE
 P:     Eduard - Gabriel Munteanu
 M:     eduard.munteanu@linux360.ro
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     Documentation/trace/kmemtrace.txt
 F:     include/trace/kmemtrace.h
@@ -3433,7 +3419,6 @@ P:        David S. Miller
 M:     davem@davemloft.net
 P:     Masami Hiramatsu
 M:     mhiramat@redhat.com
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     Documentation/kprobes.txt
 F:     include/linux/kprobes.h
@@ -3442,7 +3427,6 @@ F:        kernel/kprobes.c
 KS0108 LCD CONTROLLER DRIVER
 P:     Miguel Ojeda Sandonis
 M:     miguel.ojeda.sandonis@gmail.com
-L:     linux-kernel@vger.kernel.org
 W:     http://miguelojeda.es/auxdisplay.htm
 W:     http://jair.lab.fi.uva.es/~migojed/auxdisplay.htm
 S:     Maintained
@@ -3606,7 +3590,6 @@ P:        Peter Zijlstra
 M:     peterz@infradead.org
 P:     Ingo Molnar
 M:     mingo@redhat.com
-L:     linux-kernel@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/peterz/linux-2.6-lockdep.git
 S:     Maintained
 F:     Documentation/lockdep*.txt
@@ -3658,7 +3641,6 @@ L:        linux-m32r-ja@ml.linux-m32r.org (in Japanese)
 W:     http://www.linux-m32r.org/
 S:     Maintained
 F:     arch/m32r/
-F:     include/asm-m32r/
 
 M68K ARCHITECTURE
 P:     Geert Uytterhoeven
@@ -3742,7 +3724,6 @@ F:        include/linux/mv643xx.h
 MARVELL SOC MMC/SD/SDIO CONTROLLER DRIVER
 P:     Nicolas Pitre
 M:     nico@cam.org
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 
 MARVELL YUKON / SYSKONNECT DRIVER
@@ -3796,7 +3777,6 @@ F:        drivers/scsi/megaraid/
 
 MEMORY MANAGEMENT
 L:     linux-mm@kvack.org
-L:     linux-kernel@vger.kernel.org
 W:     http://www.linux-mm.org
 S:     Maintained
 F:     include/linux/mm.h
@@ -3810,7 +3790,6 @@ M:        xemul@openvz.org
 P:     KAMEZAWA Hiroyuki
 M:     kamezawa.hiroyu@jp.fujitsu.com
 L:     linux-mm@kvack.org
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     mm/memcontrol.c
 
@@ -3853,7 +3832,6 @@ F:        arch/mips/
 MISCELLANEOUS MCA-SUPPORT
 P:     James Bottomley
 M:     James.Bottomley@HansenPartnership.com
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     Documentation/ia64/mca.txt
 F:     Documentation/mca.txt
@@ -3863,7 +3841,6 @@ F:        include/linux/mca*
 MODULE SUPPORT
 P:     Rusty Russell
 M:     rusty@rustcorp.com.au
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     include/linux/module.h
 F:     kernel/module.c
@@ -3887,7 +3864,6 @@ F:        drivers/mmc/host/imxmmc.*
 MOUSE AND MISC DEVICES [GENERAL]
 P:     Alessandro Rubini
 M:     rubini@ipvvis.unipv.it
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     drivers/input/mouse/
 F:     include/linux/gpio_mouse.h
@@ -3895,7 +3871,6 @@ F:        include/linux/gpio_mouse.h
 MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL CARD
 P:     Jiri Slaby
 M:     jirislaby@gmail.com
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     Documentation/serial/moxa-smartio
 F:     drivers/char/mxser.*
@@ -3911,7 +3886,6 @@ F:        drivers/platform/x86/msi-laptop.c
 MULTIFUNCTION DEVICES (MFD)
 P:     Samuel Ortiz
 M:     sameo@linux.intel.com
-L:     linux-kernel@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6.git
 S:     Supported
 F:     drivers/mfd/
@@ -3919,7 +3893,6 @@ F:        drivers/mfd/
 MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM
 P:     Pierre Ossman
 M:     pierre@ossman.eu
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     drivers/mmc/
 F:     include/linux/mmc/
@@ -3927,7 +3900,6 @@ F:        include/linux/mmc/
 MULTIMEDIA CARD (MMC) ETC. OVER SPI
 P:     David Brownell
 M:     dbrownell@users.sourceforge.net
-L:     linux-kernel@vger.kernel.org
 S:     Odd Fixes
 F:     drivers/mmc/host/mmc_spi.c
 F:     include/linux/spi/mmc_spi.h
@@ -3942,7 +3914,6 @@ F:        sound/oss/msnd*
 MULTITECH MULTIPORT CARD (ISICOM)
 P:     Jiri Slaby
 M:     jirislaby@gmail.com
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     drivers/char/isicom.c
 F:     include/linux/isicom.h
@@ -4186,7 +4157,6 @@ NTFS FILESYSTEM
 P:     Anton Altaparmakov
 M:     aia21@cantab.net
 L:     linux-ntfs-dev@lists.sourceforge.net
-L:     linux-kernel@vger.kernel.org
 W:     http://www.linux-ntfs.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/aia21/ntfs-2.6.git
 S:     Maintained
@@ -4420,7 +4390,6 @@ M:        akataria@vmware.com
 P:     Rusty Russell
 M:     rusty@rustcorp.com.au
 L:     virtualization@lists.osdl.org
-L:     linux-kernel@vger.kernel.org
 S:     Supported
 F:     Documentation/ia64/paravirt_ops.txt
 F:     arch/*/kernel/paravirt*
@@ -4471,7 +4440,6 @@ F:        include/linux/leds-pca9532.h
 PCI ERROR RECOVERY
 P:     Linas Vepstas
 M:     linas@austin.ibm.com
-L:     linux-kernel@vger.kernel.org
 L:     linux-pci@vger.kernel.org
 S:     Supported
 F:     Documentation/PCI/pci-error-recovery.txt
@@ -4480,7 +4448,6 @@ F:        Documentation/powerpc/eeh-pci-error-recovery.txt
 PCI SUBSYSTEM
 P:     Jesse Barnes
 M:     jbarnes@virtuousgeek.org
-L:     linux-kernel@vger.kernel.org
 L:     linux-pci@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6.git
 S:     Supported
@@ -4515,7 +4482,6 @@ F:        drivers/net/pcnet32.c
 PER-TASK DELAY ACCOUNTING
 P:     Balbir Singh
 M:     balbir@linux.vnet.ibm.com
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     include/linux/delayacct.h
 F:     kernel/delayacct.c
@@ -4547,7 +4513,6 @@ F:        drivers/mtd/devices/phram.c
 PKTCDVD DRIVER
 P:     Peter Osterlund
 M:     petero2@telia.com
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     drivers/block/pktcdvd.c
 F:     include/linux/pktcdvd.h
@@ -4555,7 +4520,6 @@ F:        include/linux/pktcdvd.h
 POSIX CLOCKS and TIMERS
 P:     Thomas Gleixner
 M:     tglx@linutronix.de
-L:     linux-kernel@vger.kernel.org
 S:     Supported
 F:     fs/timerfd.c
 F:     include/linux/timer*
@@ -4566,7 +4530,6 @@ P:        Anton Vorontsov
 M:     cbou@mail.ru
 P:     David Woodhouse
 M:     dwmw2@infradead.org
-L:     linux-kernel@vger.kernel.org
 T:     git git://git.infradead.org/battery-2.6.git
 S:     Maintained
 F:     include/linux/power_supply.h
@@ -4618,7 +4581,6 @@ F:        include/linux/if_pppol2tp.h
 PREEMPTIBLE KERNEL
 P:     Robert Love
 M:     rml@tech9.net
-L:     linux-kernel@vger.kernel.org
 L:     kpreempt-tech@lists.sourceforge.net
 W:     ftp://ftp.kernel.org/pub/linux/kernel/people/rml/preempt-kernel
 S:     Supported
@@ -4681,7 +4643,6 @@ P:        Roland McGrath
 M:     roland@redhat.com
 P:     Oleg Nesterov
 M:     oleg@redhat.com
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     include/asm-generic/syscall.h
 F:     include/linux/ptrace.h
@@ -4767,7 +4728,6 @@ F:        drivers/net/qlge/
 QNX4 FILESYSTEM
 P:     Anders Larsen
 M:     al@alarsen.net
-L:     linux-kernel@vger.kernel.org
 W:     http://www.alarsen.net/linux/qnx4fs/
 S:     Maintained
 F:     fs/qnx4/
@@ -4814,7 +4774,6 @@ F:        drivers/char/random.c
 RAPIDIO SUBSYSTEM
 P:     Matt Porter
 M:     mporter@kernel.crashing.org
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     drivers/rapidio/
 
@@ -4828,7 +4787,8 @@ F:        drivers/net/wireless/ray*
 RCUTORTURE MODULE
 P:     Josh Triplett
 M:     josh@freedesktop.org
-L:     linux-kernel@vger.kernel.org
+P:     Paul E. McKenney
+M:     paulmck@linux.vnet.ibm.com
 S:     Maintained
 F:     Documentation/RCU/torture.txt
 F:     kernel/rcutorture.c
@@ -4836,7 +4796,6 @@ F:        kernel/rcutorture.c
 RDC R-321X SoC
 P:     Florian Fainelli
 M:     florian@openwrt.org
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 
 RDC R6040 FAST ETHERNET DRIVER
@@ -4856,8 +4815,9 @@ F:        net/rds/
 READ-COPY UPDATE (RCU)
 P:     Dipankar Sarma
 M:     dipankar@in.ibm.com
+P:     Paul E. McKenney
+M:     paulmck@linux.vnet.ibm.com
 W:     http://www.rdrop.com/users/paulmck/rclock/
-L:     linux-kernel@vger.kernel.org
 S:     Supported
 F:     Documentation/RCU/rcu.txt
 F:     Documentation/RCU/rcuref.txt
@@ -4868,7 +4828,6 @@ F:        kernel/rcupdate.c
 REAL TIME CLOCK DRIVER
 P:     Paul Gortmaker
 M:     p_gortmaker@yahoo.com
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     Documentation/rtc.txt
 F:     drivers/rtc/
@@ -5006,7 +4965,6 @@ S3C24XX SD/MMC Driver
 P:     Ben Dooks
 M:     ben-linux@fluff.org
 L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
-L:     linux-kernel@vger.kernel.org
 S:     Supported
 F:     drivers/mmc/host/s3cmci.*
 
@@ -5032,7 +4990,6 @@ P:        Ingo Molnar
 M:     mingo@elte.hu
 P:     Peter Zijlstra
 M:     peterz@infradead.org
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     kernel/sched*
 F:     include/linux/sched.h
@@ -5134,7 +5091,6 @@ F:        drivers/mmc/host/sdhci.*
 SECURITY SUBSYSTEM
 P:     James Morris
 M:     jmorris@namei.org
-L:     linux-kernel@vger.kernel.org
 L:     linux-security-module@vger.kernel.org (suggested Cc:)
 T:     git git://www.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6.git
 W:     http://security.wiki.kernel.org/
@@ -5153,7 +5109,6 @@ P:        James Morris
 M:     jmorris@namei.org
 P:     Eric Paris
 M:     eparis@parisplace.org
-L:     linux-kernel@vger.kernel.org (kernel issues)
 L:     selinux@tycho.nsa.gov (subscribers-only, general discussion)
 W:     http://selinuxproject.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6.git
@@ -5416,7 +5371,6 @@ F:        include/linux/sony-laptop.h
 SONY MEMORYSTICK CARD SUPPORT
 P:     Alex Dubov
 M:     oakad@yahoo.com
-L:     linux-kernel@vger.kernel.org
 W:     http://tifmxx.berlios.de/
 S:     Maintained
 F:     drivers/memstick/host/tifm_ms.c
@@ -5426,7 +5380,7 @@ P:        Jaroslav Kysela
 M:     perex@perex.cz
 P:     Takashi Iwai
 M:     tiwai@suse.de
-L:     alsa-devel@alsa-project.org (subscribers-only)
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 W:     http://www.alsa-project.org/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6.git
 T:     git git://git.alsa-project.org/alsa-kernel.git
@@ -5441,7 +5395,7 @@ M:        lrg@slimlogic.co.uk
 P:     Mark Brown
 M:     broonie@opensource.wolfsonmicro.com
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git
-L:     alsa-devel@alsa-project.org (subscribers-only)
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 W:     http://alsa-project.org/main/index.php/ASoC
 S:     Supported
 F:     sound/soc/
@@ -5459,7 +5413,6 @@ F:        arch/sparc/
 SPECIALIX IO8+ MULTIPORT SERIAL CARD DRIVER
 P:     Roger Wolff
 M:     R.E.Wolff@BitWizard.nl
-L:     linux-kernel@vger.kernel.org
 S:     Supported
 F:     Documentation/serial/specialix.txt
 F:     drivers/char/specialix*
@@ -5505,7 +5458,6 @@ F:        fs/squashfs/
 SRM (Alpha) environment access
 P:     Jan-Benedict Glaw
 M:     jbglaw@lug-owl.de
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     arch/alpha/kernel/srm_env.c
 
@@ -5520,7 +5472,6 @@ S:        Maintained
 STAGING SUBSYSTEM
 P:     Greg Kroah-Hartman
 M:     gregkh@suse.de
-L:     linux-kernel@vger.kernel.org
 T:     quilt kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
 S:     Maintained
 F:     drivers/staging/
@@ -5600,7 +5551,6 @@ F:        include/linux/sysv_fs.h
 TASKSTATS STATISTICS INTERFACE
 P:     Balbir Singh
 M:     balbir@linux.vnet.ibm.com
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     Documentation/accounting/taskstats*
 F:     include/linux/taskstats*
@@ -5693,7 +5643,6 @@ P:        Kentaro Takeda
 M:     takedakn@nttdata.co.jp
 P:     Tetsuo Handa
 M:     penguin-kernel@I-love.SAKURA.ne.jp
-L:     linux-kernel@vger.kernel.org (kernel issues)
 L:     tomoyo-users-en@lists.sourceforge.jp (subscribers-only, for developers and users in English)
 L:     tomoyo-dev@lists.sourceforge.jp (subscribers-only, for developers in Japanese)
 L:     tomoyo-users@lists.sourceforge.jp (subscribers-only, for users in Japanese)
@@ -5745,14 +5694,17 @@ F:      drivers/char/tpm/
 TRIVIAL PATCHES
 P:     Jiri Kosina
 M:     trivial@kernel.org
-L:     linux-kernel@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial.git
 S:     Maintained
+F:     drivers/char/tty_*
+F:     drivers/serial/serial_core.c
+F:     include/linux/serial_core.h
+F:     include/linux/serial.h
+F:     include/linux/tty.h
 
 TTY LAYER
 P:     Alan Cox
 M:     alan@lxorguk.ukuu.org.uk
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 T:     stgit http://zeniv.linux.org.uk/~alan/ttydev/
 
@@ -5825,7 +5777,6 @@ F:        fs/udf/
 UFS FILESYSTEM
 P:     Evgeniy Dushistov
 M:     dushistov@mail.ru
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     Documentation/filesystems/ufs.txt
 F:     fs/ufs/
@@ -5842,7 +5793,6 @@ F:        include/linux/uwb/
 UNIFORM CDROM DRIVER
 P:     Jens Axboe
 M:     axboe@kernel.dk
-L:     linux-kernel@vger.kernel.org
 W:     http://www.kernel.dk
 S:     Maintained
 F:     Documentation/cdrom/
@@ -5871,7 +5821,6 @@ F:        drivers/usb/class/cdc-acm.*
 USB BLOCK DRIVER (UB ub)
 P:     Pete Zaitcev
 M:     zaitcev@redhat.com
-L:     linux-kernel@vger.kernel.org
 L:     linux-usb@vger.kernel.org
 S:     Supported
 F:     drivers/block/ub.c
@@ -6164,6 +6113,12 @@ L:       linux-wireless@vger.kernel.org
 S:     Maintained
 F:     drivers/net/wireless/rndis_wlan.c
 
+USB XHCI DRIVER
+P:     Sarah Sharp
+M:     sarah.a.sharp@intel.com
+L:     linux-usb@vger.kernel.org
+S:     Supported
+
 USB ZC0301 DRIVER
 P:     Luca Risolia
 M:     luca.risolia@studio.unibo.it
@@ -6211,7 +6166,6 @@ P:        Hans J. Koch
 M:     hjk@linutronix.de
 P:     Greg Kroah-Hartman
 M:     gregkh@suse.de
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     Documentation/DocBook/uio-howto.tmpl
 F:     drivers/uio/
@@ -6237,7 +6191,6 @@ F:        drivers/video/uvesafb.*
 VFAT/FAT/MSDOS FILESYSTEM
 P:     OGAWA Hirofumi
 M:     hirofumi@mail.parknet.co.jp
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     Documentation/filesystems/vfat.txt
 F:     fs/fat/
@@ -6281,6 +6234,14 @@ F:       drivers/net/macvlan.c
 F:     include/linux/if_*vlan.h
 F:     net/8021q/
 
+VLYNQ BUS
+P:     Florian Fainelli
+M:     florian@openwrt.org
+L:     openwrt-devel@lists.openwrt.org
+S:     Maintained
+F:     drivers/vlynq/vlynq.c
+F:     include/linux/vlynq.h
+
 VOLTAGE AND CURRENT REGULATOR FRAMEWORK
 P:     Liam Girdwood
 M:     lrg@slimlogic.co.uk
@@ -6334,7 +6295,6 @@ F:        drivers/hwmon/w83793.c
 W83L51xD SD/MMC CARD INTERFACE DRIVER
 P:     Pierre Ossman
 M:     pierre@ossman.eu
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     drivers/mmc/host/wbsd.*
 
@@ -6421,7 +6381,6 @@ M:        mingo@redhat.com
 P:     H. Peter Anvin
 M:     hpa@zytor.com
 M:     x86@kernel.org
-L:     linux-kernel@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86.git
 S:     Maintained
 F:     Documentation/x86/
@@ -6457,7 +6416,6 @@ XILINX SYSTEMACE DRIVER
 P:     Grant Likely
 M:     grant.likely@secretlab.ca
 W:     http://www.secretlab.ca/
-L:     linux-kernel@vger.kernel.org
 S:     Maintained
 F:     drivers/block/xsysace.c
 
@@ -6522,5 +6480,9 @@ F:        drivers/serial/zs.*
 
 THE REST
 P:     Linus Torvalds
+M:     torvalds@linux-foundation.org
+L:     linux-kernel@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
 S:     Buried alive in reporters
+F:     *
+F:     */
index fef5c1450e471643968802394079689f95213fc9..a71c9c1455a722fed428bb89d0c2b677b7a7087e 100644 (file)
@@ -1,10 +1,3 @@
 /*
  * 8253/8254 Programmable Interval Timer
  */
-
-#ifndef _8253PIT_H
-#define _8253PIT_H
-
-#define PIT_TICK_RATE  1193180UL
-
-#endif
index 3e6735a34c571b011172cf54ee3e09db254434da..a8d4ec8ea4b60f679c3986f0548fe055888d5755 100644 (file)
@@ -3,30 +3,12 @@
 
 /* Dummy header just to define km_type. */
 
-
 #ifdef CONFIG_DEBUG_HIGHMEM
-# define D(n) __KM_FENCE_##n ,
-#else
-# define D(n)
+#define  __WITH_KM_FENCE
 #endif
 
-enum km_type {
-D(0)   KM_BOUNCE_READ,
-D(1)   KM_SKB_SUNRPC_DATA,
-D(2)   KM_SKB_DATA_SOFTIRQ,
-D(3)   KM_USER0,
-D(4)   KM_USER1,
-D(5)   KM_BIO_SRC_IRQ,
-D(6)   KM_BIO_DST_IRQ,
-D(7)   KM_PTE0,
-D(8)   KM_PTE1,
-D(9)   KM_IRQ0,
-D(10)  KM_IRQ1,
-D(11)  KM_SOFTIRQ0,
-D(12)  KM_SOFTIRQ1,
-D(13)  KM_TYPE_NR
-};
+#include <asm-generic/kmap_types.h>
 
-#undef D
+#undef __WITH_KM_FENCE
 
 #endif
index c2938e574a40c2de349556430bc83fc0038569c0..19b86328ffd7907d437eca4ab61055dfadda1a09 100644 (file)
 
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-struct mm_struct init_mm = INIT_MM(init_mm);
 struct task_struct init_task = INIT_TASK(init_task);
-
-EXPORT_SYMBOL(init_mm);
 EXPORT_SYMBOL(init_task);
 
 union thread_union init_thread_union
index 67c19f8a9944804ad9ef3cd2ca56de73fc9c97fc..38c805dfc5445dd02ba8683d6c538d9daf4c8822 100644 (file)
@@ -227,7 +227,7 @@ struct irqaction timer_irqaction = {
        .name           = "timer",
 };
 
-static struct hw_interrupt_type rtc_irq_type = {
+static struct irq_chip rtc_irq_type = {
        .typename       = "RTC",
        .startup        = rtc_startup,
        .shutdown       = rtc_enable_disable,
index 9405bee9894e9c4febd62efb2e2487dc63e5bf13..50bfec9b588ffbc8ba4d08a47c532bf5f0de7299 100644 (file)
@@ -83,7 +83,7 @@ i8259a_end_irq(unsigned int irq)
                i8259a_enable_irq(irq);
 }
 
-struct hw_interrupt_type i8259a_irq_type = {
+struct irq_chip i8259a_irq_type = {
        .typename       = "XT-PIC",
        .startup        = i8259a_startup_irq,
        .shutdown       = i8259a_disable_irq,
index cc9a8a7aa279e05b5a16876f52f563467611eb2f..b63ccd7386f18230293c036acddab148f22b015a 100644 (file)
@@ -36,7 +36,7 @@ extern void i8259a_disable_irq(unsigned int);
 extern void i8259a_mask_and_ack_irq(unsigned int);
 extern unsigned int i8259a_startup_irq(unsigned int);
 extern void i8259a_end_irq(unsigned int);
-extern struct hw_interrupt_type i8259a_irq_type;
+extern struct irq_chip i8259a_irq_type;
 extern void init_i8259a_irqs(void);
 
 extern void handle_irq(int irq);
index d53edbccbfe5d88653c59433be2d29147800c33f..69199a76ec4a41f6d165f66a56738a5b048340bd 100644 (file)
@@ -70,7 +70,7 @@ pyxis_mask_and_ack_irq(unsigned int irq)
        *(vulp)PYXIS_INT_MASK;
 }
 
-static struct hw_interrupt_type pyxis_irq_type = {
+static struct irq_chip pyxis_irq_type = {
        .typename       = "PYXIS",
        .startup        = pyxis_startup_irq,
        .shutdown       = pyxis_disable_irq,
index a03fbca4940eb0d0881b4d197cd3e84a3cf2b68a..85229369a1f8bfa31e7e326f1e0bc42020550a75 100644 (file)
@@ -48,7 +48,7 @@ srm_end_irq(unsigned int irq)
 }
 
 /* Handle interrupts from the SRM, assuming no additional weirdness.  */
-static struct hw_interrupt_type srm_irq_type = {
+static struct irq_chip srm_irq_type = {
        .typename       = "SRM",
        .startup        = srm_startup_irq,
        .shutdown       = srm_disable_irq,
index 80df86cd746bd2e8ca81ef82f338f7b337c229d5..d2634e4476b4589f03831f575ec00751b0434ca9 100644 (file)
@@ -252,9 +252,9 @@ reserve_std_resources(void)
 }
 
 #define PFN_MAX                PFN_DOWN(0x80000000)
-#define for_each_mem_cluster(memdesc, cluster, i)              \
-       for ((cluster) = (memdesc)->cluster, (i) = 0;           \
-            (i) < (memdesc)->numclusters; (i)++, (cluster)++)
+#define for_each_mem_cluster(memdesc, _cluster, i)             \
+       for ((_cluster) = (memdesc)->cluster, (i) = 0;          \
+            (i) < (memdesc)->numclusters; (i)++, (_cluster)++)
 
 static unsigned long __init
 get_mem_size_limit(char *s)
index e53a1e1c2f217233abfc19ff40249f7bcde269b8..382035ef7394666e20f7a4b9c821f2f71051e800 100644 (file)
@@ -89,7 +89,7 @@ alcor_end_irq(unsigned int irq)
                alcor_enable_irq(irq);
 }
 
-static struct hw_interrupt_type alcor_irq_type = {
+static struct irq_chip alcor_irq_type = {
        .typename       = "ALCOR",
        .startup        = alcor_startup_irq,
        .shutdown       = alcor_disable_irq,
index ace475c124f69d9d2e248268e8ef3436c4262f1e..ed349436732ba2ded473fc8c65776b422cb77b09 100644 (file)
@@ -71,7 +71,7 @@ cabriolet_end_irq(unsigned int irq)
                cabriolet_enable_irq(irq);
 }
 
-static struct hw_interrupt_type cabriolet_irq_type = {
+static struct irq_chip cabriolet_irq_type = {
        .typename       = "CABRIOLET",
        .startup        = cabriolet_startup_irq,
        .shutdown       = cabriolet_disable_irq,
index 5bd5259324b7c8827adb237facd7bf120edd4ca2..46e70ece5176ec1372e26dc09072759b26de5c43 100644 (file)
@@ -198,7 +198,7 @@ clipper_set_affinity(unsigned int irq, const struct cpumask *affinity)
        return 0;
 }
 
-static struct hw_interrupt_type dp264_irq_type = {
+static struct irq_chip dp264_irq_type = {
        .typename       = "DP264",
        .startup        = dp264_startup_irq,
        .shutdown       = dp264_disable_irq,
@@ -209,7 +209,7 @@ static struct hw_interrupt_type dp264_irq_type = {
        .set_affinity   = dp264_set_affinity,
 };
 
-static struct hw_interrupt_type clipper_irq_type = {
+static struct irq_chip clipper_irq_type = {
        .typename       = "CLIPPER",
        .startup        = clipper_startup_irq,
        .shutdown       = clipper_disable_irq,
@@ -298,7 +298,7 @@ clipper_srm_device_interrupt(unsigned long vector)
 }
 
 static void __init
-init_tsunami_irqs(struct hw_interrupt_type * ops, int imin, int imax)
+init_tsunami_irqs(struct irq_chip * ops, int imin, int imax)
 {
        long i;
        for (i = imin; i <= imax; ++i) {
index 9c5a306dc0ee825a47d3d8c0bd27e2d091069086..660c23ef661f686bfbb7c6e2fe382ad3eb8b3478 100644 (file)
@@ -69,7 +69,7 @@ eb64p_end_irq(unsigned int irq)
                eb64p_enable_irq(irq);
 }
 
-static struct hw_interrupt_type eb64p_irq_type = {
+static struct irq_chip eb64p_irq_type = {
        .typename       = "EB64P",
        .startup        = eb64p_startup_irq,
        .shutdown       = eb64p_disable_irq,
index baf60f36cbd773114f5d8e69a151b03d98608986..b99ea488d8446139d4fabdaa53dbeeedf51446eb 100644 (file)
@@ -80,7 +80,7 @@ eiger_end_irq(unsigned int irq)
                eiger_enable_irq(irq);
 }
 
-static struct hw_interrupt_type eiger_irq_type = {
+static struct irq_chip eiger_irq_type = {
        .typename       = "EIGER",
        .startup        = eiger_startup_irq,
        .shutdown       = eiger_disable_irq,
index 2b5caf3d9b1526678506fef65bc0e746b61edc9f..ef0b83a070accb165129291fb58b2bfa19f748e7 100644 (file)
@@ -118,7 +118,7 @@ jensen_local_end(unsigned int irq)
                i8259a_end_irq(1);
 }
 
-static struct hw_interrupt_type jensen_local_irq_type = {
+static struct irq_chip jensen_local_irq_type = {
        .typename       = "LOCAL",
        .startup        = jensen_local_startup,
        .shutdown       = jensen_local_shutdown,
index c5a1a2438c678191eeb6bb1c39b518cdf1c4adc9..bbfc4f20ca72a2ed9f6e0ac2c3172fc81f8c33d1 100644 (file)
@@ -169,7 +169,7 @@ marvel_irq_noop_return(unsigned int irq)
        return 0; 
 }
 
-static struct hw_interrupt_type marvel_legacy_irq_type = {
+static struct irq_chip marvel_legacy_irq_type = {
        .typename       = "LEGACY",
        .startup        = marvel_irq_noop_return,
        .shutdown       = marvel_irq_noop,
@@ -179,7 +179,7 @@ static struct hw_interrupt_type marvel_legacy_irq_type = {
        .end            = marvel_irq_noop,
 };
 
-static struct hw_interrupt_type io7_lsi_irq_type = {
+static struct irq_chip io7_lsi_irq_type = {
        .typename       = "LSI",
        .startup        = io7_startup_irq,
        .shutdown       = io7_disable_irq,
@@ -189,7 +189,7 @@ static struct hw_interrupt_type io7_lsi_irq_type = {
        .end            = io7_end_irq,
 };
 
-static struct hw_interrupt_type io7_msi_irq_type = {
+static struct irq_chip io7_msi_irq_type = {
        .typename       = "MSI",
        .startup        = io7_startup_irq,
        .shutdown       = io7_disable_irq,
@@ -273,8 +273,8 @@ init_one_io7_msi(struct io7 *io7, unsigned int which, unsigned int where)
 
 static void __init
 init_io7_irqs(struct io7 *io7, 
-             struct hw_interrupt_type *lsi_ops,
-             struct hw_interrupt_type *msi_ops)
+             struct irq_chip *lsi_ops,
+             struct irq_chip *msi_ops)
 {
        long base = (io7->pe << MARVEL_IRQ_VEC_PE_SHIFT) + 16;
        long i;
index 8d3e9429c5ee60c17d9a015ebff09a40feabe9e0..4e366641a08ed20c4f6cba1755f2e9082216a5df 100644 (file)
@@ -68,7 +68,7 @@ mikasa_end_irq(unsigned int irq)
                mikasa_enable_irq(irq);
 }
 
-static struct hw_interrupt_type mikasa_irq_type = {
+static struct irq_chip mikasa_irq_type = {
        .typename       = "MIKASA",
        .startup        = mikasa_startup_irq,
        .shutdown       = mikasa_disable_irq,
index 538876b62449a215034d053036f3e0e114e51dd4..35753a173bac3073305d8c8a18156d5e7b90840a 100644 (file)
@@ -73,7 +73,7 @@ noritake_end_irq(unsigned int irq)
                 noritake_enable_irq(irq);
 }
 
-static struct hw_interrupt_type noritake_irq_type = {
+static struct irq_chip noritake_irq_type = {
        .typename       = "NORITAKE",
        .startup        = noritake_startup_irq,
        .shutdown       = noritake_disable_irq,
index 672cb2df53dfc7e6b53814701f181d346ebf9599..f3aec7e085c8c6f0a0165a7f47af0fe076312377 100644 (file)
@@ -135,7 +135,7 @@ rawhide_end_irq(unsigned int irq)
                rawhide_enable_irq(irq);
 }
 
-static struct hw_interrupt_type rawhide_irq_type = {
+static struct irq_chip rawhide_irq_type = {
        .typename       = "RAWHIDE",
        .startup        = rawhide_startup_irq,
        .shutdown       = rawhide_disable_irq,
index f15a329b6011167791b6baf2f898de662a5fb1d1..d9f9cfeb9931354cee9d6df304877941ef13ecea 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/sched.h>
 #include <linux/pci.h>
 #include <linux/ioport.h>
+#include <linux/timex.h>
 #include <linux/init.h>
 
 #include <asm/ptrace.h>
index ce1faa6f1df1f4e1aba6ac57f3f8001f75bdf2f4..fc9246373452896439e58c01c8c595a1771c7d63 100644 (file)
@@ -72,7 +72,7 @@ rx164_end_irq(unsigned int irq)
                rx164_enable_irq(irq);
 }
 
-static struct hw_interrupt_type rx164_irq_type = {
+static struct irq_chip rx164_irq_type = {
        .typename       = "RX164",
        .startup        = rx164_startup_irq,
        .shutdown       = rx164_disable_irq,
index 9e263256a42d551c386c345147d77817f8d221a7..426eb6906d0192a96872aa5697d2a0fc3bcb57a8 100644 (file)
@@ -501,7 +501,7 @@ sable_lynx_mask_and_ack_irq(unsigned int irq)
        spin_unlock(&sable_lynx_irq_lock);
 }
 
-static struct hw_interrupt_type sable_lynx_irq_type = {
+static struct irq_chip sable_lynx_irq_type = {
        .typename       = "SABLE/LYNX",
        .startup        = sable_lynx_startup_irq,
        .shutdown       = sable_lynx_disable_irq,
index 9bd9a31450c64a414ba08cc137ae349a535b0497..830318c21661dba4f36b2443e90686a7e4689d5b 100644 (file)
@@ -74,7 +74,7 @@ takara_end_irq(unsigned int irq)
                takara_enable_irq(irq);
 }
 
-static struct hw_interrupt_type takara_irq_type = {
+static struct irq_chip takara_irq_type = {
        .typename       = "TAKARA",
        .startup        = takara_startup_irq,
        .shutdown       = takara_disable_irq,
index 8dd239ebdb9e2cc3489c3d128402a9da37033a29..88978fc60f835061b35746d8623b6713606a559b 100644 (file)
@@ -185,7 +185,7 @@ titan_srm_device_interrupt(unsigned long vector)
 
 
 static void __init
-init_titan_irqs(struct hw_interrupt_type * ops, int imin, int imax)
+init_titan_irqs(struct irq_chip * ops, int imin, int imax)
 {
        long i;
        for (i = imin; i <= imax; ++i) {
@@ -194,7 +194,7 @@ init_titan_irqs(struct hw_interrupt_type * ops, int imin, int imax)
        }
 }
 
-static struct hw_interrupt_type titan_irq_type = {
+static struct irq_chip titan_irq_type = {
        .typename       = "TITAN",
        .startup        = titan_startup_irq,
        .shutdown       = titan_disable_irq,
index 42c3eede4d099a3a970f9d78e25f42f3f8eeb8b1..e91b4c3838a8d3e5f21f4e5aa01d7135014fbe14 100644 (file)
@@ -157,7 +157,7 @@ wildfire_end_irq(unsigned int irq)
                wildfire_enable_irq(irq);
 }
 
-static struct hw_interrupt_type wildfire_irq_type = {
+static struct irq_chip wildfire_irq_type = {
        .typename       = "WILDFIRE",
        .startup        = wildfire_startup_irq,
        .shutdown       = wildfire_disable_irq,
index a13de49d126579c58f2b4d3131dd861741628d59..0eab55749423f2a9e8df8fade6a890efa6c0f480 100644 (file)
@@ -28,9 +28,9 @@ EXPORT_SYMBOL(node_data);
 #define DBGDCONT(args...)
 #endif
 
-#define for_each_mem_cluster(memdesc, cluster, i)              \
-       for ((cluster) = (memdesc)->cluster, (i) = 0;           \
-            (i) < (memdesc)->numclusters; (i)++, (cluster)++)
+#define for_each_mem_cluster(memdesc, _cluster, i)             \
+       for ((_cluster) = (memdesc)->cluster, (i) = 0;          \
+            (i) < (memdesc)->numclusters; (i)++, (_cluster)++)
 
 static void __init show_mem_layout(void)
 {
index e859af349467420e3107074cfa94f7d993125c70..3f470866bb89ebe4f903db8dfb389313505df502 100644 (file)
 
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-struct mm_struct init_mm = INIT_MM(init_mm);
-
-EXPORT_SYMBOL(init_mm);
-
 /*
  * Initial thread structure.
  *
index 095521e9ee246755980af5a59f76986f89ecb59c..01791d74e08ec543e6aab65394c137921a6552f4 100644 (file)
@@ -380,12 +380,12 @@ static struct pca953x_platform_data pca9536_data = {
        .gpio_base      = NR_BUILTIN_GPIO,
 };
 
-static int gpio_bus_switch;
+static int gpio_bus_switch = -EINVAL;
 
 static int pcm990_camera_set_bus_param(struct soc_camera_link *link,
-               unsigned long flags)
+                                      unsigned long flags)
 {
-       if (gpio_bus_switch <= 0) {
+       if (gpio_bus_switch < 0) {
                if (flags == SOCAM_DATAWIDTH_10)
                        return 0;
                else
@@ -404,25 +404,34 @@ static unsigned long pcm990_camera_query_bus_param(struct soc_camera_link *link)
 {
        int ret;
 
-       if (!gpio_bus_switch) {
+       if (gpio_bus_switch < 0) {
                ret = gpio_request(NR_BUILTIN_GPIO, "camera");
                if (!ret) {
                        gpio_bus_switch = NR_BUILTIN_GPIO;
                        gpio_direction_output(gpio_bus_switch, 0);
-               } else
-                       gpio_bus_switch = -EINVAL;
+               }
        }
 
-       if (gpio_bus_switch > 0)
+       if (gpio_bus_switch >= 0)
                return SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_10;
        else
                return SOCAM_DATAWIDTH_10;
 }
 
+static void pcm990_camera_free_bus(struct soc_camera_link *link)
+{
+       if (gpio_bus_switch < 0)
+               return;
+
+       gpio_free(gpio_bus_switch);
+       gpio_bus_switch = -EINVAL;
+}
+
 static struct soc_camera_link iclink = {
        .bus_id = 0, /* Must match with the camera ID above */
        .query_bus_param = pcm990_camera_query_bus_param,
        .set_bus_param = pcm990_camera_set_bus_param,
+       .free_bus = pcm990_camera_free_bus,
 };
 
 /* Board I2C devices. */
diff --git a/arch/arm/plat-s3c/include/plat/regs-usb-hsotg-phy.h b/arch/arm/plat-s3c/include/plat/regs-usb-hsotg-phy.h
new file mode 100644 (file)
index 0000000..36a85f5
--- /dev/null
@@ -0,0 +1,50 @@
+/* arch/arm/plat-s3c/include/plat/regs-usb-hsotg-phy.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      http://armlinux.simtec.co.uk/
+ *      Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C - USB2.0 Highspeed/OtG device PHY registers
+ *
+ * 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.
+*/
+
+/* Note, this is a seperate header file as some of the clock framework
+ * needs to touch this if the clk_48m is used as the USB OHCI or other
+ * peripheral source.
+*/
+
+#ifndef __PLAT_S3C64XX_REGS_USB_HSOTG_PHY_H
+#define __PLAT_S3C64XX_REGS_USB_HSOTG_PHY_H __FILE__
+
+/* S3C64XX_PA_USB_HSPHY */
+
+#define S3C_HSOTG_PHYREG(x)    ((x) + S3C_VA_USB_HSPHY)
+
+#define S3C_PHYPWR                             S3C_HSOTG_PHYREG(0x00)
+#define SRC_PHYPWR_OTG_DISABLE                 (1 << 4)
+#define SRC_PHYPWR_ANALOG_POWERDOWN            (1 << 3)
+#define SRC_PHYPWR_FORCE_SUSPEND               (1 << 1)
+
+#define S3C_PHYCLK                             S3C_HSOTG_PHYREG(0x04)
+#define S3C_PHYCLK_MODE_USB11                  (1 << 6)
+#define S3C_PHYCLK_EXT_OSC                     (1 << 5)
+#define S3C_PHYCLK_CLK_FORCE                   (1 << 4)
+#define S3C_PHYCLK_ID_PULL                     (1 << 2)
+#define S3C_PHYCLK_CLKSEL_MASK                 (0x3 << 0)
+#define S3C_PHYCLK_CLKSEL_SHIFT                        (0)
+#define S3C_PHYCLK_CLKSEL_48M                  (0x0 << 0)
+#define S3C_PHYCLK_CLKSEL_12M                  (0x2 << 0)
+#define S3C_PHYCLK_CLKSEL_24M                  (0x3 << 0)
+
+#define S3C_RSTCON                             S3C_HSOTG_PHYREG(0x08)
+#define S3C_RSTCON_PHYCLK                      (1 << 2)
+#define S3C_RSTCON_HCLK                                (1 << 2)
+#define S3C_RSTCON_PHY                         (1 << 0)
+
+#define S3C_PHYTUNE                            S3C_HSOTG_PHYREG(0x20)
+
+#endif /* __PLAT_S3C64XX_REGS_USB_HSOTG_PHY_H */
diff --git a/arch/arm/plat-s3c/include/plat/regs-usb-hsotg.h b/arch/arm/plat-s3c/include/plat/regs-usb-hsotg.h
new file mode 100644 (file)
index 0000000..8d18d9d
--- /dev/null
@@ -0,0 +1,377 @@
+/* arch/arm/plat-s3c/include/plat/regs-usb-hsotg.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      http://armlinux.simtec.co.uk/
+ *      Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C - USB2.0 Highspeed/OtG device block registers
+ *
+ * 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 __PLAT_S3C64XX_REGS_USB_HSOTG_H
+#define __PLAT_S3C64XX_REGS_USB_HSOTG_H __FILE__
+
+#define S3C_HSOTG_REG(x) (x)
+
+#define S3C_GOTGCTL                            S3C_HSOTG_REG(0x000)
+#define S3C_GOTGCTL_BSESVLD                    (1 << 19)
+#define S3C_GOTGCTL_ASESVLD                    (1 << 18)
+#define S3C_GOTGCTL_DBNC_SHORT                 (1 << 17)
+#define S3C_GOTGCTL_CONID_B                    (1 << 16)
+#define S3C_GOTGCTL_DEVHNPEN                   (1 << 11)
+#define S3C_GOTGCTL_HSSETHNPEN                 (1 << 10)
+#define S3C_GOTGCTL_HNPREQ                     (1 << 9)
+#define S3C_GOTGCTL_HSTNEGSCS                  (1 << 8)
+#define S3C_GOTGCTL_SESREQ                     (1 << 1)
+#define S3C_GOTGCTL_SESREQSCS                  (1 << 0)
+
+#define S3C_GOTGINT                            S3C_HSOTG_REG(0x004)
+#define S3C_GOTGINT_DbnceDone                  (1 << 19)
+#define S3C_GOTGINT_ADevTOUTChg                        (1 << 18)
+#define S3C_GOTGINT_HstNegDet                  (1 << 17)
+#define S3C_GOTGINT_HstnegSucStsChng           (1 << 9)
+#define S3C_GOTGINT_SesReqSucStsChng           (1 << 8)
+#define S3C_GOTGINT_SesEndDet                  (1 << 2)
+
+#define S3C_GAHBCFG                            S3C_HSOTG_REG(0x008)
+#define S3C_GAHBCFG_PTxFEmpLvl                 (1 << 8)
+#define S3C_GAHBCFG_NPTxFEmpLvl                        (1 << 7)
+#define S3C_GAHBCFG_DMAEn                      (1 << 5)
+#define S3C_GAHBCFG_HBstLen_MASK               (0xf << 1)
+#define S3C_GAHBCFG_HBstLen_SHIFT              (1)
+#define S3C_GAHBCFG_HBstLen_Single             (0x0 << 1)
+#define S3C_GAHBCFG_HBstLen_Incr               (0x1 << 1)
+#define S3C_GAHBCFG_HBstLen_Incr4              (0x3 << 1)
+#define S3C_GAHBCFG_HBstLen_Incr8              (0x5 << 1)
+#define S3C_GAHBCFG_HBstLen_Incr16             (0x7 << 1)
+#define S3C_GAHBCFG_GlblIntrEn                 (1 << 0)
+
+#define S3C_GUSBCFG                            S3C_HSOTG_REG(0x00C)
+#define S3C_GUSBCFG_PHYLPClkSel                        (1 << 15)
+#define S3C_GUSBCFG_HNPCap                     (1 << 9)
+#define S3C_GUSBCFG_SRPCap                     (1 << 8)
+#define S3C_GUSBCFG_PHYIf16                    (1 << 3)
+#define S3C_GUSBCFG_TOutCal_MASK               (0x7 << 0)
+#define S3C_GUSBCFG_TOutCal_SHIFT              (0)
+#define S3C_GUSBCFG_TOutCal_LIMIT              (0x7)
+#define S3C_GUSBCFG_TOutCal(_x)                        ((_x) << 0)
+
+#define S3C_GRSTCTL                            S3C_HSOTG_REG(0x010)
+
+#define S3C_GRSTCTL_AHBIdle                    (1 << 31)
+#define S3C_GRSTCTL_DMAReq                     (1 << 30)
+#define S3C_GRSTCTL_TxFNum_MASK                        (0x1f << 6)
+#define S3C_GRSTCTL_TxFNum_SHIFT               (6)
+#define S3C_GRSTCTL_TxFNum_LIMIT               (0x1f)
+#define S3C_GRSTCTL_TxFNum(_x)                 ((_x) << 6)
+#define S3C_GRSTCTL_TxFFlsh                    (1 << 5)
+#define S3C_GRSTCTL_RxFFlsh                    (1 << 4)
+#define S3C_GRSTCTL_INTknQFlsh                 (1 << 3)
+#define S3C_GRSTCTL_FrmCntrRst                 (1 << 2)
+#define S3C_GRSTCTL_HSftRst                    (1 << 1)
+#define S3C_GRSTCTL_CSftRst                    (1 << 0)
+
+#define S3C_GINTSTS                            S3C_HSOTG_REG(0x014)
+#define S3C_GINTMSK                            S3C_HSOTG_REG(0x018)
+
+#define S3C_GINTSTS_WkUpInt                    (1 << 31)
+#define S3C_GINTSTS_SessReqInt                 (1 << 30)
+#define S3C_GINTSTS_DisconnInt                 (1 << 29)
+#define S3C_GINTSTS_ConIDStsChng               (1 << 28)
+#define S3C_GINTSTS_PTxFEmp                    (1 << 26)
+#define S3C_GINTSTS_HChInt                     (1 << 25)
+#define S3C_GINTSTS_PrtInt                     (1 << 24)
+#define S3C_GINTSTS_FetSusp                    (1 << 22)
+#define S3C_GINTSTS_incompIP                   (1 << 21)
+#define S3C_GINTSTS_IncomplSOIN                        (1 << 20)
+#define S3C_GINTSTS_OEPInt                     (1 << 19)
+#define S3C_GINTSTS_IEPInt                     (1 << 18)
+#define S3C_GINTSTS_EPMis                      (1 << 17)
+#define S3C_GINTSTS_EOPF                       (1 << 15)
+#define S3C_GINTSTS_ISOutDrop                  (1 << 14)
+#define S3C_GINTSTS_EnumDone                   (1 << 13)
+#define S3C_GINTSTS_USBRst                     (1 << 12)
+#define S3C_GINTSTS_USBSusp                    (1 << 11)
+#define S3C_GINTSTS_ErlySusp                   (1 << 10)
+#define S3C_GINTSTS_GOUTNakEff                 (1 << 7)
+#define S3C_GINTSTS_GINNakEff                  (1 << 6)
+#define S3C_GINTSTS_NPTxFEmp                   (1 << 5)
+#define S3C_GINTSTS_RxFLvl                     (1 << 4)
+#define S3C_GINTSTS_SOF                                (1 << 3)
+#define S3C_GINTSTS_OTGInt                     (1 << 2)
+#define S3C_GINTSTS_ModeMis                    (1 << 1)
+#define S3C_GINTSTS_CurMod_Host                        (1 << 0)
+
+#define S3C_GRXSTSR                            S3C_HSOTG_REG(0x01C)
+#define S3C_GRXSTSP                            S3C_HSOTG_REG(0x020)
+
+#define S3C_GRXSTS_FN_MASK                     (0x7f << 25)
+#define S3C_GRXSTS_FN_SHIFT                    (25)
+
+#define S3C_GRXSTS_PktSts_MASK                 (0xf << 17)
+#define S3C_GRXSTS_PktSts_SHIFT                        (17)
+#define S3C_GRXSTS_PktSts_GlobalOutNAK         (0x1 << 17)
+#define S3C_GRXSTS_PktSts_OutRX                        (0x2 << 17)
+#define S3C_GRXSTS_PktSts_OutDone              (0x3 << 17)
+#define S3C_GRXSTS_PktSts_SetupDone            (0x4 << 17)
+#define S3C_GRXSTS_PktSts_SetupRX              (0x6 << 17)
+
+#define S3C_GRXSTS_DPID_MASK                   (0x3 << 15)
+#define S3C_GRXSTS_DPID_SHIFT                  (15)
+#define S3C_GRXSTS_ByteCnt_MASK                        (0x7ff << 4)
+#define S3C_GRXSTS_ByteCnt_SHIFT               (4)
+#define S3C_GRXSTS_EPNum_MASK                  (0xf << 0)
+#define S3C_GRXSTS_EPNum_SHIFT                 (0)
+
+#define S3C_GRXFSIZ                            S3C_HSOTG_REG(0x024)
+
+#define S3C_GNPTXFSIZ                          S3C_HSOTG_REG(0x028)
+
+#define S3C_GNPTXFSIZ_NPTxFDep_MASK            (0xffff << 16)
+#define S3C_GNPTXFSIZ_NPTxFDep_SHIFT           (16)
+#define S3C_GNPTXFSIZ_NPTxFDep_LIMIT           (0xffff)
+#define S3C_GNPTXFSIZ_NPTxFDep(_x)             ((_x) << 16)
+#define S3C_GNPTXFSIZ_NPTxFStAddr_MASK         (0xffff << 0)
+#define S3C_GNPTXFSIZ_NPTxFStAddr_SHIFT                (0)
+#define S3C_GNPTXFSIZ_NPTxFStAddr_LIMIT                (0xffff)
+#define S3C_GNPTXFSIZ_NPTxFStAddr(_x)          ((_x) << 0)
+
+#define S3C_GNPTXSTS                           S3C_HSOTG_REG(0x02C)
+
+#define S3C_GNPTXSTS_NPtxQTop_MASK             (0x7f << 24)
+#define S3C_GNPTXSTS_NPtxQTop_SHIFT            (24)
+
+#define S3C_GNPTXSTS_NPTxQSpcAvail_MASK                (0xff << 16)
+#define S3C_GNPTXSTS_NPTxQSpcAvail_SHIFT       (16)
+#define S3C_GNPTXSTS_NPTxQSpcAvail_GET(_v)     (((_v) >> 16) & 0xff)
+
+#define S3C_GNPTXSTS_NPTxFSpcAvail_MASK                (0xffff << 0)
+#define S3C_GNPTXSTS_NPTxFSpcAvail_SHIFT       (0)
+#define S3C_GNPTXSTS_NPTxFSpcAvail_GET(_v)     (((_v) >> 0) & 0xffff)
+
+
+#define S3C_HPTXFSIZ                           S3C_HSOTG_REG(0x100)
+
+#define S3C_DPTXFSIZn(_a)                      S3C_HSOTG_REG(0x104 + (((_a) - 1) * 4))
+
+#define S3C_DPTXFSIZn_DPTxFSize_MASK           (0xffff << 16)
+#define S3C_DPTXFSIZn_DPTxFSize_SHIFT          (16)
+#define S3C_DPTXFSIZn_DPTxFSize_GET(_v)                (((_v) >> 16) & 0xffff)
+#define S3C_DPTXFSIZn_DPTxFSize_LIMIT          (0xffff)
+#define S3C_DPTXFSIZn_DPTxFSize(_x)            ((_x) << 16)
+
+#define S3C_DPTXFSIZn_DPTxFStAddr_MASK         (0xffff << 0)
+#define S3C_DPTXFSIZn_DPTxFStAddr_SHIFT                (0)
+
+/* Device mode registers */
+#define S3C_DCFG                               S3C_HSOTG_REG(0x800)
+
+#define S3C_DCFG_EPMisCnt_MASK                 (0x1f << 18)
+#define S3C_DCFG_EPMisCnt_SHIFT                        (18)
+#define S3C_DCFG_EPMisCnt_LIMIT                        (0x1f)
+#define S3C_DCFG_EPMisCnt(_x)                  ((_x) << 18)
+
+#define S3C_DCFG_PerFrInt_MASK                 (0x3 << 11)
+#define S3C_DCFG_PerFrInt_SHIFT                        (11)
+#define S3C_DCFG_PerFrInt_LIMIT                        (0x3)
+#define S3C_DCFG_PerFrInt(_x)                  ((_x) << 11)
+
+#define S3C_DCFG_DevAddr_MASK                  (0x7f << 4)
+#define S3C_DCFG_DevAddr_SHIFT                 (4)
+#define S3C_DCFG_DevAddr_LIMIT                 (0x7f)
+#define S3C_DCFG_DevAddr(_x)                   ((_x) << 4)
+
+#define S3C_DCFG_NZStsOUTHShk                  (1 << 2)
+
+#define S3C_DCFG_DevSpd_MASK                   (0x3 << 0)
+#define S3C_DCFG_DevSpd_SHIFT                  (0)
+#define S3C_DCFG_DevSpd_HS                     (0x0 << 0)
+#define S3C_DCFG_DevSpd_FS                     (0x1 << 0)
+#define S3C_DCFG_DevSpd_LS                     (0x2 << 0)
+#define S3C_DCFG_DevSpd_FS48                   (0x3 << 0)
+
+#define S3C_DCTL                               S3C_HSOTG_REG(0x804)
+
+#define S3C_DCTL_PWROnPrgDone                  (1 << 11)
+#define S3C_DCTL_CGOUTNak                      (1 << 10)
+#define S3C_DCTL_SGOUTNak                      (1 << 9)
+#define S3C_DCTL_CGNPInNAK                     (1 << 8)
+#define S3C_DCTL_SGNPInNAK                     (1 << 7)
+#define S3C_DCTL_TstCtl_MASK                   (0x7 << 4)
+#define S3C_DCTL_TstCtl_SHIFT                  (4)
+#define S3C_DCTL_GOUTNakSts                    (1 << 3)
+#define S3C_DCTL_GNPINNakSts                   (1 << 2)
+#define S3C_DCTL_SftDiscon                     (1 << 1)
+#define S3C_DCTL_RmtWkUpSig                    (1 << 0)
+
+#define S3C_DSTS                               S3C_HSOTG_REG(0x808)
+
+#define S3C_DSTS_SOFFN_MASK                    (0x3fff << 8)
+#define S3C_DSTS_SOFFN_SHIFT                   (8)
+#define S3C_DSTS_SOFFN_LIMIT                   (0x3fff)
+#define S3C_DSTS_SOFFN(_x)                     ((_x) << 8)
+#define S3C_DSTS_ErraticErr                    (1 << 3)
+#define S3C_DSTS_EnumSpd_MASK                  (0x3 << 1)
+#define S3C_DSTS_EnumSpd_SHIFT                 (1)
+#define S3C_DSTS_EnumSpd_HS                    (0x0 << 1)
+#define S3C_DSTS_EnumSpd_FS                    (0x1 << 1)
+#define S3C_DSTS_EnumSpd_LS                    (0x2 << 1)
+#define S3C_DSTS_EnumSpd_FS48                  (0x3 << 1)
+
+#define S3C_DSTS_SuspSts                       (1 << 0)
+
+#define S3C_DIEPMSK                            S3C_HSOTG_REG(0x810)
+
+#define S3C_DIEPMSK_INEPNakEffMsk              (1 << 6)
+#define S3C_DIEPMSK_INTknEPMisMsk              (1 << 5)
+#define S3C_DIEPMSK_INTknTXFEmpMsk             (1 << 4)
+#define S3C_DIEPMSK_TimeOUTMsk                 (1 << 3)
+#define S3C_DIEPMSK_AHBErrMsk                  (1 << 2)
+#define S3C_DIEPMSK_EPDisbldMsk                        (1 << 1)
+#define S3C_DIEPMSK_XferComplMsk               (1 << 0)
+
+#define S3C_DOEPMSK                            S3C_HSOTG_REG(0x814)
+
+#define S3C_DOEPMSK_Back2BackSetup             (1 << 6)
+#define S3C_DOEPMSK_OUTTknEPdisMsk             (1 << 4)
+#define S3C_DOEPMSK_SetupMsk                   (1 << 3)
+#define S3C_DOEPMSK_AHBErrMsk                  (1 << 2)
+#define S3C_DOEPMSK_EPDisbldMsk                        (1 << 1)
+#define S3C_DOEPMSK_XferComplMsk               (1 << 0)
+
+#define S3C_DAINT                              S3C_HSOTG_REG(0x818)
+#define S3C_DAINTMSK                           S3C_HSOTG_REG(0x81C)
+
+#define S3C_DAINT_OutEP_SHIFT                  (16)
+#define S3C_DAINT_OutEP(x)                     (1 << ((x) + 16))
+#define S3C_DAINT_InEP(x)                      (1 << (x))
+
+#define S3C_DTKNQR1                            S3C_HSOTG_REG(0x820)
+#define S3C_DTKNQR2                            S3C_HSOTG_REG(0x824)
+#define S3C_DTKNQR3                            S3C_HSOTG_REG(0x830)
+#define S3C_DTKNQR4                            S3C_HSOTG_REG(0x834)
+
+#define S3C_DVBUSDIS                           S3C_HSOTG_REG(0x828)
+#define S3C_DVBUSPULSE                         S3C_HSOTG_REG(0x82C)
+
+#define S3C_DIEPCTL0                           S3C_HSOTG_REG(0x900)
+#define S3C_DOEPCTL0                           S3C_HSOTG_REG(0xB00)
+#define S3C_DIEPCTL(_a)                                S3C_HSOTG_REG(0x900 + ((_a) * 0x20))
+#define S3C_DOEPCTL(_a)                                S3C_HSOTG_REG(0xB00 + ((_a) * 0x20))
+
+/* EP0 specialness:
+ * bits[29..28] - reserved (no SetD0PID, SetD1PID)
+ * bits[25..22] - should always be zero, this isn't a periodic endpoint
+ * bits[10..0] - MPS setting differenct for EP0
+*/
+#define S3C_D0EPCTL_MPS_MASK                   (0x3 << 0)
+#define S3C_D0EPCTL_MPS_SHIFT                  (0)
+#define S3C_D0EPCTL_MPS_64                     (0x0 << 0)
+#define S3C_D0EPCTL_MPS_32                     (0x1 << 0)
+#define S3C_D0EPCTL_MPS_16                     (0x2 << 0)
+#define S3C_D0EPCTL_MPS_8                      (0x3 << 0)
+
+#define S3C_DxEPCTL_EPEna                      (1 << 31)
+#define S3C_DxEPCTL_EPDis                      (1 << 30)
+#define S3C_DxEPCTL_SetD1PID                   (1 << 29)
+#define S3C_DxEPCTL_SetOddFr                   (1 << 29)
+#define S3C_DxEPCTL_SetD0PID                   (1 << 28)
+#define S3C_DxEPCTL_SetEvenFr                  (1 << 28)
+#define S3C_DxEPCTL_SNAK                       (1 << 27)
+#define S3C_DxEPCTL_CNAK                       (1 << 26)
+#define S3C_DxEPCTL_TxFNum_MASK                        (0xf << 22)
+#define S3C_DxEPCTL_TxFNum_SHIFT               (22)
+#define S3C_DxEPCTL_TxFNum_LIMIT               (0xf)
+#define S3C_DxEPCTL_TxFNum(_x)                 ((_x) << 22)
+
+#define S3C_DxEPCTL_Stall                      (1 << 21)
+#define S3C_DxEPCTL_Snp                                (1 << 20)
+#define S3C_DxEPCTL_EPType_MASK                        (0x3 << 18)
+#define S3C_DxEPCTL_EPType_SHIFT               (18)
+#define S3C_DxEPCTL_EPType_Control             (0x0 << 18)
+#define S3C_DxEPCTL_EPType_Iso                 (0x1 << 18)
+#define S3C_DxEPCTL_EPType_Bulk                        (0x2 << 18)
+#define S3C_DxEPCTL_EPType_Intterupt           (0x3 << 18)
+
+#define S3C_DxEPCTL_NAKsts                     (1 << 17)
+#define S3C_DxEPCTL_DPID                       (1 << 16)
+#define S3C_DxEPCTL_EOFrNum                    (1 << 16)
+#define S3C_DxEPCTL_USBActEp                   (1 << 15)
+#define S3C_DxEPCTL_NextEp_MASK                        (0xf << 11)
+#define S3C_DxEPCTL_NextEp_SHIFT               (11)
+#define S3C_DxEPCTL_NextEp_LIMIT               (0xf)
+#define S3C_DxEPCTL_NextEp(_x)                 ((_x) << 11)
+
+#define S3C_DxEPCTL_MPS_MASK                   (0x7ff << 0)
+#define S3C_DxEPCTL_MPS_SHIFT                  (0)
+#define S3C_DxEPCTL_MPS_LIMIT                  (0x7ff)
+#define S3C_DxEPCTL_MPS(_x)                    ((_x) << 0)
+
+#define S3C_DIEPINT(_a)                                S3C_HSOTG_REG(0x908 + ((_a) * 0x20))
+#define S3C_DOEPINT(_a)                                S3C_HSOTG_REG(0xB08 + ((_a) * 0x20))
+
+#define S3C_DxEPINT_INEPNakEff                 (1 << 6)
+#define S3C_DxEPINT_Back2BackSetup             (1 << 6)
+#define S3C_DxEPINT_INTknEPMis                 (1 << 5)
+#define S3C_DxEPINT_INTknTXFEmp                        (1 << 4)
+#define S3C_DxEPINT_OUTTknEPdis                        (1 << 4)
+#define S3C_DxEPINT_Timeout                    (1 << 3)
+#define S3C_DxEPINT_Setup                      (1 << 3)
+#define S3C_DxEPINT_AHBErr                     (1 << 2)
+#define S3C_DxEPINT_EPDisbld                   (1 << 1)
+#define S3C_DxEPINT_XferCompl                  (1 << 0)
+
+#define S3C_DIEPTSIZ0                          S3C_HSOTG_REG(0x910)
+
+#define S3C_DIEPTSIZ0_PktCnt_MASK              (0x3 << 19)
+#define S3C_DIEPTSIZ0_PktCnt_SHIFT             (19)
+#define S3C_DIEPTSIZ0_PktCnt_LIMIT             (0x3)
+#define S3C_DIEPTSIZ0_PktCnt(_x)               ((_x) << 19)
+
+#define S3C_DIEPTSIZ0_XferSize_MASK            (0x7f << 0)
+#define S3C_DIEPTSIZ0_XferSize_SHIFT           (0)
+#define S3C_DIEPTSIZ0_XferSize_LIMIT           (0x7f)
+#define S3C_DIEPTSIZ0_XferSize(_x)             ((_x) << 0)
+
+
+#define DOEPTSIZ0                              S3C_HSOTG_REG(0xB10)
+#define S3C_DOEPTSIZ0_SUPCnt_MASK              (0x3 << 29)
+#define S3C_DOEPTSIZ0_SUPCnt_SHIFT             (29)
+#define S3C_DOEPTSIZ0_SUPCnt_LIMIT             (0x3)
+#define S3C_DOEPTSIZ0_SUPCnt(_x)               ((_x) << 29)
+
+#define S3C_DOEPTSIZ0_PktCnt                   (1 << 19)
+#define S3C_DOEPTSIZ0_XferSize_MASK            (0x7f << 0)
+#define S3C_DOEPTSIZ0_XferSize_SHIFT           (0)
+
+#define S3C_DIEPTSIZ(_a)                       S3C_HSOTG_REG(0x910 + ((_a) * 0x20))
+#define S3C_DOEPTSIZ(_a)                       S3C_HSOTG_REG(0xB10 + ((_a) * 0x20))
+
+#define S3C_DxEPTSIZ_MC_MASK                   (0x3 << 29)
+#define S3C_DxEPTSIZ_MC_SHIFT                  (29)
+#define S3C_DxEPTSIZ_MC_LIMIT                  (0x3)
+#define S3C_DxEPTSIZ_MC(_x)                    ((_x) << 29)
+
+#define S3C_DxEPTSIZ_PktCnt_MASK               (0x3ff << 19)
+#define S3C_DxEPTSIZ_PktCnt_SHIFT              (19)
+#define S3C_DxEPTSIZ_PktCnt_GET(_v)            (((_v) >> 19) & 0x3ff)
+#define S3C_DxEPTSIZ_PktCnt_LIMIT              (0x3ff)
+#define S3C_DxEPTSIZ_PktCnt(_x)                        ((_x) << 19)
+
+#define S3C_DxEPTSIZ_XferSize_MASK             (0x7ffff << 0)
+#define S3C_DxEPTSIZ_XferSize_SHIFT            (0)
+#define S3C_DxEPTSIZ_XferSize_GET(_v)          (((_v) >> 0) & 0x7ffff)
+#define S3C_DxEPTSIZ_XferSize_LIMIT            (0x7ffff)
+#define S3C_DxEPTSIZ_XferSize(_x)              ((_x) << 0)
+
+
+#define S3C_DIEPDMA(_a)                                S3C_HSOTG_REG(0x914 + ((_a) * 0x20))
+#define S3C_DOEPDMA(_a)                                S3C_HSOTG_REG(0xB14 + ((_a) * 0x20))
+
+#define S3C_EPFIFO(_a)                         S3C_HSOTG_REG(0x1000 + ((_a) * 0x1000))
+
+#endif /* __PLAT_S3C64XX_REGS_USB_HSOTG_H */
index 993d56ee3cf303375a57328680fdc23aa25728f6..57ec9f2dcd953b2ebe9270f1c9dbfa6cf99d2401 100644 (file)
 
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-struct mm_struct init_mm = INIT_MM(init_mm);
-
-EXPORT_SYMBOL(init_mm);
-
 /*
  * Initial thread structure. Must be aligned on an 8192-byte boundary.
  */
index a60cfe757914afb4d4be86494848574cf01b56b6..8ea0d942cdeaf62b6e81ca535c044608c16a308e 100644 (file)
@@ -6,59 +6,65 @@
 mainmenu "Blackfin Kernel Configuration"
 
 config MMU
-       bool
-       default n
+       def_bool n
 
 config FPU
-       bool
-       default n
+       def_bool n
 
 config RWSEM_GENERIC_SPINLOCK
-       bool
-       default y
+       def_bool y
 
 config RWSEM_XCHGADD_ALGORITHM
-       bool
-       default n
+       def_bool n
 
 config BLACKFIN
-       bool
-       default y
+       def_bool y
+       select HAVE_FUNCTION_GRAPH_TRACER
+       select HAVE_FUNCTION_TRACER
        select HAVE_IDE
+       select HAVE_KERNEL_GZIP
+       select HAVE_KERNEL_BZIP2
+       select HAVE_KERNEL_LZMA
        select HAVE_OPROFILE
        select ARCH_WANT_OPTIONAL_GPIOLIB
 
+config GENERIC_BUG
+       def_bool y
+       depends on BUG
+
 config ZONE_DMA
-       bool
-       default y
+       def_bool y
 
 config GENERIC_FIND_NEXT_BIT
-       bool
-       default y
+       def_bool y
 
 config GENERIC_HWEIGHT
-       bool
-       default y
+       def_bool y
 
 config GENERIC_HARDIRQS
-       bool
-       default y
+       def_bool y
 
 config GENERIC_IRQ_PROBE
-       bool
-       default y
+       def_bool y
 
 config GENERIC_GPIO
-       bool
-       default y
+       def_bool y
 
 config FORCE_MAX_ZONEORDER
        int
        default "14"
 
 config GENERIC_CALIBRATE_DELAY
-       bool
-       default y
+       def_bool y
+
+config LOCKDEP_SUPPORT
+       def_bool y
+
+config STACKTRACE_SUPPORT
+       def_bool y
+
+config TRACE_IRQFLAGS_SUPPORT
+       def_bool y
 
 source "init/Kconfig"
 
@@ -408,12 +414,12 @@ comment "Clock/PLL Setup"
 
 config CLKIN_HZ
        int "Frequency of the crystal on the board in Hz"
+       default "10000000" if BFIN532_IP0X
        default "11059200" if BFIN533_STAMP
+       default "24576000" if PNAV10
+       default "25000000" # most people use this
        default "27000000" if BFIN533_EZKIT
-       default "25000000" if (BFIN537_STAMP || BFIN527_EZKIT || H8606_HVSISTEMAS || BLACKSTAMP || BFIN526_EZBRD || BFIN538_EZKIT || BFIN518F-EZBRD)
        default "30000000" if BFIN561_EZKIT
-       default "24576000" if PNAV10
-       default "10000000" if BFIN532_IP0X
        help
          The frequency of CLKIN crystal oscillator on the board in Hz.
          Warning: This value should match the crystal on the board. Otherwise,
index d54c8283825c429c3573209f1343259c6baaac95..6f9533c3d752b6d718ad4712a8de66624ffb49ba 100644 (file)
@@ -137,7 +137,7 @@ archclean:
 
 INSTALL_PATH ?= /tftpboot
 boot := arch/$(ARCH)/boot
-BOOT_TARGETS = vmImage
+BOOT_TARGETS = vmImage vmImage.bz2 vmImage.gz vmImage.lzma
 PHONY += $(BOOT_TARGETS) install
 KBUILD_IMAGE := $(boot)/vmImage
 
@@ -150,7 +150,10 @@ install:
        $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) install
 
 define archhelp
-  echo  '* vmImage         - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage)'
+  echo  '* vmImage         - Alias to selected kernel format (vmImage.gz by default)'
+  echo  '  vmImage.bz2     - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage.bz2)'
+  echo  '* vmImage.gz      - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage.gz)'
+  echo  '  vmImage.lzma    - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage.lzma)'
   echo  '  install         - Install kernel using'
   echo  '                     (your) ~/bin/$(CROSS_COMPILE)installkernel or'
   echo  '                     (distribution) PATH: $(CROSS_COMPILE)installkernel or'
index 3ae03994b88de9636a05bafb1bc1ee0361ad19b1..229e5080867770d755f4721911774dddfa40ab05 100644 (file)
@@ -1 +1,2 @@
-+vmImage
+vmImage*
+vmlinux*
index e028d13481a93660c9843cde769517500c8046f5..3ab6f23561ddfa8287a642cd82954e219db22fcc 100644 (file)
@@ -8,24 +8,41 @@
 
 MKIMAGE := $(srctree)/scripts/mkuboot.sh
 
-targets := vmImage
-extra-y += vmlinux.bin vmlinux.gz
+targets := vmImage vmImage.bz2 vmImage.gz vmImage.lzma
+extra-y += vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma
 
 quiet_cmd_uimage = UIMAGE  $@
       cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A $(ARCH) -O linux -T kernel \
-                   -C gzip -n 'Linux-$(KERNELRELEASE)' -a $(CONFIG_BOOT_LOAD) \
+                   -C $(2) -n 'Linux-$(KERNELRELEASE)' -a $(CONFIG_BOOT_LOAD) \
                    -e $(shell $(NM) vmlinux | awk '$$NF == "__start" {print $$1}') \
                    -d $< $@
 
 $(obj)/vmlinux.bin: vmlinux FORCE
        $(call if_changed,objcopy)
 
-$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE
+$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
        $(call if_changed,gzip)
 
-$(obj)/vmImage: $(obj)/vmlinux.gz
-       $(call if_changed,uimage)
-       @$(kecho) 'Kernel: $@ is ready'
+$(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE
+       $(call if_changed,bzip2)
+
+$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE
+       $(call if_changed,lzma)
+
+$(obj)/vmImage.bz2: $(obj)/vmlinux.bin.bz2
+       $(call if_changed,uimage,bzip2)
+
+$(obj)/vmImage.gz: $(obj)/vmlinux.bin.gz
+       $(call if_changed,uimage,gzip)
+
+$(obj)/vmImage.lzma: $(obj)/vmlinux.bin.lzma
+       $(call if_changed,uimage,lzma)
+
+suffix-$(CONFIG_KERNEL_GZIP)  := gz
+suffix-$(CONFIG_KERNEL_BZIP2) := bz2
+suffix-$(CONFIG_KERNEL_LZMA)  := lzma
+$(obj)/vmImage: $(obj)/vmImage.$(suffix-y)
+       @ln -sf $(notdir $<) $@
 
 install:
        sh $(srctree)/$(src)/install.sh $(KERNELRELEASE) $(BOOTIMAGE) System.map "$(INSTALL_PATH)"
index 7bbf44e4ddf9642a264396d26eba88e7ce08f842..b1d92f13ef9602ca8b54a14d30b3335b735350e2 100644 (file)
@@ -90,7 +90,7 @@ static inline int atomic_test_mask(int mask, atomic_t *v)
 
 static inline void atomic_add(int i, atomic_t *v)
 {
-       long flags;
+       unsigned long flags;
 
        local_irq_save_hw(flags);
        v->counter += i;
@@ -99,7 +99,7 @@ static inline void atomic_add(int i, atomic_t *v)
 
 static inline void atomic_sub(int i, atomic_t *v)
 {
-       long flags;
+       unsigned long flags;
 
        local_irq_save_hw(flags);
        v->counter -= i;
@@ -110,7 +110,7 @@ static inline void atomic_sub(int i, atomic_t *v)
 static inline int atomic_add_return(int i, atomic_t *v)
 {
        int __temp = 0;
-       long flags;
+       unsigned long flags;
 
        local_irq_save_hw(flags);
        v->counter += i;
@@ -124,7 +124,7 @@ static inline int atomic_add_return(int i, atomic_t *v)
 static inline int atomic_sub_return(int i, atomic_t *v)
 {
        int __temp = 0;
-       long flags;
+       unsigned long flags;
 
        local_irq_save_hw(flags);
        v->counter -= i;
@@ -136,7 +136,7 @@ static inline int atomic_sub_return(int i, atomic_t *v)
 
 static inline void atomic_inc(volatile atomic_t *v)
 {
-       long flags;
+       unsigned long flags;
 
        local_irq_save_hw(flags);
        v->counter++;
@@ -145,7 +145,7 @@ static inline void atomic_inc(volatile atomic_t *v)
 
 static inline void atomic_dec(volatile atomic_t *v)
 {
-       long flags;
+       unsigned long flags;
 
        local_irq_save_hw(flags);
        v->counter--;
@@ -154,7 +154,7 @@ static inline void atomic_dec(volatile atomic_t *v)
 
 static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
 {
-       long flags;
+       unsigned long flags;
 
        local_irq_save_hw(flags);
        v->counter &= ~mask;
@@ -163,7 +163,7 @@ static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
 
 static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
 {
-       long flags;
+       unsigned long flags;
 
        local_irq_save_hw(flags);
        v->counter |= mask;
index daffc0684e753bd4f3f19a9e060988b694fa8219..e39277ea43e8bfd38e4daacd8792526762ae284e 100644 (file)
@@ -31,7 +31,7 @@
 
 #ifndef __ASSEMBLY__
 
-#include <asm-generic/sections.h>
+#include <asm/sections.h>
 #include <asm/ptrace.h>
 #include <asm/user.h>
 #include <linux/linkage.h>
@@ -99,15 +99,6 @@ extern const char bfin_board_name[];
 extern unsigned long bfin_sic_iwr[];
 extern unsigned vr_wakeup;
 extern u16 _bfin_swrst; /* shadow for Software Reset Register (SWRST) */
-extern unsigned long _ramstart, _ramend, _rambase;
-extern unsigned long memory_start, memory_end, physical_mem_end;
-extern char _stext_l1[], _etext_l1[], _sdata_l1[], _edata_l1[], _sbss_l1[],
-       _ebss_l1[], _l1_lma_start[], _sdata_b_l1[], _sbss_b_l1[], _ebss_b_l1[],
-       _stext_l2[], _etext_l2[], _sdata_l2[], _edata_l2[], _sbss_l2[],
-       _ebss_l2[], _l2_lma_start[];
-
-/* only used when MTD_UCLINUX */
-extern unsigned long memory_mtd_start, memory_mtd_end, mtd_size;
 
 #ifdef CONFIG_BFIN_ICACHE_LOCK
 extern void cache_grab_lock(int way);
index 21b036eadab1d4e8450499c2c9c097f0f0546495..75fee2f7d9f240b3c98d5080a35016eca8e60399 100644 (file)
@@ -109,7 +109,8 @@ static inline void clear_bit(int nr, volatile unsigned long *addr)
 
 static inline void change_bit(int nr, volatile unsigned long *addr)
 {
-       int mask, flags;
+       int mask;
+       unsigned long flags;
        unsigned long *ADDR = (unsigned long *)addr;
 
        ADDR += nr >> 5;
index 6d3e11b1fc576c6f141c98e3086e477c691a23df..655e49540e41d902b6396d5a2dbbb4ae594b2778 100644 (file)
@@ -2,13 +2,58 @@
 #define _BLACKFIN_BUG_H
 
 #ifdef CONFIG_BUG
-#define HAVE_ARCH_BUG
 
-#define BUG() do { \
-       dump_bfin_trace_buffer(); \
-       printk(KERN_EMERG "BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
-       panic("BUG!"); \
-} while (0)
+#define BFIN_BUG_OPCODE        0xefcd
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+
+#define _BUG_OR_WARN(flags)                                            \
+       asm volatile(                                                   \
+               "1:     .hword  %0\n"                                   \
+               "       .section __bug_table,\"a\",@progbits\n"         \
+               "2:     .long   1b\n"                                   \
+               "       .long   %1\n"                                   \
+               "       .short  %2\n"                                   \
+               "       .short  %3\n"                                   \
+               "       .org    2b + %4\n"                              \
+               "       .previous"                                      \
+               :                                                       \
+               : "i"(BFIN_BUG_OPCODE), "i"(__FILE__),                  \
+                 "i"(__LINE__), "i"(flags),                            \
+                 "i"(sizeof(struct bug_entry)))
+
+#else
+
+#define _BUG_OR_WARN(flags)                                            \
+       asm volatile(                                                   \
+               "1:     .hword  %0\n"                                   \
+               "       .section __bug_table,\"a\",@progbits\n"         \
+               "2:     .long   1b\n"                                   \
+               "       .short  %1\n"                                   \
+               "       .org    2b + %2\n"                              \
+               "       .previous"                                      \
+               :                                                       \
+               : "i"(BFIN_BUG_OPCODE), "i"(flags),                     \
+                 "i"(sizeof(struct bug_entry)))
+
+#endif /* CONFIG_DEBUG_BUGVERBOSE */
+
+#define BUG()                                                          \
+       do {                                                            \
+               _BUG_OR_WARN(0);                                        \
+               for (;;);                                               \
+       } while (0)
+
+#define WARN_ON(condition)                                                     \
+       ({                                                              \
+               int __ret_warn_on = !!(condition);                      \
+               if (unlikely(__ret_warn_on))                            \
+                       _BUG_OR_WARN(BUGFLAG_WARNING);                  \
+               unlikely(__ret_warn_on);                                \
+       })
+
+#define HAVE_ARCH_BUG
+#define HAVE_ARCH_WARN_ON
 
 #endif
 
index 86637814cf252b9146f398367aea451b9b829b41..2ef669ed9222f03df97a7b05e1e7e5cca8d43c2e 100644 (file)
 #define L1_CACHE_SHIFT_MAX     5
 
 #if defined(CONFIG_SMP) && \
-    !defined(CONFIG_BFIN_CACHE_COHERENT) && \
-    defined(CONFIG_BFIN_DCACHE)
-#define __ARCH_SYNC_CORE_DCACHE
+    !defined(CONFIG_BFIN_CACHE_COHERENT)
+# if defined(CONFIG_BFIN_ICACHE)
+# define __ARCH_SYNC_CORE_ICACHE
+# endif
+# if defined(CONFIG_BFIN_DCACHE)
+# define __ARCH_SYNC_CORE_DCACHE
+# endif
 #ifndef __ASSEMBLY__
 asmlinkage void __raw_smp_mark_barrier_asm(void);
 asmlinkage void __raw_smp_check_barrier_asm(void);
@@ -51,6 +55,7 @@ static inline void smp_check_barrier(void)
 }
 
 void resync_core_dcache(void);
+void resync_core_icache(void);
 #endif
 #endif
 
index 94697f0f6f402fc2bf772ca778b96dddf750344d..5c17dee53b5dca8fa3fe0e0520958c18a4ac8be8 100644 (file)
@@ -37,6 +37,7 @@ extern void blackfin_dcache_flush_range(unsigned long start_address, unsigned lo
 extern void blackfin_dcache_invalidate_range(unsigned long start_address, unsigned long end_address);
 extern void blackfin_dflush_page(void *page);
 extern void blackfin_invalidate_entire_dcache(void);
+extern void blackfin_invalidate_entire_icache(void);
 
 #define flush_dcache_mmap_lock(mapping)                do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)      do { } while (0)
@@ -97,7 +98,7 @@ do { memcpy(dst, src, len);                                           \
 extern unsigned long reserved_mem_dcache_on;
 extern unsigned long reserved_mem_icache_on;
 
-static inline int bfin_addr_dcachable(unsigned long addr)
+static inline int bfin_addr_dcacheable(unsigned long addr)
 {
 #ifdef CONFIG_BFIN_DCACHE
        if (addr < (_ramend - DMA_UNCACHED_REGION))
index c2594ef877f69bc96771f1f2d75c6509f3b4584d..565b8136855ed16d5237376cc7186878dcc46855 100644 (file)
@@ -34,6 +34,7 @@ struct blackfin_cpudata {
        unsigned int dmemctl;
        unsigned long loops_per_jiffy;
        unsigned long dcache_invld_count;
+       unsigned long icache_invld_count;
 };
 
 DECLARE_PER_CPU(struct blackfin_cpudata, cpu_data);
index 40a8c178f10d9e85a2873c83247c3f2fe553f408..8643680f0f786cf53bf94a40f6d4241a511565ec 100644 (file)
@@ -1 +1,13 @@
-/* empty */
+/*
+ * Blackfin ftrace code
+ *
+ * Copyright 2009 Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __ASM_BFIN_FTRACE_H__
+#define __ASM_BFIN_FTRACE_H__
+
+#define MCOUNT_INSN_SIZE       8 /* sizeof mcount call: LINK + CALL */
+
+#endif
index 51d0bf5e2899d4543810e344d842591057b210ee..bbe1c3726b69acf41cc7ffb2038e5c183c718ecf 100644 (file)
 #include <asm/atomic.h>
 #include <asm/traps.h>
 
-#define IPIPE_ARCH_STRING     "1.9-01"
+#define IPIPE_ARCH_STRING     "1.10-00"
 #define IPIPE_MAJOR_NUMBER    1
-#define IPIPE_MINOR_NUMBER    9
-#define IPIPE_PATCH_NUMBER    1
+#define IPIPE_MINOR_NUMBER    10
+#define IPIPE_PATCH_NUMBER    0
 
 #ifdef CONFIG_SMP
 #error "I-pipe/blackfin: SMP not implemented"
@@ -54,10 +54,11 @@ do {                                                \
 
 #define task_hijacked(p)                                               \
        ({                                                              \
-               int __x__ = ipipe_current_domain != ipipe_root_domain;  \
-               /* We would need to clear the SYNC flag for the root domain */ \
-               /* over the current processor in SMP mode. */           \
-               local_irq_enable_hw(); __x__;                           \
+               int __x__ = __ipipe_root_domain_p;                      \
+               __clear_bit(IPIPE_SYNC_FLAG, &ipipe_root_cpudom_var(status)); \
+               if (__x__)                                              \
+                       local_irq_enable_hw();                          \
+               !__x__;                                                 \
        })
 
 struct ipipe_domain;
@@ -179,23 +180,24 @@ static inline unsigned long __ipipe_ffnz(unsigned long ul)
 
 #define __ipipe_run_isr(ipd, irq)                                      \
        do {                                                            \
-               if (ipd == ipipe_root_domain) {                         \
+               if (!__ipipe_pipeline_head_p(ipd))                      \
                        local_irq_enable_hw();                          \
-                       if (ipipe_virtual_irq_p(irq))                   \
+               if (ipd == ipipe_root_domain) {                         \
+                       if (unlikely(ipipe_virtual_irq_p(irq))) {       \
+                               irq_enter();                            \
                                ipd->irqs[irq].handler(irq, ipd->irqs[irq].cookie); \
-                       else                                            \
+                               irq_exit();                             \
+                       } else                                          \
                                ipd->irqs[irq].handler(irq, &__raw_get_cpu_var(__ipipe_tick_regs)); \
-                       local_irq_disable_hw();                         \
                } else {                                                \
                        __clear_bit(IPIPE_SYNC_FLAG, &ipipe_cpudom_var(ipd, status)); \
-                       local_irq_enable_nohead(ipd);                   \
                        ipd->irqs[irq].handler(irq, ipd->irqs[irq].cookie); \
                        /* Attempt to exit the outer interrupt level before \
                         * starting the deferred IRQ processing. */     \
-                       local_irq_disable_nohead(ipd);                  \
                        __ipipe_run_irqtail();                          \
                        __set_bit(IPIPE_SYNC_FLAG, &ipipe_cpudom_var(ipd, status)); \
                }                                                       \
+               local_irq_disable_hw();                                 \
        } while (0)
 
 #define __ipipe_syscall_watched_p(p, sc)       \
index 7645e85a5f6f70319c2a20158c0f5d39fbe84ce7..400bdd52ce8732a6ed577978c65e9efcebb26f8e 100644 (file)
 #ifndef _BFIN_IRQ_H_
 #define _BFIN_IRQ_H_
 
-/* SYS_IRQS and NR_IRQS are defined in <mach-bf5xx/irq.h>*/
-#include <mach/irq.h>
-#include <asm/pda.h>
-#include <asm/processor.h>
-
-#ifdef CONFIG_SMP
-/* Forward decl needed due to cdef inter dependencies */
-static inline uint32_t __pure bfin_dspid(void);
-# define blackfin_core_id() (bfin_dspid() & 0xff)
-# define bfin_irq_flags cpu_pda[blackfin_core_id()].imask
-#else
-extern unsigned long bfin_irq_flags;
-#endif
-
-#ifdef CONFIG_IPIPE
-
-#include <linux/ipipe_trace.h>
+#include <linux/irqflags.h>
 
-void __ipipe_unstall_root(void);
-
-void __ipipe_restore_root(unsigned long flags);
-
-#ifdef CONFIG_DEBUG_HWERR
-# define __all_masked_irq_flags 0x3f
-# define __save_and_cli_hw(x) \
-       __asm__ __volatile__( \
-               "cli %0;" \
-               "sti %1;" \
-               : "=&d"(x) \
-               : "d" (0x3F) \
-       )
-#else
-# define __all_masked_irq_flags 0x1f
-# define __save_and_cli_hw(x) \
-       __asm__ __volatile__( \
-               "cli %0;" \
-               : "=&d"(x) \
-       )
-#endif
-
-#define irqs_enabled_from_flags_hw(x)  ((x) != __all_masked_irq_flags)
-#define raw_irqs_disabled_flags(flags) (!irqs_enabled_from_flags_hw(flags))
-#define local_test_iflag_hw(x)         irqs_enabled_from_flags_hw(x)
-
-#define local_save_flags(x)                                     \
-       do {                                                     \
-               (x) = __ipipe_test_root() ?                      \
-                       __all_masked_irq_flags : bfin_irq_flags; \
-               barrier();                                       \
-       } while (0)
-
-#define local_irq_save(x)                                       \
-       do {                                                     \
-               (x) = __ipipe_test_and_stall_root() ?            \
-                       __all_masked_irq_flags : bfin_irq_flags; \
-               barrier();                                       \
-       } while (0)
-
-static inline void local_irq_restore(unsigned long x)
-{
-       barrier();
-       __ipipe_restore_root(x == __all_masked_irq_flags);
-}
-
-#define local_irq_disable()                    \
-       do {                                    \
-               __ipipe_stall_root();           \
-               barrier();                      \
-       } while (0)
-
-static inline void local_irq_enable(void)
-{
-       barrier();
-       __ipipe_unstall_root();
-}
-
-#define irqs_disabled()                __ipipe_test_root()
-
-#define local_save_flags_hw(x) \
-       __asm__ __volatile__( \
-               "cli %0;" \
-               "sti %0;" \
-               : "=d"(x) \
-       )
-
-#define        irqs_disabled_hw()                              \
-       ({                                              \
-               unsigned long flags;                    \
-               local_save_flags_hw(flags);             \
-               !irqs_enabled_from_flags_hw(flags);     \
-       })
-
-static inline unsigned long raw_mangle_irq_bits(int virt, unsigned long real)
-{
-       /* Merge virtual and real interrupt mask bits into a single
-          32bit word. */
-       return (real & ~(1 << 31)) | ((virt != 0) << 31);
-}
-
-static inline int raw_demangle_irq_bits(unsigned long *x)
-{
-       int virt = (*x & (1 << 31)) != 0;
-       *x &= ~(1L << 31);
-       return virt;
-}
-
-#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
-
-#define local_irq_disable_hw()                                         \
-       do {                                                            \
-               int _tmp_dummy;                                         \
-               if (!irqs_disabled_hw())                                \
-                       ipipe_trace_begin(0x80000000);                  \
-               __asm__ __volatile__ ("cli %0;" : "=d" (_tmp_dummy) : );        \
-       } while (0)
-
-#define local_irq_enable_hw()                                          \
-       do {                                                            \
-               if (irqs_disabled_hw())                                 \
-                       ipipe_trace_end(0x80000000);                    \
-               __asm__ __volatile__ ("sti %0;" : : "d"(bfin_irq_flags));       \
-       } while (0)
-
-#define local_irq_save_hw(x)                           \
-       do {                                            \
-               __save_and_cli_hw(x);                   \
-               if (local_test_iflag_hw(x))             \
-                       ipipe_trace_begin(0x80000001);  \
-       } while (0)
-
-#define local_irq_restore_hw(x)                                \
-       do {                                            \
-               if (local_test_iflag_hw(x)) {           \
-                       ipipe_trace_end(0x80000001);    \
-                       local_irq_enable_hw_notrace();  \
-               }                                       \
-       } while (0)
-
-#define local_irq_disable_hw_notrace()                                 \
-       do {                                                            \
-               int _tmp_dummy;                                         \
-               __asm__ __volatile__ ("cli %0;" : "=d" (_tmp_dummy) : );        \
-       } while (0)
-
-#define local_irq_enable_hw_notrace() \
-       __asm__ __volatile__( \
-               "sti %0;" \
-               : \
-               : "d"(bfin_irq_flags) \
-       )
-
-#define local_irq_save_hw_notrace(x) __save_and_cli_hw(x)
-
-#define local_irq_restore_hw_notrace(x)                        \
-       do {                                            \
-               if (local_test_iflag_hw(x))             \
-                       local_irq_enable_hw_notrace();  \
-       } while (0)
-
-#else /* CONFIG_IPIPE_TRACE_IRQSOFF */
-
-#define local_irq_enable_hw() \
-       __asm__ __volatile__( \
-               "sti %0;" \
-               : \
-               : "d"(bfin_irq_flags) \
-       )
-
-#define local_irq_disable_hw()                 \
-       do {                                    \
-               int _tmp_dummy;                 \
-               __asm__ __volatile__ (          \
-                       "cli %0;"               \
-                       : "=d" (_tmp_dummy));   \
-       } while (0)
-
-#define local_irq_restore_hw(x) \
-       do { \
-               if (irqs_enabled_from_flags_hw(x)) \
-                       local_irq_enable_hw(); \
-       } while (0)
-
-#define local_irq_save_hw(x)           __save_and_cli_hw(x)
-
-#define local_irq_disable_hw_notrace() local_irq_disable_hw()
-#define local_irq_enable_hw_notrace()  local_irq_enable_hw()
-#define local_irq_save_hw_notrace(x)   local_irq_save_hw(x)
-#define local_irq_restore_hw_notrace(x)        local_irq_restore_hw(x)
-
-#endif  /* CONFIG_IPIPE_TRACE_IRQSOFF */
-
-#else /* !CONFIG_IPIPE */
-
-/*
- * Interrupt configuring macros.
- */
-#define local_irq_disable() \
-       do { \
-               int __tmp_dummy; \
-               __asm__ __volatile__( \
-                       "cli %0;" \
-                       : "=d" (__tmp_dummy) \
-               ); \
-       } while (0)
-
-#define local_irq_enable() \
-       __asm__ __volatile__( \
-               "sti %0;" \
-               : \
-               : "d" (bfin_irq_flags) \
-       )
-
-#ifdef CONFIG_DEBUG_HWERR
-# define __save_and_cli(x) \
-       __asm__ __volatile__( \
-               "cli %0;" \
-               "sti %1;" \
-               : "=&d" (x) \
-               : "d" (0x3F) \
-       )
-#else
-# define __save_and_cli(x) \
-       __asm__ __volatile__( \
-               "cli %0;" \
-               : "=&d" (x) \
-       )
-#endif
-
-#define local_save_flags(x) \
-       __asm__ __volatile__( \
-               "cli %0;" \
-               "sti %0;" \
-               : "=d" (x) \
-       )
-
-#ifdef CONFIG_DEBUG_HWERR
-#define irqs_enabled_from_flags(x) (((x) & ~0x3f) != 0)
-#else
-#define irqs_enabled_from_flags(x) ((x) != 0x1f)
-#endif
-
-#define local_irq_restore(x) \
-       do { \
-               if (irqs_enabled_from_flags(x)) \
-                       local_irq_enable(); \
-       } while (0)
-
-/* For spinlocks etc */
-#define local_irq_save(x) __save_and_cli(x)
-
-#define irqs_disabled()                                \
-({                                             \
-       unsigned long flags;                    \
-       local_save_flags(flags);                \
-       !irqs_enabled_from_flags(flags);        \
-})
-
-#define local_irq_save_hw(x)           local_irq_save(x)
-#define local_irq_restore_hw(x)                local_irq_restore(x)
-#define local_irq_enable_hw()          local_irq_enable()
-#define local_irq_disable_hw()         local_irq_disable()
-#define irqs_disabled_hw()             irqs_disabled()
+/* SYS_IRQS and NR_IRQS are defined in <mach-bf5xx/irq.h> */
+#include <mach/irq.h>
 
-#endif /* !CONFIG_IPIPE */
+/* Xenomai IPIPE helpers */
+#define local_irq_restore_hw(x) local_irq_restore(x)
+#define local_irq_save_hw(x)    local_irq_save(x)
+#define local_irq_enable_hw(x)  local_irq_enable(x)
+#define local_irq_disable_hw(x) local_irq_disable(x)
+#define irqs_disabled_hw(x)     irqs_disabled(x)
 
 #if ANOMALY_05000244 && defined(CONFIG_BFIN_ICACHE)
 # define NOP_PAD_ANOMALY_05000244 "nop; nop;"
diff --git a/arch/blackfin/include/asm/irqflags.h b/arch/blackfin/include/asm/irqflags.h
new file mode 100644 (file)
index 0000000..139cba4
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * interface to Blackfin CEC
+ *
+ * Copyright 2009 Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __ASM_BFIN_IRQFLAGS_H__
+#define __ASM_BFIN_IRQFLAGS_H__
+
+#ifdef CONFIG_SMP
+# include <asm/pda.h>
+# include <asm/processor.h>
+/* Forward decl needed due to cdef inter dependencies */
+static inline uint32_t __pure bfin_dspid(void);
+# define blackfin_core_id() (bfin_dspid() & 0xff)
+# define bfin_irq_flags cpu_pda[blackfin_core_id()].imask
+#else
+extern unsigned long bfin_irq_flags;
+#endif
+
+static inline void bfin_sti(unsigned long flags)
+{
+       asm volatile("sti %0;" : : "d" (flags));
+}
+
+static inline unsigned long bfin_cli(void)
+{
+       unsigned long flags;
+       asm volatile("cli %0;" : "=d" (flags));
+       return flags;
+}
+
+static inline void raw_local_irq_disable(void)
+{
+       bfin_cli();
+}
+static inline void raw_local_irq_enable(void)
+{
+       bfin_sti(bfin_irq_flags);
+}
+
+#define raw_local_save_flags(flags) do { (flags) = bfin_read_IMASK(); } while (0)
+
+#define raw_irqs_disabled_flags(flags) (((flags) & ~0x3f) == 0)
+
+static inline void raw_local_irq_restore(unsigned long flags)
+{
+       if (!raw_irqs_disabled_flags(flags))
+               raw_local_irq_enable();
+}
+
+static inline unsigned long __raw_local_irq_save(void)
+{
+       unsigned long flags = bfin_cli();
+#ifdef CONFIG_DEBUG_HWERR
+       bfin_sti(0x3f);
+#endif
+       return flags;
+}
+#define raw_local_irq_save(flags) do { (flags) = __raw_local_irq_save(); } while (0)
+
+#endif
index e215f7104974fb76957d66695185f9e925edc519..0a88622339ee363d0663d53390a2106e26e51038 100644 (file)
@@ -1,21 +1,6 @@
 #ifndef _ASM_KMAP_TYPES_H
 #define _ASM_KMAP_TYPES_H
 
-enum km_type {
-       KM_BOUNCE_READ,
-       KM_SKB_SUNRPC_DATA,
-       KM_SKB_DATA_SOFTIRQ,
-       KM_USER0,
-       KM_USER1,
-       KM_BIO_SRC_IRQ,
-       KM_BIO_DST_IRQ,
-       KM_PTE0,
-       KM_PTE1,
-       KM_IRQ0,
-       KM_IRQ1,
-       KM_SOFTIRQ0,
-       KM_SOFTIRQ1,
-       KM_TYPE_NR
-};
+#include <asm-generic/kmap_types.h>
 
 #endif
diff --git a/arch/blackfin/include/asm/mutex-dec.h b/arch/blackfin/include/asm/mutex-dec.h
deleted file mode 100644 (file)
index 0134151..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * include/asm-generic/mutex-dec.h
- *
- * Generic implementation of the mutex fastpath, based on atomic
- * decrement/increment.
- */
-#ifndef _ASM_GENERIC_MUTEX_DEC_H
-#define _ASM_GENERIC_MUTEX_DEC_H
-
-/**
- *  __mutex_fastpath_lock - try to take the lock by moving the count
- *                          from 1 to a 0 value
- *  @count: pointer of type atomic_t
- *  @fail_fn: function to call if the original value was not 1
- *
- * Change the count from 1 to a value lower than 1, and call <fail_fn> if
- * it wasn't 1 originally. This function MUST leave the value lower than
- * 1 even when the "1" assertion wasn't true.
- */
-static inline void
-__mutex_fastpath_lock(atomic_t *count, fastcall void (*fail_fn)(atomic_t *))
-{
-       if (unlikely(atomic_dec_return(count) < 0))
-               fail_fn(count);
-       else
-               smp_mb();
-}
-
-/**
- *  __mutex_fastpath_lock_retval - try to take the lock by moving the count
- *                                 from 1 to a 0 value
- *  @count: pointer of type atomic_t
- *  @fail_fn: function to call if the original value was not 1
- *
- * Change the count from 1 to a value lower than 1, and call <fail_fn> if
- * it wasn't 1 originally. This function returns 0 if the fastpath succeeds,
- * or anything the slow path function returns.
- */
-static inline int
-__mutex_fastpath_lock_retval(atomic_t *count, fastcall int (*fail_fn)(atomic_t *))
-{
-       if (unlikely(atomic_dec_return(count) < 0))
-               return fail_fn(count);
-       else {
-               smp_mb();
-               return 0;
-       }
-}
-
-/**
- *  __mutex_fastpath_unlock - try to promote the count from 0 to 1
- *  @count: pointer of type atomic_t
- *  @fail_fn: function to call if the original value was not 0
- *
- * Try to promote the count from 0 to 1. If it wasn't 0, call <fail_fn>.
- * In the failure case, this function is allowed to either set the value to
- * 1, or to set it to a value lower than 1.
- *
- * If the implementation sets it to a value of lower than 1, then the
- * __mutex_slowpath_needs_to_unlock() macro needs to return 1, it needs
- * to return 0 otherwise.
- */
-static inline void
-__mutex_fastpath_unlock(atomic_t *count, fastcall void (*fail_fn)(atomic_t *))
-{
-       smp_mb();
-       if (unlikely(atomic_inc_return(count) <= 0))
-               fail_fn(count);
-}
-
-#define __mutex_slowpath_needs_to_unlock()             1
-
-/**
- * __mutex_fastpath_trylock - try to acquire the mutex, without waiting
- *
- *  @count: pointer of type atomic_t
- *  @fail_fn: fallback function
- *
- * Change the count from 1 to a value lower than 1, and return 0 (failure)
- * if it wasn't 1 originally, or return 1 (success) otherwise. This function
- * MUST leave the value lower than 1 even when the "1" assertion wasn't true.
- * Additionally, if the value was < 0 originally, this function must not leave
- * it to 0 on failure.
- *
- * If the architecture has no effective trylock variant, it should call the
- * <fail_fn> spinlock-based trylock variant unconditionally.
- */
-static inline int
-__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *))
-{
-       /*
-        * We have two variants here. The cmpxchg based one is the best one
-        * because it never induce a false contention state.  It is included
-        * here because architectures using the inc/dec algorithms over the
-        * xchg ones are much more likely to support cmpxchg natively.
-        *
-        * If not we fall back to the spinlock based variant - that is
-        * just as efficient (and simpler) as a 'destructive' probing of
-        * the mutex state would be.
-        */
-#ifdef __HAVE_ARCH_CMPXCHG
-       if (likely(atomic_cmpxchg(count, 1, 0) == 1)) {
-               smp_mb();
-               return 1;
-       }
-       return 0;
-#else
-       return fail_fn(count);
-#endif
-}
-
-#endif
index 1443c3353a8c811bc701f16a078ef04ec52c9ad6..e7fd0ecd73f75de4d2a7df13b85a5049e046b7aa 100644 (file)
@@ -4,4 +4,15 @@
 /* nothing to see, move along */
 #include <asm-generic/sections.h>
 
+/* only used when MTD_UCLINUX */
+extern unsigned long memory_mtd_start, memory_mtd_end, mtd_size;
+
+extern unsigned long _ramstart, _ramend, _rambase;
+extern unsigned long memory_start, memory_end, physical_mem_end;
+
+extern char _stext_l1[], _etext_l1[], _sdata_l1[], _edata_l1[], _sbss_l1[],
+       _ebss_l1[], _l1_lma_start[], _sdata_b_l1[], _sbss_b_l1[], _ebss_b_l1[],
+       _stext_l2[], _etext_l2[], _sdata_l2[], _edata_l2[], _sbss_l2[],
+       _ebss_l2[], _l2_lma_start[];
+
 #endif
index a4c8254bec5514eff746b217417816930f34a291..294dbda24164c442beea46664f8133c9c6bba85d 100644 (file)
 #define _BLACKFIN_SYSTEM_H
 
 #include <linux/linkage.h>
-#include <linux/compiler.h>
+#include <linux/irqflags.h>
 #include <mach/anomaly.h>
+#include <asm/cache.h>
 #include <asm/pda.h>
-#include <asm/processor.h>
 #include <asm/irq.h>
 
 /*
index cf5066d3efd2b79f6e9f287de452ec8efd96385a..da35133c171de5e57fdee251e2c16b2b7d8ea5a7 100644 (file)
 #define __NR_inotify_init1     365
 #define __NR_preadv            366
 #define __NR_pwritev           367
+#define __NR_rt_tgsigqueueinfo 368
 
-#define __NR_syscall           368
+#define __NR_syscall           369
 #define NR_syscalls            __NR_syscall
 
 /* Old optional stuff no one actually uses */
index fd4d4328a0f2aa94fb5ef97afcc01f0018e89edf..3731088e181b4a85b010971423e817b448bfed3a 100644 (file)
@@ -15,6 +15,10 @@ else
     obj-y += time.o
 endif
 
+obj-$(CONFIG_FUNCTION_TRACER)        += ftrace-entry.o
+obj-$(CONFIG_FUNCTION_GRAPH_TRACER)  += ftrace.o
+CFLAGS_REMOVE_ftrace.o = -pg
+
 obj-$(CONFIG_IPIPE)                  += ipipe.o
 obj-$(CONFIG_IPIPE_TRACE_MCOUNT)     += mcount.o
 obj-$(CONFIG_BFIN_GPTIMERS)          += gptimers.o
@@ -23,6 +27,7 @@ obj-$(CONFIG_MODULES)                += module.o
 obj-$(CONFIG_KGDB)                   += kgdb.o
 obj-$(CONFIG_KGDB_TESTS)             += kgdb_test.o
 obj-$(CONFIG_EARLY_PRINTK)           += early_printk.o
+obj-$(CONFIG_STACKTRACE)             += stacktrace.o
 
 # the kgdb test puts code into L2 and without linker
 # relaxation, we need to force long calls to/from it
index 763ed84ba459f3236fd7831075cdb002bd610d96..e0bf8cc06907abd67040c37127f0091792c39a8a 100644 (file)
@@ -453,10 +453,10 @@ void *dma_memcpy(void *pdst, const void *psrc, size_t size)
        unsigned long src = (unsigned long)psrc;
        size_t bulk, rest;
 
-       if (bfin_addr_dcachable(src))
+       if (bfin_addr_dcacheable(src))
                blackfin_dcache_flush_range(src, src + size);
 
-       if (bfin_addr_dcachable(dst))
+       if (bfin_addr_dcacheable(dst))
                blackfin_dcache_invalidate_range(dst, dst + size);
 
        bulk = size & ~0xffff;
index 53e893ff708aa547674aaab28c0974c54272f37c..aa05e638fb7cb6fa3d4b5cd7e05b2c3ecc128eb1 100644 (file)
@@ -103,3 +103,8 @@ EXPORT_SYMBOL(__raw_smp_mark_barrier_asm);
 EXPORT_SYMBOL(__raw_smp_check_barrier_asm);
 #endif
 #endif
+
+#ifdef CONFIG_FUNCTION_TRACER
+extern void _mcount(void);
+EXPORT_SYMBOL(_mcount);
+#endif
index 87463ce87f5aef0073e0d5fcebad50eb61404cf7..784923e52a9a740714d37f74feca5272bc1c84fc 100644 (file)
@@ -151,7 +151,7 @@ static noinline int dcplb_miss(unsigned int cpu)
 
        d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB;
 #ifdef CONFIG_BFIN_DCACHE
-       if (bfin_addr_dcachable(addr)) {
+       if (bfin_addr_dcacheable(addr)) {
                d_data |= CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND;
 #ifdef CONFIG_BFIN_WT
                d_data |= CPLB_L1_AOW | CPLB_WT;
index 8cbb47c7b6639a76434f395b820304a62ecf9f82..12b030842fdbc1623c99997c60e67d534f168112 100644 (file)
@@ -28,6 +28,7 @@
 #include <asm/cplbinit.h>
 #include <asm/cplb.h>
 #include <asm/mmu_context.h>
+#include <asm/traps.h>
 
 /*
  * WARNING
@@ -100,28 +101,6 @@ static inline void write_icplb_data(int cpu, int idx, unsigned long data,
 #endif
 }
 
-/*
- * Given the contents of the status register, return the index of the
- * CPLB that caused the fault.
- */
-static inline int faulting_cplb_index(int status)
-{
-       int signbits = __builtin_bfin_norm_fr1x32(status & 0xFFFF);
-       return 30 - signbits;
-}
-
-/*
- * Given the contents of the status register and the DCPLB_DATA contents,
- * return true if a write access should be permitted.
- */
-static inline int write_permitted(int status, unsigned long data)
-{
-       if (status & FAULT_USERSUPV)
-               return !!(data & CPLB_SUPV_WR);
-       else
-               return !!(data & CPLB_USER_WR);
-}
-
 /* Counters to implement round-robin replacement.  */
 static int icplb_rr_index[NR_CPUS] PDT_ATTR;
 static int dcplb_rr_index[NR_CPUS] PDT_ATTR;
@@ -245,43 +224,16 @@ MGR_ATTR static int dcplb_miss(int cpu)
        return CPLB_RELOADED;
 }
 
-MGR_ATTR static noinline int dcplb_protection_fault(int cpu)
-{
-       int status = bfin_read_DCPLB_STATUS();
-
-       nr_dcplb_prot[cpu]++;
-
-       if (likely(status & FAULT_RW)) {
-               int idx = faulting_cplb_index(status);
-               unsigned long regaddr = DCPLB_DATA0 + idx * 4;
-               unsigned long data = bfin_read32(regaddr);
-
-               /* Check if fault is to dirty a clean page */
-               if (!(data & CPLB_WT) && !(data & CPLB_DIRTY) &&
-                   write_permitted(status, data)) {
-
-                       dcplb_tbl[cpu][idx].data = data;
-                       bfin_write32(regaddr, data);
-                       return CPLB_RELOADED;
-               }
-       }
-
-       return CPLB_PROT_VIOL;
-}
-
 MGR_ATTR int cplb_hdr(int seqstat, struct pt_regs *regs)
 {
        int cause = seqstat & 0x3f;
        unsigned int cpu = smp_processor_id();
        switch (cause) {
-       case 0x2C:
+       case VEC_CPLB_I_M:
                return icplb_miss(cpu);
-       case 0x26:
+       case VEC_CPLB_M:
                return dcplb_miss(cpu);
        default:
-               if (unlikely(cause == 0x23))
-                       return dcplb_protection_fault(cpu);
-
                return CPLB_UNKNOWN_ERR;
        }
 }
index 3302719173ca63ba39656ad5d8a5623c74994993..2ab56811841c6c6982e8cc00d1ca2724addc54d1 100644 (file)
@@ -202,11 +202,15 @@ asmlinkage void __init init_early_exception_vectors(void)
 asmlinkage void __init early_trap_c(struct pt_regs *fp, void *retaddr)
 {
        /* This can happen before the uart is initialized, so initialize
-        * the UART now
+        * the UART now (but only if we are running on the processor we think
+        * we are compiled for - otherwise we write to MMRs that don't exist,
+        * and cause other problems. Nothing comes out the UART, but it does
+        * end up in the __buf_log.
         */
-       if (likely(early_console == NULL))
+       if (likely(early_console == NULL) && CPUID == bfin_cpuid())
                setup_early_printk(DEFAULT_EARLY_PORT);
 
+       printk(KERN_EMERG "Early panic\n");
        dump_bfin_mem(fp);
        show_regs(fp);
        dump_bfin_trace_buffer();
diff --git a/arch/blackfin/kernel/ftrace-entry.S b/arch/blackfin/kernel/ftrace-entry.S
new file mode 100644 (file)
index 0000000..6980b7a
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * mcount and friends -- ftrace stuff
+ *
+ * Copyright (C) 2009 Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/linkage.h>
+#include <asm/ftrace.h>
+
+.text
+
+/* GCC will have called us before setting up the function prologue, so we
+ * can clobber the normal scratch registers, but we need to make sure to
+ * save/restore the registers used for argument passing (R0-R2) in case
+ * the profiled function is using them.  With data registers, R3 is the
+ * only one we can blow away.  With pointer registers, we have P0-P2.
+ *
+ * Upon entry, the RETS will point to the top of the current profiled
+ * function.  And since GCC setup the frame for us, the previous function
+ * will be waiting there.  mmmm pie.
+ */
+ENTRY(__mcount)
+       /* save third function arg early so we can do testing below */
+       [--sp] = r2;
+
+       /* load the function pointer to the tracer */
+       p0.l = _ftrace_trace_function;
+       p0.h = _ftrace_trace_function;
+       r3 = [p0];
+
+       /* optional micro optimization: don't call the stub tracer */
+       r2.l = _ftrace_stub;
+       r2.h = _ftrace_stub;
+       cc = r2 == r3;
+       if ! cc jump .Ldo_trace;
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       /* if the ftrace_graph_return function pointer is not set to
+        * the ftrace_stub entry, call prepare_ftrace_return().
+        */
+       p0.l = _ftrace_graph_return;
+       p0.h = _ftrace_graph_return;
+       r3 = [p0];
+       cc = r2 == r3;
+       if ! cc jump _ftrace_graph_caller;
+
+       /* similarly, if the ftrace_graph_entry function pointer is not
+        * set to the ftrace_graph_entry_stub entry, ...
+        */
+       p0.l = _ftrace_graph_entry;
+       p0.h = _ftrace_graph_entry;
+       r2.l = _ftrace_graph_entry_stub;
+       r2.h = _ftrace_graph_entry_stub;
+       r3 = [p0];
+       cc = r2 == r3;
+       if ! cc jump _ftrace_graph_caller;
+#endif
+
+       r2 = [sp++];
+       rts;
+
+.Ldo_trace:
+
+       /* save first/second function arg and the return register */
+       [--sp] = r0;
+       [--sp] = r1;
+       [--sp] = rets;
+
+       /* setup the tracer function */
+       p0 = r3;
+
+       /* tracer(ulong frompc, ulong selfpc):
+        *  frompc: the pc that did the call to ...
+        *  selfpc: ... this location
+        * the selfpc itself will need adjusting for the mcount call
+        */
+       r1 = rets;
+       r0 = [fp + 4];
+       r1 += -MCOUNT_INSN_SIZE;
+
+       /* call the tracer */
+       call (p0);
+
+       /* restore state and get out of dodge */
+.Lfinish_trace:
+       rets = [sp++];
+       r1 = [sp++];
+       r0 = [sp++];
+       r2 = [sp++];
+
+.globl _ftrace_stub
+_ftrace_stub:
+       rts;
+ENDPROC(__mcount)
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+/* The prepare_ftrace_return() function is similar to the trace function
+ * except it takes a pointer to the location of the frompc.  This is so
+ * the prepare_ftrace_return() can hijack it temporarily for probing
+ * purposes.
+ */
+ENTRY(_ftrace_graph_caller)
+       /* save first/second function arg and the return register */
+       [--sp] = r0;
+       [--sp] = r1;
+       [--sp] = rets;
+
+       r0 = fp;
+       r1 = rets;
+       r0 += 4;
+       r1 += -MCOUNT_INSN_SIZE;
+       call _prepare_ftrace_return;
+
+       jump .Lfinish_trace;
+ENDPROC(_ftrace_graph_caller)
+
+/* Undo the rewrite caused by ftrace_graph_caller().  The common function
+ * ftrace_return_to_handler() will return the original rets so we can
+ * restore it and be on our way.
+ */
+ENTRY(_return_to_handler)
+       /* make sure original return values are saved */
+       [--sp] = p0;
+       [--sp] = r0;
+       [--sp] = r1;
+
+       /* get original return address */
+       call _ftrace_return_to_handler;
+       rets = r0;
+
+       /* anomaly 05000371 - make sure we have at least three instructions
+        * between rets setting and the return
+        */
+       r1 = [sp++];
+       r0 = [sp++];
+       p0 = [sp++];
+       rts;
+ENDPROC(_return_to_handler)
+#endif
diff --git a/arch/blackfin/kernel/ftrace.c b/arch/blackfin/kernel/ftrace.c
new file mode 100644 (file)
index 0000000..905bfc4
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * ftrace graph code
+ *
+ * Copyright (C) 2009 Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/ftrace.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <asm/atomic.h>
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+
+/*
+ * Hook the return address and push it in the stack of return addrs
+ * in current thread info.
+ */
+void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
+{
+       struct ftrace_graph_ent trace;
+       unsigned long return_hooker = (unsigned long)&return_to_handler;
+
+       if (unlikely(atomic_read(&current->tracing_graph_pause)))
+               return;
+
+       if (ftrace_push_return_trace(*parent, self_addr, &trace.depth) == -EBUSY)
+               return;
+
+       trace.func = self_addr;
+
+       /* Only trace if the calling function expects to */
+       if (!ftrace_graph_entry(&trace)) {
+               current->curr_ret_stack--;
+               return;
+       }
+
+       /* all is well in the world !  hijack RETS ... */
+       *parent = return_hooker;
+}
+
+#endif
index 2c228c020978eee16b8edecc047d12689fb1c016..c26c34de9f3cb096580d3d48ef9de3a728d9f975 100644 (file)
 
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-
-struct mm_struct init_mm = INIT_MM(init_mm);
-EXPORT_SYMBOL(init_mm);
-
 /*
  * Initial task structure.
  *
index 5fc424803a1788409a3b51d479c242d9ee16b6ae..d8cde1fc5cb937f9540485b70754e5b8a871fee3 100644 (file)
@@ -99,7 +99,7 @@ void __ipipe_handle_irq(unsigned irq, struct pt_regs *regs)
         * interrupt.
         */
        m_ack = (regs == NULL || irq == IRQ_SYSTMR || irq == IRQ_CORETMR);
-       this_domain = ipipe_current_domain;
+       this_domain = __ipipe_current_domain;
 
        if (unlikely(test_bit(IPIPE_STICKY_FLAG, &this_domain->irqs[irq].control)))
                head = &this_domain->p_link;
@@ -212,7 +212,9 @@ void __ipipe_unstall_root_raw(void)
 
 int __ipipe_syscall_root(struct pt_regs *regs)
 {
+       struct ipipe_percpu_domain_data *p;
        unsigned long flags;
+       int ret;
 
        /*
         * We need to run the IRQ tail hook whenever we don't
@@ -231,29 +233,31 @@ int __ipipe_syscall_root(struct pt_regs *regs)
        /*
         * This routine either returns:
         * 0 -- if the syscall is to be passed to Linux;
-        * 1 -- if the syscall should not be passed to Linux, and no
+        * >0 -- if the syscall should not be passed to Linux, and no
         * tail work should be performed;
-        * -1 -- if the syscall should not be passed to Linux but the
+        * <0 -- if the syscall should not be passed to Linux but the
         * tail work has to be performed (for handling signals etc).
         */
 
-       if (__ipipe_event_monitored_p(IPIPE_EVENT_SYSCALL) &&
-           __ipipe_dispatch_event(IPIPE_EVENT_SYSCALL, regs) > 0) {
-               if (ipipe_root_domain_p && !in_atomic()) {
-                       /*
-                        * Sync pending VIRQs before _TIF_NEED_RESCHED
-                        * is tested.
-                        */
-                       local_irq_save_hw(flags);
-                       if ((ipipe_root_cpudom_var(irqpend_himask) & IPIPE_IRQMASK_VIRT) != 0)
-                               __ipipe_sync_pipeline(IPIPE_IRQMASK_VIRT);
-                       local_irq_restore_hw(flags);
-                       return -1;
-               }
+       if (!__ipipe_event_monitored_p(IPIPE_EVENT_SYSCALL))
+               return 0;
+
+       ret = __ipipe_dispatch_event(IPIPE_EVENT_SYSCALL, regs);
+
+       local_irq_save_hw(flags);
+
+       if (!__ipipe_root_domain_p) {
+               local_irq_restore_hw(flags);
                return 1;
        }
 
-       return 0;
+       p = ipipe_root_cpudom_ptr();
+       if ((p->irqpend_himask & IPIPE_IRQMASK_VIRT) != 0)
+               __ipipe_sync_pipeline(IPIPE_IRQMASK_VIRT);
+
+       local_irq_restore_hw(flags);
+
+       return -ret;
 }
 
 unsigned long ipipe_critical_enter(void (*syncfn) (void))
@@ -329,9 +333,7 @@ asmlinkage void __ipipe_sync_root(void)
 
 void ___ipipe_sync_pipeline(unsigned long syncmask)
 {
-       struct ipipe_domain *ipd = ipipe_current_domain;
-
-       if (ipd == ipipe_root_domain) {
+       if (__ipipe_root_domain_p) {
                if (test_bit(IPIPE_SYNCDEFER_FLAG, &ipipe_root_cpudom_var(status)))
                        return;
        }
index 80447f99c2b5f43cb0af2662e8e3717e214ab3e3..6454babdfaff571f7a04cab973f1d377b6041460 100644 (file)
@@ -1098,7 +1098,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
                        CPUID, bfin_cpuid());
 
        seq_printf(m, "model name\t: ADSP-%s %lu(MHz CCLK) %lu(MHz SCLK) (%s)\n"
-               "stepping\t: %d\n",
+               "stepping\t: %d ",
                cpu, cclk/1000000, sclk/1000000,
 #ifdef CONFIG_MPU
                "mpu on",
@@ -1107,7 +1107,16 @@ static int show_cpuinfo(struct seq_file *m, void *v)
 #endif
                revid);
 
-       seq_printf(m, "cpu MHz\t\t: %lu.%03lu/%lu.%03lu\n",
+       if (bfin_revid() != bfin_compiled_revid()) {
+               if (bfin_compiled_revid() == -1)
+                       seq_printf(m, "(Compiled for Rev none)");
+               else if (bfin_compiled_revid() == 0xffff)
+                       seq_printf(m, "(Compiled for Rev any)");
+               else
+                       seq_printf(m, "(Compiled for Rev %d)", bfin_compiled_revid());
+       }
+
+       seq_printf(m, "\ncpu MHz\t\t: %lu.%03lu/%lu.%03lu\n",
                cclk/1000000, cclk%1000000,
                sclk/1000000, sclk%1000000);
        seq_printf(m, "bogomips\t: %lu.%02lu\n"
@@ -1172,6 +1181,9 @@ static int show_cpuinfo(struct seq_file *m, void *v)
 #ifdef __ARCH_SYNC_CORE_DCACHE
        seq_printf(m, "SMP Dcache Flushes\t: %lu\n\n", cpudata->dcache_invld_count);
 #endif
+#ifdef __ARCH_SYNC_CORE_ICACHE
+       seq_printf(m, "SMP Icache Flushes\t: %lu\n\n", cpudata->icache_invld_count);
+#endif
 #ifdef CONFIG_BFIN_ICACHE_LOCK
        switch ((cpudata->imemctl >> 3) & WAYALL_L) {
        case WAY0_L:
diff --git a/arch/blackfin/kernel/stacktrace.c b/arch/blackfin/kernel/stacktrace.c
new file mode 100644 (file)
index 0000000..30301e1
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Blackfin stacktrace code (mostly copied from avr32)
+ *
+ * Copyright 2009 Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/sched.h>
+#include <linux/stacktrace.h>
+#include <linux/thread_info.h>
+#include <linux/module.h>
+
+register unsigned long current_frame_pointer asm("FP");
+
+struct stackframe {
+       unsigned long fp;
+       unsigned long rets;
+};
+
+/*
+ * Save stack-backtrace addresses into a stack_trace buffer.
+ */
+void save_stack_trace(struct stack_trace *trace)
+{
+       unsigned long low, high;
+       unsigned long fp;
+       struct stackframe *frame;
+       int skip = trace->skip;
+
+       low = (unsigned long)task_stack_page(current);
+       high = low + THREAD_SIZE;
+       fp = current_frame_pointer;
+
+       while (fp >= low && fp <= (high - sizeof(*frame))) {
+               frame = (struct stackframe *)fp;
+
+               if (skip) {
+                       skip--;
+               } else {
+                       trace->entries[trace->nr_entries++] = frame->rets;
+                       if (trace->nr_entries >= trace->max_entries)
+                               break;
+               }
+
+               /*
+                * The next frame must be at a higher address than the
+                * current frame.
+                */
+               low = fp + sizeof(*frame);
+               fp = frame->fp;
+       }
+}
+EXPORT_SYMBOL_GPL(save_stack_trace);
index aa76dfb0226ecd6dcf03136c463eb2969ac78f4b..d279552fe9b01633738880454872ce4e581dc03f 100644 (file)
@@ -27,6 +27,7 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+#include <linux/bug.h>
 #include <linux/uaccess.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
@@ -238,6 +239,11 @@ asmlinkage void double_fault_c(struct pt_regs *fp)
 
 }
 
+static int kernel_mode_regs(struct pt_regs *regs)
+{
+       return regs->ipend & 0xffc0;
+}
+
 asmlinkage void trap_c(struct pt_regs *fp)
 {
 #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON
@@ -246,6 +252,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
 #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
        unsigned int cpu = smp_processor_id();
 #endif
+       const char *strerror = NULL;
        int sig = 0;
        siginfo_t info;
        unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE;
@@ -259,27 +266,10 @@ asmlinkage void trap_c(struct pt_regs *fp)
         * double faults if the stack has become corrupt
         */
 
-       /* If the fault was caused by a kernel thread, or interrupt handler
-        * we will kernel panic, so the system reboots.
-        * If KGDB is enabled, don't set this for kernel breakpoints
-       */
-
-       /* TODO: check to see if we are in some sort of deferred HWERR
-        * that we should be able to recover from, not kernel panic
-        */
-       if ((bfin_read_IPEND() & 0xFFC0) && (trapnr != VEC_STEP)
-#ifdef CONFIG_KGDB
-               && (trapnr != VEC_EXCPT02)
+#ifndef CONFIG_KGDB
+       /* IPEND is skipped if KGDB isn't enabled (see entry code) */
+       fp->ipend = bfin_read_IPEND();
 #endif
-       ){
-               console_verbose();
-               oops_in_progress = 1;
-       } else if (current) {
-               if (current->mm == NULL) {
-                       console_verbose();
-                       oops_in_progress = 1;
-               }
-       }
 
        /* trap_c() will be called for exceptions. During exceptions
         * processing, the pc value should be set with retx value.
@@ -307,15 +297,15 @@ asmlinkage void trap_c(struct pt_regs *fp)
                sig = SIGTRAP;
                CHK_DEBUGGER_TRAP_MAYBE();
                /* Check if this is a breakpoint in kernel space */
-               if (fp->ipend & 0xffc0)
-                       return;
+               if (kernel_mode_regs(fp))
+                       goto traps_done;
                else
                        break;
        /* 0x03 - User Defined, userspace stack overflow */
        case VEC_EXCPT03:
                info.si_code = SEGV_STACKFLOW;
                sig = SIGSEGV;
-               verbose_printk(KERN_NOTICE EXC_0x03(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x03(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x02 - KGDB initial connection and break signal trap */
@@ -324,7 +314,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
                info.si_code = TRAP_ILLTRAP;
                sig = SIGTRAP;
                CHK_DEBUGGER_TRAP();
-               return;
+               goto traps_done;
 #endif
        /* 0x04 - User Defined */
        /* 0x05 - User Defined */
@@ -344,7 +334,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
        case VEC_EXCPT04 ... VEC_EXCPT15:
                info.si_code = ILL_ILLPARAOP;
                sig = SIGILL;
-               verbose_printk(KERN_NOTICE EXC_0x04(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x04(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x10 HW Single step, handled here */
@@ -353,15 +343,15 @@ asmlinkage void trap_c(struct pt_regs *fp)
                sig = SIGTRAP;
                CHK_DEBUGGER_TRAP_MAYBE();
                /* Check if this is a single step in kernel space */
-               if (fp->ipend & 0xffc0)
-                       return;
+               if (kernel_mode_regs(fp))
+                       goto traps_done;
                else
                        break;
        /* 0x11 - Trace Buffer Full, handled here */
        case VEC_OVFLOW:
                info.si_code = TRAP_TRACEFLOW;
                sig = SIGTRAP;
-               verbose_printk(KERN_NOTICE EXC_0x11(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x11(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x12 - Reserved, Caught by default */
@@ -381,37 +371,54 @@ asmlinkage void trap_c(struct pt_regs *fp)
        /* 0x20 - Reserved, Caught by default */
        /* 0x21 - Undefined Instruction, handled here */
        case VEC_UNDEF_I:
+#ifdef CONFIG_BUG
+               if (kernel_mode_regs(fp)) {
+                       switch (report_bug(fp->pc, fp)) {
+                       case BUG_TRAP_TYPE_NONE:
+                               break;
+                       case BUG_TRAP_TYPE_WARN:
+                               dump_bfin_trace_buffer();
+                               fp->pc += 2;
+                               goto traps_done;
+                       case BUG_TRAP_TYPE_BUG:
+                               /* call to panic() will dump trace, and it is
+                                * off at this point, so it won't be clobbered
+                                */
+                               panic("BUG()");
+                       }
+               }
+#endif
                info.si_code = ILL_ILLOPC;
                sig = SIGILL;
-               verbose_printk(KERN_NOTICE EXC_0x21(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x21(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x22 - Illegal Instruction Combination, handled here */
        case VEC_ILGAL_I:
                info.si_code = ILL_ILLPARAOP;
                sig = SIGILL;
-               verbose_printk(KERN_NOTICE EXC_0x22(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x22(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x23 - Data CPLB protection violation, handled here */
        case VEC_CPLB_VL:
                info.si_code = ILL_CPLB_VI;
                sig = SIGBUS;
-               verbose_printk(KERN_NOTICE EXC_0x23(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x23(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x24 - Data access misaligned, handled here */
        case VEC_MISALI_D:
                info.si_code = BUS_ADRALN;
                sig = SIGBUS;
-               verbose_printk(KERN_NOTICE EXC_0x24(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x24(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x25 - Unrecoverable Event, handled here */
        case VEC_UNCOV:
                info.si_code = ILL_ILLEXCPT;
                sig = SIGILL;
-               verbose_printk(KERN_NOTICE EXC_0x25(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x25(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x26 - Data CPLB Miss, normal case is handled in _cplb_hdr,
@@ -419,7 +426,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
        case VEC_CPLB_M:
                info.si_code = BUS_ADRALN;
                sig = SIGBUS;
-               verbose_printk(KERN_NOTICE EXC_0x26(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x26(KERN_NOTICE);
                break;
        /* 0x27 - Data CPLB Multiple Hits - Linux Trap Zero, handled here */
        case VEC_CPLB_MHIT:
@@ -427,10 +434,10 @@ asmlinkage void trap_c(struct pt_regs *fp)
                sig = SIGSEGV;
 #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
                if (cpu_pda[cpu].dcplb_fault_addr < FIXED_CODE_START)
-                       verbose_printk(KERN_NOTICE "NULL pointer access\n");
+                       strerror = KERN_NOTICE "NULL pointer access\n";
                else
 #endif
-                       verbose_printk(KERN_NOTICE EXC_0x27(KERN_NOTICE));
+                       strerror = KERN_NOTICE EXC_0x27(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x28 - Emulation Watchpoint, handled here */
@@ -440,8 +447,8 @@ asmlinkage void trap_c(struct pt_regs *fp)
                pr_debug(EXC_0x28(KERN_DEBUG));
                CHK_DEBUGGER_TRAP_MAYBE();
                /* Check if this is a watchpoint in kernel space */
-               if (fp->ipend & 0xffc0)
-                       return;
+               if (kernel_mode_regs(fp))
+                       goto traps_done;
                else
                        break;
 #ifdef CONFIG_BF535
@@ -449,7 +456,7 @@ asmlinkage void trap_c(struct pt_regs *fp)
        case VEC_ISTRU_VL:      /* ADSP-BF535 only (MH) */
                info.si_code = BUS_OPFETCH;
                sig = SIGBUS;
-               verbose_printk(KERN_NOTICE "BF535: VEC_ISTRU_VL\n");
+               strerror = KERN_NOTICE "BF535: VEC_ISTRU_VL\n";
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
 #else
@@ -459,21 +466,21 @@ asmlinkage void trap_c(struct pt_regs *fp)
        case VEC_MISALI_I:
                info.si_code = BUS_ADRALN;
                sig = SIGBUS;
-               verbose_printk(KERN_NOTICE EXC_0x2A(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x2A(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x2B - Instruction CPLB protection violation, handled here */
        case VEC_CPLB_I_VL:
                info.si_code = ILL_CPLB_VI;
                sig = SIGBUS;
-               verbose_printk(KERN_NOTICE EXC_0x2B(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x2B(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x2C - Instruction CPLB miss, handled in _cplb_hdr */
        case VEC_CPLB_I_M:
                info.si_code = ILL_CPLB_MISS;
                sig = SIGBUS;
-               verbose_printk(KERN_NOTICE EXC_0x2C(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x2C(KERN_NOTICE);
                break;
        /* 0x2D - Instruction CPLB Multiple Hits, handled here */
        case VEC_CPLB_I_MHIT:
@@ -481,17 +488,17 @@ asmlinkage void trap_c(struct pt_regs *fp)
                sig = SIGSEGV;
 #ifdef CONFIG_DEBUG_HUNT_FOR_ZERO
                if (cpu_pda[cpu].icplb_fault_addr < FIXED_CODE_START)
-                       verbose_printk(KERN_NOTICE "Jump to NULL address\n");
+                       strerror = KERN_NOTICE "Jump to NULL address\n";
                else
 #endif
-                       verbose_printk(KERN_NOTICE EXC_0x2D(KERN_NOTICE));
+                       strerror = KERN_NOTICE EXC_0x2D(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x2E - Illegal use of Supervisor Resource, handled here */
        case VEC_ILL_RES:
                info.si_code = ILL_PRVOPC;
                sig = SIGILL;
-               verbose_printk(KERN_NOTICE EXC_0x2E(KERN_NOTICE));
+               strerror = KERN_NOTICE EXC_0x2E(KERN_NOTICE);
                CHK_DEBUGGER_TRAP_MAYBE();
                break;
        /* 0x2F - Reserved, Caught by default */
@@ -519,17 +526,17 @@ asmlinkage void trap_c(struct pt_regs *fp)
                case (SEQSTAT_HWERRCAUSE_SYSTEM_MMR):
                        info.si_code = BUS_ADRALN;
                        sig = SIGBUS;
-                       verbose_printk(KERN_NOTICE HWC_x2(KERN_NOTICE));
+                       strerror = KERN_NOTICE HWC_x2(KERN_NOTICE);
                        break;
                /* External Memory Addressing Error */
                case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR):
                        info.si_code = BUS_ADRERR;
                        sig = SIGBUS;
-                       verbose_printk(KERN_NOTICE HWC_x3(KERN_NOTICE));
+                       strerror = KERN_NOTICE HWC_x3(KERN_NOTICE);
                        break;
                /* Performance Monitor Overflow */
                case (SEQSTAT_HWERRCAUSE_PERF_FLOW):
-                       verbose_printk(KERN_NOTICE HWC_x12(KERN_NOTICE));
+                       strerror = KERN_NOTICE HWC_x12(KERN_NOTICE);
                        break;
                /* RAISE 5 instruction */
                case (SEQSTAT_HWERRCAUSE_RAISE_5):
@@ -546,7 +553,6 @@ asmlinkage void trap_c(struct pt_regs *fp)
         * if we get here we hit a reserved one, so panic
         */
        default:
-               oops_in_progress = 1;
                info.si_code = ILL_ILLPARAOP;
                sig = SIGILL;
                verbose_printk(KERN_EMERG "Caught Unhandled Exception, code = %08lx\n",
@@ -557,6 +563,16 @@ asmlinkage void trap_c(struct pt_regs *fp)
 
        BUG_ON(sig == 0);
 
+       /* If the fault was caused by a kernel thread, or interrupt handler
+        * we will kernel panic, so the system reboots.
+        */
+       if (kernel_mode_regs(fp) || (current && !current->mm)) {
+               console_verbose();
+               oops_in_progress = 1;
+               if (strerror)
+                       verbose_printk(strerror);
+       }
+
        if (sig != SIGTRAP) {
                dump_bfin_process(fp);
                dump_bfin_mem(fp);
@@ -606,8 +622,8 @@ asmlinkage void trap_c(struct pt_regs *fp)
        if (ANOMALY_05000461 && trapnr == VEC_HWERR && !access_ok(VERIFY_READ, fp->pc, 8))
                fp->pc = SAFE_USER_INSTRUCTION;
 
+ traps_done:
        trace_buffer_restore(j);
-       return;
 }
 
 /* Typical exception handling routines */
@@ -792,6 +808,18 @@ void dump_bfin_trace_buffer(void)
 }
 EXPORT_SYMBOL(dump_bfin_trace_buffer);
 
+#ifdef CONFIG_BUG
+int is_valid_bugaddr(unsigned long addr)
+{
+       unsigned short opcode;
+
+       if (!get_instruction(&opcode, (unsigned short *)addr))
+               return 0;
+
+       return opcode == BFIN_BUG_OPCODE;
+}
+#endif
+
 /*
  * Checks to see if the address pointed to is either a
  * 16-bit CALL instruction, or a 32-bit CALL instruction
index 8b67167cb4f4cdeac39c465c0be0a5ba4f52711e..6ac307ca0d805a7487d1990b59978bcf9f834ec1 100644 (file)
@@ -54,6 +54,7 @@ SECTIONS
                SCHED_TEXT
 #endif
                LOCK_TEXT
+               IRQENTRY_TEXT
                KPROBES_TEXT
                *(.text.*)
                *(.fixup)
@@ -166,6 +167,20 @@ SECTIONS
        }
        PERCPU(4)
        SECURITY_INIT
+
+       /* we have to discard exit text and such at runtime, not link time, to
+        * handle embedded cross-section references (alt instructions, bug
+        * table, eh_frame, etc...)
+        */
+       .exit.text :
+       {
+               EXIT_TEXT
+       }
+       .exit.data :
+       {
+               EXIT_DATA
+       }
+
        .init.ramfs :
        {
                . = ALIGN(4);
@@ -264,8 +279,6 @@ SECTIONS
 
        /DISCARD/ :
        {
-               EXIT_TEXT
-               EXIT_DATA
                *(.exitcall.exit)
        }
 }
index 762a7f02970ac0508ce99f3de9d1dd6d9432bc20..cd605e7d8518c43ce400cb3ab9be75e4b3c26244 100644 (file)
@@ -116,6 +116,7 @@ __sum16 ip_compute_csum(const void *buff, int len)
 {
        return (__force __sum16)~do_csum(buff, len);
 }
+EXPORT_SYMBOL(ip_compute_csum);
 
 /*
  * copy from fs while checksumming, otherwise like csum_partial
@@ -130,6 +131,7 @@ csum_partial_copy_from_user(const void __user *src, void *dst,
        memcpy(dst, (__force void *)src, len);
        return csum_partial(dst, len, sum);
 }
+EXPORT_SYMBOL(csum_partial_copy_from_user);
 
 /*
  * copy from ds while checksumming, otherwise like csum_partial
index 62bba09bcce689dfe908b5b702e76fb20877921f..1382f0382359a1dc44b743b900d285abedb537dd 100644 (file)
@@ -246,7 +246,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
                .modalias = "m25p80", /* Name of spi_driver for this device */
                .max_speed_hz = 25000000,     /* max spi clock (SCK) speed in HZ */
                .bus_num = 0, /* Framework bus number */
-               .chip_select = 1, /* Framework chip select. On STAMP537 it is SPISSEL1*/
+               .chip_select = 2, /* On BF518F-EZBRD it's SPI0_SSEL2 */
                .platform_data = &bfin_spi_flash_data,
                .controller_data = &spi_flash_chip_info,
                .mode = SPI_MODE_3,
@@ -369,6 +369,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI0,
                .end   = CH_SPI0,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI0,
+               .end   = IRQ_SPI0,
                .flags = IORESOURCE_IRQ,
        },
 };
@@ -399,6 +404,11 @@ static struct resource bfin_spi1_resource[] = {
        [1] = {
                .start = CH_SPI1,
                .end   = CH_SPI1,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI1,
+               .end   = IRQ_SPI1,
                .flags = IORESOURCE_IRQ,
        },
 };
index 6d6f9effa0bb8e36f38f99ba9f7a8cfdb6798b16..1eaf27ff722ebf878880c2278970c8a3d6a8002b 100644 (file)
@@ -664,6 +664,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
        },
 };
index 1435c5d38cd515127d5f6b16f60fc084f8c96287..9f9c0005dcf12a7fc3b19d155ff5e4db62ef4b15 100644 (file)
@@ -467,6 +467,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
        },
 };
index 147edd1eb1ad44f52850a8d9977a36dbbfd5aab0..3e5b7db6b0658d2a629c154bdc35f0905839578c 100644 (file)
@@ -723,6 +723,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
        },
 };
index 895f213ea454d11038c536a5c0e9645093e6ea51..38cf8ffd6d74ac68a14d723f739ecf78aa92b60d 100644 (file)
@@ -266,6 +266,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
        }
 };
index 0765872a8ada70a9114bfc98266ad7798e384ca9..9ecdc361fa6d56f299555fa28fb7b04298c81211 100644 (file)
@@ -162,6 +162,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
        }
 };
index a727e538fa2857e128baa6d9b61a73f0c06b8eb0..1443e92d8b6241e56138fc08a82e5c5b28eb6c24 100644 (file)
@@ -160,6 +160,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
        }
 };
index 842f1c9c239336e684bc2f7fd7ad0d733a27ffb7..89a5ec4ca048ad6b6716e5791bdd70783949c783 100644 (file)
@@ -196,6 +196,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
        }
 };
index e19c565ade160e4639c4f17bddf4c4e13c17c225..a68ade8a3ca2a876c721c030efa84dfa01087d0d 100644 (file)
@@ -299,6 +299,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
        }
 };
index 4fee196731279f5eb86a794be4894d6eefb114db..2a87d1cfcd06661f6d7307cd7d8e07362033a0fd 100644 (file)
@@ -182,8 +182,13 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
-       }
+       },
 };
 
 /* SPI controller data */
index 3c159819e5550ee178d93cf33a2a4efbbeacd6c2..399f81da7b933f5a189a3aef59e4f4ece80f7d5c 100644 (file)
@@ -184,6 +184,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
        },
 };
index 26707ce39f29b98666593b011deb89c8912e5ede..838240f151f5b79dc26e88152e9b7cc54fd9bde7 100644 (file)
@@ -398,8 +398,13 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
-       }
+       },
 };
 
 /* SPI controller data */
index dfb5036f8a6b2d8dacdb414227f010196b830e39..ff7228caa7da042b537f81242e6cf822a6436969 100644 (file)
@@ -1345,7 +1345,7 @@ static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
 #if defined(CONFIG_PMIC_ADP5520) || defined(CONFIG_PMIC_ADP5520_MODULE)
        {
                I2C_BOARD_INFO("pmic-adp5520", 0x32),
-               .irq = IRQ_PF7,
+               .irq = IRQ_PG0,
                .platform_data = (void *)&adp5520_pdev_data,
        },
 #endif
index 280574591201e54b98b61d65513d6d92d79098a3..e523e6e610d0b04f98b45aa4f049ea36f78053ac 100644 (file)
@@ -182,6 +182,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
        }
 };
index e37cb937888422128cd4f987ac36b517966d6b56..57695b4c3c0964c60413da1b7c55e889059282ae 100644 (file)
@@ -352,6 +352,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI0,
                .end   = CH_SPI0,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI0,
+               .end   = IRQ_SPI0,
                .flags = IORESOURCE_IRQ,
        }
 };
@@ -366,6 +371,11 @@ static struct resource bfin_spi1_resource[] = {
        [1] = {
                .start = CH_SPI1,
                .end   = CH_SPI1,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI1,
+               .end   = IRQ_SPI1,
                .flags = IORESOURCE_IRQ,
        }
 };
index f53ad682530b9849c0f20504cf6d4d66ccaa82ff..f5a3c30a41bd299d5c1899b4e18564309deab658 100644 (file)
@@ -612,6 +612,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI0,
                .end   = CH_SPI0,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI0,
+               .end   = IRQ_SPI0,
                .flags = IORESOURCE_IRQ,
        }
 };
@@ -626,6 +631,11 @@ static struct resource bfin_spi1_resource[] = {
        [1] = {
                .start = CH_SPI1,
                .end   = CH_SPI1,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI1,
+               .end   = IRQ_SPI1,
                .flags = IORESOURCE_IRQ,
        }
 };
index add5a17452cec8010bf3386de428a6d47ce3af1e..805a57b5e6501b6d850d85d58ea831c84b2ab413 100644 (file)
@@ -396,6 +396,8 @@ static struct platform_device bfin_sir3_device = {
 #endif
 
 #if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
+#include <linux/smsc911x.h>
+
 static struct resource smsc911x_resources[] = {
        {
                .name = "smsc911x-memory",
@@ -409,11 +411,22 @@ static struct resource smsc911x_resources[] = {
                .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
        },
 };
+
+static struct smsc911x_platform_config smsc911x_config = {
+       .flags = SMSC911X_USE_32BIT,
+       .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+       .irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+       .phy_interface = PHY_INTERFACE_MODE_MII,
+};
+
 static struct platform_device smsc911x_device = {
        .name = "smsc911x",
        .id = 0,
        .num_resources = ARRAY_SIZE(smsc911x_resources),
        .resource = smsc911x_resources,
+       .dev = {
+               .platform_data = &smsc911x_config,
+       },
 };
 #endif
 
@@ -741,6 +754,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI0,
                .end   = CH_SPI0,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI0,
+               .end   = IRQ_SPI0,
                .flags = IORESOURCE_IRQ,
        }
 };
@@ -755,6 +773,11 @@ static struct resource bfin_spi1_resource[] = {
        [1] = {
                .start = CH_SPI1,
                .end   = CH_SPI1,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI1,
+               .end   = IRQ_SPI1,
                .flags = IORESOURCE_IRQ,
        }
 };
index 0dd9685e5d53f967e9e76a3aea1a317f983c8911..0c9d72c5f5babdef3fab2e5cdb9e87eced038b04 100644 (file)
@@ -177,8 +177,13 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
-       }
+       },
 };
 
 /* SPI controller data */
index 0e2178a1aec501023cd3051f18d8cc75346aa133..b5ef7ff7b7bdca0284f41624509e893a5d254f40 100644 (file)
@@ -304,6 +304,11 @@ static struct resource bfin_spi0_resource[] = {
        [1] = {
                .start = CH_SPI,
                .end   = CH_SPI,
+               .flags = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start = IRQ_SPI,
+               .end   = IRQ_SPI,
                .flags = IORESOURCE_IRQ,
        }
 };
index e6ab1f815123b62e6269f335294ea76378fd530c..b59ce3cb380718a5030e9ce99e154ad5e9bd54db 100644 (file)
 void blackfin_invalidate_entire_dcache(void)
 {
        u32 dmem = bfin_read_DMEM_CONTROL();
-       SSYNC();
        bfin_write_DMEM_CONTROL(dmem & ~0xc);
        SSYNC();
        bfin_write_DMEM_CONTROL(dmem);
        SSYNC();
 }
+
+/* Invalidate the Entire Instruction cache by
+ * clearing IMC bit
+ */
+void blackfin_invalidate_entire_icache(void)
+{
+       u32 imem = bfin_read_IMEM_CONTROL();
+       bfin_write_IMEM_CONTROL(imem & ~0x4);
+       SSYNC();
+       bfin_write_IMEM_CONTROL(imem);
+       SSYNC();
+}
+
index da0558ad1b1a7495764d2b375de4de409e7df992..31fa313e81cf0c42c51ff8524f1e32a692bf17b2 100644 (file)
@@ -42,6 +42,7 @@
 #include <asm/thread_info.h>  /* TIF_NEED_RESCHED */
 #include <asm/asm-offsets.h>
 #include <asm/trace.h>
+#include <asm/traps.h>
 
 #include <asm/context.S>
 
@@ -84,13 +85,15 @@ ENTRY(_ex_workaround_261)
        if !cc jump _bfin_return_from_exception;
        /* fall through */
        R7 = P4;
-       R6 = 0x26;      /* Data CPLB Miss */
+       R6 = VEC_CPLB_M;        /* Data CPLB Miss */
        cc = R6 == R7;
        if cc jump _ex_dcplb_miss (BP);
-       R6 = 0x23;      /* Data CPLB Miss */
+#ifdef CONFIG_MPU
+       R6 = VEC_CPLB_VL;       /* Data CPLB Violation */
        cc = R6 == R7;
        if cc jump _ex_dcplb_viol (BP);
-       /* Handle 0x23 Data CPLB Protection Violation
+#endif
+       /* Handle Data CPLB Protection Violation
         * and Data CPLB Multiple Hits - Linux Trap Zero
         */
        jump _ex_trap_c;
@@ -270,7 +273,7 @@ ENTRY(_bfin_return_from_exception)
        r6.l = lo(SEQSTAT_EXCAUSE);
        r6.h = hi(SEQSTAT_EXCAUSE);
        r7 = r7 & r6;
-       r6 = 0x25;
+       r6 = VEC_UNCOV;
        CC = R7 == R6;
        if CC JUMP _double_fault;
 #endif
@@ -1605,6 +1608,7 @@ ENTRY(_sys_call_table)
        .long _sys_inotify_init1        /* 365 */
        .long _sys_preadv
        .long _sys_pwritev
+       .long _sys_rt_tgsigqueueinfo
 
        .rept NR_syscalls-(.-_sys_call_table)/4
        .long _sys_ni_syscall
index 3b8ebaee77f2d1dd38adbaa5a2a6f0eac036a5db..61840059dfac30feb314fcf373f4ef51dea943cd 100644 (file)
@@ -144,7 +144,7 @@ static void ipi_call_function(unsigned int cpu, struct ipi_message *msg)
 
 static irqreturn_t ipi_handler(int irq, void *dev_instance)
 {
-       struct ipi_message *msg, *mg;
+       struct ipi_message *msg;
        struct ipi_message_queue *msg_queue;
        unsigned int cpu = smp_processor_id();
 
@@ -154,7 +154,8 @@ static irqreturn_t ipi_handler(int irq, void *dev_instance)
        msg_queue->count++;
 
        spin_lock(&msg_queue->lock);
-       list_for_each_entry_safe(msg, mg, &msg_queue->head, list) {
+       while (!list_empty(&msg_queue->head)) {
+               msg = list_entry(msg_queue->head.next, typeof(*msg), list);
                list_del(&msg->list);
                switch (msg->type) {
                case BFIN_IPI_RESCHEDULE:
@@ -221,7 +222,7 @@ int smp_call_function(void (*func)(void *info), void *info, int wait)
        for_each_cpu_mask(cpu, callmap) {
                msg_queue = &per_cpu(ipi_msg_queue, cpu);
                spin_lock_irqsave(&msg_queue->lock, flags);
-               list_add(&msg->list, &msg_queue->head);
+               list_add_tail(&msg->list, &msg_queue->head);
                spin_unlock_irqrestore(&msg_queue->lock, flags);
                platform_send_ipi_cpu(cpu);
        }
@@ -261,7 +262,7 @@ int smp_call_function_single(int cpuid, void (*func) (void *info), void *info,
 
        msg_queue = &per_cpu(ipi_msg_queue, cpu);
        spin_lock_irqsave(&msg_queue->lock, flags);
-       list_add(&msg->list, &msg_queue->head);
+       list_add_tail(&msg->list, &msg_queue->head);
        spin_unlock_irqrestore(&msg_queue->lock, flags);
        platform_send_ipi_cpu(cpu);
 
@@ -292,7 +293,7 @@ void smp_send_reschedule(int cpu)
 
        msg_queue = &per_cpu(ipi_msg_queue, cpu);
        spin_lock_irqsave(&msg_queue->lock, flags);
-       list_add(&msg->list, &msg_queue->head);
+       list_add_tail(&msg->list, &msg_queue->head);
        spin_unlock_irqrestore(&msg_queue->lock, flags);
        platform_send_ipi_cpu(cpu);
 
@@ -320,7 +321,7 @@ void smp_send_stop(void)
        for_each_cpu_mask(cpu, callmap) {
                msg_queue = &per_cpu(ipi_msg_queue, cpu);
                spin_lock_irqsave(&msg_queue->lock, flags);
-               list_add(&msg->list, &msg_queue->head);
+               list_add_tail(&msg->list, &msg_queue->head);
                spin_unlock_irqrestore(&msg_queue->lock, flags);
                platform_send_ipi_cpu(cpu);
        }
@@ -468,6 +469,17 @@ void smp_icache_flush_range_others(unsigned long start, unsigned long end)
 }
 EXPORT_SYMBOL_GPL(smp_icache_flush_range_others);
 
+#ifdef __ARCH_SYNC_CORE_ICACHE
+void resync_core_icache(void)
+{
+       unsigned int cpu = get_cpu();
+       blackfin_invalidate_entire_icache();
+       ++per_cpu(cpu_data, cpu).icache_invld_count;
+       put_cpu();
+}
+EXPORT_SYMBOL(resync_core_icache);
+#endif
+
 #ifdef __ARCH_SYNC_CORE_DCACHE
 unsigned long barrier_mask __attribute__ ((__section__(".l2.bss")));
 
index 492988cb9077978be3a9589173e37381aaaed87a..d2d643c4ea592947cfdf440d3842345c0eff9b44 100644 (file)
@@ -5,21 +5,6 @@
  * is actually used on cris. 
  */
 
-enum km_type {
-       KM_BOUNCE_READ,
-       KM_SKB_SUNRPC_DATA,
-       KM_SKB_DATA_SOFTIRQ,
-       KM_USER0,
-       KM_USER1,
-       KM_BIO_SRC_IRQ,
-       KM_BIO_DST_IRQ,
-       KM_PTE0,
-       KM_PTE1,
-       KM_IRQ0,
-       KM_IRQ1,
-       KM_SOFTIRQ0,
-       KM_SOFTIRQ1,
-       KM_TYPE_NR
-};
+#include <asm-generic/kmap_types.h>
 
 #endif
index 4df0b320d524e351847e9f2b270237731b2b1607..51dcd04d2777f01b87a86108d500efb800be1d2d 100644 (file)
 
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-struct mm_struct init_mm = INIT_MM(init_mm);
-
-EXPORT_SYMBOL(init_mm);
-
 /*
  * Initial thread structure.
  *
index 29429a8b7f6a44b0a6e52629c9b134d0f72317e3..1d3df1d9495c3379180ad6b9cf683cc9b5f24b25 100644 (file)
 
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-struct mm_struct init_mm = INIT_MM(init_mm);
-
-EXPORT_SYMBOL(init_mm);
-
 /*
  * Initial thread structure.
  *
index 1ec8a3427120876f6ef7d998b72798a37c0cc53a..be12a7160116ae7cfd40d9cb90e948e158b7a5a5 100644 (file)
@@ -1,21 +1,6 @@
 #ifndef _ASM_H8300_KMAP_TYPES_H
 #define _ASM_H8300_KMAP_TYPES_H
 
-enum km_type {
-       KM_BOUNCE_READ,
-       KM_SKB_SUNRPC_DATA,
-       KM_SKB_DATA_SOFTIRQ,
-       KM_USER0,
-       KM_USER1,
-       KM_BIO_SRC_IRQ,
-       KM_BIO_DST_IRQ,
-       KM_PTE0,
-       KM_PTE1,
-       KM_IRQ0,
-       KM_IRQ1,
-       KM_SOFTIRQ0,
-       KM_SOFTIRQ1,
-       KM_TYPE_NR
-};
+#include <asm-generic/kmap_types.h>
 
 #endif
index cb5dc552da97899e4f443b40efd5fae50de4f3f1..089c65ed6eb327c5e8ffa39e5a69a5c6e5d86921 100644 (file)
 
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-struct mm_struct init_mm = INIT_MM(init_mm);
-
-EXPORT_SYMBOL(init_mm);
-
 /*
  * Initial task structure.
  *
index 56ceb68eb99d244fffc70feab344e337ec385f7d..fe63b2dc9d075c8ceabc4e28bc7e246bff31f30a 100644 (file)
@@ -1131,7 +1131,7 @@ sba_alloc_coherent (struct device *dev, size_t size, dma_addr_t *dma_handle, gfp
 #ifdef CONFIG_NUMA
        {
                struct page *page;
-               page = alloc_pages_node(ioc->node == MAX_NUMNODES ?
+               page = alloc_pages_exact_node(ioc->node == MAX_NUMNODES ?
                                        numa_node_id() : ioc->node, flags,
                                        get_order(size));
 
index 5d1658aa2b3bf2a4770ce77c02519439a0c73857..05d5f9996105223e0e61908c6622ab99fdf02e7d 100644 (file)
@@ -1,30 +1,12 @@
 #ifndef _ASM_IA64_KMAP_TYPES_H
 #define _ASM_IA64_KMAP_TYPES_H
 
-
 #ifdef CONFIG_DEBUG_HIGHMEM
-# define D(n) __KM_FENCE_##n ,
-#else
-# define D(n)
+#define  __WITH_KM_FENCE
 #endif
 
-enum km_type {
-D(0)   KM_BOUNCE_READ,
-D(1)   KM_SKB_SUNRPC_DATA,
-D(2)   KM_SKB_DATA_SOFTIRQ,
-D(3)   KM_USER0,
-D(4)   KM_USER1,
-D(5)   KM_BIO_SRC_IRQ,
-D(6)   KM_BIO_DST_IRQ,
-D(7)   KM_PTE0,
-D(8)   KM_PTE1,
-D(9)   KM_IRQ0,
-D(10)  KM_IRQ1,
-D(11)  KM_SOFTIRQ0,
-D(12)  KM_SOFTIRQ1,
-D(13)  KM_TYPE_NR
-};
+#include <asm-generic/kmap_types.h>
 
-#undef D
+#undef __WITH_KM_FENCE
 
 #endif /* _ASM_IA64_KMAP_TYPES_H */
index 5b0e830c6f33212d48b28ec74f24113f6c1bc5ef..c475fc281be755accd969935eb8bd278069a1ffe 100644 (file)
 
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-struct mm_struct init_mm = INIT_MM(init_mm);
-
-EXPORT_SYMBOL(init_mm);
-
 /*
  * Initial task structure.
  *
index 8f33a8840422ce96bc1a6df85f4876e0f5180b1d..5b17bd4022754ddcf1fcc8f5d37e4adcfbd6cdd6 100644 (file)
@@ -1829,8 +1829,7 @@ ia64_mca_cpu_init(void *cpu_data)
                        data = mca_bootmem();
                        first_time = 0;
                } else
-                       data = page_address(alloc_pages_node(numa_node_id(),
-                                       GFP_KERNEL, get_order(sz)));
+                       data = __get_free_pages(GFP_KERNEL, get_order(sz));
                if (!data)
                        panic("Could not allocate MCA memory for cpu %d\n",
                                        cpu);
index 8a06dc480594c0d3e93636eccad9ea9316944127..bdc176cb5e85bc471649d47259951274db3c29e9 100644 (file)
@@ -5595,7 +5595,7 @@ pfm_interrupt_handler(int irq, void *arg)
                (*pfm_alt_intr_handler->handler)(irq, arg, regs);
        }
 
-       put_cpu_no_resched();
+       put_cpu();
        return IRQ_HANDLED;
 }
 
index 8eff8c1d40a628404db5f8b0d70b82b3fd693eb8..6ba72ab42fcc513bac46bcb18eab8f7ed8ab198f 100644 (file)
@@ -98,7 +98,8 @@ static int uncached_add_chunk(struct uncached_pool *uc_pool, int nid)
 
        /* attempt to allocate a granule's worth of cached memory pages */
 
-       page = alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
+       page = alloc_pages_exact_node(nid,
+                               GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
                                IA64_GRANULE_SHIFT-PAGE_SHIFT);
        if (!page) {
                mutex_unlock(&uc_pool->add_chunk_mutex);
index d876423e4e755465d8249f4aeb01610490f62cff..98b684928e12eae87c840344f1e256c1d118702c 100644 (file)
@@ -90,7 +90,8 @@ static void *sn_dma_alloc_coherent(struct device *dev, size_t size,
         */
        node = pcibus_to_node(pdev->bus);
        if (likely(node >=0)) {
-               struct page *p = alloc_pages_node(node, flags, get_order(size));
+               struct page *p = alloc_pages_exact_node(node,
+                                               flags, get_order(size));
 
                if (likely(p))
                        cpuaddr = page_address(p);
index fa94dc6410ea1129083a401f01558e5028e05c23..4cdb5e3a06bfa6714bd724878f8e5c252d4be16e 100644 (file)
@@ -2,28 +2,11 @@
 #define __M32R_KMAP_TYPES_H
 
 #ifdef CONFIG_DEBUG_HIGHMEM
-# define D(n) __KM_FENCE_##n ,
-#else
-# define D(n)
+#define  __WITH_KM_FENCE
 #endif
 
-enum km_type {
-D(0)   KM_BOUNCE_READ,
-D(1)   KM_SKB_SUNRPC_DATA,
-D(2)   KM_SKB_DATA_SOFTIRQ,
-D(3)   KM_USER0,
-D(4)   KM_USER1,
-D(5)   KM_BIO_SRC_IRQ,
-D(6)   KM_BIO_DST_IRQ,
-D(7)   KM_PTE0,
-D(8)   KM_PTE1,
-D(9)   KM_IRQ0,
-D(10)  KM_IRQ1,
-D(11)  KM_SOFTIRQ0,
-D(12)  KM_SOFTIRQ1,
-D(13)  KM_TYPE_NR
-};
+#include <asm-generic/kmap_types.h>
 
-#undef D
+#undef __WITH_KM_FENCE
 
 #endif /* __M32R_KMAP_TYPES_H */
index 016885c6f26094b3191fc8f790410d7a99b5c143..fce57e5d3f913950b96c5185209bc3e9b066f986 100644 (file)
 
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-struct mm_struct init_mm = INIT_MM(init_mm);
-
-EXPORT_SYMBOL(init_mm);
-
 /*
  * Initial thread structure.
  *
index 7daf897292cf65c2ec12832265f26035cda399af..b7a78ad429b78f270913e620ea875083467141d0 100644 (file)
@@ -154,9 +154,9 @@ unsigned long __init zone_sizes_init(void)
         *  Use all area of internal RAM.
         *  see __alloc_pages()
         */
-       NODE_DATA(1)->node_zones->pages_min = 0;
-       NODE_DATA(1)->node_zones->pages_low = 0;
-       NODE_DATA(1)->node_zones->pages_high = 0;
+       NODE_DATA(1)->node_zones->watermark[WMARK_MIN] = 0;
+       NODE_DATA(1)->node_zones->watermark[WMARK_LOW] = 0;
+       NODE_DATA(1)->node_zones->watermark[WMARK_HIGH] = 0;
 
        return holes;
 }
index 98138b4e92208efa78dd3dcd5549f155c9b79a9b..922fdfdadeaa220830d52a99f97a1cbe22e7ebd1 100644 (file)
@@ -63,7 +63,7 @@ static void shutdown_m32104ut_irq(unsigned int irq)
        outl(M32R_ICUCR_ILEVEL7, port);
 }
 
-static struct hw_interrupt_type m32104ut_irq_type =
+static struct irq_chip m32104ut_irq_type =
 {
        .typename = "M32104UT-IRQ",
        .startup = startup_m32104ut_irq,
index 77b0ae9379e99c532a88c219bbef4c79e36f2cab..9c1bc7487c1e652ff6bd9cb77ea79c5cdb989caf 100644 (file)
@@ -69,7 +69,7 @@ static void shutdown_m32700ut_irq(unsigned int irq)
        outl(M32R_ICUCR_ILEVEL7, port);
 }
 
-static struct hw_interrupt_type m32700ut_irq_type =
+static struct irq_chip m32700ut_irq_type =
 {
        .typename = "M32700UT-IRQ",
        .startup = startup_m32700ut_irq,
@@ -146,7 +146,7 @@ static void shutdown_m32700ut_pld_irq(unsigned int irq)
        outw(PLD_ICUCR_ILEVEL7, port);
 }
 
-static struct hw_interrupt_type m32700ut_pld_irq_type =
+static struct irq_chip m32700ut_pld_irq_type =
 {
        .typename = "M32700UT-PLD-IRQ",
        .startup = startup_m32700ut_pld_irq,
@@ -215,7 +215,7 @@ static void shutdown_m32700ut_lanpld_irq(unsigned int irq)
        outw(PLD_ICUCR_ILEVEL7, port);
 }
 
-static struct hw_interrupt_type m32700ut_lanpld_irq_type =
+static struct irq_chip m32700ut_lanpld_irq_type =
 {
        .typename = "M32700UT-PLD-LAN-IRQ",
        .startup = startup_m32700ut_lanpld_irq,
@@ -284,7 +284,7 @@ static void shutdown_m32700ut_lcdpld_irq(unsigned int irq)
        outw(PLD_ICUCR_ILEVEL7, port);
 }
 
-static struct hw_interrupt_type m32700ut_lcdpld_irq_type =
+static struct irq_chip m32700ut_lcdpld_irq_type =
 {
        .typename = "M32700UT-PLD-LCD-IRQ",
        .startup = startup_m32700ut_lcdpld_irq,
index 3ec087ff2214d226f36c86b31c6de932a38d2244..fb4b17799b66fd090b04f4d02364044f5558123d 100644 (file)
@@ -63,7 +63,7 @@ static void shutdown_mappi_irq(unsigned int irq)
        outl(M32R_ICUCR_ILEVEL7, port);
 }
 
-static struct hw_interrupt_type mappi_irq_type =
+static struct irq_chip mappi_irq_type =
 {
        .typename = "MAPPI-IRQ",
        .startup = startup_mappi_irq,
index d87969c6356e3041ea1856916c7f496419a5558e..6a65eda0a056c67ef039a34cc5d0326251be14d5 100644 (file)
@@ -70,7 +70,7 @@ static void shutdown_mappi2_irq(unsigned int irq)
        outl(M32R_ICUCR_ILEVEL7, port);
 }
 
-static struct hw_interrupt_type mappi2_irq_type =
+static struct irq_chip mappi2_irq_type =
 {
        .typename = "MAPPI2-IRQ",
        .startup = startup_mappi2_irq,
index 785b4bd6d9fd4c3ddf414f3a7b5e1698329734b0..9c337aeac94b7db1a1d3d0f9307ef2116e15c687 100644 (file)
@@ -70,7 +70,7 @@ static void shutdown_mappi3_irq(unsigned int irq)
        outl(M32R_ICUCR_ILEVEL7, port);
 }
 
-static struct hw_interrupt_type mappi3_irq_type =
+static struct irq_chip mappi3_irq_type =
 {
        .typename = "MAPPI3-IRQ",
        .startup = startup_mappi3_irq,
index 6faa5db68e950132b9b62269dd131527e9bdb80e..ed865741c38df1c6d9702e94bb17f033fdcca5c2 100644 (file)
@@ -61,7 +61,7 @@ static void shutdown_oaks32r_irq(unsigned int irq)
        outl(M32R_ICUCR_ILEVEL7, port);
 }
 
-static struct hw_interrupt_type oaks32r_irq_type =
+static struct irq_chip oaks32r_irq_type =
 {
        .typename = "OAKS32R-IRQ",
        .startup = startup_oaks32r_irq,
index fab13fd85422a593817d9d2282548b0c05a03044..80d68065701963dff6107f6377bb7fc1c3416707 100644 (file)
@@ -70,7 +70,7 @@ static void shutdown_opsput_irq(unsigned int irq)
        outl(M32R_ICUCR_ILEVEL7, port);
 }
 
-static struct hw_interrupt_type opsput_irq_type =
+static struct irq_chip opsput_irq_type =
 {
        .typename = "OPSPUT-IRQ",
        .startup = startup_opsput_irq,
@@ -147,7 +147,7 @@ static void shutdown_opsput_pld_irq(unsigned int irq)
        outw(PLD_ICUCR_ILEVEL7, port);
 }
 
-static struct hw_interrupt_type opsput_pld_irq_type =
+static struct irq_chip opsput_pld_irq_type =
 {
        .typename = "OPSPUT-PLD-IRQ",
        .startup = startup_opsput_pld_irq,
@@ -216,7 +216,7 @@ static void shutdown_opsput_lanpld_irq(unsigned int irq)
        outw(PLD_ICUCR_ILEVEL7, port);
 }
 
-static struct hw_interrupt_type opsput_lanpld_irq_type =
+static struct irq_chip opsput_lanpld_irq_type =
 {
        .typename = "OPSPUT-PLD-LAN-IRQ",
        .startup = startup_opsput_lanpld_irq,
@@ -285,7 +285,7 @@ static void shutdown_opsput_lcdpld_irq(unsigned int irq)
        outw(PLD_ICUCR_ILEVEL7, port);
 }
 
-static struct hw_interrupt_type opsput_lcdpld_irq_type =
+static struct irq_chip opsput_lcdpld_irq_type =
 {
        "OPSPUT-PLD-LCD-IRQ",
        startup_opsput_lcdpld_irq,
index 89588d649eb7cc0f42c41bcafb91d51145438eff..757302660af84f2f09ffbb0e48fcf946ab27cd45 100644 (file)
@@ -61,7 +61,7 @@ static void shutdown_mappi_irq(unsigned int irq)
        outl(M32R_ICUCR_ILEVEL7, port);
 }
 
-static struct hw_interrupt_type mappi_irq_type =
+static struct irq_chip mappi_irq_type =
 {
        .typename = "M32700-IRQ",
        .startup = startup_mappi_irq,
@@ -134,7 +134,7 @@ static void shutdown_m32700ut_pld_irq(unsigned int irq)
        outw(PLD_ICUCR_ILEVEL7, port);
 }
 
-static struct hw_interrupt_type m32700ut_pld_irq_type =
+static struct irq_chip m32700ut_pld_irq_type =
 {
        .typename = "USRV-PLD-IRQ",
        .startup = startup_m32700ut_pld_irq,
index c843c63d380161411f70e046e16c66705b9a6fac..3413cc1390ecffbd3e43c4c0bdecbfa74f791326 100644 (file)
@@ -1,21 +1,6 @@
 #ifndef __ASM_M68K_KMAP_TYPES_H
 #define __ASM_M68K_KMAP_TYPES_H
 
-enum km_type {
-       KM_BOUNCE_READ,
-       KM_SKB_SUNRPC_DATA,
-       KM_SKB_DATA_SOFTIRQ,
-       KM_USER0,
-       KM_USER1,
-       KM_BIO_SRC_IRQ,
-       KM_BIO_DST_IRQ,
-       KM_PTE0,
-       KM_PTE1,
-       KM_IRQ0,
-       KM_IRQ1,
-       KM_SOFTIRQ0,
-       KM_SOFTIRQ1,
-       KM_TYPE_NR
-};
+#include <asm-generic/kmap_types.h>
 
 #endif /* __ASM_M68K_KMAP_TYPES_H */
index ec37fb56c127a095ed8f5060c8af8ff6672f90d0..72bad65dba3a1d3b4091f074c22207aa8f9a277b 100644 (file)
  */
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-struct mm_struct init_mm = INIT_MM(init_mm);
-
-EXPORT_SYMBOL(init_mm);
-
 union thread_union init_thread_union
 __attribute__((section(".data.init_task"), aligned(THREAD_SIZE)))
        = { INIT_THREAD_INFO(init_task) };
index fe282de1d596dcb4b93d4077ba8c5fe4c6f3aaee..45e97a207fedaf57a2cab44f97d7d0370cf95e2b 100644 (file)
 
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-struct mm_struct init_mm = INIT_MM(init_mm);
-
-EXPORT_SYMBOL(init_mm);
-
 /*
  * Initial task structure.
  *
index 4d7e222f5dd7252a78f99561ce5d505db619d2c8..25975252d83dbd0b5e92211a6957bcdbe961cfd8 100644 (file)
@@ -1,29 +1,6 @@
-/*
- * Copyright (C) 2006 Atmark Techno, Inc.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
 #ifndef _ASM_MICROBLAZE_KMAP_TYPES_H
 #define _ASM_MICROBLAZE_KMAP_TYPES_H
 
-enum km_type {
-       KM_BOUNCE_READ,
-       KM_SKB_SUNRPC_DATA,
-       KM_SKB_DATA_SOFTIRQ,
-       KM_USER0,
-       KM_USER1,
-       KM_BIO_SRC_IRQ,
-       KM_BIO_DST_IRQ,
-       KM_PTE0,
-       KM_PTE1,
-       KM_IRQ0,
-       KM_IRQ1,
-       KM_SOFTIRQ0,
-       KM_SOFTIRQ1,
-       KM_TYPE_NR,
-};
+#include <asm-generic/kmap_types.h>
 
 #endif /* _ASM_MICROBLAZE_KMAP_TYPES_H */
index 783da855a2e34df9f9aa071287b236aec843faf0..d6d35b2e5fe877b303e90f498b326542aeed6a40 100644 (file)
@@ -963,7 +963,7 @@ CONFIG_EEPROM_LEGACY=y
 CONFIG_SENSORS_PCF8574=y
 # CONFIG_PCF8575 is not set
 CONFIG_SENSORS_PCF8591=y
-CONFIG_SENSORS_MAX6875=y
+CONFIG_EEPROM_MAX6875=y
 # CONFIG_SENSORS_TSL2550 is not set
 CONFIG_I2C_DEBUG_CORE=y
 CONFIG_I2C_DEBUG_ALGO=y
index 8426d3b9501ca1aefb5cb31f37e6f22e3e553de0..fadb351d249bbfdc2fc0291ba44b27b4ab2c5afe 100644 (file)
@@ -1849,7 +1849,7 @@ CONFIG_EEPROM_LEGACY=m
 CONFIG_SENSORS_PCF8574=m
 CONFIG_SENSORS_PCA9539=m
 CONFIG_SENSORS_PCF8591=m
-CONFIG_SENSORS_MAX6875=m
+CONFIG_EEPROM_MAX6875=m
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
index 5dabc870b32295779a6d2a93bbed0d90ac6a1f90..032ca73f181bec27c0f7b741862ada66ec104342 100644 (file)
@@ -12,8 +12,6 @@
 #define PIT_CH0                        0x40
 #define PIT_CH2                        0x42
 
-#define PIT_TICK_RATE          1193182UL
-
 extern spinlock_t i8253_lock;
 
 extern void setup_pit_timer(void);
index 806aae3c533892b1e65917c4742943ff2692374b..58e91ed0388f7393150b6da2569428f9828b8488 100644 (file)
@@ -1,30 +1,12 @@
 #ifndef _ASM_KMAP_TYPES_H
 #define _ASM_KMAP_TYPES_H
 
-
 #ifdef CONFIG_DEBUG_HIGHMEM
-# define D(n) __KM_FENCE_##n ,
-#else
-# define D(n)
+#define  __WITH_KM_FENCE
 #endif
 
-enum km_type {
-D(0)   KM_BOUNCE_READ,
-D(1)   KM_SKB_SUNRPC_DATA,
-D(2)   KM_SKB_DATA_SOFTIRQ,
-D(3)   KM_USER0,
-D(4)   KM_USER1,
-D(5)   KM_BIO_SRC_IRQ,
-D(6)   KM_BIO_DST_IRQ,
-D(7)   KM_PTE0,
-D(8)   KM_PTE1,
-D(9)   KM_IRQ0,
-D(10)  KM_IRQ1,
-D(11)  KM_SOFTIRQ0,
-D(12)  KM_SOFTIRQ1,
-D(13)  KM_TYPE_NR
-};
+#include <asm-generic/kmap_types.h>
 
-#undef D
+#undef __WITH_KM_FENCE
 
 #endif
index 149cd914526e8e2e2d1c407852879cf2111fa822..5b457a40c784f84997c9bc24c17de910ecbe61b3 100644 (file)
 
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-struct mm_struct init_mm = INIT_MM(init_mm);
-
-EXPORT_SYMBOL(init_mm);
-
 /*
  * Initial thread structure.
  *
index 7396cd719900255c0379eda6b4d62dafe5fa8c6f..6827feb4de9671b7ef72201e55bff0abdffa6329 100644 (file)
@@ -38,7 +38,7 @@ int __init sni_eisa_root_init(void)
        if (!r)
                return r;
 
-       eisa_root_dev.dev.driver_data = &eisa_bus_root;
+       dev_set_drvdata(&eisa_root_dev.dev, &eisa_bus_root);
 
        if (eisa_root_register(&eisa_bus_root)) {
                /* A real bridge may have been registered before
index 3398f9f356030767fde04242fdb1229809176ffd..76d093b58d4fe8248852737b2df0422379680036 100644 (file)
@@ -1,31 +1,6 @@
-/* MN10300 kmap_atomic() slot IDs
- *
- * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
 #ifndef _ASM_KMAP_TYPES_H
 #define _ASM_KMAP_TYPES_H
 
-enum km_type {
-       KM_BOUNCE_READ,
-       KM_SKB_SUNRPC_DATA,
-       KM_SKB_DATA_SOFTIRQ,
-       KM_USER0,
-       KM_USER1,
-       KM_BIO_SRC_IRQ,
-       KM_BIO_DST_IRQ,
-       KM_PTE0,
-       KM_PTE1,
-       KM_IRQ0,
-       KM_IRQ1,
-       KM_SOFTIRQ0,
-       KM_SOFTIRQ1,
-       KM_TYPE_NR
-};
+#include <asm-generic/kmap_types.h>
 
 #endif /* _ASM_KMAP_TYPES_H */
index 5ac3566f8c98b62c5a96673665b09f12d5a48696..80d423b80af30cfebbf7364829153c6f3314a3b1 100644 (file)
@@ -20,9 +20,6 @@
 
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-struct mm_struct init_mm = INIT_MM(init_mm);
-EXPORT_SYMBOL(init_mm);
-
 /*
  * Initial thread structure.
  *
index 806aae3c533892b1e65917c4742943ff2692374b..58e91ed0388f7393150b6da2569428f9828b8488 100644 (file)
@@ -1,30 +1,12 @@
 #ifndef _ASM_KMAP_TYPES_H
 #define _ASM_KMAP_TYPES_H
 
-
 #ifdef CONFIG_DEBUG_HIGHMEM
-# define D(n) __KM_FENCE_##n ,
-#else
-# define D(n)
+#define  __WITH_KM_FENCE
 #endif
 
-enum km_type {
-D(0)   KM_BOUNCE_READ,
-D(1)   KM_SKB_SUNRPC_DATA,
-D(2)   KM_SKB_DATA_SOFTIRQ,
-D(3)   KM_USER0,
-D(4)   KM_USER1,
-D(5)   KM_BIO_SRC_IRQ,
-D(6)   KM_BIO_DST_IRQ,
-D(7)   KM_PTE0,
-D(8)   KM_PTE1,
-D(9)   KM_IRQ0,
-D(10)  KM_IRQ1,
-D(11)  KM_SOFTIRQ0,
-D(12)  KM_SOFTIRQ1,
-D(13)  KM_TYPE_NR
-};
+#include <asm-generic/kmap_types.h>
 
-#undef D
+#undef __WITH_KM_FENCE
 
 #endif
index 1e25a45d64c17fd48d461489c3f2e950ed29ee53..82974b20fc106b85c0462cc83e78eb2c3201a1c4 100644 (file)
 
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-struct mm_struct init_mm = INIT_MM(init_mm);
-
-EXPORT_SYMBOL(init_mm);
-
 /*
  * Initial task structure.
  *
index 93a61898b25936f5d0abeef302745f7ca25b91c3..9fb344d5a86a737e459c998d8e83a653ccf19501 100644 (file)
@@ -93,10 +93,6 @@ config GENERIC_HWEIGHT
        bool
        default y
 
-config GENERIC_CALIBRATE_DELAY
-       bool
-       default y
-
 config GENERIC_FIND_NEXT_BIT
        bool
        default y
@@ -129,6 +125,7 @@ config PPC
        select USE_GENERIC_SMP_HELPERS if SMP
        select HAVE_OPROFILE
        select HAVE_SYSCALL_WRAPPERS if PPC64
+       select GENERIC_ATOMIC64 if PPC32
 
 config EARLY_PRINTK
        bool
index 51b2387bdba0e82dfd8b75de48b56a18cd4fd2ef..98312d169c859926932356cd7018a57ffed23e9f 100644 (file)
@@ -18,6 +18,9 @@
 #   $5 and more - kernel boot files; zImage*, uImage, cuImage.*, etc.
 #
 
+# Bail with error code if anything goes wrong
+set -e
+
 # User may have a custom install script
 
 if [ -x ~/bin/${CROSS_COMPILE}installkernel ]; then exec ~/bin/${CROSS_COMPILE}installkernel "$@"; fi
index 7d044dfd9236e55cdf1defd64760275285213e84..12dc7c40961632287270c473a37518236d1830b9 100644 (file)
@@ -1808,7 +1808,7 @@ CONFIG_PCF8575=m
 CONFIG_SENSORS_PCA9539=m
 CONFIG_SENSORS_PCF8591=m
 # CONFIG_TPS65010 is not set
-CONFIG_SENSORS_MAX6875=m
+CONFIG_EEPROM_MAX6875=m
 CONFIG_SENSORS_TSL2550=m
 CONFIG_MCU_MPC8349EMITX=m
 # CONFIG_I2C_DEBUG_CORE is not set
index b70d6e53b303519a7e22ae6eb43e28be6dbd2f4b..a71c9c1455a722fed428bb89d0c2b677b7a7087e 100644 (file)
@@ -1,10 +1,3 @@
-#ifndef _ASM_POWERPC_8253PIT_H
-#define _ASM_POWERPC_8253PIT_H
-
 /*
  * 8253/8254 Programmable Interval Timer
  */
-
-#define PIT_TICK_RATE  1193182UL
-
-#endif /* _ASM_POWERPC_8253PIT_H */
index b7d2d07b6f965f5a613c92b12ebaf23fd938c141..4012483b1899d32a84097bbbdb543c80f025f0d0 100644 (file)
@@ -470,6 +470,9 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
 
 #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
 
+#else  /* __powerpc64__ */
+#include <asm-generic/atomic64.h>
+
 #endif /* __powerpc64__ */
 
 #include <asm-generic/atomic-long.h>
index 53512374e1c9daea22bd71d6d153b69d1b0e0d42..b7f8f4a87cc04cc882f1179414dd34c3e189c58f 100644 (file)
@@ -80,7 +80,7 @@ static inline void local_irq_disable(void)
        __asm__ __volatile__("wrteei 0": : :"memory");
 #else
        unsigned long msr;
-       __asm__ __volatile__("": : :"memory");
+
        msr = mfmsr();
        SET_MSR_EE(msr & ~MSR_EE);
 #endif
@@ -92,7 +92,7 @@ static inline void local_irq_enable(void)
        __asm__ __volatile__("wrteei 1": : :"memory");
 #else
        unsigned long msr;
-       __asm__ __volatile__("": : :"memory");
+
        msr = mfmsr();
        SET_MSR_EE(msr | MSR_EE);
 #endif
@@ -108,7 +108,6 @@ static inline void local_irq_save_ptr(unsigned long *flags)
 #else
        SET_MSR_EE(msr & ~MSR_EE);
 #endif
-       __asm__ __volatile__("": : :"memory");
 }
 
 #define local_save_flags(flags)        ((flags) = mfmsr())
index 7464c0daddd1d02f5f8f66d1df9a26f92bbc7783..7ead7c16fb7cdb563ee41f0146b16471bf700d7a 100644 (file)
 #define IOMMU_PAGE_MASK       (~((1 << IOMMU_PAGE_SHIFT) - 1))
 #define IOMMU_PAGE_ALIGN(addr) _ALIGN_UP(addr, IOMMU_PAGE_SIZE)
 
+/* Cell page table entries */
+#define CBE_IOPTE_PP_W         0x8000000000000000ul /* protection: write */
+#define CBE_IOPTE_PP_R         0x4000000000000000ul /* protection: read */
+#define CBE_IOPTE_M            0x2000000000000000ul /* coherency required */
+#define CBE_IOPTE_SO_R         0x1000000000000000ul /* ordering: writes */
+#define CBE_IOPTE_SO_RW                0x1800000000000000ul /* ordering: r & w */
+#define CBE_IOPTE_RPN_Mask     0x07fffffffffff000ul /* RPN */
+#define CBE_IOPTE_H            0x0000000000000800ul /* cache hint */
+#define CBE_IOPTE_IOID_Mask    0x00000000000007fful /* ioid */
+
 /* Boot time flags */
 extern int iommu_is_off;
 extern int iommu_force_on;
index cdb6fd814de8880541d2c4130b33ea7e7b9f6234..7f065e178ec463cc7ab648883cfa57c2a0f33928 100644 (file)
@@ -53,6 +53,13 @@ enum ps3_param_av_multi_out ps3_os_area_get_av_multi_out(void);
 extern u64 ps3_os_area_get_rtc_diff(void);
 extern void ps3_os_area_set_rtc_diff(u64 rtc_diff);
 
+struct ps3_os_area_flash_ops {
+       ssize_t (*read)(void *buf, size_t count, loff_t pos);
+       ssize_t (*write)(const void *buf, size_t count, loff_t pos);
+};
+
+extern void ps3_os_area_flash_register(const struct ps3_os_area_flash_ops *ops);
+
 /* dma routines */
 
 enum ps3_dma_page_size {
@@ -418,15 +425,15 @@ static inline struct ps3_system_bus_driver *
  * @data: Data to set
  */
 
-static inline void ps3_system_bus_set_driver_data(
+static inline void ps3_system_bus_set_drvdata(
        struct ps3_system_bus_device *dev, void *data)
 {
-       dev->core.driver_data = data;
+       dev_set_drvdata(&dev->core, data);
 }
-static inline void *ps3_system_bus_get_driver_data(
+static inline void *ps3_system_bus_get_drvdata(
        struct ps3_system_bus_device *dev)
 {
-       return dev->core.driver_data;
+       return dev_get_drvdata(&dev->core);
 }
 
 /* These two need global scope for get_dma_ops(). */
@@ -520,7 +527,4 @@ void ps3_sync_irq(int node);
 u32 ps3_get_hw_thread_id(int cpu);
 u64 ps3_get_spe_id(void *arg);
 
-/* mutex synchronizing GPU accesses and video mode changes */
-extern struct mutex ps3_gpu_mutex;
-
 #endif
diff --git a/arch/powerpc/include/asm/ps3gpu.h b/arch/powerpc/include/asm/ps3gpu.h
new file mode 100644 (file)
index 0000000..b2b8959
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ *  PS3 GPU declarations.
+ *
+ *  Copyright 2009 Sony 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; 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _ASM_POWERPC_PS3GPU_H
+#define _ASM_POWERPC_PS3GPU_H
+
+#include <linux/mutex.h>
+
+#include <asm/lv1call.h>
+
+
+#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC   0x101
+#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP   0x102
+
+#define L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP       0x600
+#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT                0x601
+#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC   0x602
+#define L1GPU_CONTEXT_ATTRIBUTE_FB_CLOSE       0x603
+
+#define L1GPU_FB_BLIT_WAIT_FOR_COMPLETION      (1ULL << 32)
+
+#define L1GPU_DISPLAY_SYNC_HSYNC               1
+#define L1GPU_DISPLAY_SYNC_VSYNC               2
+
+
+/* mutex synchronizing GPU accesses and video mode changes */
+extern struct mutex ps3_gpu_mutex;
+
+
+static inline int lv1_gpu_display_sync(u64 context_handle, u64 head,
+                                      u64 ddr_offset)
+{
+       return lv1_gpu_context_attribute(context_handle,
+                                        L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
+                                        head, ddr_offset, 0, 0);
+}
+
+static inline int lv1_gpu_display_flip(u64 context_handle, u64 head,
+                                      u64 ddr_offset)
+{
+       return lv1_gpu_context_attribute(context_handle,
+                                        L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
+                                        head, ddr_offset, 0, 0);
+}
+
+static inline int lv1_gpu_fb_setup(u64 context_handle, u64 xdr_lpar,
+                                  u64 xdr_size, u64 ioif_offset)
+{
+       return lv1_gpu_context_attribute(context_handle,
+                                        L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP,
+                                        xdr_lpar, xdr_size, ioif_offset, 0);
+}
+
+static inline int lv1_gpu_fb_blit(u64 context_handle, u64 ddr_offset,
+                                 u64 ioif_offset, u64 sync_width, u64 pitch)
+{
+       return lv1_gpu_context_attribute(context_handle,
+                                        L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
+                                        ddr_offset, ioif_offset, sync_width,
+                                        pitch);
+}
+
+static inline int lv1_gpu_fb_close(u64 context_handle)
+{
+       return lv1_gpu_context_attribute(context_handle,
+                                        L1GPU_CONTEXT_ATTRIBUTE_FB_CLOSE, 0,
+                                        0, 0, 0);
+}
+
+#endif /* _ASM_POWERPC_PS3GPU_H */
index fb359b0a6937de645c8101709ac4ade7fd9df446..a3c28e46947c7e30f3690c8cb00ee985090b1082 100644 (file)
                        asm volatile("mfmsr %0" : "=r" (rval)); rval;})
 #ifdef CONFIG_PPC64
 #define __mtmsrd(v, l) asm volatile("mtmsrd %0," __stringify(l) \
-                                    : : "r" (v))
+                                    : : "r" (v) : "memory")
 #define mtmsrd(v)      __mtmsrd((v), 0)
 #define mtmsr(v)       mtmsrd(v)
 #else
-#define mtmsr(v)       asm volatile("mtmsr %0" : : "r" (v))
+#define mtmsr(v)       asm volatile("mtmsr %0" : : "r" (v) : "memory")
 #endif
 
 #define mfspr(rn)      ({unsigned long rval; \
index a0b92de51c7edfa594941f134de592c77eb49b3e..370600ca2765332ec542ff0c269aa3d5b614c9f0 100644 (file)
@@ -325,3 +325,4 @@ SYSCALL(inotify_init1)
 SYSCALL_SPU(perf_counter_open)
 COMPAT_SYS_SPU(preadv)
 COMPAT_SYS_SPU(pwritev)
+COMPAT_SYS(rt_tgsigqueueinfo)
index 4badac2d11d1a7f3c8989ffb5be20dd4cd131a57..cef080bfc607be937cd816bd9f3ac5cca443aaac 100644 (file)
 #define __NR_perf_counter_open 319
 #define __NR_preadv            320
 #define __NR_pwritev           321
+#define __NR_rt_tgsigqueueinfo 322
 
 #ifdef __KERNEL__
 
-#define __NR_syscalls          322
+#define __NR_syscalls          323
 
 #define __NR__exit __NR_exit
 #define NR_syscalls    __NR_syscalls
index a7def5f90cadbe2392b7ecfd6aa65f80570b1014..612b0c4dc26d90d818d299805a34c7b453eb09c3 100644 (file)
@@ -125,6 +125,7 @@ PHONY += systbl_chk
 systbl_chk: $(src)/systbl_chk.sh $(obj)/systbl_chk.i
        $(call cmd,systbl_chk)
 
+ifeq ($(CONFIG_PPC_OF_BOOT_TRAMPOLINE),y)
 $(obj)/built-in.o:             prom_init_check
 
 quiet_cmd_prom_init_check = CALL    $<
@@ -133,5 +134,6 @@ quiet_cmd_prom_init_check = CALL    $<
 PHONY += prom_init_check
 prom_init_check: $(src)/prom_init_check.sh $(obj)/prom_init.o
        $(call cmd,prom_init_check)
+endif
 
 clean-files := vmlinux.lds
index 688b329800bd25f559c75f2ea6f0dcdd22ade3b1..ffc4253fef55e99a59070b09f1b912e51bfb4de8 100644 (file)
@@ -9,10 +9,6 @@
 
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-struct mm_struct init_mm = INIT_MM(init_mm);
-
-EXPORT_SYMBOL(init_mm);
-
 /*
  * Initial thread structure.
  *
index 2f0e64b53642eb0c68191cd62929b906a2eba97c..ef6f64950e9b54080ca56a22845bb14ddbdaf1d4 100644 (file)
 #include <asm/sections.h>
 #include <asm/machdep.h>
 
-#ifdef CONFIG_LOGO_LINUX_CLUT224
 #include <linux/linux_logo.h>
-extern const struct linux_logo logo_linux_clut224;
-#endif
 
 /*
  * Properties whose value is longer than this get excluded from our
index f46548e6604550ac45309c07932efcb5db08a818..1f6816003ebef9bebcbb3319e83bac2243437d47 100644 (file)
@@ -424,8 +424,8 @@ void __init setup_system(void)
        printk("htab_hash_mask                = 0x%lx\n", htab_hash_mask);
 #endif /* CONFIG_PPC_STD_MMU_64 */
        if (PHYSICAL_START > 0)
-               printk("physical_start                = 0x%lx\n",
-                      PHYSICAL_START);
+               printk("physical_start                = 0x%llx\n",
+                      (unsigned long long)PHYSICAL_START);
        printk("-----------------------------------------------------\n");
 
        DBG(" <- setup_system()\n");
index bee1443da7634d3cf9a062d9223a11d4a63540de..15391c2ab013bc0691228b97076d126fa5dc1aa1 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/jiffies.h>
 #include <linux/posix-timers.h>
 #include <linux/irq.h>
+#include <linux/delay.h>
 
 #include <asm/io.h>
 #include <asm/processor.h>
@@ -1143,6 +1144,15 @@ void div128_by_32(u64 dividend_high, u64 dividend_low,
 
 }
 
+/* We don't need to calibrate delay, we use the CPU timebase for that */
+void calibrate_delay(void)
+{
+       /* Some generic code (such as spinlock debug) use loops_per_jiffy
+        * as the number of __delay(1) in a jiffy, so make it so
+        */
+       loops_per_jiffy = tb_ticks_per_jiffy;
+}
+
 static int __init rtc_init(void)
 {
        struct platform_device *pdev;
index 0ce45c2b42f8eb67a1ea5156fcf476bdb3f3924a..c71498dbf211780675293c205d258cd17350f987 100644 (file)
@@ -329,7 +329,7 @@ static struct irq_host_ops msic_host_ops = {
 
 static int axon_msi_shutdown(struct of_device *device)
 {
-       struct axon_msic *msic = device->dev.platform_data;
+       struct axon_msic *msic = dev_get_drvdata(&device->dev);
        u32 tmp;
 
        pr_debug("axon_msi: disabling %s\n",
@@ -416,7 +416,7 @@ static int axon_msi_probe(struct of_device *device,
        msic->read_offset = dcr_read(msic->dcr_host, MSIC_WRITE_OFFSET_REG)
                                & MSIC_FIFO_SIZE_MASK;
 
-       device->dev.platform_data = msic;
+       dev_set_drvdata(&device->dev, msic);
 
        ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs;
        ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs;
index bed4690de3944162eca2918e8df1164e1fd5b678..5b34fc211f35bb9b4f4ac5d3fdded3293f6c044c 100644 (file)
 #define IOSTE_PS_1M            0x0000000000000005ul /*   - 1MB  */
 #define IOSTE_PS_16M           0x0000000000000007ul /*   - 16MB */
 
-/* Page table entries */
-#define IOPTE_PP_W             0x8000000000000000ul /* protection: write */
-#define IOPTE_PP_R             0x4000000000000000ul /* protection: read */
-#define IOPTE_M                        0x2000000000000000ul /* coherency required */
-#define IOPTE_SO_R             0x1000000000000000ul /* ordering: writes */
-#define IOPTE_SO_RW             0x1800000000000000ul /* ordering: r & w */
-#define IOPTE_RPN_Mask         0x07fffffffffff000ul /* RPN */
-#define IOPTE_H                        0x0000000000000800ul /* cache hint */
-#define IOPTE_IOID_Mask                0x00000000000007fful /* ioid */
-
 
 /* IOMMU sizing */
 #define IO_SEGMENT_SHIFT       28
@@ -193,19 +183,21 @@ static int tce_build_cell(struct iommu_table *tbl, long index, long npages,
         */
        const unsigned long prot = 0xc48;
        base_pte =
-               ((prot << (52 + 4 * direction)) & (IOPTE_PP_W | IOPTE_PP_R))
-               | IOPTE_M | IOPTE_SO_RW | (window->ioid & IOPTE_IOID_Mask);
+               ((prot << (52 + 4 * direction)) &
+                (CBE_IOPTE_PP_W | CBE_IOPTE_PP_R)) |
+               CBE_IOPTE_M | CBE_IOPTE_SO_RW |
+               (window->ioid & CBE_IOPTE_IOID_Mask);
 #else
-       base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW |
-               (window->ioid & IOPTE_IOID_Mask);
+       base_pte = CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | CBE_IOPTE_M |
+               CBE_IOPTE_SO_RW | (window->ioid & CBE_IOPTE_IOID_Mask);
 #endif
        if (unlikely(dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs)))
-               base_pte &= ~IOPTE_SO_RW;
+               base_pte &= ~CBE_IOPTE_SO_RW;
 
        io_pte = (unsigned long *)tbl->it_base + (index - tbl->it_offset);
 
        for (i = 0; i < npages; i++, uaddr += IOMMU_PAGE_SIZE)
-               io_pte[i] = base_pte | (__pa(uaddr) & IOPTE_RPN_Mask);
+               io_pte[i] = base_pte | (__pa(uaddr) & CBE_IOPTE_RPN_Mask);
 
        mb();
 
@@ -231,8 +223,9 @@ static void tce_free_cell(struct iommu_table *tbl, long index, long npages)
 #else
        /* spider bridge does PCI reads after freeing - insert a mapping
         * to a scratch page instead of an invalid entry */
-       pte = IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW | __pa(window->iommu->pad_page)
-               | (window->ioid & IOPTE_IOID_Mask);
+       pte = CBE_IOPTE_PP_R | CBE_IOPTE_M | CBE_IOPTE_SO_RW |
+               __pa(window->iommu->pad_page) |
+               (window->ioid & CBE_IOPTE_IOID_Mask);
 #endif
 
        io_pte = (unsigned long *)tbl->it_base + (index - tbl->it_offset);
@@ -1001,7 +994,7 @@ static void insert_16M_pte(unsigned long addr, unsigned long *ptab,
        pr_debug("iommu: addr %lx ptab %p segment %lx offset %lx\n",
                  addr, ptab, segment, offset);
 
-       ptab[offset] = base_pte | (__pa(addr) & IOPTE_RPN_Mask);
+       ptab[offset] = base_pte | (__pa(addr) & CBE_IOPTE_RPN_Mask);
 }
 
 static void cell_iommu_setup_fixed_ptab(struct cbe_iommu *iommu,
@@ -1016,14 +1009,14 @@ static void cell_iommu_setup_fixed_ptab(struct cbe_iommu *iommu,
 
        pr_debug("iommu: mapping 0x%lx pages from 0x%lx\n", fsize, fbase);
 
-       base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M
-                   | (cell_iommu_get_ioid(np) & IOPTE_IOID_Mask);
+       base_pte = CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | CBE_IOPTE_M |
+               (cell_iommu_get_ioid(np) & CBE_IOPTE_IOID_Mask);
 
        if (iommu_fixed_is_weak)
                pr_info("IOMMU: Using weak ordering for fixed mapping\n");
        else {
                pr_info("IOMMU: Using strong ordering for fixed mapping\n");
-               base_pte |= IOPTE_SO_RW;
+               base_pte |= CBE_IOPTE_SO_RW;
        }
 
        for (uaddr = 0; uaddr < fsize; uaddr += (1 << 24)) {
index 296b5268754efc651f261a8f3688e54b5281ac26..5e0a191764fc0158b5eb7377af019615c3540767 100644 (file)
@@ -122,8 +122,8 @@ static int __init cbe_ptcal_enable_on_node(int nid, int order)
 
        area->nid = nid;
        area->order = order;
-       area->pages = alloc_pages_node(area->nid, GFP_KERNEL | GFP_THISNODE,
-                                       area->order);
+       area->pages = alloc_pages_exact_node(area->nid, GFP_KERNEL|GFP_THISNODE,
+                                               area->order);
 
        if (!area->pages) {
                printk(KERN_WARNING "%s: no page on node %d\n",
index 9abd210d87c1362f831b7a50bae27bb78d6c31f7..8547e86bfb42ff2650c50dea4bdb3533e647a1b6 100644 (file)
@@ -752,17 +752,8 @@ static int __init init_spu_base(void)
                goto out_unregister_sysdev_class;
        }
 
-       if (ret > 0) {
-               /*
-                * We cannot put the forward declaration in
-                * <linux/linux_logo.h> because of conflicting session type
-                * conflicts for const and __initdata with different compiler
-                * versions
-                */
-               extern const struct linux_logo logo_spe_clut224;
-
+       if (ret > 0)
                fb_append_extra_logo(&logo_spe_clut224, ret);
-       }
 
        mutex_lock(&spu_full_list_mutex);
        xmon_register_spus(&spu_full_list);
index 4543c4bc3a56e158cb47a3387d97c715dabc515e..c5a87a72057b42b700fe1a514795185e12b31f80 100644 (file)
@@ -204,7 +204,8 @@ static void __init dt_prop_u32(struct iseries_flat_dt *dt, const char *name,
        dt_prop(dt, name, &data, sizeof(u32));
 }
 
-static void __init dt_prop_u64(struct iseries_flat_dt *dt, const char *name,
+static void __init __maybe_unused dt_prop_u64(struct iseries_flat_dt *dt,
+                                             const char *name,
                u64 data)
 {
        dt_prop(dt, name, &data, sizeof(u64));
index 3689c2413d24d758faf9bd9bda5c41400d1b6b71..fef4d5150517474460aa5c97bea5efb5c32254f9 100644 (file)
@@ -267,7 +267,8 @@ static struct pending_event *new_pending_event(void)
        return ev;
 }
 
-static int signal_vsp_instruction(struct vsp_cmd_data *vsp_cmd)
+static int __maybe_unused
+signal_vsp_instruction(struct vsp_cmd_data *vsp_cmd)
 {
        struct pending_event *ev = new_pending_event();
        int rc;
index 9a2b6d948610c003485e38ded9e561f6514760fa..846eb8b57fd1dbb80fca175bb2813e97f0e7ef49 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/lmb.h>
 
 #include <asm/firmware.h>
+#include <asm/iommu.h>
 #include <asm/prom.h>
 #include <asm/udbg.h>
 #include <asm/lv1call.h>
@@ -605,9 +606,8 @@ static int dma_ioc0_map_pages(struct ps3_dma_region *r, unsigned long phys_addr,
                                       r->ioid,
                                       iopte_flag);
                if (result) {
-                       printk(KERN_WARNING "%s:%d: lv1_map_device_dma_region "
-                               "failed: %s\n", __func__, __LINE__,
-                               ps3_result(result));
+                       pr_warning("%s:%d: lv1_put_iopte failed: %s\n",
+                                  __func__, __LINE__, ps3_result(result));
                        goto fail_map;
                }
                DBG("%s: pg=%d bus=%#lx, lpar=%#lx, ioid=%#x\n", __func__,
@@ -1001,7 +1001,8 @@ static int dma_sb_region_create_linear(struct ps3_dma_region *r)
                if (len > r->len)
                        len = r->len;
                result = dma_sb_map_area(r, virt_addr, len, &tmp,
-                       IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M);
+                       CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | CBE_IOPTE_SO_RW |
+                       CBE_IOPTE_M);
                BUG_ON(result);
        }
 
@@ -1014,7 +1015,8 @@ static int dma_sb_region_create_linear(struct ps3_dma_region *r)
                else
                        len -= map.rm.size - r->offset;
                result = dma_sb_map_area(r, virt_addr, len, &tmp,
-                       IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M);
+                       CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | CBE_IOPTE_SO_RW |
+                       CBE_IOPTE_M);
                BUG_ON(result);
        }
 
index cf1cd0f8c18f9dca3b9917cc509dbc2179119b67..d6487a9c801900d3aa9ee9db65a245f44f26f702 100644 (file)
@@ -226,6 +226,44 @@ static struct property property_av_multi_out = {
        .value = &saved_params.av_multi_out,
 };
 
+
+static DEFINE_MUTEX(os_area_flash_mutex);
+
+static const struct ps3_os_area_flash_ops *os_area_flash_ops;
+
+void ps3_os_area_flash_register(const struct ps3_os_area_flash_ops *ops)
+{
+       mutex_lock(&os_area_flash_mutex);
+       os_area_flash_ops = ops;
+       mutex_unlock(&os_area_flash_mutex);
+}
+EXPORT_SYMBOL_GPL(ps3_os_area_flash_register);
+
+static ssize_t os_area_flash_read(void *buf, size_t count, loff_t pos)
+{
+       ssize_t res = -ENODEV;
+
+       mutex_lock(&os_area_flash_mutex);
+       if (os_area_flash_ops)
+               res = os_area_flash_ops->read(buf, count, pos);
+       mutex_unlock(&os_area_flash_mutex);
+
+       return res;
+}
+
+static ssize_t os_area_flash_write(const void *buf, size_t count, loff_t pos)
+{
+       ssize_t res = -ENODEV;
+
+       mutex_lock(&os_area_flash_mutex);
+       if (os_area_flash_ops)
+               res = os_area_flash_ops->write(buf, count, pos);
+       mutex_unlock(&os_area_flash_mutex);
+
+       return res;
+}
+
+
 /**
  * os_area_set_property - Add or overwrite a saved_params value to the device tree.
  *
@@ -352,12 +390,12 @@ static int db_verify(const struct os_area_db *db)
        if (memcmp(db->magic_num, OS_AREA_DB_MAGIC_NUM,
                sizeof(db->magic_num))) {
                pr_debug("%s:%d magic_num failed\n", __func__, __LINE__);
-               return -1;
+               return -EINVAL;
        }
 
        if (db->version != 1) {
                pr_debug("%s:%d version failed\n", __func__, __LINE__);
-               return -1;
+               return -EINVAL;
        }
 
        return 0;
@@ -578,59 +616,48 @@ static void os_area_db_init(struct os_area_db *db)
  *
  */
 
-static void __maybe_unused update_flash_db(void)
+static int update_flash_db(void)
 {
-       int result;
-       int file;
-       off_t offset;
+       const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE;
+       struct os_area_header *header;
        ssize_t count;
-       static const unsigned int buf_len = 8 * OS_AREA_SEGMENT_SIZE;
-       const struct os_area_header *header;
+       int error;
+       loff_t pos;
        struct os_area_db* db;
 
        /* Read in header and db from flash. */
 
-       file = sys_open("/dev/ps3flash", O_RDWR, 0);
-
-       if (file < 0) {
-               pr_debug("%s:%d sys_open failed\n", __func__, __LINE__);
-               goto fail_open;
-       }
-
        header = kmalloc(buf_len, GFP_KERNEL);
-
        if (!header) {
-               pr_debug("%s:%d kmalloc failed\n", __func__, __LINE__);
-               goto fail_malloc;
+               pr_debug("%s: kmalloc failed\n", __func__);
+               return -ENOMEM;
        }
 
-       offset = sys_lseek(file, 0, SEEK_SET);
-
-       if (offset != 0) {
-               pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__);
-               goto fail_header_seek;
+       count = os_area_flash_read(header, buf_len, 0);
+       if (count < 0) {
+               pr_debug("%s: os_area_flash_read failed %zd\n", __func__,
+                        count);
+               error = count;
+               goto fail;
        }
 
-       count = sys_read(file, (char __user *)header, buf_len);
-
-       result = count < OS_AREA_SEGMENT_SIZE || verify_header(header)
-               || count < header->db_area_offset * OS_AREA_SEGMENT_SIZE;
-
-       if (result) {
-               pr_debug("%s:%d verify_header failed\n", __func__, __LINE__);
+       pos = header->db_area_offset * OS_AREA_SEGMENT_SIZE;
+       if (count < OS_AREA_SEGMENT_SIZE || verify_header(header) ||
+           count < pos) {
+               pr_debug("%s: verify_header failed\n", __func__);
                dump_header(header);
-               goto fail_header;
+               error = -EINVAL;
+               goto fail;
        }
 
        /* Now got a good db offset and some maybe good db data. */
 
-       db = (void*)header + header->db_area_offset * OS_AREA_SEGMENT_SIZE;
+       db = (void *)header + pos;
 
-       result = db_verify(db);
-
-       if (result) {
-               printk(KERN_NOTICE "%s:%d: Verify of flash database failed, "
-                       "formatting.\n", __func__, __LINE__);
+       error = db_verify(db);
+       if (error) {
+               pr_notice("%s: Verify of flash database failed, formatting.\n",
+                         __func__);
                dump_db(db);
                os_area_db_init(db);
        }
@@ -639,29 +666,16 @@ static void __maybe_unused update_flash_db(void)
 
        db_set_64(db, &os_area_db_id_rtc_diff, saved_params.rtc_diff);
 
-       offset = sys_lseek(file, header->db_area_offset * OS_AREA_SEGMENT_SIZE,
-               SEEK_SET);
-
-       if (offset != header->db_area_offset * OS_AREA_SEGMENT_SIZE) {
-               pr_debug("%s:%d sys_lseek failed\n", __func__, __LINE__);
-               goto fail_db_seek;
-       }
-
-       count = sys_write(file, (const char __user *)db,
-               sizeof(struct os_area_db));
-
+       count = os_area_flash_write(db, sizeof(struct os_area_db), pos);
        if (count < sizeof(struct os_area_db)) {
-               pr_debug("%s:%d sys_write failed\n", __func__, __LINE__);
+               pr_debug("%s: os_area_flash_write failed %zd\n", __func__,
+                        count);
+               error = count < 0 ? count : -EIO;
        }
 
-fail_db_seek:
-fail_header:
-fail_header_seek:
+fail:
        kfree(header);
-fail_malloc:
-       sys_close(file);
-fail_open:
-       return;
+       return error;
 }
 
 /**
@@ -674,11 +688,11 @@ fail_open:
 static void os_area_queue_work_handler(struct work_struct *work)
 {
        struct device_node *node;
+       int error;
 
        pr_debug(" -> %s:%d\n", __func__, __LINE__);
 
        node = of_find_node_by_path("/");
-
        if (node) {
                os_area_set_property(node, &property_rtc_diff);
                of_node_put(node);
@@ -686,12 +700,10 @@ static void os_area_queue_work_handler(struct work_struct *work)
                pr_debug("%s:%d of_find_node_by_path failed\n",
                        __func__, __LINE__);
 
-#if defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE)
-       update_flash_db();
-#else
-       printk(KERN_WARNING "%s:%d: No flash rom driver configured.\n",
-               __func__, __LINE__);
-#endif
+       error = update_flash_db();
+       if (error)
+               pr_warning("%s: Could not update FLASH ROM\n", __func__);
+
        pr_debug(" <- %s:%d\n", __func__, __LINE__);
 }
 
@@ -808,7 +820,7 @@ u64 ps3_os_area_get_rtc_diff(void)
 {
        return saved_params.rtc_diff;
 }
-EXPORT_SYMBOL(ps3_os_area_get_rtc_diff);
+EXPORT_SYMBOL_GPL(ps3_os_area_get_rtc_diff);
 
 /**
  * ps3_os_area_set_rtc_diff - Set the rtc diff value.
@@ -824,7 +836,7 @@ void ps3_os_area_set_rtc_diff(u64 rtc_diff)
                os_area_queue_work();
        }
 }
-EXPORT_SYMBOL(ps3_os_area_set_rtc_diff);
+EXPORT_SYMBOL_GPL(ps3_os_area_set_rtc_diff);
 
 /**
  * ps3_os_area_get_av_multi_out - Returns the default video mode.
index 136aa0637d9c0bbc67e10f13b98d96f5540aa288..9a196a88eda794d6d07f50abefaebc7a21902427 100644 (file)
@@ -232,14 +232,4 @@ int ps3_repository_read_spu_resource_id(unsigned int res_index,
 int ps3_repository_read_vuart_av_port(unsigned int *port);
 int ps3_repository_read_vuart_sysmgr_port(unsigned int *port);
 
-/* Page table entries */
-#define IOPTE_PP_W             0x8000000000000000ul /* protection: write */
-#define IOPTE_PP_R             0x4000000000000000ul /* protection: read */
-#define IOPTE_M                        0x2000000000000000ul /* coherency required */
-#define IOPTE_SO_R             0x1000000000000000ul /* ordering: writes */
-#define IOPTE_SO_RW             0x1800000000000000ul /* ordering: r & w */
-#define IOPTE_RPN_Mask         0x07fffffffffff000ul /* RPN */
-#define IOPTE_H                        0x0000000000000800ul /* cache hint */
-#define IOPTE_IOID_Mask                0x00000000000007fful /* ioid */
-
 #endif
index 1a7b5ae0c83e3eb92bccde0b6201ad78a6cb7a27..149bea2ce58370b606fc51132760123d1bebadba 100644 (file)
@@ -32,6 +32,7 @@
 #include <asm/udbg.h>
 #include <asm/prom.h>
 #include <asm/lv1call.h>
+#include <asm/ps3gpu.h>
 
 #include "platform.h"
 
index 9a73d0238639307cd2f1f16d5352def20aa27e86..9fead0faf38bbd5930fe0dd0f75fcc1f2711c296 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/udbg.h>
 #include <asm/lv1call.h>
 #include <asm/firmware.h>
+#include <asm/iommu.h>
 
 #include "platform.h"
 
@@ -531,7 +532,8 @@ static void * ps3_alloc_coherent(struct device *_dev, size_t size,
        }
 
        result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle,
-                            IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M);
+                            CBE_IOPTE_PP_W | CBE_IOPTE_PP_R |
+                            CBE_IOPTE_SO_RW | CBE_IOPTE_M);
 
        if (result) {
                pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
@@ -575,7 +577,8 @@ static dma_addr_t ps3_sb_map_page(struct device *_dev, struct page *page,
 
        result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size,
                             &bus_addr,
-                            IOPTE_PP_R | IOPTE_PP_W | IOPTE_SO_RW | IOPTE_M);
+                            CBE_IOPTE_PP_R | CBE_IOPTE_PP_W |
+                            CBE_IOPTE_SO_RW | CBE_IOPTE_M);
 
        if (result) {
                pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
@@ -596,16 +599,16 @@ static dma_addr_t ps3_ioc0_map_page(struct device *_dev, struct page *page,
        u64 iopte_flag;
        void *ptr = page_address(page) + offset;
 
-       iopte_flag = IOPTE_M;
+       iopte_flag = CBE_IOPTE_M;
        switch (direction) {
        case DMA_BIDIRECTIONAL:
-               iopte_flag |= IOPTE_PP_R | IOPTE_PP_W | IOPTE_SO_RW;
+               iopte_flag |= CBE_IOPTE_PP_R | CBE_IOPTE_PP_W | CBE_IOPTE_SO_RW;
                break;
        case DMA_TO_DEVICE:
-               iopte_flag |= IOPTE_PP_R | IOPTE_SO_R;
+               iopte_flag |= CBE_IOPTE_PP_R | CBE_IOPTE_SO_R;
                break;
        case DMA_FROM_DEVICE:
-               iopte_flag |= IOPTE_PP_W | IOPTE_SO_RW;
+               iopte_flag |= CBE_IOPTE_PP_W | CBE_IOPTE_SO_RW;
                break;
        default:
                /* not happned */
index 99dc3ded6b4975dc190d0243b856d539c9a932ce..a14dba0e4d67105c89838e8416d2dab0443640a2 100644 (file)
@@ -348,6 +348,9 @@ config ARCH_ENABLE_MEMORY_HOTPLUG
 config ARCH_ENABLE_MEMORY_HOTREMOVE
        def_bool y
 
+config ARCH_HIBERNATION_POSSIBLE
+       def_bool y if 64BIT
+
 source "mm/Kconfig"
 
 comment "I/O subsystem configuration"
@@ -592,6 +595,12 @@ config SECCOMP
 
 endmenu
 
+menu "Power Management"
+
+source "kernel/power/Kconfig"
+
+endmenu
+
 source "net/Kconfig"
 
 config PCMCIA
index 578c61f15a4beff789126dfa98478992e028ca2a..0ff387cebf88e5032847811ae959a5afa607d3a9 100644 (file)
@@ -88,7 +88,9 @@ LDFLAGS_vmlinux := -e start
 head-y         := arch/s390/kernel/head.o arch/s390/kernel/init_task.o
 
 core-y         += arch/s390/mm/ arch/s390/kernel/ arch/s390/crypto/ \
-                  arch/s390/appldata/ arch/s390/hypfs/ arch/s390/kvm/
+                  arch/s390/appldata/ arch/s390/hypfs/ arch/s390/kvm/ \
+                  arch/s390/power/
+
 libs-y         += arch/s390/lib/
 drivers-y      += drivers/s390/
 drivers-$(CONFIG_MATHEMU) += arch/s390/math-emu/
index 1dfc7100c7ee358cb0a0e131b43d36145f64a6fd..264528e4f58d5ea3fa0ff12f534c925df21001a6 100644 (file)
@@ -5,7 +5,7 @@
  * Exports appldata_register_ops() and appldata_unregister_ops() for the
  * data gathering modules.
  *
- * Copyright IBM Corp. 2003, 2008
+ * Copyright IBM Corp. 2003, 2009
  *
  * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
@@ -26,6 +26,8 @@
 #include <linux/notifier.h>
 #include <linux/cpu.h>
 #include <linux/workqueue.h>
+#include <linux/suspend.h>
+#include <linux/platform_device.h>
 #include <asm/appldata.h>
 #include <asm/timer.h>
 #include <asm/uaccess.h>
@@ -41,6 +43,9 @@
 
 #define TOD_MICRO      0x01000                 /* nr. of TOD clock units
                                                   for 1 microsecond */
+
+static struct platform_device *appldata_pdev;
+
 /*
  * /proc entries (sysctl)
  */
@@ -86,6 +91,7 @@ static atomic_t appldata_expire_count = ATOMIC_INIT(0);
 static DEFINE_SPINLOCK(appldata_timer_lock);
 static int appldata_interval = APPLDATA_CPU_INTERVAL;
 static int appldata_timer_active;
+static int appldata_timer_suspended = 0;
 
 /*
  * Work queue
@@ -475,6 +481,93 @@ void appldata_unregister_ops(struct appldata_ops *ops)
 /********************** module-ops management <END> **************************/
 
 
+/**************************** suspend / resume *******************************/
+static int appldata_freeze(struct device *dev)
+{
+       struct appldata_ops *ops;
+       int rc;
+       struct list_head *lh;
+
+       get_online_cpus();
+       spin_lock(&appldata_timer_lock);
+       if (appldata_timer_active) {
+               __appldata_vtimer_setup(APPLDATA_DEL_TIMER);
+               appldata_timer_suspended = 1;
+       }
+       spin_unlock(&appldata_timer_lock);
+       put_online_cpus();
+
+       mutex_lock(&appldata_ops_mutex);
+       list_for_each(lh, &appldata_ops_list) {
+               ops = list_entry(lh, struct appldata_ops, list);
+               if (ops->active == 1) {
+                       rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
+                                       (unsigned long) ops->data, ops->size,
+                                       ops->mod_lvl);
+                       if (rc != 0)
+                               pr_err("Stopping the data collection for %s "
+                                      "failed with rc=%d\n", ops->name, rc);
+               }
+       }
+       mutex_unlock(&appldata_ops_mutex);
+       return 0;
+}
+
+static int appldata_restore(struct device *dev)
+{
+       struct appldata_ops *ops;
+       int rc;
+       struct list_head *lh;
+
+       get_online_cpus();
+       spin_lock(&appldata_timer_lock);
+       if (appldata_timer_suspended) {
+               __appldata_vtimer_setup(APPLDATA_ADD_TIMER);
+               appldata_timer_suspended = 0;
+       }
+       spin_unlock(&appldata_timer_lock);
+       put_online_cpus();
+
+       mutex_lock(&appldata_ops_mutex);
+       list_for_each(lh, &appldata_ops_list) {
+               ops = list_entry(lh, struct appldata_ops, list);
+               if (ops->active == 1) {
+                       ops->callback(ops->data);       // init record
+                       rc = appldata_diag(ops->record_nr,
+                                       APPLDATA_START_INTERVAL_REC,
+                                       (unsigned long) ops->data, ops->size,
+                                       ops->mod_lvl);
+                       if (rc != 0) {
+                               pr_err("Starting the data collection for %s "
+                                      "failed with rc=%d\n", ops->name, rc);
+                       }
+               }
+       }
+       mutex_unlock(&appldata_ops_mutex);
+       return 0;
+}
+
+static int appldata_thaw(struct device *dev)
+{
+       return appldata_restore(dev);
+}
+
+static struct dev_pm_ops appldata_pm_ops = {
+       .freeze         = appldata_freeze,
+       .thaw           = appldata_thaw,
+       .restore        = appldata_restore,
+};
+
+static struct platform_driver appldata_pdrv = {
+       .driver = {
+               .name   = "appldata",
+               .owner  = THIS_MODULE,
+               .pm     = &appldata_pm_ops,
+       },
+};
+/************************* suspend / resume <END> ****************************/
+
+
 /******************************* init / exit *********************************/
 
 static void __cpuinit appldata_online_cpu(int cpu)
@@ -531,11 +624,23 @@ static struct notifier_block __cpuinitdata appldata_nb = {
  */
 static int __init appldata_init(void)
 {
-       int i;
+       int i, rc;
+
+       rc = platform_driver_register(&appldata_pdrv);
+       if (rc)
+               return rc;
 
+       appldata_pdev = platform_device_register_simple("appldata", -1, NULL,
+                                                       0);
+       if (IS_ERR(appldata_pdev)) {
+               rc = PTR_ERR(appldata_pdev);
+               goto out_driver;
+       }
        appldata_wq = create_singlethread_workqueue("appldata");
-       if (!appldata_wq)
-               return -ENOMEM;
+       if (!appldata_wq) {
+               rc = -ENOMEM;
+               goto out_device;
+       }
 
        get_online_cpus();
        for_each_online_cpu(i)
@@ -547,6 +652,12 @@ static int __init appldata_init(void)
 
        appldata_sysctl_header = register_sysctl_table(appldata_dir_table);
        return 0;
+
+out_device:
+       platform_device_unregister(appldata_pdev);
+out_driver:
+       platform_driver_unregister(&appldata_pdrv);
+       return rc;
 }
 
 __initcall(appldata_init);
index ba007d8df9411867260f9b75591219ed8872da0d..2a541955117688b23de8b40557dfd944d1dce02c 100644 (file)
@@ -1,11 +1,9 @@
 /*
- *  include/asm-s390/ccwdev.h
- *  include/asm-s390x/ccwdev.h
+ * Copyright  IBM Corp. 2002, 2009
  *
- *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Arnd Bergmann <arndb@de.ibm.com>
+ * Author(s): Arnd Bergmann <arndb@de.ibm.com>
  *
- *  Interface for CCW device drivers
+ * Interface for CCW device drivers
  */
 #ifndef _S390_CCWDEV_H_
 #define _S390_CCWDEV_H_
@@ -104,6 +102,11 @@ struct ccw_device {
  * @set_offline: called when setting device offline
  * @notify: notify driver of device state changes
  * @shutdown: called at device shutdown
+ * @prepare: prepare for pm state transition
+ * @complete: undo work done in @prepare
+ * @freeze: callback for freezing during hibernation snapshotting
+ * @thaw: undo work done in @freeze
+ * @restore: callback for restoring after hibernation
  * @driver: embedded device driver structure
  * @name: device driver name
  */
@@ -116,6 +119,11 @@ struct ccw_driver {
        int (*set_offline) (struct ccw_device *);
        int (*notify) (struct ccw_device *, int);
        void (*shutdown) (struct ccw_device *);
+       int (*prepare) (struct ccw_device *);
+       void (*complete) (struct ccw_device *);
+       int (*freeze)(struct ccw_device *);
+       int (*thaw) (struct ccw_device *);
+       int (*restore)(struct ccw_device *);
        struct device_driver driver;
        char *name;
 };
@@ -184,6 +192,7 @@ extern void ccw_device_get_id(struct ccw_device *, struct ccw_dev_id *);
 #define to_ccwdrv(n) container_of(n, struct ccw_driver, driver)
 
 extern struct ccw_device *ccw_device_probe_console(void);
+extern int ccw_device_force_console(void);
 
 // FIXME: these have to go
 extern int _ccw_device_get_subchannel_number(struct ccw_device *);
index a27f68985a791d7c5317a8574c0605ef1c54064c..c79c1e787b86fc67903c0823d9637b94a784ac93 100644 (file)
@@ -38,6 +38,11 @@ struct ccwgroup_device {
  * @set_online: function called when device is set online
  * @set_offline: function called when device is set offline
  * @shutdown: function called when device is shut down
+ * @prepare: prepare for pm state transition
+ * @complete: undo work done in @prepare
+ * @freeze: callback for freezing during hibernation snapshotting
+ * @thaw: undo work done in @freeze
+ * @restore: callback for restoring after hibernation
  * @driver: embedded driver structure
  */
 struct ccwgroup_driver {
@@ -51,6 +56,11 @@ struct ccwgroup_driver {
        int (*set_online) (struct ccwgroup_device *);
        int (*set_offline) (struct ccwgroup_device *);
        void (*shutdown)(struct ccwgroup_device *);
+       int (*prepare) (struct ccwgroup_device *);
+       void (*complete) (struct ccwgroup_device *);
+       int (*freeze)(struct ccwgroup_device *);
+       int (*thaw) (struct ccwgroup_device *);
+       int (*restore)(struct ccwgroup_device *);
 
        struct device_driver driver;
 };
index fd1574648223b5aaa3a9bb60255098a64b4db919..94ec3ee07983f8e9b97c6d857b5e7702bbfa36ee 100644 (file)
@@ -2,22 +2,7 @@
 #ifndef _ASM_KMAP_TYPES_H
 #define _ASM_KMAP_TYPES_H
 
-enum km_type {
-       KM_BOUNCE_READ,
-       KM_SKB_SUNRPC_DATA,
-       KM_SKB_DATA_SOFTIRQ,
-       KM_USER0,
-       KM_USER1,
-       KM_BIO_SRC_IRQ,
-       KM_BIO_DST_IRQ,
-       KM_PTE0,
-       KM_PTE1,
-       KM_IRQ0,
-       KM_IRQ1,
-       KM_SOFTIRQ0,
-       KM_SOFTIRQ1,    
-       KM_TYPE_NR
-};
+#include <asm-generic/kmap_types.h>
 
 #endif
 #endif /* __KERNEL__ */
diff --git a/arch/s390/include/asm/suspend.h b/arch/s390/include/asm/suspend.h
new file mode 100644 (file)
index 0000000..dc75c61
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __ASM_S390_SUSPEND_H
+#define __ASM_S390_SUSPEND_H
+
+static inline int arch_prepare_suspend(void)
+{
+       return 0;
+}
+
+#endif
+
index 3a8b26eb1f2e827d3d6de72b508dd307c08de6a0..4fb83c1cdb77a206d72136830107e912f83a1dd1 100644 (file)
@@ -1,11 +1,7 @@
 /*
- *  include/asm-s390/system.h
+ * Copyright IBM Corp. 1999, 2009
  *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
- *
- *  Derived from "include/asm-i386/system.h"
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
  */
 
 #ifndef __ASM_SYSTEM_H
@@ -469,6 +465,20 @@ extern psw_t sysc_restore_trace_psw;
 extern psw_t io_restore_trace_psw;
 #endif
 
+static inline int tprot(unsigned long addr)
+{
+       int rc = -EFAULT;
+
+       asm volatile(
+               "       tprot   0(%1),0\n"
+               "0:     ipm     %0\n"
+               "       srl     %0,28\n"
+               "1:\n"
+               EX_TABLE(0b,1b)
+               : "+d" (rc) : "a" (addr) : "cc");
+       return rc;
+}
+
 #endif /* __KERNEL__ */
 
 #endif
index fb263736826c8d73d0e2f0031afbbd24c88c69a9..f9b144049dc983ef16419a415feadb14e2c0374b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  arch/s390/kernel/early.c
  *
- *    Copyright IBM Corp. 2007
+ *    Copyright IBM Corp. 2007, 2009
  *    Author(s): Hongjie Yang <hongjie@us.ibm.com>,
  *              Heiko Carstens <heiko.carstens@de.ibm.com>
  */
@@ -210,7 +210,7 @@ static noinline __init void detect_machine_type(void)
                machine_flags |= MACHINE_FLAG_VM;
 }
 
-static __init void early_pgm_check_handler(void)
+static void early_pgm_check_handler(void)
 {
        unsigned long addr;
        const struct exception_table_entry *fixup;
@@ -222,7 +222,7 @@ static __init void early_pgm_check_handler(void)
        S390_lowcore.program_old_psw.addr = fixup->fixup | PSW_ADDR_AMODE;
 }
 
-static noinline __init void setup_lowcore_early(void)
+void setup_lowcore_early(void)
 {
        psw_t psw;
 
index 7db95c0b86938603176baf5496f23338cd455bc2..fe787f9e5f3f375753291b01f1e135546b5875b6 100644 (file)
 
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-struct mm_struct init_mm = INIT_MM(init_mm);
-
-EXPORT_SYMBOL(init_mm);
-
 /*
  * Initial thread structure.
  *
index 9872999c66d1e4304afad270652bee5cda303da7..559af0d07878867cb0e382226c33852af5e17e62 100644 (file)
@@ -1,6 +1,7 @@
 /*
- *    Copyright IBM Corp. 2008
- *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ * Copyright IBM Corp. 2008, 2009
+ *
+ * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
  */
 
 #include <linux/kernel.h>
@@ -9,20 +10,6 @@
 #include <asm/sclp.h>
 #include <asm/setup.h>
 
-static inline int tprot(unsigned long addr)
-{
-       int rc = -EFAULT;
-
-       asm volatile(
-               "       tprot   0(%1),0\n"
-               "0:     ipm     %0\n"
-               "       srl     %0,28\n"
-               "1:\n"
-               EX_TABLE(0b,1b)
-               : "+d" (rc) : "a" (addr) : "cc");
-       return rc;
-}
-
 #define ADDR2G (1ULL << 31)
 
 static void find_memory_chunks(struct mem_chunk chunk[])
index cc8c484984e33160375b11fd9f147c764b805cde..fd8e3111a4e8f6dd862d45b9787d0f23fff51b60 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  arch/s390/kernel/smp.c
  *
- *    Copyright IBM Corp. 1999,2007
+ *    Copyright IBM Corp. 1999, 2009
  *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
  *              Martin Schwidefsky (schwidefsky@de.ibm.com)
  *              Heiko Carstens (heiko.carstens@de.ibm.com)
@@ -1031,6 +1031,42 @@ out:
 static SYSDEV_CLASS_ATTR(dispatching, 0644, dispatching_show,
                         dispatching_store);
 
+/*
+ * If the resume kernel runs on another cpu than the suspended kernel,
+ * we have to switch the cpu IDs in the logical map.
+ */
+void smp_switch_boot_cpu_in_resume(u32 resume_phys_cpu_id,
+                                  struct _lowcore *suspend_lowcore)
+{
+       int cpu, suspend_cpu_id, resume_cpu_id;
+       u32 suspend_phys_cpu_id;
+
+       suspend_phys_cpu_id = __cpu_logical_map[suspend_lowcore->cpu_nr];
+       suspend_cpu_id = suspend_lowcore->cpu_nr;
+
+       for_each_present_cpu(cpu) {
+               if (__cpu_logical_map[cpu] == resume_phys_cpu_id) {
+                       resume_cpu_id = cpu;
+                       goto found;
+               }
+       }
+       panic("Could not find resume cpu in logical map.\n");
+
+found:
+       printk("Resume  cpu ID: %i/%i\n", resume_phys_cpu_id, resume_cpu_id);
+       printk("Suspend cpu ID: %i/%i\n", suspend_phys_cpu_id, suspend_cpu_id);
+
+       __cpu_logical_map[resume_cpu_id] = suspend_phys_cpu_id;
+       __cpu_logical_map[suspend_cpu_id] = resume_phys_cpu_id;
+
+       lowcore_ptr[suspend_cpu_id]->cpu_addr = resume_phys_cpu_id;
+}
+
+u32 smp_get_phys_cpu_id(void)
+{
+       return __cpu_logical_map[smp_processor_id()];
+}
+
 static int __init topology_init(void)
 {
        int cpu;
index 4ca8e826bf303b4d8694f0757fe8b471ba52d099..565667207985c15e6e5ca4526dd2a36ec33b293e 100644 (file)
@@ -313,3 +313,22 @@ int s390_enable_sie(void)
        return 0;
 }
 EXPORT_SYMBOL_GPL(s390_enable_sie);
+
+#ifdef CONFIG_DEBUG_PAGEALLOC
+#ifdef CONFIG_HIBERNATION
+bool kernel_page_present(struct page *page)
+{
+       unsigned long addr;
+       int cc;
+
+       addr = page_to_phys(page);
+       asm("lra %1,0(%1)\n"
+           "ipm %0\n"
+           "srl %0,28"
+           :"=d"(cc),"+a"(addr)::"cc");
+       return cc == 0;
+}
+
+#endif /* CONFIG_HIBERNATION */
+#endif /* CONFIG_DEBUG_PAGEALLOC */
+
diff --git a/arch/s390/power/Makefile b/arch/s390/power/Makefile
new file mode 100644 (file)
index 0000000..973bb45
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Makefile for s390 PM support
+#
+
+obj-$(CONFIG_HIBERNATION) += suspend.o
+obj-$(CONFIG_HIBERNATION) += swsusp.o
+obj-$(CONFIG_HIBERNATION) += swsusp_64.o
+obj-$(CONFIG_HIBERNATION) += swsusp_asm64.o
diff --git a/arch/s390/power/suspend.c b/arch/s390/power/suspend.c
new file mode 100644 (file)
index 0000000..b3351ec
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Suspend support specific for s390.
+ *
+ * Copyright IBM Corp. 2009
+ *
+ * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com>
+ */
+
+#include <linux/mm.h>
+#include <linux/suspend.h>
+#include <linux/reboot.h>
+#include <linux/pfn.h>
+#include <asm/sections.h>
+#include <asm/ipl.h>
+
+/*
+ * References to section boundaries
+ */
+extern const void __nosave_begin, __nosave_end;
+
+/*
+ *  check if given pfn is in the 'nosave' or in the read only NSS section
+ */
+int pfn_is_nosave(unsigned long pfn)
+{
+       unsigned long nosave_begin_pfn = __pa(&__nosave_begin) >> PAGE_SHIFT;
+       unsigned long nosave_end_pfn = PAGE_ALIGN(__pa(&__nosave_end))
+                                       >> PAGE_SHIFT;
+       unsigned long eshared_pfn = PFN_DOWN(__pa(&_eshared)) - 1;
+       unsigned long stext_pfn = PFN_DOWN(__pa(&_stext));
+
+       if (pfn >= nosave_begin_pfn && pfn < nosave_end_pfn)
+               return 1;
+       if (pfn >= stext_pfn && pfn <= eshared_pfn) {
+               if (ipl_info.type == IPL_TYPE_NSS)
+                       return 1;
+       } else if ((tprot(pfn * PAGE_SIZE) && pfn > 0))
+               return 1;
+       return 0;
+}
diff --git a/arch/s390/power/swsusp.c b/arch/s390/power/swsusp.c
new file mode 100644 (file)
index 0000000..e6a4fe9
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Support for suspend and resume on s390
+ *
+ * Copyright IBM Corp. 2009
+ *
+ * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com>
+ *
+ */
+
+
+/*
+ * save CPU registers before creating a hibernation image and before
+ * restoring the memory state from it
+ */
+void save_processor_state(void)
+{
+       /* implentation contained in the
+        * swsusp_arch_suspend function
+        */
+}
+
+/*
+ * restore the contents of CPU registers
+ */
+void restore_processor_state(void)
+{
+       /* implentation contained in the
+        * swsusp_arch_resume function
+        */
+}
diff --git a/arch/s390/power/swsusp_64.c b/arch/s390/power/swsusp_64.c
new file mode 100644 (file)
index 0000000..9516a51
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Support for suspend and resume on s390
+ *
+ * Copyright IBM Corp. 2009
+ *
+ * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com>
+ *
+ */
+
+#include <asm/system.h>
+#include <linux/interrupt.h>
+
+void do_after_copyback(void)
+{
+       mb();
+}
+
diff --git a/arch/s390/power/swsusp_asm64.S b/arch/s390/power/swsusp_asm64.S
new file mode 100644 (file)
index 0000000..3c74e7d
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * S390 64-bit swsusp implementation
+ *
+ * Copyright IBM Corp. 2009
+ *
+ * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com>
+ *           Michael Holzheu <holzheu@linux.vnet.ibm.com>
+ */
+
+#include <asm/page.h>
+#include <asm/ptrace.h>
+#include <asm/asm-offsets.h>
+
+/*
+ * Save register context in absolute 0 lowcore and call swsusp_save() to
+ * create in-memory kernel image. The context is saved in the designated
+ * "store status" memory locations (see POP).
+ * We return from this function twice. The first time during the suspend to
+ * disk process. The second time via the swsusp_arch_resume() function
+ * (see below) in the resume process.
+ * This function runs with disabled interrupts.
+ */
+       .section .text
+       .align  2
+       .globl swsusp_arch_suspend
+swsusp_arch_suspend:
+       stmg    %r6,%r15,__SF_GPRS(%r15)
+       lgr     %r1,%r15
+       aghi    %r15,-STACK_FRAME_OVERHEAD
+       stg     %r1,__SF_BACKCHAIN(%r15)
+
+       /* Deactivate DAT */
+       stnsm   __SF_EMPTY(%r15),0xfb
+
+       /* Switch off lowcore protection */
+       stctg   %c0,%c0,__SF_EMPTY(%r15)
+       ni      __SF_EMPTY+4(%r15),0xef
+       lctlg   %c0,%c0,__SF_EMPTY(%r15)
+
+       /* Store prefix register on stack */
+       stpx    __SF_EMPTY(%r15)
+
+       /* Setup base register for lowcore (absolute 0) */
+       llgf    %r1,__SF_EMPTY(%r15)
+
+       /* Get pointer to save area */
+       aghi    %r1,0x1000
+
+       /* Store registers */
+       mvc     0x318(4,%r1),__SF_EMPTY(%r15)   /* move prefix to lowcore */
+       stfpc   0x31c(%r1)                      /* store fpu control */
+       std     0,0x200(%r1)                    /* store f0 */
+       std     1,0x208(%r1)                    /* store f1 */
+       std     2,0x210(%r1)                    /* store f2 */
+       std     3,0x218(%r1)                    /* store f3 */
+       std     4,0x220(%r1)                    /* store f4 */
+       std     5,0x228(%r1)                    /* store f5 */
+       std     6,0x230(%r1)                    /* store f6 */
+       std     7,0x238(%r1)                    /* store f7 */
+       std     8,0x240(%r1)                    /* store f8 */
+       std     9,0x248(%r1)                    /* store f9 */
+       std     10,0x250(%r1)                   /* store f10 */
+       std     11,0x258(%r1)                   /* store f11 */
+       std     12,0x260(%r1)                   /* store f12 */
+       std     13,0x268(%r1)                   /* store f13 */
+       std     14,0x270(%r1)                   /* store f14 */
+       std     15,0x278(%r1)                   /* store f15 */
+       stam    %a0,%a15,0x340(%r1)             /* store access registers */
+       stctg   %c0,%c15,0x380(%r1)             /* store control registers */
+       stmg    %r0,%r15,0x280(%r1)             /* store general registers */
+
+       stpt    0x328(%r1)                      /* store timer */
+       stckc   0x330(%r1)                      /* store clock comparator */
+
+       /* Activate DAT */
+       stosm   __SF_EMPTY(%r15),0x04
+
+       /* Set prefix page to zero */
+       xc      __SF_EMPTY(4,%r15),__SF_EMPTY(%r15)
+       spx     __SF_EMPTY(%r15)
+
+       /* Setup lowcore */
+       brasl   %r14,setup_lowcore_early
+
+       /* Save image */
+       brasl   %r14,swsusp_save
+
+       /* Switch on lowcore protection */
+       stctg   %c0,%c0,__SF_EMPTY(%r15)
+       oi      __SF_EMPTY+4(%r15),0x10
+       lctlg   %c0,%c0,__SF_EMPTY(%r15)
+
+       /* Restore prefix register and return */
+       lghi    %r1,0x1000
+       spx     0x318(%r1)
+       lmg     %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15)
+       lghi    %r2,0
+       br      %r14
+
+/*
+ * Restore saved memory image to correct place and restore register context.
+ * Then we return to the function that called swsusp_arch_suspend().
+ * swsusp_arch_resume() runs with disabled interrupts.
+ */
+       .globl swsusp_arch_resume
+swsusp_arch_resume:
+       stmg    %r6,%r15,__SF_GPRS(%r15)
+       lgr     %r1,%r15
+       aghi    %r15,-STACK_FRAME_OVERHEAD
+       stg     %r1,__SF_BACKCHAIN(%r15)
+
+       /* Save boot cpu number */
+       brasl   %r14,smp_get_phys_cpu_id
+       lgr     %r10,%r2
+
+       /* Deactivate DAT */
+       stnsm   __SF_EMPTY(%r15),0xfb
+
+       /* Switch off lowcore protection */
+       stctg   %c0,%c0,__SF_EMPTY(%r15)
+       ni      __SF_EMPTY+4(%r15),0xef
+       lctlg   %c0,%c0,__SF_EMPTY(%r15)
+
+       /* Set prefix page to zero */
+       xc      __SF_EMPTY(4,%r15),__SF_EMPTY(%r15)
+       spx     __SF_EMPTY(%r15)
+
+       /* Restore saved image */
+       larl    %r1,restore_pblist
+       lg      %r1,0(%r1)
+       ltgr    %r1,%r1
+       jz      2f
+0:
+       lg      %r2,8(%r1)
+       lg      %r4,0(%r1)
+       lghi    %r3,PAGE_SIZE
+       lghi    %r5,PAGE_SIZE
+1:
+       mvcle   %r2,%r4,0
+       jo      1b
+       lg      %r1,16(%r1)
+       ltgr    %r1,%r1
+       jnz     0b
+2:
+       ptlb                            /* flush tlb */
+
+       /* Restore registers */
+       lghi    %r13,0x1000             /* %r1 = pointer to save arae */
+
+       spt     0x328(%r13)             /* reprogram timer */
+       //sckc  0x330(%r13)             /* set clock comparator */
+
+       lctlg   %c0,%c15,0x380(%r13)    /* load control registers */
+       lam     %a0,%a15,0x340(%r13)    /* load access registers */
+
+       lfpc    0x31c(%r13)             /* load fpu control */
+       ld      0,0x200(%r13)           /* load f0 */
+       ld      1,0x208(%r13)           /* load f1 */
+       ld      2,0x210(%r13)           /* load f2 */
+       ld      3,0x218(%r13)           /* load f3 */
+       ld      4,0x220(%r13)           /* load f4 */
+       ld      5,0x228(%r13)           /* load f5 */
+       ld      6,0x230(%r13)           /* load f6 */
+       ld      7,0x238(%r13)           /* load f7 */
+       ld      8,0x240(%r13)           /* load f8 */
+       ld      9,0x248(%r13)           /* load f9 */
+       ld      10,0x250(%r13)          /* load f10 */
+       ld      11,0x258(%r13)          /* load f11 */
+       ld      12,0x260(%r13)          /* load f12 */
+       ld      13,0x268(%r13)          /* load f13 */
+       ld      14,0x270(%r13)          /* load f14 */
+       ld      15,0x278(%r13)          /* load f15 */
+
+       /* Load old stack */
+       lg      %r15,0x2f8(%r13)
+
+       /* Pointer to save arae */
+       lghi    %r13,0x1000
+
+       /* Switch CPUs */
+       lgr     %r2,%r10                /* get cpu id */
+       llgf    %r3,0x318(%r13)
+       brasl   %r14,smp_switch_boot_cpu_in_resume
+
+       /* Restore prefix register */
+       spx     0x318(%r13)
+
+       /* Switch on lowcore protection */
+       stctg   %c0,%c0,__SF_EMPTY(%r15)
+       oi      __SF_EMPTY+4(%r15),0x10
+       lctlg   %c0,%c0,__SF_EMPTY(%r15)
+
+       /* Activate DAT */
+       stosm   __SF_EMPTY(%r15),0x04
+
+       /* Return 0 */
+       lmg     %r6,%r15,STACK_FRAME_OVERHEAD + __SF_GPRS(%r15)
+       lghi    %r2,0
+       br      %r14
index 586cd045e2db213df61a3a9a46a3aaf2ecd08b8d..ac1c620d1c7d7bfae7cde2fef9f95a13ff9dc30d 100644 (file)
@@ -15,7 +15,9 @@ config SUPERH
        select HAVE_IOREMAP_PROT if MMU
        select HAVE_ARCH_TRACEHOOK
        select HAVE_DMA_API_DEBUG
+       select HAVE_PERF_COUNTER
        select RTC_LIB
+       select GENERIC_ATOMIC64
        help
          The SuperH is a RISC processor targeted for use in embedded systems
          and consumer electronics; it was also used in the Sega Dreamcast
@@ -50,6 +52,10 @@ config GENERIC_BUG
        def_bool y
        depends on BUG && SUPERH32
 
+config GENERIC_CSUM
+       def_bool y
+       depends on SUPERH64
+
 config GENERIC_FIND_NEXT_BIT
        def_bool y
 
index 8179cc9be9a4a343ab5af583cbfe52792067aa07..8ece0b5bd0282495f872bc71f0ad56227d312b12 100644 (file)
@@ -39,6 +39,7 @@ config EARLY_SCIF_CONSOLE_PORT
                                CPU_SUBTYPE_SH7722 || CPU_SUBTYPE_SH7366 || \
                                CPU_SUBTYPE_SH7343
        default "0xffea0000" if CPU_SUBTYPE_SH7785
+       default "0xffeb0000" if CPU_SUBTYPE_SH7786
        default "0xfffe8000" if CPU_SUBTYPE_SH7203
        default "0xfffe9800" if CPU_SUBTYPE_SH7206 || CPU_SUBTYPE_SH7263
        default "0xffe80000" if CPU_SH4
index 1c4d83ef2a4724e10da98bd42d58941d4a03ba15..7ffd1b4315bd9711119d9319b7a4204c1d332fe2 100644 (file)
@@ -349,15 +349,6 @@ static int ov7725_power(struct device *dev, int mode)
        return 0;
 }
 
-static struct ov772x_camera_info ov7725_info = {
-       .buswidth  = SOCAM_DATAWIDTH_8,
-       .flags = OV772X_FLAG_VFLIP | OV772X_FLAG_HFLIP,
-       .edgectrl = OV772X_AUTO_EDGECTRL(0xf, 0),
-       .link = {
-               .power  = ov7725_power,
-       },
-};
-
 static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
        .flags = SH_CEU_FLAG_USE_8BIT_BUS,
 };
@@ -402,25 +393,48 @@ static struct platform_device sdcard_cn3_device = {
        },
 };
 
-static struct platform_device *ap325rxa_devices[] __initdata = {
-       &smsc9118_device,
-       &ap325rxa_nor_flash_device,
-       &lcdc_device,
-       &ceu_device,
-       &nand_flash_device,
-       &sdcard_cn3_device,
-};
-
 static struct i2c_board_info __initdata ap325rxa_i2c_devices[] = {
        {
                I2C_BOARD_INFO("pcf8563", 0x51),
        },
+};
+
+static struct i2c_board_info ap325rxa_i2c_camera[] = {
        {
                I2C_BOARD_INFO("ov772x", 0x21),
-               .platform_data = &ov7725_info,
        },
 };
 
+static struct ov772x_camera_info ov7725_info = {
+       .buswidth       = SOCAM_DATAWIDTH_8,
+       .flags          = OV772X_FLAG_VFLIP | OV772X_FLAG_HFLIP,
+       .edgectrl       = OV772X_AUTO_EDGECTRL(0xf, 0),
+       .link = {
+               .power          = ov7725_power,
+               .board_info     = &ap325rxa_i2c_camera[0],
+               .i2c_adapter_id = 0,
+               .module_name    = "ov772x",
+       },
+};
+
+static struct platform_device ap325rxa_camera = {
+       .name   = "soc-camera-pdrv",
+       .id     = 0,
+       .dev    = {
+               .platform_data = &ov7725_info.link,
+       },
+};
+
+static struct platform_device *ap325rxa_devices[] __initdata = {
+       &smsc9118_device,
+       &ap325rxa_nor_flash_device,
+       &lcdc_device,
+       &ceu_device,
+       &nand_flash_device,
+       &sdcard_cn3_device,
+       &ap325rxa_camera,
+};
+
 static struct spi_board_info ap325rxa_spi_devices[] = {
        {
                .modalias = "mmc_spi",
index 7be56fb06c1f0a7aecbd95ee47f0fa805535518e..42410a15d2552762a13604f37e9985dabb7d027d 100644 (file)
 #include <linux/fb.h>
 #include <linux/mtd/physmap.h>
 #include <linux/delay.h>
+#include <linux/interrupt.h>
 #include <linux/i2c.h>
 #include <linux/i2c-pca-platform.h>
 #include <linux/i2c-algo-pca.h>
+#include <linux/usb/r8a66597.h>
 #include <linux/irq.h>
 #include <linux/clk.h>
 #include <linux/errno.h>
 #include <mach/sh7785lcr.h>
+#include <cpu/sh7785.h>
 #include <asm/heartbeat.h>
 #include <asm/clock.h>
-#include <cpu/sh7785.h>
 
 /*
  * NOTE: This board has 2 physical memory maps.
@@ -98,18 +100,21 @@ static struct platform_device nor_flash_device = {
        .resource       = nor_flash_resources,
 };
 
+static struct r8a66597_platdata r8a66597_data = {
+       .xtal = R8A66597_PLATDATA_XTAL_12MHZ,
+       .vif = 1,
+};
+
 static struct resource r8a66597_usb_host_resources[] = {
        [0] = {
-               .name   = "r8a66597_hcd",
                .start  = R8A66597_ADDR,
                .end    = R8A66597_ADDR + R8A66597_SIZE - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .name   = "r8a66597_hcd",
                .start  = 2,
                .end    = 2,
-               .flags  = IORESOURCE_IRQ,
+               .flags  = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
        },
 };
 
@@ -119,6 +124,7 @@ static struct platform_device r8a66597_usb_host_device = {
        .dev = {
                .dma_mask               = NULL,
                .coherent_dma_mask      = 0xffffffff,
+               .platform_data          = &r8a66597_data,
        },
        .num_resources  = ARRAY_SIZE(r8a66597_usb_host_resources),
        .resource       = r8a66597_usb_host_resources,
index beb88c4da2c1e8aa80131c1472894f77344d6761..36b8bac9b1247f25ad1fa88c3d010af9b7e4f131 100644 (file)
@@ -2,6 +2,7 @@
  * Renesas Technology Corp. SH7786 Urquell Support.
  *
  * Copyright (C) 2008  Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ * Copyright (C) 2009  Paul Mundt
  *
  * Based on board-sh7785lcr.c
  * Copyright (C) 2008  Yoshihiro Shimoda
@@ -178,6 +179,11 @@ static void __init urquell_init_irq(void)
        plat_irq_setup_pins(IRQ_MODE_IRL3210_MASK);
 }
 
+static int urquell_mode_pins(void)
+{
+       return __raw_readw(UBOARDREG(MDSWMR));
+}
+
 /* Initialize the board */
 static void __init urquell_setup(char **cmdline_p)
 {
@@ -193,4 +199,5 @@ static struct sh_machine_vector mv_urquell __initmv = {
        .mv_name        = "Urquell",
        .mv_setup       = urquell_setup,
        .mv_init_irq    = urquell_init_irq,
+       .mv_mode_pins   = urquell_mode_pins,
 };
index 20fe72c515d520d732f5b373b93c11c7cac252ff..1639f89150005d588ba96e32d481a78385950c9a 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/ata_platform.h>
 #include <linux/types.h>
+#include <linux/mtd/physmap.h>
 #include <linux/i2c.h>
 #include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/usb/r8a66597.h>
 #include <net/ax88796.h>
 #include <asm/machvec.h>
 #include <mach/highlander.h>
 #include <asm/io.h>
 #include <asm/io_trapped.h>
 
+static struct r8a66597_platdata r8a66597_data = {
+       .xtal = R8A66597_PLATDATA_XTAL_12MHZ,
+       .vif = 1,
+};
+
 static struct resource r8a66597_usb_host_resources[] = {
        [0] = {
-               .name   = "r8a66597_hcd",
                .start  = 0xA4200000,
                .end    = 0xA42000FF,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .name   = "r8a66597_hcd",
                .start  = IRQ_EXT1,             /* irq number */
                .end    = IRQ_EXT1,
-               .flags  = IORESOURCE_IRQ,
+               .flags  = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
        },
 };
 
@@ -48,6 +54,7 @@ static struct platform_device r8a66597_usb_host_device = {
        .dev = {
                .dma_mask               = NULL,         /* don't use dma */
                .coherent_dma_mask      = 0xffffffff,
+               .platform_data          = &r8a66597_data,
        },
        .num_resources  = ARRAY_SIZE(r8a66597_usb_host_resources),
        .resource       = r8a66597_usb_host_resources,
@@ -178,6 +185,53 @@ static struct platform_device ax88796_device = {
        .resource       = ax88796_resources,
 };
 
+static struct mtd_partition nor_flash_partitions[] = {
+       {
+               .name           = "loader",
+               .offset         = 0x00000000,
+               .size           = 512 * 1024,
+       },
+       {
+               .name           = "bootenv",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 512 * 1024,
+       },
+       {
+               .name           = "kernel",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = 4 * 1024 * 1024,
+       },
+       {
+               .name           = "data",
+               .offset         = MTDPART_OFS_APPEND,
+               .size           = MTDPART_SIZ_FULL,
+       },
+};
+
+static struct physmap_flash_data nor_flash_data = {
+       .width          = 4,
+       .parts          = nor_flash_partitions,
+       .nr_parts       = ARRAY_SIZE(nor_flash_partitions),
+};
+
+/* This config is flash board for mass production. */
+static struct resource nor_flash_resources[] = {
+       [0]     = {
+               .start  = PA_NORFLASH_ADDR,
+               .end    = PA_NORFLASH_ADDR + PA_NORFLASH_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       }
+};
+
+static struct platform_device nor_flash_device = {
+       .name           = "physmap-flash",
+       .dev            = {
+               .platform_data  = &nor_flash_data,
+       },
+       .num_resources  = ARRAY_SIZE(nor_flash_resources),
+       .resource       = nor_flash_resources,
+};
+
 static struct resource smbus_resources[] = {
        [0] = {
                .start  = PA_SMCR,
@@ -209,6 +263,7 @@ static struct platform_device *r7780rp_devices[] __initdata = {
        &m66592_usb_peripheral_device,
        &heartbeat_device,
        &smbus_device,
+       &nor_flash_device,
 #ifndef CONFIG_SH_R7780RP
        &ax88796_device,
 #endif
@@ -247,9 +302,10 @@ device_initcall(r7780rp_devices_setup);
 /*
  * Platform specific clocks
  */
-static void ivdr_clk_enable(struct clk *clk)
+static int ivdr_clk_enable(struct clk *clk)
 {
        ctrl_outw(ctrl_inw(PA_IVDRCTL) | (1 << IVDR_CK_ON), PA_IVDRCTL);
+       return 0;
 }
 
 static void ivdr_clk_disable(struct clk *clk)
index 6ed401cd3156af429569bf197c99fc1cbfe861e6..f70f4644deb4e835ed54fdea8f3a39a6d3ee2ebd 100644 (file)
@@ -381,21 +381,6 @@ static struct platform_device migor_ceu_device = {
        },
 };
 
-static struct ov772x_camera_info ov7725_info = {
-       .buswidth  = SOCAM_DATAWIDTH_8,
-       .link = {
-               .power  = ov7725_power,
-       },
-};
-
-static struct tw9910_video_info tw9910_info = {
-       .buswidth = SOCAM_DATAWIDTH_8,
-       .mpout    = TW9910_MPO_FIELD,
-       .link = {
-               .power  = tw9910_power,
-       }
-};
-
 struct spi_gpio_platform_data sdcard_cn9_platform_data = {
        .sck = GPIO_PTD0,
        .mosi = GPIO_PTD1,
@@ -410,16 +395,6 @@ static struct platform_device sdcard_cn9_device = {
        },
 };
 
-static struct platform_device *migor_devices[] __initdata = {
-       &smc91x_eth_device,
-       &sh_keysc_device,
-       &migor_lcdc_device,
-       &migor_ceu_device,
-       &migor_nor_flash_device,
-       &migor_nand_flash_device,
-       &sdcard_cn9_device,
-};
-
 static struct i2c_board_info migor_i2c_devices[] = {
        {
                I2C_BOARD_INFO("rs5c372b", 0x32),
@@ -428,16 +403,66 @@ static struct i2c_board_info migor_i2c_devices[] = {
                I2C_BOARD_INFO("migor_ts", 0x51),
                .irq = 38, /* IRQ6 */
        },
+};
+
+static struct i2c_board_info migor_i2c_camera[] = {
        {
                I2C_BOARD_INFO("ov772x", 0x21),
-               .platform_data = &ov7725_info,
        },
        {
                I2C_BOARD_INFO("tw9910", 0x45),
-               .platform_data = &tw9910_info,
        },
 };
 
+static struct ov772x_camera_info ov7725_info = {
+       .buswidth       = SOCAM_DATAWIDTH_8,
+       .link = {
+               .power          = ov7725_power,
+               .board_info     = &migor_i2c_camera[0],
+               .i2c_adapter_id = 0,
+               .module_name    = "ov772x",
+       },
+};
+
+static struct tw9910_video_info tw9910_info = {
+       .buswidth       = SOCAM_DATAWIDTH_8,
+       .mpout          = TW9910_MPO_FIELD,
+       .link = {
+               .power          = tw9910_power,
+               .board_info     = &migor_i2c_camera[1],
+               .i2c_adapter_id = 0,
+               .module_name    = "tw9910",
+       }
+};
+
+static struct platform_device migor_camera[] = {
+       {
+               .name   = "soc-camera-pdrv",
+               .id     = 0,
+               .dev    = {
+                       .platform_data = &ov7725_info.link,
+               },
+       }, {
+               .name   = "soc-camera-pdrv",
+               .id     = 1,
+               .dev    = {
+                       .platform_data = &tw9910_info.link,
+               },
+       },
+};
+
+static struct platform_device *migor_devices[] __initdata = {
+       &smc91x_eth_device,
+       &sh_keysc_device,
+       &migor_lcdc_device,
+       &migor_ceu_device,
+       &migor_nor_flash_device,
+       &migor_nand_flash_device,
+       &sdcard_cn9_device,
+       &migor_camera[0],
+       &migor_camera[1],
+};
+
 static struct spi_board_info migor_spi_devices[] = {
        {
                .modalias = "mmc_spi",
index b8d43b638fcff2118cf007b8f9cc745e79a0917f..121744c087144bc48ea6f85f197f3cd00760dbc3 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <linux/irq.h>
 #include <linux/io.h>
 #include <mach-se/mach/se7780.h>
 
index a340492087fa138b054759e6663d297a4a2eeb1d..8913ae39a8025db3f789ccf2e75bd2094730d19e 100644 (file)
@@ -15,6 +15,8 @@
 #include <linux/io.h>
 #include <linux/smc91x.h>
 #include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/usb/r8a66597.h>
 #include <asm/ilsel.h>
 
 static struct resource heartbeat_resources[] = {
@@ -58,17 +60,20 @@ static struct platform_device smc91x_device = {
        },
 };
 
+static struct r8a66597_platdata r8a66597_data = {
+       .xtal = R8A66597_PLATDATA_XTAL_12MHZ,
+       .vif = 1,
+};
+
 static struct resource r8a66597_usb_host_resources[] = {
        [0] = {
-               .name   = "r8a66597_hcd",
                .start  = 0x18040000,
                .end    = 0x18080000 - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .name   = "r8a66597_hcd",
                /* Filled in by ilsel */
-               .flags  = IORESOURCE_IRQ,
+               .flags  = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
        },
 };
 
@@ -78,6 +83,7 @@ static struct platform_device r8a66597_usb_host_device = {
        .dev = {
                .dma_mask               = NULL,         /* don't use dma */
                .coherent_dma_mask      = 0xffffffff,
+               .platform_data          = &r8a66597_data,
        },
        .num_resources  = ARRAY_SIZE(r8a66597_usb_host_resources),
        .resource       = r8a66597_usb_host_resources,
index 943da63a385231cafd9bf0ab06fd3212ff7ba604..d393d9e5bdddfc4cbf4b067f4f12d4bc7d050240 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc3
-# Mon Apr 27 12:53:28 2009
+# Linux kernel version: 2.6.30
+# Tue Jun 16 16:08:44 2009
 #
 CONFIG_SUPERH=y
 CONFIG_SUPERH32=y
@@ -20,6 +20,7 @@ CONFIG_GENERIC_CLOCKEVENTS=y
 # CONFIG_ARCH_SUSPEND_POSSIBLE is not set
 CONFIG_ARCH_HIBERNATION_POSSIBLE=y
 CONFIG_SYS_SUPPORTS_PCI=y
+CONFIG_SYS_SUPPORTS_TMU=y
 CONFIG_STACKTRACE_SUPPORT=y
 CONFIG_LOCKDEP_SUPPORT=y
 CONFIG_HAVE_LATENCYTOP_SUPPORT=y
@@ -92,6 +93,10 @@ CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_AIO=y
+
+#
+# Performance Counters
+#
 CONFIG_VM_EVENT_COUNTERS=y
 CONFIG_PCI_QUIRKS=y
 CONFIG_COMPAT_BRK=y
@@ -100,7 +105,7 @@ CONFIG_SLAB=y
 # CONFIG_SLOB is not set
 CONFIG_PROFILING=y
 CONFIG_TRACEPOINTS=y
-# CONFIG_MARKERS is not set
+CONFIG_MARKERS=y
 CONFIG_OPROFILE=m
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
@@ -185,6 +190,7 @@ CONFIG_CPU_SUBTYPE_SH7780=y
 CONFIG_QUICKLIST=y
 CONFIG_MMU=y
 CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_FORCE_MAX_ZONEORDER=11
 CONFIG_MEMORY_START=0x08000000
 CONFIG_MEMORY_SIZE=0x08000000
 # CONFIG_29BIT is not set
@@ -203,7 +209,6 @@ CONFIG_PAGE_SIZE_4KB=y
 # CONFIG_PAGE_SIZE_8KB is not set
 # CONFIG_PAGE_SIZE_16KB is not set
 # CONFIG_PAGE_SIZE_64KB is not set
-CONFIG_ENTRY_OFFSET=0x00001000
 CONFIG_HUGETLB_PAGE_SIZE_64K=y
 # CONFIG_HUGETLB_PAGE_SIZE_256K is not set
 # CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
@@ -225,6 +230,7 @@ CONFIG_NR_QUICK=2
 CONFIG_UNEVICTABLE_LRU=y
 CONFIG_HAVE_MLOCK=y
 CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
 
 #
 # Cache configuration
@@ -258,9 +264,10 @@ CONFIG_SH_R7780MP=y
 #
 # Timer and clock configuration
 #
-CONFIG_SH_TMU=y
-CONFIG_SH_TIMER_IRQ=28
+CONFIG_SH_TIMER_TMU=y
 CONFIG_SH_PCLK_FREQ=33333333
+CONFIG_SH_CLK_CPG=y
+CONFIG_SH_CLK_CPG_LEGACY=y
 # CONFIG_NO_HZ is not set
 # CONFIG_HIGH_RES_TIMERS is not set
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
@@ -301,12 +308,14 @@ CONFIG_KEXEC=y
 # CONFIG_PREEMPT_VOLUNTARY is not set
 CONFIG_PREEMPT=y
 CONFIG_GUSA=y
+# CONFIG_SPARSE_IRQ is not set
 
 #
 # Boot options
 #
 CONFIG_ZERO_PAGE_OFFSET=0x00001000
 CONFIG_BOOT_LINK_OFFSET=0x00800000
+CONFIG_ENTRY_OFFSET=0x00001000
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="console=ttySC0,115200 root=/dev/sda1"
 
@@ -445,7 +454,91 @@ CONFIG_EXTRA_FIRMWARE=""
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
 # CONFIG_CONNECTOR is not set
-# CONFIG_MTD is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+# CONFIG_MTD_CHAR is not set
+# CONFIG_MTD_BLKDEVS is not set
+# CONFIG_MTD_BLOCK is not set
+# CONFIG_MTD_BLOCK_RO is not set
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
 # CONFIG_PARPORT is not set
 CONFIG_BLK_DEV=y
 # CONFIG_BLK_CPQ_CISS_DA is not set
@@ -500,10 +593,6 @@ CONFIG_BLK_DEV_SD=y
 # CONFIG_BLK_DEV_SR is not set
 CONFIG_CHR_DEV_SG=m
 # CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
 # CONFIG_SCSI_MULTI_LUN is not set
 # CONFIG_SCSI_CONSTANTS is not set
 # CONFIG_SCSI_LOGGING is not set
@@ -521,6 +610,7 @@ CONFIG_SCSI_WAIT_SCAN=m
 CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
 # CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_SCSI_3W_9XXX is not set
 # CONFIG_SCSI_ACARD is not set
@@ -529,6 +619,7 @@ CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_AIC79XX is not set
 # CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
 # CONFIG_SCSI_ARCMSR is not set
 # CONFIG_MEGARAID_NEWGEN is not set
 # CONFIG_MEGARAID_LEGACY is not set
@@ -543,7 +634,6 @@ CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
 # CONFIG_SCSI_STEX is not set
 # CONFIG_SCSI_SYM53C8XX_2 is not set
 # CONFIG_SCSI_IPR is not set
@@ -1111,6 +1201,7 @@ CONFIG_RTC_DRV_RS5C372=y
 # on-CPU RTC drivers
 #
 CONFIG_RTC_DRV_SH=y
+# CONFIG_RTC_DRV_GENERIC is not set
 # CONFIG_DMADEVICES is not set
 # CONFIG_AUXDISPLAY is not set
 # CONFIG_UIO is not set
@@ -1138,6 +1229,7 @@ CONFIG_FILE_LOCKING=y
 # CONFIG_XFS_FS is not set
 # CONFIG_OCFS2_FS is not set
 # CONFIG_BTRFS_FS is not set
+CONFIG_FSNOTIFY=y
 CONFIG_DNOTIFY=y
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
@@ -1145,6 +1237,7 @@ CONFIG_INOTIFY_USER=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 CONFIG_FUSE_FS=m
+# CONFIG_CUSE is not set
 
 #
 # Caches
@@ -1190,6 +1283,7 @@ CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
@@ -1328,41 +1422,40 @@ CONFIG_HAVE_FUNCTION_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 CONFIG_RING_BUFFER=y
+CONFIG_EVENT_TRACING=y
+CONFIG_CONTEXT_SWITCH_TRACER=y
 CONFIG_TRACING=y
 CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
 # CONFIG_FUNCTION_TRACER is not set
 # CONFIG_IRQSOFF_TRACER is not set
 # CONFIG_PREEMPT_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
 # CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
 # CONFIG_STACK_TRACER is not set
 # CONFIG_KMEMTRACE is not set
 # CONFIG_WORKQUEUE_TRACER is not set
 # CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_RING_BUFFER_BENCHMARK is not set
 # CONFIG_DYNAMIC_DEBUG is not set
 # CONFIG_DMA_API_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
-CONFIG_SH_STANDARD_BIOS=y
-# CONFIG_EARLY_SCIF_CONSOLE is not set
-CONFIG_EARLY_PRINTK=y
+# CONFIG_SH_STANDARD_BIOS is not set
+CONFIG_EARLY_SCIF_CONSOLE=y
+CONFIG_EARLY_SCIF_CONSOLE_PORT=0xffe00000
+# CONFIG_EARLY_PRINTK is not set
 # CONFIG_DEBUG_BOOTMEM is not set
 CONFIG_DEBUG_STACKOVERFLOW=y
 # CONFIG_DEBUG_STACK_USAGE is not set
 # CONFIG_4KSTACKS is not set
-# CONFIG_IRQSTACKS is not set
 CONFIG_DUMP_CODE=y
 # CONFIG_SH_NO_BSS_INIT is not set
-# CONFIG_MORE_COMPILE_OPTIONS is not set
 
 #
 # Security options
index d2ffc477549ad6fe0897ad11df6ad015cbdf4a8e..d6303d0e494e30275bcb2da54890685aa788d97e 100644 (file)
@@ -8,6 +8,7 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7751R)       += pci-sh7751.o ops-sh4.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7763)       += pci-sh7780.o ops-sh4.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7780)       += pci-sh7780.o ops-sh4.o
 obj-$(CONFIG_CPU_SUBTYPE_SH7785)       += pci-sh7780.o ops-sh4.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7786)       += ops-sh7786.o
 obj-$(CONFIG_CPU_SH5)                  += pci-sh5.o ops-sh5.o
 
 obj-$(CONFIG_SH_DREAMCAST)             += ops-dreamcast.o fixups-dreamcast.o \
index e83d0d3aabe25b66d524f139dda49427a8974c9d..16e0a1baad88b099f30faee9f416fcc87bbdd77c 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/pci.h>
 #include <linux/module.h>
 #include <linux/io.h>
-#include <linux/irq.h>
 #include <mach/pci.h>
 
 /*
diff --git a/arch/sh/drivers/pci/ops-sh7786.c b/arch/sh/drivers/pci/ops-sh7786.c
new file mode 100644 (file)
index 0000000..48f594b
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Generic SH7786 PCI-Express operations.
+ *
+ *  Copyright (C) 2009  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include "pcie-sh7786.h"
+
+enum {
+       PCI_ACCESS_READ,
+       PCI_ACCESS_WRITE,
+};
+
+static DEFINE_SPINLOCK(sh7786_pcie_lock);
+
+static int sh7786_pcie_config_access(unsigned char access_type,
+               struct pci_bus *bus, unsigned int devfn, int where, u32 *data)
+{
+       struct pci_channel *chan = bus->sysdata;
+       int dev, func;
+
+       dev = PCI_SLOT(devfn);
+       func = PCI_FUNC(devfn);
+
+       if (bus->number > 255 || dev > 31 || func > 7)
+               return PCIBIOS_FUNC_NOT_SUPPORTED;
+       if (devfn)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       /* Set the PIO address */
+       pci_write_reg(chan, (bus->number << 24) | (dev << 19) |
+                               (func << 16) | (where & ~3), SH4A_PCIEPAR);
+
+       /* Enable the configuration access */
+       pci_write_reg(chan, (1 << 31), SH4A_PCIEPCTLR);
+
+       if (access_type == PCI_ACCESS_READ)
+               *data = pci_read_reg(chan, SH4A_PCIEPDR);
+       else
+               pci_write_reg(chan, *data, SH4A_PCIEPDR);
+
+       /* Check for master and target aborts */
+       if (pci_read_reg(chan, SH4A_PCIEPCICONF1) & ((1 << 29) | (1 << 28)))
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int sh7786_pcie_read(struct pci_bus *bus, unsigned int devfn,
+                           int where, int size, u32 *val)
+{
+       unsigned long flags;
+       int ret;
+       u32 data;
+
+        if ((size == 2) && (where & 1))
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+       else if ((size == 4) && (where & 3))
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+
+       spin_lock_irqsave(&sh7786_pcie_lock, flags);
+       ret = sh7786_pcie_config_access(PCI_ACCESS_READ, bus,
+                                       devfn, where, &data);
+       if (ret != PCIBIOS_SUCCESSFUL)
+               goto out;
+
+       if (size == 1)
+               *val = (data >> ((where & 3) << 3)) & 0xff;
+       else if (size == 2)
+               *val = (data >> ((where & 2) << 3)) & 0xffff;
+       else
+               *val = data;
+
+       dev_dbg(&bus->dev, "pcie-config-read: bus=%3d devfn=0x%04x "
+               "where=0x%04x size=%d val=0x%08lx\n", bus->number,
+               devfn, where, size, (unsigned long)*val);
+
+out:
+       spin_unlock_irqrestore(&sh7786_pcie_lock, flags);
+       return ret;
+}
+
+static int sh7786_pcie_write(struct pci_bus *bus, unsigned int devfn,
+                            int where, int size, u32 val)
+{
+       unsigned long flags;
+       int shift, ret;
+       u32 data;
+
+        if ((size == 2) && (where & 1))
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+       else if ((size == 4) && (where & 3))
+               return PCIBIOS_BAD_REGISTER_NUMBER;
+
+       spin_lock_irqsave(&sh7786_pcie_lock, flags);
+       ret = sh7786_pcie_config_access(PCI_ACCESS_READ, bus,
+                                       devfn, where, &data);
+       if (ret != PCIBIOS_SUCCESSFUL)
+               goto out;
+
+       dev_dbg(&bus->dev, "pcie-config-write: bus=%3d devfn=0x%04x "
+               "where=0x%04x size=%d val=%08lx\n", bus->number,
+               devfn, where, size, (unsigned long)val);
+
+       if (size == 1) {
+               shift = (where & 3) << 3;
+               data &= ~(0xff << shift);
+               data |= ((val & 0xff) << shift);
+       } else if (size == 2) {
+               shift = (where & 2) << 3;
+               data &= ~(0xffff << shift);
+               data |= ((val & 0xffff) << shift);
+       } else
+               data = val;
+
+       ret = sh7786_pcie_config_access(PCI_ACCESS_WRITE, bus,
+                                       devfn, where, &data);
+out:
+       spin_unlock_irqrestore(&sh7786_pcie_lock, flags);
+       return ret;
+}
+
+struct pci_ops sh7786_pci_ops = {
+       .read   = sh7786_pcie_read,
+       .write  = sh7786_pcie_write,
+};
index 54d77cbb8b39e62fa718191f1275df5b40ab8b56..9a1c423ad167705fae6ae4b1741ff1353800eb6c 100644 (file)
@@ -53,12 +53,8 @@ static DEFINE_MUTEX(pci_scan_mutex);
 
 void __devinit register_pci_controller(struct pci_channel *hose)
 {
-       if (request_resource(&iomem_resource, hose->mem_resource) < 0)
-               goto out;
-       if (request_resource(&ioport_resource, hose->io_resource) < 0) {
-               release_resource(hose->mem_resource);
-               goto out;
-       }
+       request_resource(&iomem_resource, hose->mem_resource);
+       request_resource(&ioport_resource, hose->io_resource);
 
        *hose_tail = hose;
        hose_tail = &hose->next;
@@ -80,12 +76,6 @@ void __devinit register_pci_controller(struct pci_channel *hose)
                pcibios_scanbus(hose);
                mutex_unlock(&pci_scan_mutex);
        }
-
-       return;
-
-out:
-       printk(KERN_WARNING
-              "Skipping PCI bus scan due to resource conflict\n");
 }
 
 static int __init pcibios_init(void)
diff --git a/arch/sh/drivers/pci/pcie-sh7786.h b/arch/sh/drivers/pci/pcie-sh7786.h
new file mode 100644 (file)
index 0000000..c655290
--- /dev/null
@@ -0,0 +1,589 @@
+/*
+ * SH7786 PCI-Express controller definitions.
+ *
+ * Copyright (C) 2008, 2009 Renesas Technology Corp.
+ * All rights reserved.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#ifndef __PCI_SH7786_H
+#define __PCI_SH7786_H
+
+/* PCIe bus-0(x4) on SH7786 */                 // Rev1.171
+#define SH4A_PCIE_SPW_BASE     0xFE000000      /* spw config address for controller 0 */
+#define SH4A_PCIE_SPW_BASE1    0xFE200000      /* spw config address for controller 1 (Rev1.14)*/
+#define SH4A_PCIE_SPW_BASE2    0xFCC00000      /* spw config address for controller 2 (Rev1.171)*/
+#define SH4A_PCIE_SPW_BASE_LEN 0x00080000
+
+#define SH4A_PCI_CNFG_BASE     0xFE040000      /* pci config address for controller 0 */
+#define SH4A_PCI_CNFG_BASE1    0xFE240000      /* pci config address for controller 1 (Rev1.14)*/
+#define SH4A_PCI_CNFG_BASE2    0xFCC40000      /* pci config address for controller 2 (Rev1.171)*/
+#define SH4A_PCI_CNFG_BASE_LEN 0x00040000
+
+#define SH4A_PCIPIO_ADDR_OFFSET        0x000001c0      /* offset to pci config_address */
+#define SH4A_PCIPIO_DATA_OFFSET        0x00000220      /* offset to pci config_data */
+
+/*
+ * for PEX8111(Max Payload Size=128B,PCIIO_SIZE=64K),
+ * for other(Max Payload Size=4096B,PCIIO_SIZE=8M)
+ */
+
+/* PCI0-0: PCI I/O space */
+#define SH4A_PCIIO_BASE                0xFD000000      /* PCI I/O for controller 0 */
+#define SH4A_PCIIO_BASE1       0xFD800000      /* PCI I/O for controller 1 (Rev1.14)*/
+#define SH4A_PCIIO_BASE2       0xFC800000      /* PCI I/O for controller 2 (Rev1.171)*/
+
+#define SH4A_PCIIO_SIZE64      0x00010000      /* PLX allows only 64K */
+#define SH4A_PCIIO_SIZE                0x00800000      /* 8M */
+#define SH4A_PCIIO_SIZE2       0x00400000      /* 4M (Rev1.171)*/
+
+/* PCI0-1: PCI memory space 29-bit address */
+#define SH4A_PCIMEM_BASE       0x10000000
+#define SH4A_PCIMEM_SIZE       0x04000000      /* 64M */
+
+/* PCI0-2: PCI memory space 32-bit address */
+#define SH4A_PCIMEM_BASEA      0xC0000000      /*  for controller 0 */
+#define SH4A_PCIMEM_BASEA1     0xA0000000      /*  for controller 1 (Rev1.14)*/
+#define SH4A_PCIMEM_BASEA2     0x80000000      /*  for controller 2 (Rev1.171)*/
+#define SH4A_PCIMEM_SIZEA      0x20000000      /* 512M */
+
+/* PCI0: PCI memory target transfer 32-bit address translation value(Rev1.11T)*/
+#define SH4A_PCIBMSTR_TRANSLATION      0x20000000
+
+#define SH4A_PCI_DEVICE_ID             0x0002
+#define SH4A_PCI_VENDOR_ID             0x1912
+
+// PCI compatible 000-03f
+#define PCI_CMD                0x004
+#define PCI_RID                0x008
+#define PCI_IBAR       0x010
+#define PCI_MBAR0      0x014
+#define PCI_MBAR1      0x018
+
+/* PCI power management/MSI/capablity 040-0ff */
+/* PCIE extended 100-fff */
+
+/* SH7786 device identification */     // Rev1.171
+#define SH4A_PVR               (0xFF000030)
+#define SH4A_PVR_SHX3          (0x10400000)
+#define SH4A_PRR               (0xFF000044)
+#define SH4A_PRR_SH7786                (0x00000400)    // Rev1.171
+
+/*     SPVCR0          */
+#define        SH4A_PCIEVCR0           (0x000000)      /* R - 0x0000 0000 32 */
+#define                BITS_TOP_MB     (24)
+#define                MASK_TOP_MB     (0xff<<BITS_TOP_MB)
+#define                BITS_BOT_MB     (16)
+#define                MASK_BOT_MB     (0xff<<BITS_BOT_MB)
+#define                BITS_VC_ID      (0)
+#define                MASK_VC_ID      (0xffff<<BITS_VC_ID)
+
+/*     SPVCR1          */
+#define        SH4A_PCIEVCR1           (0x000004)      /* R - 0x0000 0000 32*/
+#define                BITS_BADOPC     (5)             /* 5 BADOPC 0 R/W */
+#define                MASK_BADOPC     (1<<BITS_BADOPC)
+#define                BITS_BADDEST    (4)             /*4 BADDEST 0 R/W  */
+#define                MASK_BADDEST    (1<<BITS_BADDEST)
+#define                BITS_UNSOLRESP  (3)             /* 3 UNSOLRESP 0 R/W  */
+#define                MASK_UNSOLRESP  (1<<BITS_UNSOLRESP)
+#define                BITS_ERRSNT     (1)             /* 1 ERRSNT 0 */
+#define                MASK_ERRSNT     (1<<BITS_ERRSNT)
+#define                BITS_ERRRCV     (0)             /* 0 ERRRCV 0 */
+#define                MASK_ERRRCV     (1<<BITS_ERRRCV)
+
+/*     PCIEECR         */
+#define        SH4A_PCIEECR            (0x000008)      /* R/W - 0x0000 0000 32 */
+#define                BITS_ENBL       (0)     /* 0 ENBL 0 R/W */
+#define                MASK_ENBL       (1<<BITS_ENBL)
+
+/*     PCIEPAR         */
+#define        SH4A_PCIEPAR            (0x000010)      /* R/W - 0x0000 0000 32 */
+#define                BITS_BN         (24)
+#define                MASK_BN         (0xff<<BITS_BN)
+#define                BITS_DN         (19)
+#define                MASK_DN         (0x1f<<BITS_DN)
+#define                BITS_FN         (16)
+#define                MASK_FN         (0x7<<BITS_FN)
+#define                BITS_EREGNO     (8)
+#define                MASK_EREGNO     (0xff<<BITS_EREGNO)
+#define                BITS_REGNO      (2)
+#define                MASK_REGNO      (0x3f<<BITS_REGNO)
+
+/*     PCIEPCTLR       */
+#define        SH4A_PCIEPCTLR          (0x000018)      /* R/W - 0x0000 0000 32 */
+#define                BITS_CCIE       (31)    /*  31 CCIE */
+#define                MASK_CCIE       (1<<BITS_CCIE)
+#define                BITS_TYPE       (8)
+#define                MASK_TYPE       (1<<BITS_TYPE)
+#define                BITS_C_VC       (0)
+#define                MASK_C_VC       (1<<BITS_C_VC)
+
+/*     PCIEPDR         */
+#define        SH4A_PCIEPDR            (0x000020)      /* R/W - 0x0000 0000 32 */
+#define                BITS_PDR        (0)
+#define                MASK_PDR        (0xffffffff<<BITS_PDR)
+
+/*     PCIEMSGALR      */
+#define        SH4A_PCIEMSGALR         (0x000030)      /* R/W - 0x0000 0000 32 */
+#define                BITS_MSGADRL    (0)
+#define                MASK_MSGADRL    (0xffffffff<<BITS_MSGADRL)
+
+/*     PCIEMSGAHR      */
+#define        SH4A_PCIEMSGAHR         (0x000034)      /* R/W - 0x0000 0000 32 */
+#define                BITS_MSGADRH    (0)
+#define                MASK_MSGADRH    (0xffffffff<<BITS_MSGADRH)
+
+/*     PCIEMSGCTLR     */
+#define        SH4A_PCIEMSGCTLR        (0x000038)      /* R/W - 0x0000 0000 32 */
+#define                BITS_MSGIE      (31)
+#define                MASK_MSGIE      (1<<BITS_MSGIE)
+#define                BITS_MROUTE     (16)
+#define                MASK_MROUTE     (0x7<<BITS_MROUTE)
+#define                BITS_MCODE      (8)
+#define                MASK_MCODE      (0xff<<BITS_MCODE)
+#define                BITS_M_VC       (0)
+#define                MASK_M_VC       (1<<BITS_M_VC)
+
+/*     PCIEMSG         */
+#define        SH4A_PCIEMSG            (0x000040)      /* W - - 32     */
+#define                BITS_MDATA      (0)
+#define                MASK_MDATA      (0xffffffff<<BITS_MDATA)
+
+/*     PCIEPHYCTLR     */
+#define        SH4A_PCIEPHYCTLR        (0x010000)      /* R/W - 0x0000 0000 32 */
+#define                BITS_CKE        (0)
+#define                MASK_CKE        (1<<BITS_CKE)
+
+/*     PCIERMSGIER     */
+#define        SH4A_PCIERMSGIER        (0x004040)      /* R/W - 0x0000 0000 32 */
+
+/*     PCIEPHYADRR     */
+#define        SH4A_PCIEPHYADRR        (0x010004)      /* R/W - 0x0000 0000 32 */
+#define                BITS_ACK        (24)                    // Rev1.171
+#define                MASK_ACK        (1<<BITS_ACK)           // Rev1.171
+#define                BITS_CMD        (16)                    // Rev1.171
+#define                MASK_CMD        (0x03<<BITS_CMD)        // Rev1.171
+#define                BITS_LANE       (8)
+#define                MASK_LANE       (0x0f<<BITS_LANE)
+#define                BITS_ADR        (0)
+#define                MASK_ADR        (0xff<<BITS_ADR)
+
+/*     PCIEPHYDINR     */                                                      // Rev1.171 start.
+#define        SH4A_PCIEPHYDINR        (0x010008)      /* R/W - 0x0000 0000 32 */
+
+/*     PCIEPHYDOUTR    */
+#define        SH4A_PCIEPHYDOUTR       (0x01000C)      /* R/W - 0x0000 0000 32 */
+
+/*     PCIEPHYSR       */
+#define        SH4A_PCIEPHYSR          (0x010010)      /* R/W - 0x0000 0000 32 */      // Rev1.171 end.
+
+/*     PCIEPHYDATAR    */
+#define        SH4A_PCIEPHYDATAR       (0x00008)       /* R/W - 0xxxxx xxxx 32 */
+#define                BITS_DATA       (0)
+#define                MASK_DATA       (0xffffffff<<BITS_DATA)
+
+/*     PCIETCTLR       */
+#define        SH4A_PCIETCTLR          (0x020000)      /* R/W R/W 0x0000 0000 32 */
+#define                BITS_CFINT      (0)
+#define                MASK_CFINT      (1<<BITS_CFINT)
+
+/*     PCIETSTR        */
+#define        SH4A_PCIETSTR           (0x020004)      /* R/W R/W 0x0000 0000 32  */
+
+/*     PCIEINTR        */
+#define        SH4A_PCIEINTR           (0x020008)      /* R/W R/W 0x0000 0000 32  */
+#define                BITS_INT_RX_ERP                 (31)
+#define                MASK_INT_RX_ERP                 (1<<BITS_INT_RX_ERP)
+#define                BITS_INT_RX_VCX_Posted          (30)
+#define                MASK_INT_RX_VCX_Posted          (1<<BITS_INT_RX_VCX_Posted)
+#define                BITS_INT_RX_VCX_NonPosted       (29)
+#define                MASK_INT_RX_VCX_NonPosted       (1<<BITS_INT_RX_VCX_NonPosted)
+#define                BITS_INT_RX_VCX_CPL             (28)
+#define                MASK_INT_RX_VCX_CPL             (1<<BITS_INT_RX_VCX_CPL)
+#define                BITS_INT_TX_VCX_Posted          (26)
+#define                MASK_INT_TX_VCX_Posted          (1<<BITS_INT_TX_VCX_Posted)
+#define                BITS_INT_TX_VCX_NonPosted       (25)
+#define                MASK_INT_TX_VCX_NonPosted       (1<<BITS_INT_TX_VCX_NonPosted)
+#define                BITS_INT_TX_VCX_CPL             (24)
+#define                MASK_INT_TX_VCX_CPL             (1<<BITS_INT_TX_VCX_CPL)
+#define                BITS_INT_RX_VC0_Posted          (22)
+#define                MASK_INT_RX_VC0_Posted          (1<<BITS_INT_RX_VC0_Posted)
+#define                BITS_INT_RX_VC0_NonPosted       (21)
+#define                MASK_INT_RX_VC0_NonPosted       (1<<BITS_INT_RX_VC0_NonPosted)
+#define                BITS_INT_RX_VC0_CPL             (20)
+#define                MASK_INT_RX_VC0_CPL             (1<<BITS_INT_RX_VC0_CPL)
+#define                BITS_INT_TX_VC0_Posted          (18)
+#define                MASK_INT_TX_VC0_Posted          (1<<BITS_INT_TX_VC0_Posted)
+#define                BITS_INT_TX_VC0_NonPosted       (17)
+#define                MASK_INT_TX_VC0_NonPosted       (1<<BITS_INT_TX_VC0_NonPosted)
+#define                BITS_INT_TX_VC0_CPL             (16)
+#define                MASK_INT_TX_VC0_CPL             (1<<BITS_INT_TX_VC0_CPL)
+#define                BITS_INT_RX_CTRL                (15)
+#define                MASK_INT_RX_CTRL                (1<<BITS_INT_RX_CTRL)
+#define                BITS_INT_TX_CTRL                (14)
+#define                MASK_INT_TX_CTRL                (1<<BITS_INT_TX_CTRL)
+#define                BITS_INTTL                      (11)
+#define                MASK_INTTL                      (1<<BITS_INTTL)
+#define                BITS_INTDL                      (10)
+#define                MASK_INTDL                      (1<<BITS_INTDL)
+#define                BITS_INTMAC                     (9)
+#define                MASK_INTMAC                     (1<<BITS_INTMAC)
+#define                BITS_INTPM                      (8)
+#define                MASK_INTPM                      (1<<BITS_INTPM)
+
+/*     PCIEINTER       */
+#define        SH4A_PCIEINTER          (0x02000C)      /* R/W R/W 0x0000 0000 32 */
+#define                BITS_INT_RX_ERP                 (31)
+#define                MASK_INT_RX_ERP                 (1<<BITS_INT_RX_ERP)
+#define                BITS_INT_RX_VCX_Posted          (30)
+#define                MASK_INT_RX_VCX_Posted          (1<<BITS_INT_RX_VCX_Posted)
+#define                BITS_INT_RX_VCX_NonPosted       (29)
+#define                MASK_INT_RX_VCX_NonPosted       (1<<BITS_INT_RX_VCX_NonPosted)
+#define                BITS_INT_RX_VCX_CPL             (28)
+#define                MASK_INT_RX_VCX_CPL             (1<<BITS_INT_RX_VCX_CPL)
+#define                BITS_INT_TX_VCX_Posted          (26)
+#define                MASK_INT_TX_VCX_Posted          (1<<BITS_INT_TX_VCX_Posted)
+#define                BITS_INT_TX_VCX_NonPosted       (25)
+#define                MASK_INT_TX_VCX_NonPosted       (1<<BITS_INT_TX_VCX_NonPosted)
+#define                BITS_INT_TX_VCX_CPL             (24)
+#define                MASK_INT_TX_VCX_CPL             (1<<BITS_INT_TX_VCX_CPL)
+#define                BITS_INT_RX_VC0_Posted          (22)
+#define                MASK_INT_RX_VC0_Posted          (1<<BITS_INT_RX_VC0_Posted)
+#define                BITS_INT_RX_VC0_NonPosted       (21)
+#define                MASK_INT_RX_VC0_NonPosted       (1<<BITS_INT_RX_VC0_NonPosted)
+#define                BITS_INT_RX_VC0_CPL             (20)
+#define                MASK_INT_RX_VC0_CPL             (1<<BITS_INT_RX_VC0_CPL)
+#define                BITS_INT_TX_VC0_Posted          (18)
+#define                MASK_INT_TX_VC0_Posted          (1<<BITS_INT_TX_VC0_Posted)
+#define                BITS_INT_TX_VC0_NonPosted       (17)
+#define                MASK_INT_TX_VC0_NonPosted       (1<<BITS_INT_TX_VC0_NonPosted)
+#define                BITS_INT_TX_VC0_CPL             (16)
+#define                MASK_INT_TX_VC0_CPL             (1<<BITS_INT_TX_VC0_CPL)
+#define                BITS_INT_RX_CTRL                (15)
+#define                MASK_INT_RX_CTRL                (1<<BITS_INT_RX_CTRL)
+#define                BITS_INT_TX_CTRL                (14)
+#define                MASK_INT_TX_CTRL                (1<<BITS_INT_TX_CTRL)
+#define                BITS_INTTL                      (11)
+#define                MASK_INTTL                      (1<<BITS_INTTL)
+#define                BITS_INTDL                      (10)
+#define                MASK_INTDL                      (1<<BITS_INTDL)
+#define                BITS_INTMAC                     (9)
+#define                MASK_INTMAC                     (1<<BITS_INTMAC)
+#define                BITS_INTPM                      (8)
+#define                MASK_INTPM                      (1<<BITS_INTPM)
+
+/*     PCIEAIR  */
+#define        SH4A_PCIEAIR            (SH4A_PCIE_BASE + 0x020010)     /* R/W R/W 0xxxxx xxxx 32 */
+
+/*      PCIECIR         */
+#define        SH4A_PCIECIR            (SH4A_PCIE_BASE)        /* R/W R/W 0xxxxx xxxx 32 */
+
+/*      PCIEERRFR       */                                                             // Rev1.18
+#define        SH4A_PCIEERRFR          (0x020020)              /* R/W R/W 0xxxxx xxxx 32 */    // Rev1.18
+                                                                                       // Rev1.18
+/*     PCIELAR0        */
+#define        SH4A_PCIELAR0           (0x020200)      /* R/W R/W 0x0000 0000 32 */
+#define                BITS_LARn       (20)
+#define                MASK_LARn       (0xfff<<BITS_LARn)
+
+#define        SH4A_PCIE_020204        (0x020204)      /* R/W R/W 0x0000 0000 32 */
+
+/*     PCIELAMR0       */
+#define        SH4A_PCIELAMR0          (0x020208)      /* R/W R/W 0x0000 0000 32 */
+#define                BITS_LAMRn      (20)
+#define                MASK_LAMRn      (0x1ff<<BITS_LAMRn)
+#define                BITS_LAREn      (0)
+#define                MASK_LAREn      (0x1<<BITS_LAREn)
+
+/*     PCIECSCR0       */
+#define        SH4A_PCIECSCR0          (0x020210)      /* R/W R/W 0x0000 0000 32 */
+#define                BITS_RANGE      (2)
+#define                MASK_RANGE      (0x7<<BITS_RANGE)
+#define                BITS_SNPMD      (0)
+#define                MASK_SNPMD      (0x3<<BITS_SNPMD)
+
+/*     PCIECSAR0       */
+#define        SH4A_PCIECSAR0          (0x020214)      /* R/W R/W 0x0000 0000 32 */
+#define                BITS_CSADR      (0)
+#define                MASK_CSADR      (0xffffffff<<BITS_CSADR)
+
+/*     PCIESTCTLR0     */
+#define        SH4A_PCIESTCTLR0        (0x020218)      /* R/W R/W 0x0000 0000 32 */
+#define                BITS_SHPRI      (8)
+#define                MASK_SHPRI      (0x0f<<BITS_SHPRI)
+
+#define        SH4A_PCIE_020224        (0x020224)      /* R/W R/W 0x0000 0000 32 */
+
+#define        SH4A_PCIELAR1           (0x020220)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIELAMR1          (0x020228)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIECSCR1          (0x020230)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIECSAR1          (0x020234)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIESTCTLR1        (0x020238)      /* R/W R/W 0x0000 0000 32 */
+
+#define        SH4A_PCIELAR2           (0x020240)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIE_020244        (0x020244)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIELAMR2          (0x020248)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIECSCR2          (0x020250)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIECSAR2          (0x020254)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIESTCTLR2        (0x020258)      /* R/W R/W 0x0000 0000 32 */
+
+#define        SH4A_PCIELAR3           (0x020260)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIE_020264        (0x020264)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIELAMR3          (0x020268)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIECSCR3          (0x020270)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIECSAR3          (0x020274)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIESTCTLR3        (0x020278)      /* R/W R/W 0x0000 0000 32 */
+
+#define        SH4A_PCIELAR4           (0x020280)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIE_020284        (0x020284)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIELAMR4          (0x020288)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIECSCR4          (0x020290)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIECSAR4          (0x020294)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIESTCTLR4        (0x020298)      /* R/W R/W 0x0000 0000 32 */
+
+#define        SH4A_PCIELAR5           (0x0202A0)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIE_0202A4        (0x0202A4)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIELAMR5          (0x0202A8)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIECSCR5          (0x0202B0)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIECSAR5          (0x0202B4)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIESTCTLR5        (0x0202B8)      /* R/W R/W 0x0000 0000 32 */
+
+/*     PCIEPARL0       */
+#define        SH4A_PCIEPARL0          (0x020400)      /* R/W R/W 0x0000 0000 32 */
+#define                BITS_PAL        (18)
+#define                MASK_PAL        (0x3fff<<BITS_PAL)
+
+/*     PCIEPARH0       */
+#define        SH4A_PCIEPARH0          (0x020404)      /* R/W R/W 0x0000 0000 32 */
+#define                BITS_PAH        (0)
+#define                MASK_PAH        (0xffffffff<<BITS_PAH)
+
+/*     PCIEPAMR0        */
+#define        SH4A_PCIEPAMR0          (0x020408)      /* R/W R/W 0x0000 0000 32 */
+#define                BITS_PAM        (18)
+#define                MASK_PAM        (0x3fff<<BITS_PAM)
+
+/*     PCIEPTCTLR0     */
+#define        SH4A_PCIEPTCTLR0        (0x02040C)      /* R/W R/W 0x0000 0000 32 */
+#define                BITS_PARE       (31)
+#define                MASK_PARE       (0x1<<BITS_PARE)
+#define                BITS_TC         (20)
+#define                MASK_TC         (0x7<<BITS_TC)
+#define                BITS_T_VC       (16)
+#define                MASK_T_VC       (0x1<<BITS_T_VC)
+#define                BITS_LOCK       (12)
+#define                MASK_LOCK       (0x1<<BITS_LOCK)
+#define                BITS_SPC        (8)
+#define                MASK_SPC        (0x1<<BITS_SPC)
+
+#define        SH4A_PCIEPARL1          (0x020420)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEPARH1          (0x020424)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEPAMR1          (0x020428)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEPTCTLR1        (0x02042C)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEPARL2          (0x020440)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEPARH2          (0x020444)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEPAMR2          (0x020448)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEPTCTLR2        (0x02044C)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEPARL3          (0x020460)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEPARH3          (0x020464)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEPAMR3          (0x020468)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEPTCTLR3        (0x02046C)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEPARL4          (0x020480)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEPARH4          (0x020484)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEPAMR4          (0x020488)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEPTCTLR4        (0x02048C)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEPARL5          (0x0204A0)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEPARH5          (0x0204A4)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEPAMR5          (0x0204A8)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEPTCTLR5        (0x0204AC)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMAOR          (0x021000)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMSAR0         (0x021100)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMSAHR0        (0x021104)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMDAR0         (0x021108)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMDAHR0        (0x02110C)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMBCNTR0       (0x021110)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMSBCNTR0      (0x021114)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMSTRR0        (0x021118)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMCCAR0        (0x02111C)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMCCR0         (0x021120)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMCC2R0        (0x021124)      /* R/W R/W 0x0000 0000 - */
+#define        SH4A_PCIEDMCCCR0        (0x021128)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMSAR1         (0x021140)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMSAHR1        (0x021144)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMDAR1         (0x021148)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMDAHR1        (0x02114C)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMBCNTR1       (0x021150)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMSBCNTR1      (0x021154)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMSTRR1        (0x021158)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMCCAR1        (0x02115C)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMCCR1         (0x021160)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMCC2R1        (0x021164)      /* R/W R/W 0x0000 0000 - */
+#define        SH4A_PCIEDMCCCR1        (0x021168)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMSAR2         (0x021180)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMSAHR2        (0x021184)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMDAR2         (0x021188)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMDAHR2        (0x02118C)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMBCNTR2       (0x021190)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMSBCNTR2      (0x021194)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMSTRR2        (0x021198)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMCCAR2        (0x02119C)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMCCR2         (0x0211A0)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMCC2R2        (0x0211A4)      /* R/W R/W 0x0000 0000 -  */
+#define        SH4A_PCIEDMCCCR2        (0x0211A8)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMSAR3         (0x0211C0)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMSAHR3        (0x0211C4)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMDAR3         (0x0211C8)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMDAHR3        (0x0211CC)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMBCNTR3       (0x0211D0)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMSBCNTR3      (0x0211D4)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMSTRR3        (0x0211D8)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMCCAR3        (0x0211DC)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMCCR3         (0x0211E0)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEDMCC2R3        (0x0211E4)      /* R/W R/W 0x0000 0000 -  */
+#define        SH4A_PCIEDMCCCR3        (0x0211E8)      /* R/W R/W 0x0000 0000 32 */
+#define        SH4A_PCIEPCICONF0       (0x040000)      /* R R - 8/16/32 */
+#define        SH4A_PCIEPCICONF1       (0x040004)      /* R/W R/W 0x0008 0000 8/16/32 */
+#define        SH4A_PCIEPCICONF2       (0x040008)      /* R/W R/W 0xFF00 0000 8/16/32 */
+#define        SH4A_PCIEPCICONF3       (0x04000C)      /* R/W R/W 0x0000 0000 8/16/32 */
+#define        SH4A_PCIEPCICONF4       (0x040010)      /* - R/W - 8/16/32 */
+#define        SH4A_PCIEPCICONF5       (0x040014)      /* - R/W - 8/16/32 */
+#define        SH4A_PCIEPCICONF6       (0x040018)      /* - R/W - 8/16/32 */
+#define        SH4A_PCIEPCICONF7       (0x04001C)      /* - R/W - 8/16/32 */
+#define        SH4A_PCIEPCICONF8       (0x040020)      /* - R/W - 8/16/32 */
+#define        SH4A_PCIEPCICONF9       (0x040024)      /* - R/W - 8/16/32 */
+#define        SH4A_PCIEPCICONF10      (0x040028)      /* R/W R/W 0x0000 0000 8/16/32 */
+#define        SH4A_PCIEPCICONF11      (0x04002C)      /* R/W R/W 0x0000 0000 8/16/32 */
+#define        SH4A_PCIEPCICONF12      (0x040030)      /* R/W R/W 0x0000 0000 8/16/32 */
+#define        SH4A_PCIEPCICONF13      (0x040034)      /* R/W R/W 0x0000 0040 8/16/32 */
+#define        SH4A_PCIEPCICONF14      (0x040038)      /* R/W R/W 0x0000 0000 8/16/32 */
+#define        SH4A_PCIEPCICONF15      (0x04003C)      /* R/W R/W 0x0000 00FF 8/16/32 */
+#define        SH4A_PCIEPMCAP0         (0x040040)      /* R/W R 0x0003 5001 8/16/32 */
+#define        SH4A_PCIEPMCAP1         (0x040044)      /* R/W R/W 0x0000 0000 8/16/32 */
+#define        SH4A_PCIEMSICAP0        (0x040050)      /* R/W R/W 0x0180 7005 8/16/32 */
+#define        SH4A_PCIEMSICAP1        (0x040054)      /* R/W R/W 0x0000 0000 8/16/32 */
+#define        SH4A_PCIEMSICAP2        (0x040058)      /* R/W R/W 0x0000 0000 8/16/32 */
+#define        SH4A_PCIEMSICAP3        (0x04005C)      /* R/W R/W 0x0000 0000 8/16/32 */
+#define        SH4A_PCIEMSICAP4        (0x040060)      /* R/W R/W 0x0000 0000 8/16/32 */
+#define        SH4A_PCIEMSICAP5        (0x040064)      /* R/W R/W 0x0000 0000 8/16/32 */
+#define        SH4A_PCIEEXPCAP0        (0x040070)      /* R/W R/W 0x0001 0010 8/16/32 */
+#define        SH4A_PCIEEXPCAP1        (0x040074)      /* R/W R 0x0000 0005 8/16/32 */
+#define        SH4A_PCIEEXPCAP2        (0x040078)      /* R/W R/W 0x0000 0801 8/16/32 */
+#define        SH4A_PCIEEXPCAP3        (0x04007C)      /* R/W R 0x0003 F421 8/16/32 */
+#define        SH4A_PCIEEXPCAP4        (0x040080)      /* R/W R/W 0x0041 0000 8/16/32 */
+#define        SH4A_PCIEEXPCAP5        (0x040084)      /* R/W R/W 0x0000 0000 8/16/32 */
+#define        SH4A_PCIEEXPCAP6        (0x040088)      /* R/W R/W 0x0000 03C0 8/16/32 */
+#define        SH4A_PCIEEXPCAP7        (0x04008C)      /* R/W R/W 0x0000 0000 8/16/32 */
+#define        SH4A_PCIEEXPCAP8        (0x040090)      /* R/W R/W 0x0000 0000 8/16/32 */
+#define        SH4A_PCIEVCCAP0         (0x040100)      /* R/W R 0x1B01 0002 8/16/32 */
+#define        SH4A_PCIEVCCAP1         (0x040104)      /* R R 0x0000 0001 8/16/32 */
+#define        SH4A_PCIEVCCAP2         (0x040108)      /* R R 0x0000 0000 8/16/32 */
+#define        SH4A_PCIEVCCAP3         (0x04010C)      /* R R/W 0x0000 0000 8/16/32 */
+#define        SH4A_PCIEVCCAP4         (0x040110)      /* R/W R/W 0x0000 0000 8/16/32 */
+#define        SH4A_PCIEVCCAP5         (0x040114)      /* R/W R/W 0x8000 00FF 8/16/32 */
+#define        SH4A_PCIEVCCAP6         (0x040118)      /* R/W R 0x0002 0000 8/16/32 */
+#define        SH4A_PCIEVCCAP7         (0x04011C)      /* R/W R/W 0x0000 0000 8/16/32 */
+#define        SH4A_PCIEVCCAP8         (0x040120)      /* R/W R/W 0x0000 0000 8/16/32 */
+#define        SH4A_PCIEVCCAP9         (0x040124)      /* R/W R 0x0002 0000 8/16/32 */
+#define        SH4A_PCIENUMCAP0        (0x0001B0)      /* RW R 0x0001 0003 8/16/32 */
+#define        SH4A_PCIENUMCAP1        (0x0001B4)      /* R R 0x0000 0000 8/16/32 */
+#define        SH4A_PCIENUMCAP2        (0x0001B8)      /* R R 0x0000 0000 8/16/32 */
+#define        SH4A_PCIEIDSETR0        (0x041000)      /* R/W R 0x0000 FFFF 16/32 */
+#define        SH4A_PCIEIDSETR1        (0x041004)      /* R/W R 0xFF00 0000 16/32 */
+#define        SH4A_PCIEBAR0SETR       (0x041008)      /* R/W R 0x0000 0000 16/32 */
+#define        SH4A_PCIEBAR1SETR       (0x04100C)      /* R/W R 0x0000 0000 16/32 */
+#define        SH4A_PCIEBAR2SETR       (0x041010)      /* R/W R 0x0000 0000 16/32 */
+#define        SH4A_PCIEBAR3SETR       (0x041014)      /* R/W R 0x0000 0000 16/32 */
+#define        SH4A_PCIEBAR4SETR       (0x041018)      /* R/W R 0x0000 0000 16/32 */
+#define        SH4A_PCIEBAR5SETR       (0x04101C)      /* R/W R 0x0000 0000 16/32 */
+#define        SH4A_PCIECISSETR        (0x041020)      /* R/W R 0x0000 0000 16/32 */
+#define        SH4A_PCIEIDSETR2        (0x041024)      /* R/W R 0x0000 0000 16/32 */
+#define        SH4A_PCIEEROMSETR       (0x041028)      /* R/W R 0x0000 0000 16/32 */
+#define        SH4A_PCIEDSERSETR0      (0x04102C)      /* R/W R 0x0000 0000 16/32 */
+#define        SH4A_PCIEDSERSETR1      (0x041030)      /* R/W R 0x0000 0000 16/32 */
+#define        SH4A_PCIECTLR           (0x041040)      /* R/W R 0x0000 0000 16/32 */
+#define        SH4A_PCIETLSR           (0x041044)      /* R/W1C R 0x0000 0000 16/32 */
+#define        SH4A_PCIETLCTLR         (0x041048)      /* R/W R 0x0000 0000 16/32 */
+#define        SH4A_PCIEDLSR           (0x04104C)      /* R/W1C R 0x4003 0000 16/32 */
+#define        SH4A_PCIEDLCTLR         (0x041050)      /* R R 0x0000 0000 16/32 */
+#define        SH4A_PCIEMACSR          (0x041054)      /* R/W1C R 0x0041 0000 16/32 */
+#define        SH4A_PCIEMACCTLR        (0x041058)      /* R/W R 0x0000 0000 16/32 */
+#define                PCIEMACCTLR_SCR_DIS     (1 << 27)       /* scramble disable */
+#define        SH4A_PCIEPMSTR          (0x04105C)      /* R/W1C R 0x0000 0000 16/32 */
+#define        SH4A_PCIEPMCTLR         (0x041060)      /* R/W R 0x0000 0000 16/32 */
+#define        SH4A_PCIETLINTENR       (0x041064)      /* R/W R 0x0000 0000 16/32 */
+#define        SH4A_PCIEDLINTENR       (0x041068)      /* R/W R 0x0000 0000 16/32 */
+#define                PCIEDLINTENR_DLL_ACT_ENABLE     (1 << 31) /* DL active irq */
+#define        SH4A_PCIEMACINTENR      (0x04106C)      /* R/W R 0x0000 0000 16/32 */
+#define        SH4A_PCIEPMINTENR       (0x041070)      /* R/W R 0x0000 0000 16/32 */
+#define        SH4A_PCIETXDCTLR        (0x044000)      /* R/W - H'00000000_00000000 32/64 */
+#define        SH4A_PCIETXCTLR         (0x044020)      /* R/W - H'00000000_00000000 32/64 */
+#define        SH4A_PCIETXSR           (0x044028)      /* R - H'00000000_00000000 32/64 */
+#define        SH4A_PCIETXVC0DCTLR     (0x044100)      /* R/W - H'00000000_00000000 32/64 */
+#define        SH4A_PCIETXVC0SR        (0x044108)      /* R/W - H'00888000_00000000 32/64 */
+#define        SH4A_PCIEVC0PDTXR       (0x044110)      /* W - H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVC0PHTXR       (0x044118)      /* W - H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVC0NPDTXR      (0x044120)      /* W - H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVC0NPHTXR      (0x044128)      /* W - H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVC0CDTXR       (0x044130)      /* W - H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVC0CHTXR       (0x044138)      /* W - H'00000000_00000000 32/64 */
+#define        SH4A_PCIETXVCXDCTLR     (0x044200)      /* R/W - H'00000000_00000000 32/64 */
+#define        SH4A_PCIETXVCXSR        (0x044208)      /* R/W - H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVCXPDTXR       (0x044210)      /* W - H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVCXPHTXR       (0x044218)      /* W - H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVCXNPDTXR      (0x044220)      /* W - H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVCXNPHTXR      (0x044228)      /* W - H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVCXCDTXR       (0x044230)      /* W - H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVCXCHTXR       (0x044238)      /* W - H'00000000_00000000 32/64 */
+#define        SH4A_PCIERDCTLR         (0x046000)      /* RW - H'00000000_00000000 32/64 */
+#define        SH4A_PCIEERPCTLR        (0x046008)      /* RW - H'00000000_00000000 32/64 */
+#define        SH4A_PCIEERPHR          (0x046010)      /* R - H'00000000_00000000 32/64 */
+#define        SH4A_PCIEERPERR         (0x046018)      /* R - H'00000000_00000000 32/64 */
+#define        SH4A_PCIERXVC0DCTLR     (0x046100)      /* RW - H'00000000_00000000 32/64 */
+#define        SH4A_PCIERXVC0SR        (0x046108)      /* RW - H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVC0PDRXR       (0x046140)      /* R - H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVC0PHRXR       (0x046148)      /* R - H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVC0PERR        (0x046150)      /* R - H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVC0NPDRXR      (0x046158)      /* R - H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVC0NPHRXR      (0x046160)      /* R - H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVC0NPERR       (0x046168)      /* R - H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVC0CDRXR       (0x046170)      /* R - H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVC0CHRXR       (0x046178)      /* R - H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVC0CERR        (0x046180)      /* R - H'00000000_00000000 32/64 */
+#define        SH4A_PCIERXVCXDCTLR     (0x046200)      /* RW - H'00000000_00000000 32/64 */
+#define        SH4A_PCIERXVCXSR        (0x046208)      /* RW - H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVCXPDRXR       (0x046240)      /* R - H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVCXPHRXR       (0x046248)      /* R H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVCXPERR        (0x046250)      /* R H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVCXNPDRXR      (0x046258)      /* R H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVCXNPHRXR      (0x046260)      /* R H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVCXNPERR       (0x046268)      /* R H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVCXCDRXR       (0x046270)      /* R H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVCXCHRXR       (0x046278)      /* R H'00000000_00000000 32/64 */
+#define        SH4A_PCIEVCXCERR        (0x046280)      /* R H'00000000_00000000 32/64 */
+
+/* SSI Register Definition for MSI WORK AROUND --hamada */
+#define SH4A_PCI_SSI_BASE      0xFFE00000      /* spw config address   */
+#define SH4A_PCI_SSI_BASE_LEN  0x00100000      /* 1MB                  */
+
+#define        SH4A_SSICR0             (0x000000)
+#define        SH4A_SSICR1             (0x010000)
+#define        SH4A_SSICR2             (0x020000)
+#define        SH4A_SSICR3             (0x030000)
+
+#define PCI_REG(x)             ((x) + 0x40000)
+
+static inline void
+pci_write_reg(struct pci_channel *chan, unsigned long val, unsigned long reg)
+{
+       __raw_writel(val, chan->reg_base + reg);
+}
+
+static inline unsigned long
+pci_read_reg(struct pci_channel *chan, unsigned long reg)
+{
+       return __raw_readl(chan->reg_base + reg);
+}
+
+#endif /* __PCI_SH7786_H */
index a0b348068cae66f4407760abde7013d0e7034f7a..467d9415a32e5d9ae4c331e6569fc4b26b55bfdb 100644 (file)
@@ -10,29 +10,29 @@ static inline void atomic_add(int i, atomic_t *v)
 {
        unsigned long flags;
 
-       local_irq_save(flags);
+       raw_local_irq_save(flags);
        v->counter += i;
-       local_irq_restore(flags);
+       raw_local_irq_restore(flags);
 }
 
 static inline void atomic_sub(int i, atomic_t *v)
 {
        unsigned long flags;
 
-       local_irq_save(flags);
+       raw_local_irq_save(flags);
        v->counter -= i;
-       local_irq_restore(flags);
+       raw_local_irq_restore(flags);
 }
 
 static inline int atomic_add_return(int i, atomic_t *v)
 {
        unsigned long temp, flags;
 
-       local_irq_save(flags);
+       raw_local_irq_save(flags);
        temp = v->counter;
        temp += i;
        v->counter = temp;
-       local_irq_restore(flags);
+       raw_local_irq_restore(flags);
 
        return temp;
 }
@@ -41,11 +41,11 @@ static inline int atomic_sub_return(int i, atomic_t *v)
 {
        unsigned long temp, flags;
 
-       local_irq_save(flags);
+       raw_local_irq_save(flags);
        temp = v->counter;
        temp -= i;
        v->counter = temp;
-       local_irq_restore(flags);
+       raw_local_irq_restore(flags);
 
        return temp;
 }
@@ -54,18 +54,18 @@ static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
 {
        unsigned long flags;
 
-       local_irq_save(flags);
+       raw_local_irq_save(flags);
        v->counter &= ~mask;
-       local_irq_restore(flags);
+       raw_local_irq_restore(flags);
 }
 
 static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
 {
        unsigned long flags;
 
-       local_irq_save(flags);
+       raw_local_irq_save(flags);
        v->counter |= mask;
-       local_irq_restore(flags);
+       raw_local_irq_restore(flags);
 }
 
 #endif /* __ASM_SH_ATOMIC_IRQ_H */
index 157c320272cbb256b8e13915534ba80bd66227ac..e8e78137c6f556650e45c4c4c1c064836c4be61c 100644 (file)
@@ -85,4 +85,6 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
 #define smp_mb__after_atomic_inc()     barrier()
 
 #include <asm-generic/atomic-long.h>
+#include <asm-generic/atomic64.h>
+
 #endif /* __ASM_SH_ATOMIC_H */
index 67496ab0ef0421c166fd9a33a56c7e1249c2d10a..fc26d1f4b5900f932905592d0f803732e5ab1966 100644 (file)
@@ -1,5 +1,5 @@
 #ifdef CONFIG_SUPERH32
 # include "checksum_32.h"
 #else
-# include "checksum_64.h"
+# include <asm-generic/checksum.h>
 #endif
diff --git a/arch/sh/include/asm/checksum_64.h b/arch/sh/include/asm/checksum_64.h
deleted file mode 100644 (file)
index 9c62a03..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-#ifndef __ASM_SH_CHECKSUM_64_H
-#define __ASM_SH_CHECKSUM_64_H
-
-/*
- * include/asm-sh/checksum_64.h
- *
- * Copyright (C) 2000, 2001  Paolo Alberelli
- *
- * 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.
- */
-
-/*
- * computes the checksum of a memory block at buff, length len,
- * and adds in "sum" (32-bit)
- *
- * returns a 32-bit number suitable for feeding into itself
- * or csum_tcpudp_magic
- *
- * this function must be called with even lengths, except
- * for the last fragment, which may be odd
- *
- * it's best to have buff aligned on a 32-bit boundary
- */
-asmlinkage __wsum csum_partial(const void *buff, int len, __wsum sum);
-
-/*
- *     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
- *     access_ok().
- */
-
-
-__wsum csum_partial_copy_nocheck(const void *src, void *dst, int len,
-                                      __wsum sum);
-
-__wsum csum_partial_copy_from_user(const void __user *src, void *dst,
-                                        int len, __wsum sum, int *err_ptr);
-
-static inline __sum16 csum_fold(__wsum csum)
-{
-       u32 sum = (__force u32)csum;
-        sum = (sum & 0xffff) + (sum >> 16);
-        sum = (sum & 0xffff) + (sum >> 16);
-        return (__force __sum16)~sum;
-}
-
-__sum16 ip_fast_csum(const void *iph, unsigned int ihl);
-
-__wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
-                                unsigned short len, unsigned short proto,
-                                __wsum sum);
-
-/*
- * 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)
-{
-       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)
-{
-       return csum_fold(csum_partial(buff, len, 0));
-}
-
-#endif /* __ASM_SH_CHECKSUM_64_H */
index 62b63880b3332a4a209039e65b09db8607d80b22..4c51401b5537c20d6f37923cfaa2e564bc54de4d 100644 (file)
@@ -1,20 +1 @@
-#ifndef __ASM_SH_CURRENT_H
-#define __ASM_SH_CURRENT_H
-
-/*
- * Copyright (C) 1999 Niibe Yutaka
- *
- */
-
-#include <linux/thread_info.h>
-
-struct task_struct;
-
-static __inline__ struct task_struct * get_current(void)
-{
-       return current_thread_info()->task;
-}
-
-#define current get_current()
-
-#endif /* __ASM_SH_CURRENT_H */
+#include <asm-generic/current.h>
index 6bd17847387849008d62bcd6316a8ad460c4aa68..04ad0e1e637e44d2f1d6c2349583f5cf7f889dcd 100644 (file)
 #include <linux/sched.h>
 #include <linux/sysdev.h>
 #include <cpu/dma.h>
-
-/* The maximum address that we can perform a DMA transfer to on this platform */
-/* Don't define MAX_DMA_ADDRESS; it's useless on the SuperH and any
-   occurrence should be flagged as an error.  */
-/* But... */
-/* XXX: This is not applicable to SuperH, just needed for alloc_bootmem */
-#define MAX_DMA_ADDRESS                (PAGE_OFFSET+0x10000000)
+#include <asm-generic/dma.h>
 
 #ifdef CONFIG_NR_DMA_CHANNELS
 #  define MAX_DMA_CHANNELS   (CONFIG_NR_DMA_CHANNELS)
@@ -137,8 +131,6 @@ extern int dma_xfer(unsigned int chan, unsigned long from,
 
 extern int request_dma_bycap(const char **dmac, const char **caps,
                             const char *dev_id);
-extern int request_dma(unsigned int chan, const char *dev_id);
-extern void free_dma(unsigned int chan);
 extern int get_dma_residue(unsigned int chan);
 extern struct dma_info *get_dma_info(unsigned int chan);
 extern struct dma_channel *get_dma_channel(unsigned int chan);
index 5ffc9972a7eaf0f77e185cddd981dab4b8248e94..84c7e51cb6d0befd2b3c013c8bbbbaad6ae02297 100644 (file)
@@ -1,29 +1 @@
-#ifndef __ASM_SH_IPCBUF_H__
-#define __ASM_SH_IPCBUF_H__
-
-/*
- * The ipc64_perm structure for i386 architecture.
- * Note extra padding because this structure is passed back and forth
- * between kernel and user space.
- *
- * Pad space is left for:
- * - 32-bit mode_t and seq
- * - 2 miscellaneous 32-bit values
- */
-
-struct ipc64_perm
-{
-       __kernel_key_t          key;
-       __kernel_uid32_t        uid;
-       __kernel_gid32_t        gid;
-       __kernel_uid32_t        cuid;
-       __kernel_gid32_t        cgid;
-       __kernel_mode_t         mode;
-       unsigned short          __pad1;
-       unsigned short          seq;
-       unsigned short          __pad2;
-       unsigned long           __unused1;
-       unsigned long           __unused2;
-};
-
-#endif /* __ASM_SH_IPCBUF_H__ */
+#include <asm-generic/ipcbuf.h>
index a2b8c99cc06f1a6453bd9162e1e0c34e6a9b0dee..df8e1500527cedfe88267f6c9a590994acc0e9ad 100644 (file)
@@ -39,7 +39,6 @@ static inline int generic_irq_demux(int irq)
        return irq;
 }
 
-#define irq_canonicalize(irq)  (irq)
 #define irq_demux(irq)         sh_mv.mv_irq_demux(irq)
 
 void init_IRQ(void);
@@ -54,6 +53,7 @@ extern void irq_ctx_exit(int cpu);
 # define irq_ctx_exit(cpu) do { } while (0)
 #endif
 
+#include <asm-generic/irq.h>
 #ifdef CONFIG_CPU_SH5
 #include <cpu/irq.h>
 #endif
index 84d565c696befbaee91e7770721d1ec2a5ed6f8c..5962b08b6dd8a6258cdeb646fd723a86c0b81cde 100644 (file)
@@ -3,30 +3,12 @@
 
 /* Dummy header just to define km_type. */
 
-
 #ifdef CONFIG_DEBUG_HIGHMEM
-# define D(n) __KM_FENCE_##n ,
-#else
-# define D(n)
+#define  __WITH_KM_FENCE
 #endif
 
-enum km_type {
-D(0)   KM_BOUNCE_READ,
-D(1)   KM_SKB_SUNRPC_DATA,
-D(2)   KM_SKB_DATA_SOFTIRQ,
-D(3)   KM_USER0,
-D(4)   KM_USER1,
-D(5)   KM_BIO_SRC_IRQ,
-D(6)   KM_BIO_DST_IRQ,
-D(7)   KM_PTE0,
-D(8)   KM_PTE1,
-D(9)   KM_IRQ0,
-D(10)  KM_IRQ1,
-D(11)  KM_SOFTIRQ0,
-D(12)  KM_SOFTIRQ1,
-D(13)  KM_TYPE_NR
-};
+#include <asm-generic/kmap_types.h>
 
-#undef D
+#undef __WITH_KM_FENCE
 
 #endif
index 7d8b72c91a5f45d25db9dca3d5d88c6cd5454836..8eebf89f5ab17884a98543f3b37a3b710355083b 100644 (file)
@@ -1,17 +1 @@
-#ifndef __ASM_SH_MMAN_H
-#define __ASM_SH_MMAN_H
-
-#include <asm-generic/mman-common.h>
-
-#define MAP_GROWSDOWN  0x0100          /* stack-like segment */
-#define MAP_DENYWRITE  0x0800          /* ETXTBSY */
-#define MAP_EXECUTABLE 0x1000          /* mark it as an executable */
-#define MAP_LOCKED     0x2000          /* pages are locked */
-#define MAP_NORESERVE  0x4000          /* don't check for reservations */
-#define MAP_POPULATE   0x8000          /* populate (prefault) page tables */
-#define MAP_NONBLOCK   0x10000         /* do not block on IO */
-
-#define MCL_CURRENT    1               /* lock all current mappings */
-#define MCL_FUTURE     2               /* lock all future mappings */
-
-#endif /* __ASM_SH_MMAN_H */
+#include <asm-generic/mman.h>
index 2a9c55f1a83f9f7429104b4c2671460d7caba373..67d8946db19343bd673caeeb839aa1a9f231b8fe 100644 (file)
@@ -122,30 +122,30 @@ static inline void switch_mm(struct mm_struct *prev,
        unsigned int cpu = smp_processor_id();
 
        if (likely(prev != next)) {
-               cpu_set(cpu, next->cpu_vm_mask);
+               cpumask_set_cpu(cpu, mm_cpumask(next));
                set_TTB(next->pgd);
                activate_context(next, cpu);
        } else
-               if (!cpu_test_and_set(cpu, next->cpu_vm_mask))
+               if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next)))
                        activate_context(next, cpu);
 }
+
+#define activate_mm(prev, next)                switch_mm((prev),(next),NULL)
+#define deactivate_mm(tsk,mm)          do { } while (0)
+#define enter_lazy_tlb(mm,tsk)         do { } while (0)
+
 #else
-#define get_mmu_context(mm)            do { } while (0)
-#define init_new_context(tsk,mm)       (0)
-#define destroy_context(mm)            do { } while (0)
+
 #define set_asid(asid)                 do { } while (0)
 #define get_asid()                     (0)
 #define cpu_asid(cpu, mm)              ({ (void)cpu; NO_CONTEXT; })
 #define switch_and_save_asid(asid)     (0)
 #define set_TTB(pgd)                   do { } while (0)
 #define get_TTB()                      (0)
-#define activate_context(mm,cpu)       do { } while (0)
-#define switch_mm(prev,next,tsk)       do { } while (0)
-#endif /* CONFIG_MMU */
 
-#define activate_mm(prev, next)                switch_mm((prev),(next),NULL)
-#define deactivate_mm(tsk,mm)          do { } while (0)
-#define enter_lazy_tlb(mm,tsk)         do { } while (0)
+#include <asm-generic/mmu_context.h>
+
+#endif /* CONFIG_MMU */
 
 #if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4)
 /*
index 46eccd33166052851f25ffcb7259ac5666c2b26d..068bf1659750def61fe9e35f1dbb01a20d3fbd0b 100644 (file)
@@ -1,17 +1,7 @@
 #ifndef _ASM_SH_MODULE_H
 #define _ASM_SH_MODULE_H
 
-/*
- * This file contains the SH architecture specific module code.
- */
-
-struct mod_arch_specific {
-       /* Nothing to see here .. */
-};
-
-#define Elf_Shdr               Elf32_Shdr
-#define Elf_Sym                        Elf32_Sym
-#define Elf_Ehdr               Elf32_Ehdr
+#include <asm-generic/module.h>
 
 #ifdef CONFIG_CPU_LITTLE_ENDIAN
 # ifdef CONFIG_CPU_SH2
index 517432343fb5d9eb2dc84e92372ed8dc8a22a8ea..809134c644a677032e9eb2ae5d5a844806bc347e 100644 (file)
@@ -1,31 +1 @@
-#ifndef __ASM_SH_MSGBUF_H
-#define __ASM_SH_MSGBUF_H
-
-/* 
- * The msqid64_ds structure for i386 architecture.
- * Note extra padding because this structure is passed back and forth
- * between kernel and user space.
- *
- * Pad space is left for:
- * - 64-bit time_t to solve y2038 problem
- * - 2 miscellaneous 32-bit values
- */
-
-struct msqid64_ds {
-       struct ipc64_perm msg_perm;
-       __kernel_time_t msg_stime;      /* last msgsnd time */
-       unsigned long   __unused1;
-       __kernel_time_t msg_rtime;      /* last msgrcv time */
-       unsigned long   __unused2;
-       __kernel_time_t msg_ctime;      /* last change time */
-       unsigned long   __unused3;
-       unsigned long  msg_cbytes;      /* current number of bytes on queue */
-       unsigned long  msg_qnum;        /* number of messages in queue */
-       unsigned long  msg_qbytes;      /* max number of bytes on queue */
-       __kernel_pid_t msg_lspid;       /* pid of last msgsnd */
-       __kernel_pid_t msg_lrpid;       /* last receive pid */
-       unsigned long  __unused4;
-       unsigned long  __unused5;
-};
-
-#endif /* __ASM_SH_MSGBUF_H */
+#include <asm-generic/msgbuf.h>
index ae245afdfd6a1844d4373ea9a552fb6a669dcb4a..965d45427975907ae67efb45e20c8f500fd1ad3a 100644 (file)
@@ -1,22 +1 @@
-#ifndef __ASM_SH_PARAM_H
-#define __ASM_SH_PARAM_H
-
-#ifdef __KERNEL__
-# define HZ            CONFIG_HZ
-# define USER_HZ       100             /* User interfaces are in "ticks" */
-# define CLOCKS_PER_SEC        (USER_HZ)       /* frequency at which times() counts */
-#endif
-
-#ifndef HZ
-#define HZ 100
-#endif
-
-#define EXEC_PAGESIZE  4096
-
-#ifndef NOGROUP
-#define NOGROUP                (-1)
-#endif
-
-#define MAXHOSTNAMELEN 64      /* max length of hostname */
-
-#endif /* __ASM_SH_PARAM_H */
+#include <asm-generic/param.h>
index f67ba60a2acd802f63f55a04913b8720ae4d7f9c..cf252af6459087e0d01e92362bc7e2d5170e4c94 100644 (file)
@@ -1,16 +1 @@
-/*
- * Copyright (C) 1999, 2000  Tim Waugh <tim@cyberelk.demon.co.uk>
- *
- * This file should only be included by drivers/parport/parport_pc.c.
- */
-#ifndef __ASM_SH_PARPORT_H
-#define __ASM_SH_PARPORT_H
-
-static int __devinit parport_pc_find_isa_ports(int autoirq, int autodma);
-
-static int __devinit parport_pc_find_nonpci_ports(int autoirq, int autodma)
-{
-       return parport_pc_find_isa_ports(autoirq, autodma);
-}
-
-#endif /* __ASM_SH_PARPORT_H */
+#include <asm-generic/parport.h>
diff --git a/arch/sh/include/asm/perf_counter.h b/arch/sh/include/asm/perf_counter.h
new file mode 100644 (file)
index 0000000..a8153c2
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __ASM_SH_PERF_COUNTER_H
+#define __ASM_SH_PERF_COUNTER_H
+
+/* SH only supports software counters through this interface. */
+#define set_perf_counter_pending()     do { } while (0)
+
+#endif /* __ASM_SH_PERF_COUNTER_H */
index 2172732c55c841c2628ccdc7e7d7ca9a57d32e18..6a9ceaaf1aea7f0545736634e08d979c3b020e88 100644 (file)
-#ifndef __ASM_SH_POSIX_TYPES_H
-#define __ASM_SH_POSIX_TYPES_H
+#ifndef __ASM_SH_POSIX_TYPES_32_H
+#define __ASM_SH_POSIX_TYPES_32_H
 
-/*
- * This file is generally used by user-level software, so you need to
- * be a little careful about namespace pollution etc.  Also, we cannot
- * assume GCC is being used.
- */
-
-typedef unsigned long  __kernel_ino_t;
 typedef unsigned short __kernel_mode_t;
+#define __kernel_mode_t __kernel_mode_t
 typedef unsigned short __kernel_nlink_t;
-typedef long           __kernel_off_t;
-typedef int            __kernel_pid_t;
+#define __kernel_nlink_t __kernel_nlink_t
 typedef unsigned short __kernel_ipc_pid_t;
+#define __kernel_ipc_pid_t __kernel_ipc_pid_t
 typedef unsigned short __kernel_uid_t;
+#define __kernel_uid_t __kernel_uid_t
 typedef unsigned short __kernel_gid_t;
-typedef unsigned int   __kernel_size_t;
-typedef int            __kernel_ssize_t;
-typedef int            __kernel_ptrdiff_t;
-typedef long           __kernel_time_t;
-typedef long           __kernel_suseconds_t;
-typedef long           __kernel_clock_t;
-typedef int            __kernel_timer_t;
-typedef int            __kernel_clockid_t;
-typedef int            __kernel_daddr_t;
-typedef char *         __kernel_caddr_t;
-typedef unsigned short __kernel_uid16_t;
-typedef unsigned short __kernel_gid16_t;
+#define __kernel_gid_t __kernel_gid_t
+
 typedef unsigned int   __kernel_uid32_t;
+#define __kernel_uid32_t __kernel_uid32_t
 typedef unsigned int   __kernel_gid32_t;
+#define __kernel_gid32_t __kernel_gid32_t
 
 typedef unsigned short __kernel_old_uid_t;
+#define __kernel_old_uid_t __kernel_old_uid_t
 typedef unsigned short __kernel_old_gid_t;
+#define __kernel_old_gid_t __kernel_old_gid_t
 typedef unsigned short __kernel_old_dev_t;
+#define __kernel_old_dev_t __kernel_old_dev_t
 
-#ifdef __GNUC__
-typedef long long      __kernel_loff_t;
-#endif
-
-typedef struct {
-       int     val[2];
-} __kernel_fsid_t;
-
-#if defined(__KERNEL__)
-
-#undef __FD_SET
-static __inline__ void __FD_SET(unsigned long __fd, __kernel_fd_set *__fdsetp)
-{
-       unsigned long __tmp = __fd / __NFDBITS;
-       unsigned long __rem = __fd % __NFDBITS;
-       __fdsetp->fds_bits[__tmp] |= (1UL<<__rem);
-}
-
-#undef __FD_CLR
-static __inline__ void __FD_CLR(unsigned long __fd, __kernel_fd_set *__fdsetp)
-{
-       unsigned long __tmp = __fd / __NFDBITS;
-       unsigned long __rem = __fd % __NFDBITS;
-       __fdsetp->fds_bits[__tmp] &= ~(1UL<<__rem);
-}
-
-
-#undef __FD_ISSET
-static __inline__ int __FD_ISSET(unsigned long __fd, const __kernel_fd_set *__p)
-{ 
-       unsigned long __tmp = __fd / __NFDBITS;
-       unsigned long __rem = __fd % __NFDBITS;
-       return (__p->fds_bits[__tmp] & (1UL<<__rem)) != 0;
-}
-
-/*
- * This will unroll the loop for the normal constant case (8 ints,
- * for a 256-bit fd_set)
- */
-#undef __FD_ZERO
-static __inline__ void __FD_ZERO(__kernel_fd_set *__p)
-{
-       unsigned long *__tmp = __p->fds_bits;
-       int __i;
-
-       if (__builtin_constant_p(__FDSET_LONGS)) {
-               switch (__FDSET_LONGS) {
-               case 16:
-                       __tmp[ 0] = 0; __tmp[ 1] = 0;
-                       __tmp[ 2] = 0; __tmp[ 3] = 0;
-                       __tmp[ 4] = 0; __tmp[ 5] = 0;
-                       __tmp[ 6] = 0; __tmp[ 7] = 0;
-                       __tmp[ 8] = 0; __tmp[ 9] = 0;
-                       __tmp[10] = 0; __tmp[11] = 0;
-                       __tmp[12] = 0; __tmp[13] = 0;
-                       __tmp[14] = 0; __tmp[15] = 0;
-                       return;
-
-               case 8:
-                       __tmp[ 0] = 0; __tmp[ 1] = 0;
-                       __tmp[ 2] = 0; __tmp[ 3] = 0;
-                       __tmp[ 4] = 0; __tmp[ 5] = 0;
-                       __tmp[ 6] = 0; __tmp[ 7] = 0;
-                       return;
-
-               case 4:
-                       __tmp[ 0] = 0; __tmp[ 1] = 0;
-                       __tmp[ 2] = 0; __tmp[ 3] = 0;
-                       return;
-               }
-       }
-       __i = __FDSET_LONGS;
-       while (__i) {
-               __i--;
-               *__tmp = 0;
-               __tmp++;
-       }
-}
-
-#endif /* defined(__KERNEL__) */
+#include <asm-generic/posix_types.h>
 
-#endif /* __ASM_SH_POSIX_TYPES_H */
+#endif /* __ASM_SH_POSIX_TYPES_32_H */
index f83e9bd463d8fe2062b0b0ed40331ad16caf6d19..8cd11485c06bc1ac693fcc96f1018a9e209321fd 100644 (file)
-#ifndef __ASM_SH64_POSIX_TYPES_H
-#define __ASM_SH64_POSIX_TYPES_H
+#ifndef __ASM_SH_POSIX_TYPES_64_H
+#define __ASM_SH_POSIX_TYPES_64_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.
- *
- * include/asm-sh64/posix_types.h
- *
- * Copyright (C) 2000, 2001  Paolo Alberelli
- * Copyright (C) 2003  Paul Mundt
- *
- * This file is generally used by user-level software, so you need to
- * be a little careful about namespace pollution etc.  Also, we cannot
- * assume GCC is being used.
- */
-
-typedef unsigned long  __kernel_ino_t;
 typedef unsigned short __kernel_mode_t;
+#define __kernel_mode_t __kernel_mode_t
 typedef unsigned short __kernel_nlink_t;
-typedef long           __kernel_off_t;
-typedef int            __kernel_pid_t;
+#define __kernel_nlink_t __kernel_nlink_t
 typedef unsigned short __kernel_ipc_pid_t;
+#define __kernel_ipc_pid_t __kernel_ipc_pid_t
 typedef unsigned short __kernel_uid_t;
+#define __kernel_uid_t __kernel_uid_t
 typedef unsigned short __kernel_gid_t;
+#define __kernel_gid_t __kernel_gid_t
 typedef long unsigned int      __kernel_size_t;
+#define __kernel_size_t __kernel_size_t
 typedef int            __kernel_ssize_t;
+#define __kernel_ssize_t __kernel_ssize_t
 typedef int            __kernel_ptrdiff_t;
-typedef long           __kernel_time_t;
-typedef long           __kernel_suseconds_t;
-typedef long           __kernel_clock_t;
-typedef int            __kernel_timer_t;
-typedef int            __kernel_clockid_t;
-typedef int            __kernel_daddr_t;
-typedef char *         __kernel_caddr_t;
-typedef unsigned short __kernel_uid16_t;
-typedef unsigned short __kernel_gid16_t;
+#define __kernel_ptrdiff_t __kernel_ptrdiff_t
 typedef unsigned int   __kernel_uid32_t;
+#define __kernel_uid32_t __kernel_uid32_t
 typedef unsigned int   __kernel_gid32_t;
+#define __kernel_gid32_t __kernel_gid32_t
 
 typedef unsigned short __kernel_old_uid_t;
+#define __kernel_old_uid_t __kernel_old_uid_t
 typedef unsigned short __kernel_old_gid_t;
+#define __kernel_old_gid_t __kernel_old_gid_t
 typedef unsigned short __kernel_old_dev_t;
+#define __kernel_old_dev_t __kernel_old_dev_t
 
-#ifdef __GNUC__
-typedef long long      __kernel_loff_t;
-#endif
-
-typedef struct {
-       int     val[2];
-} __kernel_fsid_t;
-
-#if defined(__KERNEL__)
-
-#undef __FD_SET
-static __inline__ void __FD_SET(unsigned long __fd, __kernel_fd_set *__fdsetp)
-{
-       unsigned long __tmp = __fd / __NFDBITS;
-       unsigned long __rem = __fd % __NFDBITS;
-       __fdsetp->fds_bits[__tmp] |= (1UL<<__rem);
-}
-
-#undef __FD_CLR
-static __inline__ void __FD_CLR(unsigned long __fd, __kernel_fd_set *__fdsetp)
-{
-       unsigned long __tmp = __fd / __NFDBITS;
-       unsigned long __rem = __fd % __NFDBITS;
-       __fdsetp->fds_bits[__tmp] &= ~(1UL<<__rem);
-}
-
-
-#undef __FD_ISSET
-static __inline__ int __FD_ISSET(unsigned long __fd, const __kernel_fd_set *__p)
-{
-       unsigned long __tmp = __fd / __NFDBITS;
-       unsigned long __rem = __fd % __NFDBITS;
-       return (__p->fds_bits[__tmp] & (1UL<<__rem)) != 0;
-}
-
-/*
- * This will unroll the loop for the normal constant case (8 ints,
- * for a 256-bit fd_set)
- */
-#undef __FD_ZERO
-static __inline__ void __FD_ZERO(__kernel_fd_set *__p)
-{
-       unsigned long *__tmp = __p->fds_bits;
-       int __i;
-
-       if (__builtin_constant_p(__FDSET_LONGS)) {
-               switch (__FDSET_LONGS) {
-               case 16:
-                       __tmp[ 0] = 0; __tmp[ 1] = 0;
-                       __tmp[ 2] = 0; __tmp[ 3] = 0;
-                       __tmp[ 4] = 0; __tmp[ 5] = 0;
-                       __tmp[ 6] = 0; __tmp[ 7] = 0;
-                       __tmp[ 8] = 0; __tmp[ 9] = 0;
-                       __tmp[10] = 0; __tmp[11] = 0;
-                       __tmp[12] = 0; __tmp[13] = 0;
-                       __tmp[14] = 0; __tmp[15] = 0;
-                       return;
-
-               case 8:
-                       __tmp[ 0] = 0; __tmp[ 1] = 0;
-                       __tmp[ 2] = 0; __tmp[ 3] = 0;
-                       __tmp[ 4] = 0; __tmp[ 5] = 0;
-                       __tmp[ 6] = 0; __tmp[ 7] = 0;
-                       return;
-
-               case 4:
-                       __tmp[ 0] = 0; __tmp[ 1] = 0;
-                       __tmp[ 2] = 0; __tmp[ 3] = 0;
-                       return;
-               }
-       }
-       __i = __FDSET_LONGS;
-       while (__i) {
-               __i--;
-               *__tmp = 0;
-               __tmp++;
-       }
-}
-
-#endif /* defined(__KERNEL__) */
+#include <asm-generic/posix_types.h>
 
-#endif /* __ASM_SH64_POSIX_TYPES_H */
+#endif /* __ASM_SH_POSIX_TYPES_64_H */
index c693d268a41358b943adc608ed4b6caac91f77e3..327cc2e4c97bb174da3b9d5f8cef96d300902c98 100644 (file)
@@ -1,28 +1,8 @@
 #ifndef __ASM_SH_SCATTERLIST_H
 #define __ASM_SH_SCATTERLIST_H
 
-#include <asm/types.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
-       unsigned long   sg_magic;
-#endif
-       unsigned long   page_link;
-       unsigned int    offset;         /* for highmem, page offset */
-       unsigned int    length;
-       dma_addr_t      dma_address;
-       unsigned int    dma_length;
-};
-
 #define ISA_DMA_THRESHOLD      PHYS_ADDR_MASK
 
-/* These macros should be used after a pci_map_sg call has been done
- * to get bus addresses of each of the SG entries and their lengths.
- * You should only work with the number of sg entries pci_map_sg
- * returns, or alternatively stop on the first sg_dma_len(sg) which
- * is 0.
- */
-#define sg_dma_address(sg)     ((sg)->dma_address)
-#define sg_dma_len(sg)         ((sg)->length)
+#include <asm-generic/scatterlist.h>
 
-#endif /* !(__ASM_SH_SCATTERLIST_H) */
+#endif /* __ASM_SH_SCATTERLIST_H */
index d79f3bd570b2fca760b2771df9dc777ca638baa5..7673b83cfef73397301a171e86cf492b771ad9b4 100644 (file)
@@ -1,25 +1 @@
-#ifndef __ASM_SH_SEMBUF_H
-#define __ASM_SH_SEMBUF_H
-
-/* 
- * The semid64_ds structure for i386 architecture.
- * Note extra padding because this structure is passed back and forth
- * between kernel and user space.
- *
- * Pad space is left for:
- * - 64-bit time_t to solve y2038 problem
- * - 2 miscellaneous 32-bit values
- */
-
-struct semid64_ds {
-       struct ipc64_perm sem_perm;             /* permissions .. see ipc.h */
-       __kernel_time_t sem_otime;              /* last semop time */
-       unsigned long   __unused1;
-       __kernel_time_t sem_ctime;              /* last change time */
-       unsigned long   __unused2;
-       unsigned long   sem_nsems;              /* no. of semaphores in array */
-       unsigned long   __unused3;
-       unsigned long   __unused4;
-};
-
-#endif /* __ASM_SH_SEMBUF_H */
+#include <asm-generic/sembuf.h>
index 11f854dd13632cb29d619d8b56e95339a5de091b..a0cb0caff15241a41973f67b68756510b8bfe90e 100644 (file)
@@ -1,19 +1 @@
-/*
- * include/asm-sh/serial.h
- *
- * Configuration details for 8250, 16450, 16550, etc. serial ports
- */
-
-#ifndef _ASM_SERIAL_H
-#define _ASM_SERIAL_H
-
-/*
- * This assumes you have a 1.8432 MHz clock for your UART.
- *
- * It'd be nice if someone built a serial card with a 24.576 MHz
- * clock, since the 16550A is capable of handling a top speed of 1.5
- * megabits/second; but this requires the faster clock.
- */
-#define BASE_BAUD ( 1843200 / 16 )
-
-#endif /* _ASM_SERIAL_H */
+#include <asm-generic/serial.h>
index d450bcf59ee2548c0db6f239ce7f4363941a02f0..ce3743599b2794289a2a38d6d44bdf831d6b4276 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _SH_SETUP_H
 #define _SH_SETUP_H
 
-#define COMMAND_LINE_SIZE 256
+#include <asm-generic/setup.h>
 
 #ifdef __KERNEL__
 /*
index b2101f490521827a18c50b683f7268b5a1014853..83c05fc2de385c3260286bf12fed846617c8c095 100644 (file)
@@ -1,42 +1 @@
-#ifndef __ASM_SH_SHMBUF_H
-#define __ASM_SH_SHMBUF_H
-
-/* 
- * The shmid64_ds structure for i386 architecture.
- * Note extra padding because this structure is passed back and forth
- * between kernel and user space.
- *
- * Pad space is left for:
- * - 64-bit time_t to solve y2038 problem
- * - 2 miscellaneous 32-bit values
- */
-
-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;
-};
-
-struct shminfo64 {
-       unsigned long   shmmax;
-       unsigned long   shmmin;
-       unsigned long   shmmni;
-       unsigned long   shmseg;
-       unsigned long   shmall;
-       unsigned long   __unused1;
-       unsigned long   __unused2;
-       unsigned long   __unused3;
-       unsigned long   __unused4;
-};
-
-#endif /* __ASM_SH_SHMBUF_H */
+#include <asm-generic/shmbuf.h>
index 9cc5f014468905a3bef54d80a399391aa2e98c8f..9ac530a90bcef1eeec9c14fa4a914ab0953b2f6c 100644 (file)
 #ifndef __ASM_SH_SIGNAL_H
 #define __ASM_SH_SIGNAL_H
 
-#include <linux/types.h>
-
-/* Avoid too many header ordering problems.  */
-struct pt_regs;
-struct siginfo;
-
-#ifdef __KERNEL__
-/* Most things should be clean enough to redefine this at will, if care
-   is taken to make libc match.  */
-
-#define _NSIG          64
-#define _NSIG_BPW      32
-#define _NSIG_WORDS    (_NSIG / _NSIG_BPW)
-
-typedef unsigned long old_sigset_t;            /* at least 32 bits */
-
-typedef struct {
-       unsigned long sig[_NSIG_WORDS];
-} sigset_t;
-
-#else
-/* Here we must cater to libcs that poke about in kernel headers.  */
-
-#define NSIG           32
-typedef unsigned long sigset_t;
-
-#endif /* __KERNEL__ */
-
-#define SIGHUP          1
-#define SIGINT          2
-#define SIGQUIT                 3
-#define SIGILL          4
-#define SIGTRAP                 5
-#define SIGABRT                 6
-#define SIGIOT          6
-#define SIGBUS          7
-#define SIGFPE          8
-#define SIGKILL                 9
-#define SIGUSR1                10
-#define SIGSEGV                11
-#define SIGUSR2                12
-#define SIGPIPE                13
-#define SIGALRM                14
-#define SIGTERM                15
-#define SIGSTKFLT      16
-#define SIGCHLD                17
-#define SIGCONT                18
-#define SIGSTOP                19
-#define SIGTSTP                20
-#define SIGTTIN                21
-#define SIGTTOU                22
-#define SIGURG         23
-#define SIGXCPU                24
-#define SIGXFSZ                25
-#define SIGVTALRM      26
-#define SIGPROF                27
-#define SIGWINCH       28
-#define SIGIO          29
-#define SIGPOLL                SIGIO
-/*
-#define SIGLOST                29
-*/
-#define SIGPWR         30
-#define SIGSYS         31
-#define        SIGUNUSED       31
-
-/* These should not be considered constants from userland.  */
-#define SIGRTMIN       32
-#define SIGRTMAX       _NSIG
-
-/*
- * SA_FLAGS values:
- *
- * SA_ONSTACK indicates that a registered stack_t will be used.
- * SA_RESTART flag to get restarting signals (which were the default long ago)
- * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
- * SA_RESETHAND clears the handler when the signal is delivered.
- * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
- * SA_NODEFER prevents the current signal from being masked in the handler.
- *
- * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
- * Unix names RESETHAND and NODEFER respectively.
- */
-#define SA_NOCLDSTOP   0x00000001
-#define SA_NOCLDWAIT   0x00000002
-#define SA_SIGINFO     0x00000004
-#define SA_ONSTACK     0x08000000
-#define SA_RESTART     0x10000000
-#define SA_NODEFER     0x40000000
-#define SA_RESETHAND   0x80000000
-
-#define SA_NOMASK      SA_NODEFER
-#define SA_ONESHOT     SA_RESETHAND
-
 #define SA_RESTORER    0x04000000
 
-/* 
- * sigaltstack controls
- */
-#define SS_ONSTACK     1
-#define SS_DISABLE     2
-
-#define MINSIGSTKSZ    2048
-#define SIGSTKSZ       8192
+#include <asm-generic/signal.h>
 
-#include <asm-generic/signal-defs.h>
-
-#ifdef __KERNEL__
 struct old_sigaction {
        __sighandler_t sa_handler;
        old_sigset_t sa_mask;
@@ -116,45 +12,4 @@ struct old_sigaction {
        void (*sa_restorer)(void);
 };
 
-struct sigaction {
-       __sighandler_t sa_handler;
-       unsigned long sa_flags;
-       void (*sa_restorer)(void);
-       sigset_t sa_mask;               /* mask last for extensibility */
-};
-
-struct k_sigaction {
-       struct sigaction sa;
-};
-#else
-/* Here we must cater to libcs that poke about in kernel headers.  */
-
-struct sigaction {
-       union {
-         __sighandler_t _sa_handler;
-         void (*_sa_sigaction)(int, struct siginfo *, void *);
-       } _u;
-       sigset_t sa_mask;
-       unsigned long sa_flags;
-       void (*sa_restorer)(void);
-};
-
-#define sa_handler     _u._sa_handler
-#define sa_sigaction   _u._sa_sigaction
-
-#endif /* __KERNEL__ */
-
-typedef struct sigaltstack {
-       void *ss_sp;
-       int ss_flags;
-       size_t ss_size;
-} stack_t;
-
-#ifdef __KERNEL__
-#include <asm/sigcontext.h>
-
-#define ptrace_signal_deliver(regs, cookie) do { } while (0)
-
-#endif /* __KERNEL__ */
-
 #endif /* __ASM_SH_SIGNAL_H */
index c24e9c6a173661a307e2b2f90b9dc3ea961551ed..ca64f43abe67e3e50debcd068c35c2c6eb96f96e 100644 (file)
@@ -43,7 +43,8 @@ void plat_start_cpu(unsigned int cpu, unsigned long entry_point);
 void plat_send_ipi(unsigned int cpu, unsigned int message);
 
 void arch_send_call_function_single_ipi(int cpu);
-void arch_send_call_function_ipi(cpumask_t mask);
+extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
+#define arch_send_call_function_ipi_mask arch_send_call_function_ipi_mask
 
 #else
 
index 345653b968263521f967e7968cd1be2709daaea7..6b71384b9d8b42ac6cce8a955a73220bda4957d5 100644 (file)
@@ -1,60 +1 @@
-#ifndef __ASM_SH_SOCKET_H
-#define __ASM_SH_SOCKET_H
-
-#include <asm/sockios.h>
-
-/* For setsockopt(2) */
-#define SOL_SOCKET     1
-
-#define SO_DEBUG       1
-#define SO_REUSEADDR   2
-#define SO_TYPE                3
-#define SO_ERROR       4
-#define SO_DONTROUTE   5
-#define SO_BROADCAST   6
-#define SO_SNDBUF      7
-#define SO_RCVBUF      8
-#define SO_RCVBUFFORCE 32
-#define SO_SNDBUFFORCE 33
-#define SO_KEEPALIVE   9
-#define SO_OOBINLINE   10
-#define SO_NO_CHECK    11
-#define SO_PRIORITY    12
-#define SO_LINGER      13
-#define SO_BSDCOMPAT   14
-/* To add :#define SO_REUSEPORT 15 */
-#define SO_PASSCRED    16
-#define SO_PEERCRED    17
-#define SO_RCVLOWAT    18
-#define SO_SNDLOWAT    19
-#define SO_RCVTIMEO    20
-#define SO_SNDTIMEO    21
-
-/* Security levels - as per NRL IPv6 - don't actually do anything */
-#define SO_SECURITY_AUTHENTICATION             22
-#define SO_SECURITY_ENCRYPTION_TRANSPORT       23
-#define SO_SECURITY_ENCRYPTION_NETWORK         24
-
-#define SO_BINDTODEVICE        25
-
-/* Socket filtering */
-#define SO_ATTACH_FILTER        26
-#define SO_DETACH_FILTER        27
-
-#define SO_PEERNAME             28
-#define SO_TIMESTAMP           29
-#define SCM_TIMESTAMP          SO_TIMESTAMP
-
-#define SO_ACCEPTCONN          30
-
-#define SO_PEERSEC             31
-#define SO_PASSSEC             34
-#define SO_TIMESTAMPNS         35
-#define SCM_TIMESTAMPNS                SO_TIMESTAMPNS
-
-#define SO_MARK                        36
-
-#define SO_TIMESTAMPING                37
-#define SCM_TIMESTAMPING       SO_TIMESTAMPING
-
-#endif /* __ASM_SH_SOCKET_H */
+#include <asm-generic/socket.h>
index 0e08fe54ad71fcdb30b2a46756736e88bcdd3d34..1cd09767a7a3eed746b860d928316017dfd191f5 100644 (file)
@@ -7,8 +7,7 @@
  */
 #include <linux/compiler.h>
 #include <linux/types.h>
-
-#define __SWAB_64_THRU_32__
+#include <asm-generic/swab.h>
 
 static inline __attribute_const__ __u32 __arch_swab32(__u32 x)
 {
index 77db116948cf392a8ec3571f3d32c3cabc5a2d7e..3935b106de79bf2f8469b849576268ac1ca30bb2 100644 (file)
@@ -1,198 +1 @@
-#ifndef __ASM_SH_TERMBITS_H
-#define __ASM_SH_TERMBITS_H
-
-#include <linux/posix_types.h>
-
-typedef unsigned char  cc_t;
-typedef unsigned int   speed_t;
-typedef unsigned int   tcflag_t;
-
-#define NCCS 19
-struct termios {
-       tcflag_t c_iflag;               /* input mode flags */
-       tcflag_t c_oflag;               /* output mode flags */
-       tcflag_t c_cflag;               /* control mode flags */
-       tcflag_t c_lflag;               /* local mode flags */
-       cc_t c_line;                    /* line discipline */
-       cc_t c_cc[NCCS];                /* control characters */
-};
-
-struct termios2 {
-       tcflag_t c_iflag;               /* input mode flags */
-       tcflag_t c_oflag;               /* output mode flags */
-       tcflag_t c_cflag;               /* control mode flags */
-       tcflag_t c_lflag;               /* local mode flags */
-       cc_t c_line;                    /* line discipline */
-       cc_t c_cc[NCCS];                /* control characters */
-       speed_t c_ispeed;               /* input speed */
-       speed_t c_ospeed;               /* output speed */
-};
-
-struct ktermios {
-       tcflag_t c_iflag;               /* input mode flags */
-       tcflag_t c_oflag;               /* output mode flags */
-       tcflag_t c_cflag;               /* control mode flags */
-       tcflag_t c_lflag;               /* local mode flags */
-       cc_t c_line;                    /* line discipline */
-       cc_t c_cc[NCCS];                /* control characters */
-       speed_t c_ispeed;               /* input speed */
-       speed_t c_ospeed;               /* output speed */
-};
-
-/* c_cc characters */
-#define VINTR 0
-#define VQUIT 1
-#define VERASE 2
-#define VKILL 3
-#define VEOF 4
-#define VTIME 5
-#define VMIN 6
-#define VSWTC 7
-#define VSTART 8
-#define VSTOP 9
-#define VSUSP 10
-#define VEOL 11
-#define VREPRINT 12
-#define VDISCARD 13
-#define VWERASE 14
-#define VLNEXT 15
-#define VEOL2 16
-
-/* c_iflag bits */
-#define IGNBRK 0000001
-#define BRKINT 0000002
-#define IGNPAR 0000004
-#define PARMRK 0000010
-#define INPCK  0000020
-#define ISTRIP 0000040
-#define INLCR  0000100
-#define IGNCR  0000200
-#define ICRNL  0000400
-#define IUCLC  0001000
-#define IXON   0002000
-#define IXANY  0004000
-#define IXOFF  0010000
-#define IMAXBEL        0020000
-#define IUTF8  0040000
-
-/* c_oflag bits */
-#define OPOST  0000001
-#define OLCUC  0000002
-#define ONLCR  0000004
-#define OCRNL  0000010
-#define ONOCR  0000020
-#define ONLRET 0000040
-#define OFILL  0000100
-#define OFDEL  0000200
-#define NLDLY  0000400
-#define   NL0  0000000
-#define   NL1  0000400
-#define CRDLY  0003000
-#define   CR0  0000000
-#define   CR1  0001000
-#define   CR2  0002000
-#define   CR3  0003000
-#define TABDLY 0014000
-#define   TAB0 0000000
-#define   TAB1 0004000
-#define   TAB2 0010000
-#define   TAB3 0014000
-#define   XTABS        0014000
-#define BSDLY  0020000
-#define   BS0  0000000
-#define   BS1  0020000
-#define VTDLY  0040000
-#define   VT0  0000000
-#define   VT1  0040000
-#define FFDLY  0100000
-#define   FF0  0000000
-#define   FF1  0100000
-
-/* c_cflag bit meaning */
-#define CBAUD  0010017
-#define  B0    0000000         /* hang up */
-#define  B50   0000001
-#define  B75   0000002
-#define  B110  0000003
-#define  B134  0000004
-#define  B150  0000005
-#define  B200  0000006
-#define  B300  0000007
-#define  B600  0000010
-#define  B1200 0000011
-#define  B1800 0000012
-#define  B2400 0000013
-#define  B4800 0000014
-#define  B9600 0000015
-#define  B19200        0000016
-#define  B38400        0000017
-#define EXTA B19200
-#define EXTB B38400
-#define CSIZE  0000060
-#define   CS5  0000000
-#define   CS6  0000020
-#define   CS7  0000040
-#define   CS8  0000060
-#define CSTOPB 0000100
-#define CREAD  0000200
-#define PARENB 0000400
-#define PARODD 0001000
-#define HUPCL  0002000
-#define CLOCAL 0004000
-#define CBAUDEX 0010000
-#define           BOTHER 0010000
-#define    B57600 0010001
-#define   B115200 0010002
-#define   B230400 0010003
-#define   B460800 0010004
-#define   B500000 0010005
-#define   B576000 0010006
-#define   B921600 0010007
-#define  B1000000 0010010
-#define  B1152000 0010011
-#define  B1500000 0010012
-#define  B2000000 0010013
-#define  B2500000 0010014
-#define  B3000000 0010015
-#define  B3500000 0010016
-#define  B4000000 0010017
-#define CIBAUD   002003600000          /* input baud rate */
-#define CMSPAR   010000000000          /* mark or space (stick) parity */
-#define CRTSCTS          020000000000          /* flow control */
-
-#define IBSHIFT        16              /* Shift from CBAUD to CIBAUD */
-
-/* c_lflag bits */
-#define ISIG   0000001
-#define ICANON 0000002
-#define XCASE  0000004
-#define ECHO   0000010
-#define ECHOE  0000020
-#define ECHOK  0000040
-#define ECHONL 0000100
-#define NOFLSH 0000200
-#define TOSTOP 0000400
-#define ECHOCTL        0001000
-#define ECHOPRT        0002000
-#define ECHOKE 0004000
-#define FLUSHO 0010000
-#define PENDIN 0040000
-#define IEXTEN 0100000
-
-/* tcflow() and TCXONC use these */
-#define        TCOOFF          0
-#define        TCOON           1
-#define        TCIOFF          2
-#define        TCION           3
-
-/* tcflush() and TCFLSH use these */
-#define        TCIFLUSH        0
-#define        TCOFLUSH        1
-#define        TCIOFLUSH       2
-
-/* tcsetattr uses these */
-#define        TCSANOW         0
-#define        TCSADRAIN       1
-#define        TCSAFLUSH       2
-
-#endif /* __ASM_SH_TERMBITS_H */
+#include <asm-generic/termbits.h>
index 0a8c793c76f234a1c8ded118ed4f2a7d7eaf1de6..280d78a9d96637ccbc93bc4c0debc88eb9443bba 100644 (file)
@@ -1,90 +1 @@
-#ifndef __ASM_SH_TERMIOS_H
-#define __ASM_SH_TERMIOS_H
-
-#include <asm/termbits.h>
-#include <asm/ioctls.h>
-
-struct winsize {
-       unsigned short ws_row;
-       unsigned short ws_col;
-       unsigned short ws_xpixel;
-       unsigned short ws_ypixel;
-};
-
-#define NCC 8
-struct termio {
-       unsigned short c_iflag;         /* input mode flags */
-       unsigned short c_oflag;         /* output mode flags */
-       unsigned short c_cflag;         /* control mode flags */
-       unsigned short c_lflag;         /* local mode flags */
-       unsigned char c_line;           /* line discipline */
-       unsigned char c_cc[NCC];        /* control characters */
-};
-
-/* modem lines */
-#define TIOCM_LE       0x001
-#define TIOCM_DTR      0x002
-#define TIOCM_RTS      0x004
-#define TIOCM_ST       0x008
-#define TIOCM_SR       0x010
-#define TIOCM_CTS      0x020
-#define TIOCM_CAR      0x040
-#define TIOCM_RNG      0x080
-#define TIOCM_DSR      0x100
-#define TIOCM_CD       TIOCM_CAR
-#define TIOCM_RI       TIOCM_RNG
-#define TIOCM_OUT1     0x2000
-#define TIOCM_OUT2     0x4000
-#define TIOCM_LOOP     0x8000
-
-/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
-
-#ifdef __KERNEL__
-
-/*     intr=^C         quit=^\         erase=del       kill=^U
-       eof=^D          vtime=\0        vmin=\1         sxtc=\0
-       start=^Q        stop=^S         susp=^Z         eol=\0
-       reprint=^R      discard=^U      werase=^W       lnext=^V
-       eol2=\0
-*/
-#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
-
-/*
- * Translate a "termio" structure into a "termios". Ugh.
- */
-#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \
-       unsigned short __tmp; \
-       get_user(__tmp,&(termio)->x); \
-       *(unsigned short *) &(termios)->x = __tmp; \
-}
-
-#define user_termio_to_kernel_termios(termios, termio) \
-({ \
-       SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \
-       SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \
-       SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \
-       SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \
-       copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
-})
-
-/*
- * Translate a "termios" structure into a "termio". Ugh.
- */
-#define kernel_termios_to_user_termio(termio, termios) \
-({ \
-       put_user((termios)->c_iflag, &(termio)->c_iflag); \
-       put_user((termios)->c_oflag, &(termio)->c_oflag); \
-       put_user((termios)->c_cflag, &(termio)->c_cflag); \
-       put_user((termios)->c_lflag, &(termio)->c_lflag); \
-       put_user((termios)->c_line,  &(termio)->c_line); \
-       copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
-})
-
-#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios2))
-#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2))
-#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios))
-#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios))
-
-#endif /* __KERNEL__ */
-
-#endif /* __ASM_SH_TERMIOS_H */
+#include <asm-generic/termios.h>
index a873e24113cf7430cc5527f99278d1e11e2d6f0e..b556d49e5f2ba8742a343d6dc9bc8d61b7437029 100644 (file)
@@ -8,11 +8,6 @@
 
 #define CLOCK_TICK_RATE                (CONFIG_SH_PCLK_FREQ / 4) /* Underlying HZ */
 
-typedef unsigned long long cycles_t;
-
-static __inline__ cycles_t get_cycles (void)
-{
-       return 0;
-}
+#include <asm-generic/timex.h>
 
 #endif /* __ASM_SH_TIMEX_H */
index 8489a0905a8745d5eb7246e3a0922c68bf114909..b69ee850906d037e5bf24be4c19766729ede6825 100644 (file)
@@ -35,9 +35,6 @@
 #define cpumask_of_node(node)  ((void)node, cpu_online_mask)
 
 #define pcibus_to_node(bus)    ((void)(bus), -1)
-#define pcibus_to_cpumask(bus) (pcibus_to_node(bus) == -1 ? \
-                                       CPU_MASK_ALL : \
-                                       node_to_cpumask(pcibus_to_node(bus)))
 #define cpumask_of_pcibus(bus) (pcibus_to_node(bus) == -1 ? \
                                        CPU_MASK_ALL_PTR : \
                                        cpumask_of_node(pcibus_to_node(bus)))
index b13caca62a768665bd8e0fd9efa29a35615fe123..c7f3c94837dd706b7a1584cb5ac71042b3270e3c 100644 (file)
@@ -1,27 +1,14 @@
 #ifndef __ASM_SH_TYPES_H
 #define __ASM_SH_TYPES_H
 
-#include <asm-generic/int-ll64.h>
-
-#ifndef __ASSEMBLY__
-
-typedef unsigned short umode_t;
-
-#endif /* __ASSEMBLY__ */
+#include <asm-generic/types.h>
 
 /*
  * These aren't exported outside the kernel to avoid name space clashes
  */
 #ifdef __KERNEL__
-
-#define BITS_PER_LONG 32
-
 #ifndef __ASSEMBLY__
 
-/* Dma addresses are 32-bits wide.  */
-
-typedef u32 dma_addr_t;
-
 #ifdef CONFIG_SUPERH32
 typedef u16 insn_size_t;
 #else
@@ -29,7 +16,6 @@ typedef u32 insn_size_t;
 #endif
 
 #endif /* __ASSEMBLY__ */
-
 #endif /* __KERNEL__ */
 
 #endif /* __ASM_SH_TYPES_H */
index 202ef1d5a3c41dbee13265f1487a12555d1e04a2..9bc07b9f30fba10518b48cadc01d9aa4eaa4260f 100644 (file)
@@ -1,12 +1 @@
-#ifndef __ASM_SH_UCONTEXT_H
-#define __ASM_SH_UCONTEXT_H
-
-struct ucontext {
-       unsigned long     uc_flags;
-       struct ucontext  *uc_link;
-       stack_t           uc_stack;
-       struct sigcontext uc_mcontext;
-       sigset_t          uc_sigmask;   /* mask last for extensibility */
-};
-
-#endif /* __ASM_SH_UCONTEXT_H */
+#include <asm-generic/ucontext.h>
index 8c0ad5e4487aff72faceeff9d36fe915d96f01dc..7d14e0669961b216b16b8803e5e4c423f1fa7b96 100644 (file)
@@ -6,19 +6,7 @@
 #include <asm/unaligned-sh4a.h>
 #else
 /* Otherwise, SH can't handle unaligned accesses. */
-#ifdef __LITTLE_ENDIAN__
-# include <linux/unaligned/le_struct.h>
-# include <linux/unaligned/be_byteshift.h>
-# include <linux/unaligned/generic.h>
-# define get_unaligned __get_unaligned_le
-# define put_unaligned __put_unaligned_le
-#else
-# include <linux/unaligned/be_struct.h>
-# include <linux/unaligned/le_byteshift.h>
-# include <linux/unaligned/generic.h>
-# define get_unaligned __get_unaligned_be
-# define put_unaligned __put_unaligned_be
-#endif
+#include <asm-generic/unaligned.h>
 #endif
 
 #endif /* _ASM_SH_UNALIGNED_H */
index 65197086a1c53ad82b83b6185c1c944fecbb33c9..61d6ad93d78699a37dcf7845cd34baf37d6fb4b2 100644 (file)
 #define __NR_preadv            333
 #define __NR_pwritev           334
 #define __NR_rt_tgsigqueueinfo 335
+#define __NR_perf_counter_open 336
 
-#define NR_syscalls 336
+#define NR_syscalls 337
 
 #ifdef __KERNEL__
 
index 8014aea88ec3ca405ffae5c094780c10a4869fd3..a751699afda33ff53befadf9ce2091dc4b154c34 100644 (file)
 #define __NR_preadv            361
 #define __NR_pwritev           362
 #define __NR_rt_tgsigqueueinfo 363
+#define __NR_perf_counter_open 364
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 364
+#define NR_syscalls 365
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
index bd26a848cb0b3a2a991d31460089baa71800b792..5d9d4d5154be3f038765253d16298c9005efb013 100644 (file)
@@ -2,6 +2,9 @@
 #define __ASM_SH_RENESAS_R7780RP_H
 
 /* Box specific addresses.  */
+#define PA_NORFLASH_ADDR       0x00000000
+#define PA_NORFLASH_SIZE       0x04000000
+
 #if defined(CONFIG_SH_R7780MP)
 #define PA_BCR          0xa4000000      /* FPGA */
 #define PA_SDPOW       (-1)
index 275942e58e4f154a89e344b18b08c03f78666142..6dfe2cced3fc6e5ed32c7104b4d9f5487e2f823e 100644 (file)
@@ -1,6 +1,6 @@
 #include <linux/clk.h>
 #include <linux/compiler.h>
-#include <linux/bootmem.h>
+#include <linux/slab.h>
 #include <linux/io.h>
 #include <asm/clock.h>
 
@@ -127,10 +127,11 @@ int __init sh_clk_div6_register(struct clk *clks, int nr)
        int k;
 
        freq_table_size *= (nr_divs + 1);
-
-       freq_table = alloc_bootmem(freq_table_size * nr);
-       if (!freq_table)
+       freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL);
+       if (!freq_table) {
+               pr_err("sh_clk_div6_register: unable to alloc memory\n");
                return -ENOMEM;
+       }
 
        for (k = 0; !ret && (k < nr); k++) {
                clkp = clks + k;
@@ -175,10 +176,11 @@ int __init sh_clk_div4_register(struct clk *clks, int nr,
        int k;
 
        freq_table_size *= (nr_divs + 1);
-
-       freq_table = alloc_bootmem(freq_table_size * nr);
-       if (!freq_table)
+       freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL);
+       if (!freq_table) {
+               pr_err("sh_clk_div4_register: unable to alloc memory\n");
                return -ENOMEM;
+       }
 
        for (k = 0; !ret && (k < nr); k++) {
                clkp = clks + k;
index 318516f6bfad862911fe80a2daa14a935c9744be..c18f7d09281bbd80d333d2773b321b907044fd68 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/serial_sci.h>
 #include <linux/uio_driver.h>
 #include <linux/sh_timer.h>
+#include <linux/usb/r8a66597.h>
 #include <asm/clock.h>
 
 static struct resource iic_resources[] = {
@@ -38,18 +39,20 @@ static struct platform_device iic_device = {
        .resource       = iic_resources,
 };
 
+static struct r8a66597_platdata r8a66597_data = {
+       /* This set zero to all members */
+};
+
 static struct resource usb_host_resources[] = {
        [0] = {
-               .name   = "r8a66597_hcd",
                .start  = 0xa4d80000,
                .end    = 0xa4d800ff,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .name   = "r8a66597_hcd",
                .start  = 65,
                .end    = 65,
-               .flags  = IORESOURCE_IRQ,
+               .flags  = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
        },
 };
 
@@ -59,6 +62,7 @@ static struct platform_device usb_host_device = {
        .dev = {
                .dma_mask               = NULL,
                .coherent_dma_mask      = 0xffffffff,
+               .platform_data          = &r8a66597_data,
        },
        .num_resources  = ARRAY_SIZE(usb_host_resources),
        .resource       = usb_host_resources,
index d8f4a13aeff9d120302136d2476a593cb452b819..e1bb80b2a27b55c948f95e2e15e146fe5ff82319 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/mm.h>
 #include <linux/serial_sci.h>
 #include <linux/uio_driver.h>
+#include <linux/usb/r8a66597.h>
 #include <linux/sh_timer.h>
 #include <linux/io.h>
 #include <asm/clock.h>
@@ -396,9 +397,12 @@ static struct platform_device rtc_device = {
        .resource       = rtc_resources,
 };
 
+static struct r8a66597_platdata r8a66597_data = {
+       /* This set zero to all members */
+};
+
 static struct resource sh7723_usb_host_resources[] = {
        [0] = {
-               .name   = "r8a66597_hcd",
                .start  = 0xa4d80000,
                .end    = 0xa4d800ff,
                .flags  = IORESOURCE_MEM,
@@ -406,7 +410,7 @@ static struct resource sh7723_usb_host_resources[] = {
        [1] = {
                .start  = 65,
                .end    = 65,
-               .flags  = IORESOURCE_IRQ,
+               .flags  = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
        },
 };
 
@@ -416,6 +420,7 @@ static struct platform_device sh7723_usb_host_device = {
        .dev = {
                .dma_mask               = NULL,         /*  not use dma */
                .coherent_dma_mask      = 0xffffffff,
+               .platform_data          = &r8a66597_data,
        },
        .num_resources  = ARRAY_SIZE(sh7723_usb_host_resources),
        .resource       = sh7723_usb_host_resources,
index b8869aa20decb6f281407ab7aef1c136f486757c..2b6b0d50c576c4d04c68bbd8e9ecf9d9550c705b 100644 (file)
@@ -35,8 +35,7 @@ void __init plat_smp_setup(void)
        unsigned int cpu = 0;
        int i, num;
 
-       cpus_clear(cpu_possible_map);
-       cpu_set(cpu, cpu_possible_map);
+       init_cpu_possible(cpumask_of(cpu));
 
        __cpu_number_map[0] = 0;
        __cpu_logical_map[0] = 0;
@@ -46,7 +45,7 @@ void __init plat_smp_setup(void)
         * for the total number of cores.
         */
        for (i = 1, num = 0; i < NR_CPUS; i++) {
-               cpu_set(i, cpu_possible_map);
+               set_cpu_possible(i, true);
                __cpu_number_map[i] = ++num;
                __cpu_logical_map[num] = i;
        }
index 4c3247477aa36be3a804c212c64d1f075a486b21..066f37dc32a907fb4480f3e241b15a404f900134 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 Matt Fleming <mjf@gentoo.org>
+ * Copyright (C) 2008 Matt Fleming <matt@console-pimps.org>
  * Copyright (C) 2008 Paul Mundt <lethal@linux-sh.org>
  *
  * Code for replacing ftrace calls with jumps.
 #include <asm/ftrace.h>
 #include <asm/cacheflush.h>
 
-static unsigned char ftrace_nop[] = {
-       0x09, 0x00,             /* nop */
-       0x09, 0x00,             /* nop */
-};
-
 static unsigned char ftrace_replaced_code[MCOUNT_INSN_SIZE];
 
-unsigned char *ftrace_nop_replace(void)
+static unsigned char ftrace_nop[4];
+/*
+ * If we're trying to nop out a call to a function, we instead
+ * place a call to the address after the memory table.
+ *
+ * 8c011060 <a>:
+ * 8c011060:       02 d1           mov.l   8c01106c <a+0xc>,r1
+ * 8c011062:       22 4f           sts.l   pr,@-r15
+ * 8c011064:       02 c7           mova    8c011070 <a+0x10>,r0
+ * 8c011066:       2b 41           jmp     @r1
+ * 8c011068:       2a 40           lds     r0,pr
+ * 8c01106a:       09 00           nop
+ * 8c01106c:       68 24           .word 0x2468     <--- ip
+ * 8c01106e:       1d 8c           .word 0x8c1d
+ * 8c011070:       26 4f           lds.l   @r15+,pr <--- ip + MCOUNT_INSN_SIZE
+ *
+ * We write 0x8c011070 to 0x8c01106c so that on entry to a() we branch
+ * past the _mcount call and continue executing code like normal.
+ */
+static unsigned char *ftrace_nop_replace(unsigned long ip)
 {
+       __raw_writel(ip + MCOUNT_INSN_SIZE, ftrace_nop);
        return ftrace_nop;
 }
 
-static int is_sh_nop(unsigned char *ip)
-{
-       return strncmp(ip, ftrace_nop, sizeof(ftrace_nop));
-}
-
-unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
+static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
 {
        /* Place the address in the memory table. */
-       if (addr == CALLER_ADDR)
-               __raw_writel(addr + MCOUNT_INSN_OFFSET, ftrace_replaced_code);
-       else
-               __raw_writel(addr, ftrace_replaced_code);
+       __raw_writel(addr, ftrace_replaced_code);
 
        /*
         * No locking needed, this must be called via kstop_machine
@@ -51,7 +58,7 @@ unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
        return ftrace_replaced_code;
 }
 
-int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
+static int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
                       unsigned char *new_code)
 {
        unsigned char replaced[MCOUNT_INSN_SIZE];
@@ -66,13 +73,6 @@ int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
         * kstop_machine, or before SMP starts.
         */
 
-       /*
-        * If we're trying to nop out a call to a function, we instead
-        * place a call to the address after the memory table.
-        */
-       if (is_sh_nop(new_code) == 0)
-               __raw_writel(ip + MCOUNT_INSN_SIZE, (unsigned long)new_code);
-
        /* read the text we want to modify */
        if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE))
                return -EFAULT;
@@ -92,13 +92,13 @@ int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
 
 int ftrace_update_ftrace_func(ftrace_func_t func)
 {
-       unsigned long ip = (unsigned long)(&ftrace_call);
+       unsigned long ip = (unsigned long)(&ftrace_call) + MCOUNT_INSN_OFFSET;
        unsigned char old[MCOUNT_INSN_SIZE], *new;
 
-       memcpy(old, (unsigned char *)(ip + MCOUNT_INSN_OFFSET), MCOUNT_INSN_SIZE);
+       memcpy(old, (unsigned char *)ip, MCOUNT_INSN_SIZE);
        new = ftrace_call_replace(ip, (unsigned long)func);
 
-       return ftrace_modify_code(ip + MCOUNT_INSN_OFFSET, old, new);
+       return ftrace_modify_code(ip, old, new);
 }
 
 int ftrace_make_nop(struct module *mod,
@@ -108,7 +108,7 @@ int ftrace_make_nop(struct module *mod,
        unsigned long ip = rec->ip;
 
        old = ftrace_call_replace(ip, addr);
-       new = ftrace_nop_replace();
+       new = ftrace_nop_replace(ip);
 
        return ftrace_modify_code(rec->ip, old, new);
 }
@@ -118,7 +118,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
        unsigned char *new, *old;
        unsigned long ip = rec->ip;
 
-       old = ftrace_nop_replace();
+       old = ftrace_nop_replace(ip);
        new = ftrace_call_replace(ip, addr);
 
        return ftrace_modify_code(rec->ip, old, new);
index 80c35ff71d564d524cf01c752efd0618fa868308..1719957c0a691202b192da5c9a6329e810dcc44f 100644 (file)
@@ -10,9 +10,6 @@
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
 struct pt_regs fake_swapper_regs;
-struct mm_struct init_mm = INIT_MM(init_mm);
-EXPORT_SYMBOL(init_mm);
-
 /*
  * Initial thread structure.
  *
index 8f54ef0cfbcaa5648be466725b33ec1361639c66..f5bd156ea504ebe73bf171cd7466f78335d3e26f 100644 (file)
@@ -38,13 +38,6 @@ EXPORT_SYMBOL(clear_user_page);
 EXPORT_SYMBOL(flush_dcache_page);
 #endif
 
-/* Networking helper routines. */
-EXPORT_SYMBOL(csum_partial);
-EXPORT_SYMBOL(csum_partial_copy_nocheck);
-#ifdef CONFIG_IPV6
-EXPORT_SYMBOL(csum_ipv6_magic);
-#endif
-
 #ifdef CONFIG_VT
 EXPORT_SYMBOL(screen_info);
 #endif
index 8f40274126142847f99e7c51f71e13a22813b2cf..442d8d47a41e40baa75f18476667929d0aff9f98 100644 (file)
@@ -47,7 +47,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
        plat_prepare_cpus(max_cpus);
 
 #ifndef CONFIG_HOTPLUG_CPU
-       cpu_present_map = cpu_possible_map;
+       init_cpu_present(&cpu_possible_map);
 #endif
 }
 
@@ -58,8 +58,8 @@ void __devinit smp_prepare_boot_cpu(void)
        __cpu_number_map[0] = cpu;
        __cpu_logical_map[0] = cpu;
 
-       cpu_set(cpu, cpu_online_map);
-       cpu_set(cpu, cpu_possible_map);
+       set_cpu_online(cpu, true);
+       set_cpu_possible(cpu, true);
 }
 
 asmlinkage void __cpuinit start_secondary(void)
@@ -171,11 +171,11 @@ void smp_send_stop(void)
        smp_call_function(stop_this_cpu, 0, 0);
 }
 
-void arch_send_call_function_ipi(cpumask_t mask)
+void arch_send_call_function_ipi_mask(const struct cpumask *mask)
 {
        int cpu;
 
-       for_each_cpu_mask(cpu, mask)
+       for_each_cpu(cpu, mask)
                plat_send_ipi(cpu, SMP_MSG_FUNCTION);
 }
 
index a9fff9f731ec11c4273592f6ab932d351c7716d6..f9e21fa2f592e211002a48f41b1c1159ec061f5c 100644 (file)
@@ -352,3 +352,4 @@ ENTRY(sys_call_table)
        .long sys_preadv
        .long sys_pwritev
        .long sys_rt_tgsigqueueinfo     /* 335 */
+       .long sys_perf_counter_open
index 75c1889af1ed53c725491e8bf35cb3ed00cb382a..bf420b616ae0ed8def015839f8549ab8a99baac2 100644 (file)
@@ -390,3 +390,4 @@ sys_call_table:
        .long sys_preadv
        .long sys_pwritev
        .long sys_rt_tgsigqueueinfo
+       .long sys_perf_counter_open
index 2edde32c764be6deb519cdc20b4c8afc82c0ab61..9b352a1e3fb47af66009127566b2c25b79a66167 100644 (file)
@@ -91,21 +91,6 @@ module_init(rtc_generic_init);
 
 void (*board_time_init)(void);
 
-unsigned long long sched_clock(void)
-{
-       return (jiffies_64 - INITIAL_JIFFIES) * (NSEC_PER_SEC / HZ);
-}
-
-static void __init sh_late_time_init(void)
-{
-       /*
-        * Make sure all compiled-in early timers register themselves.
-        * Run probe() for one "earlytimer" device.
-        */
-       early_platform_driver_register_all("earlytimer");
-       early_platform_driver_probe("earlytimer", 1, 0);
-}
-
 void __init time_init(void)
 {
        if (board_time_init)
@@ -121,5 +106,15 @@ void __init time_init(void)
        local_timer_setup(smp_processor_id());
 #endif
 
-       late_time_init = sh_late_time_init;
+       /*
+        * Make sure all compiled-in early timers register themselves.
+        *
+        * Run probe() for two "earlytimer" devices, these will be the
+        * clockevents and clocksource devices respectively. In the event
+        * that only a clockevents device is available, we -ENODEV on the
+        * clocksource and the jiffies clocksource is used transparently
+        * instead. No error handling is necessary here.
+        */
+       early_platform_driver_register_all("earlytimer");
+       early_platform_driver_probe("earlytimer", 2, 0);
 }
index 46348ed07cc35cde3b5120099bfd842d1ac0b7cd..b3e0067db3583006753fb70203993eda80a439a3 100644 (file)
@@ -69,6 +69,7 @@ BUILD_TRAP_HANDLER(bug)
                insn_size_t insn = *(insn_size_t *)instruction_pointer(regs);
                if (insn == TRAPA_BUG_OPCODE)
                        handle_BUG(regs);
+               return;
        }
 #endif
 
index 4bacb9e834789873629021f34660c980f5c338b5..334bb2da36eabac7e052fa734cb5fa282b5d5a00 100644 (file)
@@ -10,7 +10,7 @@
 #
 
 # Panic should really be compiled as PIC
-lib-y  := udelay.o c-checksum.o dbg.o panic.o memcpy.o memset.o \
+lib-y  := udelay.o dbg.o panic.o memcpy.o memset.o \
          copy_user_memcpy.o copy_page.o clear_page.o strcpy.o strlen.o
 
 # Extracted from libgcc
diff --git a/arch/sh/lib64/c-checksum.c b/arch/sh/lib64/c-checksum.c
deleted file mode 100644 (file)
index 73c0877..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * arch/sh/lib64/c-checksum.c
- *
- * This file contains network checksum routines that are better done
- * in an architecture-specific manner due to speed..
- */
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <asm/byteorder.h>
-#include <asm/uaccess.h>
-
-static inline unsigned short from64to16(unsigned long long x)
-{
-       /* add up 32-bit words for 33 bits */
-       x = (x & 0xffffffff) + (x >> 32);
-       /* add up 16-bit and 17-bit words for 17+c bits */
-       x = (x & 0xffff) + (x >> 16);
-       /* add up 16-bit and 2-bit for 16+c bit */
-       x = (x & 0xffff) + (x >> 16);
-       /* add up carry.. */
-       x = (x & 0xffff) + (x >> 16);
-       return x;
-}
-
-static inline unsigned short foldto16(unsigned long x)
-{
-       /* add up 16-bit for 17 bits */
-       x = (x & 0xffff) + (x >> 16);
-       /* add up carry.. */
-       x = (x & 0xffff) + (x >> 16);
-       return x;
-}
-
-static inline unsigned short myfoldto16(unsigned long long x)
-{
-       /* Fold down to 32-bits so we don't lose in the typedef-less
-          network stack.  */
-       /* 64 to 33 */
-       x = (x & 0xffffffff) + (x >> 32);
-       /* 33 to 32 */
-       x = (x & 0xffffffff) + (x >> 32);
-
-       /* add up 16-bit for 17 bits */
-       x = (x & 0xffff) + (x >> 16);
-       /* add up carry.. */
-       x = (x & 0xffff) + (x >> 16);
-       return x;
-}
-
-#define odd(x) ((x)&1)
-#define U16(x) ntohs(x)
-
-static unsigned long do_csum(const unsigned char *buff, int len)
-{
-       int odd, count;
-       unsigned long result = 0;
-
-       pr_debug("do_csum buff %p, len %d (0x%x)\n", buff, len, len);
-#ifdef DEBUG
-       for (i = 0; i < len; i++) {
-               if ((i % 26) == 0)
-                       printk("\n");
-               printk("%02X ", buff[i]);
-       }
-#endif
-
-       if (len <= 0)
-               goto out;
-
-       odd = 1 & (unsigned long) buff;
-       if (odd) {
-               result = *buff << 8;
-               len--;
-               buff++;
-       }
-       count = len >> 1;       /* nr of 16-bit words.. */
-       if (count) {
-               if (2 & (unsigned long) buff) {
-                       result += *(unsigned short *) buff;
-                       count--;
-                       len -= 2;
-                       buff += 2;
-               }
-               count >>= 1;    /* nr of 32-bit words.. */
-               if (count) {
-                       unsigned long carry = 0;
-                       do {
-                               unsigned long w = *(unsigned long *) buff;
-                               buff += 4;
-                               count--;
-                               result += carry;
-                               result += w;
-                               carry = (w > result);
-                       } while (count);
-                       result += carry;
-                       result = (result & 0xffff) + (result >> 16);
-               }
-               if (len & 2) {
-                       result += *(unsigned short *) buff;
-                       buff += 2;
-               }
-       }
-       if (len & 1)
-               result += *buff;
-       result = foldto16(result);
-       if (odd)
-               result = ((result >> 8) & 0xff) | ((result & 0xff) << 8);
-
-       pr_debug("\nCHECKSUM is 0x%lx\n", result);
-
-      out:
-       return result;
-}
-
-/* computes the checksum of a memory block at buff, length len,
-   and adds in "sum" (32-bit)  */
-__wsum csum_partial(const void *buff, int len, __wsum sum)
-{
-       unsigned long long result = do_csum(buff, len);
-
-       /* add in old sum, and carry.. */
-       result += (__force u32)sum;
-       /* 32+c bits -> 32 bits */
-       result = (result & 0xffffffff) + (result >> 32);
-
-       pr_debug("csum_partial, buff %p len %d sum 0x%x result=0x%016Lx\n",
-               buff, len, sum, result);
-
-       return (__force __wsum)result;
-}
-
-/* Copy while checksumming, otherwise like csum_partial.  */
-__wsum
-csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
-{
-       sum = csum_partial(src, len, sum);
-       memcpy(dst, src, len);
-
-       return sum;
-}
-
-/* Copy from userspace and compute checksum.  If we catch an exception
-   then zero the rest of the buffer.  */
-__wsum
-csum_partial_copy_from_user(const void __user *src, void *dst, int len,
-                           __wsum sum, int *err_ptr)
-{
-       int missing;
-
-       pr_debug
-           ("csum_partial_copy_from_user src %p, dest %p, len %d, sum %08x, err_ptr %p\n",
-            src, dst, len, sum, err_ptr);
-       missing = copy_from_user(dst, src, len);
-       pr_debug("  access_ok %d\n", __access_ok((unsigned long) src, len));
-       pr_debug("  missing %d\n", missing);
-       if (missing) {
-               memset(dst + len - missing, 0, missing);
-               *err_ptr = -EFAULT;
-       }
-
-       return csum_partial(dst, len, sum);
-}
-
-/* Copy to userspace and compute checksum.  */
-__wsum
-csum_partial_copy_to_user(const unsigned char *src, unsigned char *dst, int len,
-                         __wsum sum, int *err_ptr)
-{
-       sum = csum_partial(src, len, sum);
-
-       if (copy_to_user(dst, src, len))
-               *err_ptr = -EFAULT;
-
-       return sum;
-}
-
-/*
- *     This is a version of ip_compute_csum() optimized for IP headers,
- *     which always checksum on 4 octet boundaries.
- */
-__sum16 ip_fast_csum(const void *iph, unsigned int ihl)
-{
-       pr_debug("ip_fast_csum %p,%d\n", iph, ihl);
-
-       return (__force __sum16)~do_csum(iph, ihl * 4);
-}
-
-__wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
-                               unsigned short len,
-                               unsigned short proto, __wsum sum)
-{
-       unsigned long long result;
-
-       pr_debug("ntohs(0x%x)=0x%x\n", 0xdead, ntohs(0xdead));
-       pr_debug("htons(0x%x)=0x%x\n", 0xdead, htons(0xdead));
-
-       result = (__force u64) saddr + (__force u64) daddr +
-                (__force u64) sum + ((len + proto) << 8);
-
-       /* Fold down to 32-bits so we don't lose in the typedef-less
-          network stack.  */
-       /* 64 to 33 */
-       result = (result & 0xffffffff) + (result >> 32);
-       /* 33 to 32 */
-       result = (result & 0xffffffff) + (result >> 32);
-
-       pr_debug("%s saddr %x daddr %x len %x proto %x sum %x result %08Lx\n",
-               __func__, saddr, daddr, len, proto, sum, result);
-
-       return (__wsum)result;
-}
-EXPORT_SYMBOL(csum_tcpudp_nofold);
index cc12cd48bbc51a41bc157681de49a2b1eeb102d3..3f8b6a92eabdff56413ed4cefd54d678290a228a 100644 (file)
@@ -37,6 +37,8 @@ config SPARC64
        select HAVE_KPROBES
        select HAVE_LMB
        select HAVE_SYSCALL_WRAPPERS
+       select HAVE_DYNAMIC_FTRACE
+       select HAVE_FTRACE_MCOUNT_RECORD
        select USE_GENERIC_SMP_HELPERS if SMP
        select RTC_DRV_CMOS
        select RTC_DRV_BQ4802
@@ -93,6 +95,9 @@ config AUDIT_ARCH
 config HAVE_SETUP_PER_CPU_AREA
        def_bool y if SPARC64
 
+config HAVE_DYNAMIC_PER_CPU_AREA
+       def_bool y if SPARC64
+
 config GENERIC_HARDIRQS_NO__DO_IRQ
        bool
        def_bool y if SPARC64
index b5d63bd8716ead259a5ea8c0c59cbabe9fd09931..0123a4c596cef67a537d6a3f660b0cbf0a3b74c6 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc2
-# Fri Apr 17 02:03:07 2009
+# Linux kernel version: 2.6.30
+# Tue Jun 16 04:59:36 2009
 #
 CONFIG_64BIT=y
 CONFIG_SPARC=y
@@ -19,6 +19,7 @@ CONFIG_LOCKDEP_SUPPORT=y
 CONFIG_HAVE_LATENCYTOP_SUPPORT=y
 CONFIG_AUDIT_ARCH=y
 CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_HAVE_DYNAMIC_PER_CPU_AREA=y
 CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_MMU=y
 CONFIG_ARCH_NO_VIRT_TO_BUS=y
@@ -82,7 +83,6 @@ CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -95,16 +95,21 @@ CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_AIO=y
+
+#
+# Performance Counters
+#
 CONFIG_VM_EVENT_COUNTERS=y
 CONFIG_PCI_QUIRKS=y
 CONFIG_SLUB_DEBUG=y
+# CONFIG_STRIP_ASM_SYMS is not set
 # CONFIG_COMPAT_BRK is not set
 # CONFIG_SLAB is not set
 CONFIG_SLUB=y
 # CONFIG_SLOB is not set
 CONFIG_PROFILING=y
 CONFIG_TRACEPOINTS=y
-# CONFIG_MARKERS is not set
+CONFIG_MARKERS=y
 CONFIG_OPROFILE=m
 CONFIG_HAVE_OPROFILE=y
 CONFIG_KPROBES=y
@@ -202,6 +207,7 @@ CONFIG_NR_QUICK=1
 CONFIG_UNEVICTABLE_LRU=y
 CONFIG_HAVE_MLOCK=y
 CONFIG_HAVE_MLOCKED_PAGE_BIT=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=8192
 CONFIG_SCHED_SMT=y
 CONFIG_SCHED_MC=y
 # CONFIG_PREEMPT_NONE is not set
@@ -321,6 +327,7 @@ CONFIG_VLAN_8021Q=m
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 # CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
 # CONFIG_NET_SCHED is not set
 # CONFIG_DCB is not set
 
@@ -340,7 +347,11 @@ CONFIG_WIRELESS=y
 CONFIG_WIRELESS_OLD_REGULATORY=y
 # CONFIG_WIRELESS_EXT is not set
 # CONFIG_LIB80211 is not set
-# CONFIG_MAC80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+CONFIG_MAC80211_DEFAULT_PS_VALUE=0
 # CONFIG_WIMAX is not set
 # CONFIG_RFKILL is not set
 # CONFIG_NET_9P is not set
@@ -364,6 +375,7 @@ CONFIG_EXTRA_FIRMWARE=""
 CONFIG_CONNECTOR=m
 # CONFIG_MTD is not set
 CONFIG_OF_DEVICE=y
+CONFIG_OF_MDIO=m
 # CONFIG_PARPORT is not set
 CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_FD is not set
@@ -399,6 +411,7 @@ CONFIG_MISC_DEVICES=y
 # CONFIG_EEPROM_AT24 is not set
 # CONFIG_EEPROM_LEGACY is not set
 # CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
 CONFIG_HAVE_IDE=y
 CONFIG_IDE=y
 
@@ -477,10 +490,6 @@ CONFIG_BLK_DEV_SR=m
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
 # CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
 CONFIG_SCSI_MULTI_LUN=y
 CONFIG_SCSI_CONSTANTS=y
 # CONFIG_SCSI_LOGGING is not set
@@ -499,6 +508,7 @@ CONFIG_SCSI_FC_ATTRS=y
 CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
 # CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_SCSI_3W_9XXX is not set
 # CONFIG_SCSI_ACARD is not set
@@ -507,6 +517,7 @@ CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_SCSI_AIC7XXX_OLD is not set
 # CONFIG_SCSI_AIC79XX is not set
 # CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
 # CONFIG_SCSI_ARCMSR is not set
 # CONFIG_MEGARAID_NEWGEN is not set
 # CONFIG_MEGARAID_LEGACY is not set
@@ -521,7 +532,6 @@ CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_MVSAS is not set
 # CONFIG_SCSI_STEX is not set
 # CONFIG_SCSI_SYM53C8XX_2 is not set
 # CONFIG_SCSI_QLOGIC_1280 is not set
@@ -569,7 +579,6 @@ CONFIG_DM_ZERO=m
 # CONFIG_IEEE1394 is not set
 # CONFIG_I2O is not set
 CONFIG_NETDEVICES=y
-CONFIG_COMPAT_NET_DEV_OPS=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_MACVLAN is not set
@@ -635,6 +644,7 @@ CONFIG_NET_PCI=y
 # CONFIG_SMSC9420 is not set
 # CONFIG_SUNDANCE is not set
 # CONFIG_TLAN is not set
+# CONFIG_KS8842 is not set
 # CONFIG_VIA_RHINE is not set
 # CONFIG_SC92031 is not set
 # CONFIG_ATL2 is not set
@@ -1127,6 +1137,11 @@ CONFIG_SND_VERBOSE_PROCFS=y
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
 CONFIG_SND_VMASTER=y
+CONFIG_SND_RAWMIDI_SEQ=m
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
 CONFIG_SND_MPU401_UART=m
 CONFIG_SND_AC97_CODEC=m
 CONFIG_SND_DRIVERS=y
@@ -1153,6 +1168,7 @@ CONFIG_SND_ALI5451=m
 # CONFIG_SND_OXYGEN is not set
 # CONFIG_SND_CS4281 is not set
 # CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CTXFI is not set
 # CONFIG_SND_DARLA20 is not set
 # CONFIG_SND_GINA20 is not set
 # CONFIG_SND_LAYLA20 is not set
@@ -1183,6 +1199,7 @@ CONFIG_SND_ALI5451=m
 # CONFIG_SND_INTEL8X0 is not set
 # CONFIG_SND_INTEL8X0M is not set
 # CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_LX6464ES is not set
 # CONFIG_SND_MAESTRO3 is not set
 # CONFIG_SND_MIXART is not set
 # CONFIG_SND_NM256 is not set
@@ -1229,6 +1246,7 @@ CONFIG_HID_BELKIN=y
 CONFIG_HID_CHERRY=y
 CONFIG_HID_CHICONY=y
 CONFIG_HID_CYPRESS=y
+CONFIG_HID_DRAGONRISE=y
 # CONFIG_DRAGONRISE_FF is not set
 CONFIG_HID_EZKEY=y
 CONFIG_HID_KYE=y
@@ -1246,9 +1264,14 @@ CONFIG_HID_PETALYNX=y
 CONFIG_HID_SAMSUNG=y
 CONFIG_HID_SONY=y
 CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
 # CONFIG_GREENASIA_FF is not set
+CONFIG_HID_SMARTJOYPLUS=y
+# CONFIG_SMARTJOYPLUS_FF is not set
 CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
 # CONFIG_THRUSTMASTER_FF is not set
+CONFIG_HID_ZEROPLUS=y
 # CONFIG_ZEROPLUS_FF is not set
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
@@ -1462,6 +1485,7 @@ CONFIG_FILE_LOCKING=y
 # CONFIG_GFS2_FS is not set
 # CONFIG_OCFS2_FS is not set
 # CONFIG_BTRFS_FS is not set
+CONFIG_FSNOTIFY=y
 CONFIG_DNOTIFY=y
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
@@ -1636,25 +1660,28 @@ CONFIG_SYSCTL_SYSCALL_CHECK=y
 # CONFIG_DEBUG_PAGEALLOC is not set
 CONFIG_NOP_TRACER=y
 CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 CONFIG_RING_BUFFER=y
+CONFIG_EVENT_TRACING=y
+CONFIG_CONTEXT_SWITCH_TRACER=y
 CONFIG_TRACING=y
+CONFIG_GENERIC_TRACER=y
 CONFIG_TRACING_SUPPORT=y
-
-#
-# Tracers
-#
+CONFIG_FTRACE=y
 # CONFIG_FUNCTION_TRACER is not set
 # CONFIG_IRQSOFF_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
-# CONFIG_CONTEXT_SWITCH_TRACER is not set
-# CONFIG_EVENT_TRACER is not set
 # CONFIG_BOOT_TRACER is not set
-# CONFIG_TRACE_BRANCH_PROFILING is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
 # CONFIG_STACK_TRACER is not set
 # CONFIG_KMEMTRACE is not set
 # CONFIG_WORKQUEUE_TRACER is not set
 CONFIG_BLK_DEV_IO_TRACE=y
 # CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_RING_BUFFER_BENCHMARK is not set
 # CONFIG_DYNAMIC_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
index a11b89ee9ef8f0a9e0758811dd633101adb4b12f..926397d345ff8c9c661ac69635ec11778c666d7b 100644 (file)
@@ -6,9 +6,6 @@
 #ifndef _SPARC64_CPUDATA_H
 #define _SPARC64_CPUDATA_H
 
-#include <asm/hypervisor.h>
-#include <asm/asi.h>
-
 #ifndef __ASSEMBLY__
 
 #include <linux/percpu.h>
@@ -38,202 +35,10 @@ DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data);
 #define cpu_data(__cpu)                per_cpu(__cpu_data, (__cpu))
 #define local_cpu_data()       __get_cpu_var(__cpu_data)
 
-/* Trap handling code needs to get at a few critical values upon
- * trap entry and to process TSB misses.  These cannot be in the
- * per_cpu() area as we really need to lock them into the TLB and
- * thus make them part of the main kernel image.  As a result we
- * try to make this as small as possible.
- *
- * This is padded out and aligned to 64-bytes to avoid false sharing
- * on SMP.
- */
-
-/* If you modify the size of this structure, please update
- * TRAP_BLOCK_SZ_SHIFT below.
- */
-struct thread_info;
-struct trap_per_cpu {
-/* D-cache line 1: Basic thread information, cpu and device mondo queues */
-       struct thread_info      *thread;
-       unsigned long           pgd_paddr;
-       unsigned long           cpu_mondo_pa;
-       unsigned long           dev_mondo_pa;
-
-/* D-cache line 2: Error Mondo Queue and kernel buffer pointers */
-       unsigned long           resum_mondo_pa;
-       unsigned long           resum_kernel_buf_pa;
-       unsigned long           nonresum_mondo_pa;
-       unsigned long           nonresum_kernel_buf_pa;
-
-/* Dcache lines 3, 4, 5, and 6: Hypervisor Fault Status */
-       struct hv_fault_status  fault_info;
-
-/* Dcache line 7: Physical addresses of CPU send mondo block and CPU list.  */
-       unsigned long           cpu_mondo_block_pa;
-       unsigned long           cpu_list_pa;
-       unsigned long           tsb_huge;
-       unsigned long           tsb_huge_temp;
-
-/* Dcache line 8: IRQ work list, and keep trap_block a power-of-2 in size.  */
-       unsigned long           irq_worklist_pa;
-       unsigned int            cpu_mondo_qmask;
-       unsigned int            dev_mondo_qmask;
-       unsigned int            resum_qmask;
-       unsigned int            nonresum_qmask;
-       void                    *hdesc;
-} __attribute__((aligned(64)));
-extern struct trap_per_cpu trap_block[NR_CPUS];
-extern void init_cur_cpu_trap(struct thread_info *);
-extern void setup_tba(void);
-extern int ncpus_probed;
 extern const struct seq_operations cpuinfo_op;
 
-extern unsigned long real_hard_smp_processor_id(void);
-
-struct cpuid_patch_entry {
-       unsigned int    addr;
-       unsigned int    cheetah_safari[4];
-       unsigned int    cheetah_jbus[4];
-       unsigned int    starfire[4];
-       unsigned int    sun4v[4];
-};
-extern struct cpuid_patch_entry __cpuid_patch, __cpuid_patch_end;
-
-struct sun4v_1insn_patch_entry {
-       unsigned int    addr;
-       unsigned int    insn;
-};
-extern struct sun4v_1insn_patch_entry __sun4v_1insn_patch,
-       __sun4v_1insn_patch_end;
-
-struct sun4v_2insn_patch_entry {
-       unsigned int    addr;
-       unsigned int    insns[2];
-};
-extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch,
-       __sun4v_2insn_patch_end;
-
 #endif /* !(__ASSEMBLY__) */
 
-#define TRAP_PER_CPU_THREAD            0x00
-#define TRAP_PER_CPU_PGD_PADDR         0x08
-#define TRAP_PER_CPU_CPU_MONDO_PA      0x10
-#define TRAP_PER_CPU_DEV_MONDO_PA      0x18
-#define TRAP_PER_CPU_RESUM_MONDO_PA    0x20
-#define TRAP_PER_CPU_RESUM_KBUF_PA     0x28
-#define TRAP_PER_CPU_NONRESUM_MONDO_PA 0x30
-#define TRAP_PER_CPU_NONRESUM_KBUF_PA  0x38
-#define TRAP_PER_CPU_FAULT_INFO                0x40
-#define TRAP_PER_CPU_CPU_MONDO_BLOCK_PA        0xc0
-#define TRAP_PER_CPU_CPU_LIST_PA       0xc8
-#define TRAP_PER_CPU_TSB_HUGE          0xd0
-#define TRAP_PER_CPU_TSB_HUGE_TEMP     0xd8
-#define TRAP_PER_CPU_IRQ_WORKLIST_PA   0xe0
-#define TRAP_PER_CPU_CPU_MONDO_QMASK   0xe8
-#define TRAP_PER_CPU_DEV_MONDO_QMASK   0xec
-#define TRAP_PER_CPU_RESUM_QMASK       0xf0
-#define TRAP_PER_CPU_NONRESUM_QMASK    0xf4
-
-#define TRAP_BLOCK_SZ_SHIFT            8
-
-#include <asm/scratchpad.h>
-
-#define __GET_CPUID(REG)                               \
-       /* Spitfire implementation (default). */        \
-661:   ldxa            [%g0] ASI_UPA_CONFIG, REG;      \
-       srlx            REG, 17, REG;                   \
-        and            REG, 0x1f, REG;                 \
-       nop;                                            \
-       .section        .cpuid_patch, "ax";             \
-       /* Instruction location. */                     \
-       .word           661b;                           \
-       /* Cheetah Safari implementation. */            \
-       ldxa            [%g0] ASI_SAFARI_CONFIG, REG;   \
-       srlx            REG, 17, REG;                   \
-       and             REG, 0x3ff, REG;                \
-       nop;                                            \
-       /* Cheetah JBUS implementation. */              \
-       ldxa            [%g0] ASI_JBUS_CONFIG, REG;     \
-       srlx            REG, 17, REG;                   \
-       and             REG, 0x1f, REG;                 \
-       nop;                                            \
-       /* Starfire implementation. */                  \
-       sethi           %hi(0x1fff40000d0 >> 9), REG;   \
-       sllx            REG, 9, REG;                    \
-       or              REG, 0xd0, REG;                 \
-       lduwa           [REG] ASI_PHYS_BYPASS_EC_E, REG;\
-       /* sun4v implementation. */                     \
-       mov             SCRATCHPAD_CPUID, REG;          \
-       ldxa            [REG] ASI_SCRATCHPAD, REG;      \
-       nop;                                            \
-       nop;                                            \
-       .previous;
-
-#ifdef CONFIG_SMP
-
-#define TRAP_LOAD_TRAP_BLOCK(DEST, TMP)                \
-       __GET_CPUID(TMP)                        \
-       sethi   %hi(trap_block), DEST;          \
-       sllx    TMP, TRAP_BLOCK_SZ_SHIFT, TMP;  \
-       or      DEST, %lo(trap_block), DEST;    \
-       add     DEST, TMP, DEST;                \
-
-/* Clobbers TMP, current address space PGD phys address into DEST.  */
-#define TRAP_LOAD_PGD_PHYS(DEST, TMP)          \
-       TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
-       ldx     [DEST + TRAP_PER_CPU_PGD_PADDR], DEST;
-
-/* Clobbers TMP, loads local processor's IRQ work area into DEST.  */
-#define TRAP_LOAD_IRQ_WORK_PA(DEST, TMP)       \
-       TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
-       add     DEST, TRAP_PER_CPU_IRQ_WORKLIST_PA, DEST;
-
-/* Clobbers TMP, loads DEST with current thread info pointer.  */
-#define TRAP_LOAD_THREAD_REG(DEST, TMP)                \
-       TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
-       ldx     [DEST + TRAP_PER_CPU_THREAD], DEST;
-
-/* Given the current thread info pointer in THR, load the per-cpu
- * area base of the current processor into DEST.  REG1, REG2, and REG3 are
- * clobbered.
- *
- * You absolutely cannot use DEST as a temporary in this code.  The
- * reason is that traps can happen during execution, and return from
- * trap will load the fully resolved DEST per-cpu base.  This can corrupt
- * the calculations done by the macro mid-stream.
- */
-#define LOAD_PER_CPU_BASE(DEST, THR, REG1, REG2, REG3) \
-       lduh    [THR + TI_CPU], REG1;                   \
-       sethi   %hi(__per_cpu_shift), REG3;             \
-       sethi   %hi(__per_cpu_base), REG2;              \
-       ldx     [REG3 + %lo(__per_cpu_shift)], REG3;    \
-       ldx     [REG2 + %lo(__per_cpu_base)], REG2;     \
-       sllx    REG1, REG3, REG3;                       \
-       add     REG3, REG2, DEST;
-
-#else
-
-#define TRAP_LOAD_TRAP_BLOCK(DEST, TMP)                \
-       sethi   %hi(trap_block), DEST;          \
-       or      DEST, %lo(trap_block), DEST;    \
-
-/* Uniprocessor versions, we know the cpuid is zero.  */
-#define TRAP_LOAD_PGD_PHYS(DEST, TMP)          \
-       TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
-       ldx     [DEST + TRAP_PER_CPU_PGD_PADDR], DEST;
-
-/* Clobbers TMP, loads local processor's IRQ work area into DEST.  */
-#define TRAP_LOAD_IRQ_WORK_PA(DEST, TMP)       \
-       TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
-       add     DEST, TRAP_PER_CPU_IRQ_WORKLIST_PA, DEST;
-
-#define TRAP_LOAD_THREAD_REG(DEST, TMP)                \
-       TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
-       ldx     [DEST + TRAP_PER_CPU_THREAD], DEST;
-
-/* No per-cpu areas on uniprocessor, so no need to load DEST.  */
-#define LOAD_PER_CPU_BASE(DEST, THR, REG1, REG2, REG3)
-
-#endif /* !(CONFIG_SMP) */
+#include <asm/trap_block.h>
 
 #endif /* _SPARC64_CPUDATA_H */
index 0f4150e26619c3a2063f92abe4ff95ca8dece6cc..204e4bf644380560394902b95445c3d9f6020ed1 100644 (file)
@@ -1,8 +1,166 @@
 #ifndef ___ASM_SPARC_DMA_MAPPING_H
 #define ___ASM_SPARC_DMA_MAPPING_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/dma-mapping_64.h>
-#else
-#include <asm/dma-mapping_32.h>
-#endif
+
+#include <linux/scatterlist.h>
+#include <linux/mm.h>
+
+#define DMA_ERROR_CODE (~(dma_addr_t)0x0)
+
+extern int dma_supported(struct device *dev, u64 mask);
+extern int dma_set_mask(struct device *dev, u64 dma_mask);
+
+#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
+#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
+#define dma_is_consistent(d, h)        (1)
+
+struct dma_ops {
+       void *(*alloc_coherent)(struct device *dev, size_t size,
+                               dma_addr_t *dma_handle, gfp_t flag);
+       void (*free_coherent)(struct device *dev, size_t size,
+                             void *cpu_addr, dma_addr_t dma_handle);
+       dma_addr_t (*map_page)(struct device *dev, struct page *page,
+                              unsigned long offset, size_t size,
+                              enum dma_data_direction direction);
+       void (*unmap_page)(struct device *dev, dma_addr_t dma_addr,
+                          size_t size,
+                          enum dma_data_direction direction);
+       int (*map_sg)(struct device *dev, struct scatterlist *sg, int nents,
+                     enum dma_data_direction direction);
+       void (*unmap_sg)(struct device *dev, struct scatterlist *sg,
+                        int nhwentries,
+                        enum dma_data_direction direction);
+       void (*sync_single_for_cpu)(struct device *dev,
+                                   dma_addr_t dma_handle, size_t size,
+                                   enum dma_data_direction direction);
+       void (*sync_single_for_device)(struct device *dev,
+                                      dma_addr_t dma_handle, size_t size,
+                                      enum dma_data_direction direction);
+       void (*sync_sg_for_cpu)(struct device *dev, struct scatterlist *sg,
+                               int nelems,
+                               enum dma_data_direction direction);
+       void (*sync_sg_for_device)(struct device *dev,
+                                  struct scatterlist *sg, int nents,
+                                  enum dma_data_direction dir);
+};
+extern const struct dma_ops *dma_ops;
+
+static inline void *dma_alloc_coherent(struct device *dev, size_t size,
+                                      dma_addr_t *dma_handle, gfp_t flag)
+{
+       return dma_ops->alloc_coherent(dev, size, dma_handle, flag);
+}
+
+static inline void dma_free_coherent(struct device *dev, size_t size,
+                                    void *cpu_addr, dma_addr_t dma_handle)
+{
+       dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
+}
+
+static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
+                                       size_t size,
+                                       enum dma_data_direction direction)
+{
+       return dma_ops->map_page(dev, virt_to_page(cpu_addr),
+                                (unsigned long)cpu_addr & ~PAGE_MASK, size,
+                                direction);
+}
+
+static inline void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
+                                   size_t size,
+                                   enum dma_data_direction direction)
+{
+       dma_ops->unmap_page(dev, dma_addr, size, direction);
+}
+
+static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
+                                     unsigned long offset, size_t size,
+                                     enum dma_data_direction direction)
+{
+       return dma_ops->map_page(dev, page, offset, size, direction);
+}
+
+static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
+                                 size_t size,
+                                 enum dma_data_direction direction)
+{
+       dma_ops->unmap_page(dev, dma_address, size, direction);
+}
+
+static inline int dma_map_sg(struct device *dev, struct scatterlist *sg,
+                            int nents, enum dma_data_direction direction)
+{
+       return dma_ops->map_sg(dev, sg, nents, direction);
+}
+
+static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+                               int nents, enum dma_data_direction direction)
+{
+       dma_ops->unmap_sg(dev, sg, nents, direction);
+}
+
+static inline void dma_sync_single_for_cpu(struct device *dev,
+                                          dma_addr_t dma_handle, size_t size,
+                                          enum dma_data_direction direction)
+{
+       dma_ops->sync_single_for_cpu(dev, 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)
+{
+       if (dma_ops->sync_single_for_device)
+               dma_ops->sync_single_for_device(dev, dma_handle, size,
+                                               direction);
+}
+
+static inline void dma_sync_sg_for_cpu(struct device *dev,
+                                      struct scatterlist *sg, int nelems,
+                                      enum dma_data_direction direction)
+{
+       dma_ops->sync_sg_for_cpu(dev, sg, nelems, direction);
+}
+
+static inline void dma_sync_sg_for_device(struct device *dev,
+                                         struct scatterlist *sg, int nelems,
+                                         enum dma_data_direction direction)
+{
+       if (dma_ops->sync_sg_for_device)
+               dma_ops->sync_sg_for_device(dev, sg, nelems, direction);
+}
+
+static inline void dma_sync_single_range_for_cpu(struct device *dev,
+                                                dma_addr_t dma_handle,
+                                                unsigned long offset,
+                                                size_t size,
+                                                enum dma_data_direction dir)
+{
+       dma_sync_single_for_cpu(dev, dma_handle+offset, size, dir);
+}
+
+static inline void dma_sync_single_range_for_device(struct device *dev,
+                                                   dma_addr_t dma_handle,
+                                                   unsigned long offset,
+                                                   size_t size,
+                                                   enum dma_data_direction dir)
+{
+       dma_sync_single_for_device(dev, dma_handle+offset, size, dir);
+}
+
+
+static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+       return (dma_addr == DMA_ERROR_CODE);
+}
+
+static inline int dma_get_cache_alignment(void)
+{
+       /*
+        * no easy way to get cache size on all processors, so return
+        * the maximum possible, to be safe
+        */
+       return (1 << INTERNODE_CACHE_SHIFT);
+}
+
 #endif
diff --git a/arch/sparc/include/asm/dma-mapping_32.h b/arch/sparc/include/asm/dma-mapping_32.h
deleted file mode 100644 (file)
index 8a57ea0..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef _ASM_SPARC_DMA_MAPPING_H
-#define _ASM_SPARC_DMA_MAPPING_H
-
-#include <linux/types.h>
-
-struct device;
-struct scatterlist;
-struct page;
-
-#define DMA_ERROR_CODE (~(dma_addr_t)0x0)
-
-extern int dma_supported(struct device *dev, u64 mask);
-extern int dma_set_mask(struct device *dev, u64 dma_mask);
-extern void *dma_alloc_coherent(struct device *dev, size_t size,
-                               dma_addr_t *dma_handle, gfp_t flag);
-extern void dma_free_coherent(struct device *dev, size_t size,
-                             void *cpu_addr, dma_addr_t dma_handle);
-extern dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
-                                size_t size,
-                                enum dma_data_direction direction);
-extern void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
-                            size_t size,
-                            enum dma_data_direction direction);
-extern dma_addr_t dma_map_page(struct device *dev, struct page *page,
-                              unsigned long offset, size_t size,
-                              enum dma_data_direction direction);
-extern void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
-                          size_t size, enum dma_data_direction direction);
-extern int dma_map_sg(struct device *dev, struct scatterlist *sg,
-                     int nents, enum dma_data_direction direction);
-extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
-                        int nents, enum dma_data_direction direction);
-extern void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
-                                   size_t size,
-                                   enum dma_data_direction direction);
-extern void dma_sync_single_for_device(struct device *dev,
-                                      dma_addr_t dma_handle,
-                                      size_t size,
-                                      enum dma_data_direction direction);
-extern void dma_sync_single_range_for_cpu(struct device *dev,
-                                         dma_addr_t dma_handle,
-                                         unsigned long offset,
-                                         size_t size,
-                                         enum dma_data_direction direction);
-extern void dma_sync_single_range_for_device(struct device *dev,
-                                            dma_addr_t dma_handle,
-                                            unsigned long offset, size_t size,
-                                            enum dma_data_direction direction);
-extern void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
-                               int nelems, enum dma_data_direction direction);
-extern void dma_sync_sg_for_device(struct device *dev,
-                                  struct scatterlist *sg, int nelems,
-                                  enum dma_data_direction direction);
-extern int dma_mapping_error(struct device *dev, dma_addr_t dma_addr);
-extern int dma_get_cache_alignment(void);
-
-#define dma_alloc_noncoherent  dma_alloc_coherent
-#define dma_free_noncoherent   dma_free_coherent
-
-#endif /* _ASM_SPARC_DMA_MAPPING_H */
diff --git a/arch/sparc/include/asm/dma-mapping_64.h b/arch/sparc/include/asm/dma-mapping_64.h
deleted file mode 100644 (file)
index bfa64f9..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-#ifndef _ASM_SPARC64_DMA_MAPPING_H
-#define _ASM_SPARC64_DMA_MAPPING_H
-
-#include <linux/scatterlist.h>
-#include <linux/mm.h>
-
-#define DMA_ERROR_CODE (~(dma_addr_t)0x0)
-
-struct dma_ops {
-       void *(*alloc_coherent)(struct device *dev, size_t size,
-                               dma_addr_t *dma_handle, gfp_t flag);
-       void (*free_coherent)(struct device *dev, size_t size,
-                             void *cpu_addr, dma_addr_t dma_handle);
-       dma_addr_t (*map_single)(struct device *dev, void *cpu_addr,
-                                size_t size,
-                                enum dma_data_direction direction);
-       void (*unmap_single)(struct device *dev, dma_addr_t dma_addr,
-                            size_t size,
-                            enum dma_data_direction direction);
-       int (*map_sg)(struct device *dev, struct scatterlist *sg, int nents,
-                     enum dma_data_direction direction);
-       void (*unmap_sg)(struct device *dev, struct scatterlist *sg,
-                        int nhwentries,
-                        enum dma_data_direction direction);
-       void (*sync_single_for_cpu)(struct device *dev,
-                                   dma_addr_t dma_handle, size_t size,
-                                   enum dma_data_direction direction);
-       void (*sync_sg_for_cpu)(struct device *dev, struct scatterlist *sg,
-                               int nelems,
-                               enum dma_data_direction direction);
-};
-extern const struct dma_ops *dma_ops;
-
-extern int dma_supported(struct device *dev, u64 mask);
-extern int dma_set_mask(struct device *dev, u64 dma_mask);
-
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
-                                      dma_addr_t *dma_handle, gfp_t flag)
-{
-       return dma_ops->alloc_coherent(dev, size, dma_handle, flag);
-}
-
-static inline void dma_free_coherent(struct device *dev, size_t size,
-                                    void *cpu_addr, dma_addr_t dma_handle)
-{
-       dma_ops->free_coherent(dev, size, cpu_addr, dma_handle);
-}
-
-static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
-                                       size_t size,
-                                       enum dma_data_direction direction)
-{
-       return dma_ops->map_single(dev, cpu_addr, size, direction);
-}
-
-static inline void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
-                                   size_t size,
-                                   enum dma_data_direction direction)
-{
-       dma_ops->unmap_single(dev, dma_addr, size, direction);
-}
-
-static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
-                                     unsigned long offset, size_t size,
-                                     enum dma_data_direction direction)
-{
-       return dma_ops->map_single(dev, page_address(page) + offset,
-                                  size, direction);
-}
-
-static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
-                                 size_t size,
-                                 enum dma_data_direction direction)
-{
-       dma_ops->unmap_single(dev, dma_address, size, direction);
-}
-
-static inline int dma_map_sg(struct device *dev, struct scatterlist *sg,
-                            int nents, enum dma_data_direction direction)
-{
-       return dma_ops->map_sg(dev, sg, nents, direction);
-}
-
-static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
-                               int nents, enum dma_data_direction direction)
-{
-       dma_ops->unmap_sg(dev, sg, nents, direction);
-}
-
-static inline void dma_sync_single_for_cpu(struct device *dev,
-                                          dma_addr_t dma_handle, size_t size,
-                                          enum dma_data_direction direction)
-{
-       dma_ops->sync_single_for_cpu(dev, 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)
-{
-       /* No flushing needed to sync cpu writes to the device.  */
-}
-
-static inline void dma_sync_single_range_for_cpu(struct device *dev,
-                                                dma_addr_t dma_handle,
-                                                unsigned long offset,
-                                                size_t size,
-                                                enum dma_data_direction direction)
-{
-       dma_sync_single_for_cpu(dev, dma_handle+offset, size, direction);
-}
-
-static inline void dma_sync_single_range_for_device(struct device *dev,
-                                                   dma_addr_t dma_handle,
-                                                   unsigned long offset,
-                                                   size_t size,
-                                                   enum dma_data_direction direction)
-{
-       /* No flushing needed to sync cpu writes to the device.  */
-}
-
-
-static inline void dma_sync_sg_for_cpu(struct device *dev,
-                                      struct scatterlist *sg, int nelems,
-                                      enum dma_data_direction direction)
-{
-       dma_ops->sync_sg_for_cpu(dev, sg, nelems, direction);
-}
-
-static inline void dma_sync_sg_for_device(struct device *dev,
-                                         struct scatterlist *sg, int nelems,
-                                         enum dma_data_direction direction)
-{
-       /* No flushing needed to sync cpu writes to the device.  */
-}
-
-static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
-{
-       return (dma_addr == DMA_ERROR_CODE);
-}
-
-static inline int dma_get_cache_alignment(void)
-{
-       /* no easy way to get cache size on all processors, so return
-        * the maximum possible, to be safe */
-       return (1 << INTERNODE_CACHE_SHIFT);
-}
-
-#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
-#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
-#define dma_is_consistent(d, h)        (1)
-
-#endif /* _ASM_SPARC64_DMA_MAPPING_H */
index d27716cd38c1ac0243a74104f3106850d24397b1..b0f18e9893db5a77cbc45e221a8159e3dc4f2fc5 100644 (file)
@@ -11,4 +11,15 @@ extern void _mcount(void);
 
 #endif
 
+#ifdef CONFIG_DYNAMIC_FTRACE
+/* reloction of mcount call site is the same as the address */
+static inline unsigned long ftrace_call_adjust(unsigned long addr)
+{
+       return addr;
+}
+
+struct dyn_arch_ftrace {
+};
+#endif /*  CONFIG_DYNAMIC_FTRACE */
+
 #endif /* _ASM_SPARC64_FTRACE */
index 602f5e034f7a48afd0d85af3f72e2fbfd382d9d4..aad21745fbb92a6d67d2ea0d1efcfeb7467a1250 100644 (file)
@@ -5,21 +5,6 @@
  * is actually used on sparc.  -DaveM
  */
 
-enum km_type {
-       KM_BOUNCE_READ,
-       KM_SKB_SUNRPC_DATA,
-       KM_SKB_DATA_SOFTIRQ,
-       KM_USER0,
-       KM_USER1,
-       KM_BIO_SRC_IRQ,
-       KM_BIO_DST_IRQ,
-       KM_PTE0,
-       KM_PTE1,
-       KM_IRQ0,
-       KM_IRQ1,
-       KM_SOFTIRQ0,
-       KM_SOFTIRQ1,
-       KM_TYPE_NR
-};
+#include <asm-generic/kmap_types.h>
 
 #endif
index 1acc7272e537bca1bfe095ea24e518b32d837a9b..9faa046713fbaf3f6491a4dc3afca964849d9912 100644 (file)
@@ -71,7 +71,8 @@ struct mdesc_notifier_client {
 
 extern void mdesc_register_notifier(struct mdesc_notifier_client *client);
 
-extern void mdesc_fill_in_cpu_data(cpumask_t mask);
+extern void mdesc_fill_in_cpu_data(cpumask_t *mask);
+extern void mdesc_populate_present_mask(cpumask_t *mask);
 
 extern void sun4v_mdesc_init(void);
 
index bee64593023e2f34d0be046dcddd47d5e3167e60..007aafb4ae97e4914dbfeba584795680d41b6adf 100644 (file)
@@ -7,20 +7,16 @@ register unsigned long __local_per_cpu_offset asm("g5");
 
 #ifdef CONFIG_SMP
 
-extern void real_setup_per_cpu_areas(void);
+#include <asm/trap_block.h>
 
-extern unsigned long __per_cpu_base;
-extern unsigned long __per_cpu_shift;
 #define __per_cpu_offset(__cpu) \
-       (__per_cpu_base + ((unsigned long)(__cpu) << __per_cpu_shift))
+       (trap_block[(__cpu)].__per_cpu_base)
 #define per_cpu_offset(x) (__per_cpu_offset(x))
 
 #define __my_cpu_offset __local_per_cpu_offset
 
 #else /* ! SMP */
 
-#define real_setup_per_cpu_areas()             do { } while (0)
-
 #endif /* SMP */
 
 #include <asm-generic/percpu.h>
index 900d44714f8dd8525776a17cdd4e40e2d2bf7a3e..be8d7aaeb60d104563e4c88936da08d7c284828a 100644 (file)
@@ -86,6 +86,8 @@ extern int of_node_to_nid(struct device_node *dp);
 #endif
 
 extern void prom_build_devicetree(void);
+extern void of_populate_present_mask(void);
+extern void of_fill_in_cpu_data(void);
 
 /* Dummy ref counting routines - to be implemented later */
 static inline struct device_node *of_node_get(struct device_node *node)
diff --git a/arch/sparc/include/asm/trap_block.h b/arch/sparc/include/asm/trap_block.h
new file mode 100644 (file)
index 0000000..7e26b2d
--- /dev/null
@@ -0,0 +1,207 @@
+#ifndef _SPARC_TRAP_BLOCK_H
+#define _SPARC_TRAP_BLOCK_H
+
+#include <asm/hypervisor.h>
+#include <asm/asi.h>
+
+#ifndef __ASSEMBLY__
+
+/* Trap handling code needs to get at a few critical values upon
+ * trap entry and to process TSB misses.  These cannot be in the
+ * per_cpu() area as we really need to lock them into the TLB and
+ * thus make them part of the main kernel image.  As a result we
+ * try to make this as small as possible.
+ *
+ * This is padded out and aligned to 64-bytes to avoid false sharing
+ * on SMP.
+ */
+
+/* If you modify the size of this structure, please update
+ * TRAP_BLOCK_SZ_SHIFT below.
+ */
+struct thread_info;
+struct trap_per_cpu {
+/* D-cache line 1: Basic thread information, cpu and device mondo queues */
+       struct thread_info      *thread;
+       unsigned long           pgd_paddr;
+       unsigned long           cpu_mondo_pa;
+       unsigned long           dev_mondo_pa;
+
+/* D-cache line 2: Error Mondo Queue and kernel buffer pointers */
+       unsigned long           resum_mondo_pa;
+       unsigned long           resum_kernel_buf_pa;
+       unsigned long           nonresum_mondo_pa;
+       unsigned long           nonresum_kernel_buf_pa;
+
+/* Dcache lines 3, 4, 5, and 6: Hypervisor Fault Status */
+       struct hv_fault_status  fault_info;
+
+/* Dcache line 7: Physical addresses of CPU send mondo block and CPU list.  */
+       unsigned long           cpu_mondo_block_pa;
+       unsigned long           cpu_list_pa;
+       unsigned long           tsb_huge;
+       unsigned long           tsb_huge_temp;
+
+/* Dcache line 8: IRQ work list, and keep trap_block a power-of-2 in size.  */
+       unsigned long           irq_worklist_pa;
+       unsigned int            cpu_mondo_qmask;
+       unsigned int            dev_mondo_qmask;
+       unsigned int            resum_qmask;
+       unsigned int            nonresum_qmask;
+       unsigned long           __per_cpu_base;
+} __attribute__((aligned(64)));
+extern struct trap_per_cpu trap_block[NR_CPUS];
+extern void init_cur_cpu_trap(struct thread_info *);
+extern void setup_tba(void);
+extern int ncpus_probed;
+
+extern unsigned long real_hard_smp_processor_id(void);
+
+struct cpuid_patch_entry {
+       unsigned int    addr;
+       unsigned int    cheetah_safari[4];
+       unsigned int    cheetah_jbus[4];
+       unsigned int    starfire[4];
+       unsigned int    sun4v[4];
+};
+extern struct cpuid_patch_entry __cpuid_patch, __cpuid_patch_end;
+
+struct sun4v_1insn_patch_entry {
+       unsigned int    addr;
+       unsigned int    insn;
+};
+extern struct sun4v_1insn_patch_entry __sun4v_1insn_patch,
+       __sun4v_1insn_patch_end;
+
+struct sun4v_2insn_patch_entry {
+       unsigned int    addr;
+       unsigned int    insns[2];
+};
+extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch,
+       __sun4v_2insn_patch_end;
+
+
+#endif /* !(__ASSEMBLY__) */
+
+#define TRAP_PER_CPU_THREAD            0x00
+#define TRAP_PER_CPU_PGD_PADDR         0x08
+#define TRAP_PER_CPU_CPU_MONDO_PA      0x10
+#define TRAP_PER_CPU_DEV_MONDO_PA      0x18
+#define TRAP_PER_CPU_RESUM_MONDO_PA    0x20
+#define TRAP_PER_CPU_RESUM_KBUF_PA     0x28
+#define TRAP_PER_CPU_NONRESUM_MONDO_PA 0x30
+#define TRAP_PER_CPU_NONRESUM_KBUF_PA  0x38
+#define TRAP_PER_CPU_FAULT_INFO                0x40
+#define TRAP_PER_CPU_CPU_MONDO_BLOCK_PA        0xc0
+#define TRAP_PER_CPU_CPU_LIST_PA       0xc8
+#define TRAP_PER_CPU_TSB_HUGE          0xd0
+#define TRAP_PER_CPU_TSB_HUGE_TEMP     0xd8
+#define TRAP_PER_CPU_IRQ_WORKLIST_PA   0xe0
+#define TRAP_PER_CPU_CPU_MONDO_QMASK   0xe8
+#define TRAP_PER_CPU_DEV_MONDO_QMASK   0xec
+#define TRAP_PER_CPU_RESUM_QMASK       0xf0
+#define TRAP_PER_CPU_NONRESUM_QMASK    0xf4
+#define TRAP_PER_CPU_PER_CPU_BASE      0xf8
+
+#define TRAP_BLOCK_SZ_SHIFT            8
+
+#include <asm/scratchpad.h>
+
+#define __GET_CPUID(REG)                               \
+       /* Spitfire implementation (default). */        \
+661:   ldxa            [%g0] ASI_UPA_CONFIG, REG;      \
+       srlx            REG, 17, REG;                   \
+        and            REG, 0x1f, REG;                 \
+       nop;                                            \
+       .section        .cpuid_patch, "ax";             \
+       /* Instruction location. */                     \
+       .word           661b;                           \
+       /* Cheetah Safari implementation. */            \
+       ldxa            [%g0] ASI_SAFARI_CONFIG, REG;   \
+       srlx            REG, 17, REG;                   \
+       and             REG, 0x3ff, REG;                \
+       nop;                                            \
+       /* Cheetah JBUS implementation. */              \
+       ldxa            [%g0] ASI_JBUS_CONFIG, REG;     \
+       srlx            REG, 17, REG;                   \
+       and             REG, 0x1f, REG;                 \
+       nop;                                            \
+       /* Starfire implementation. */                  \
+       sethi           %hi(0x1fff40000d0 >> 9), REG;   \
+       sllx            REG, 9, REG;                    \
+       or              REG, 0xd0, REG;                 \
+       lduwa           [REG] ASI_PHYS_BYPASS_EC_E, REG;\
+       /* sun4v implementation. */                     \
+       mov             SCRATCHPAD_CPUID, REG;          \
+       ldxa            [REG] ASI_SCRATCHPAD, REG;      \
+       nop;                                            \
+       nop;                                            \
+       .previous;
+
+#ifdef CONFIG_SMP
+
+#define TRAP_LOAD_TRAP_BLOCK(DEST, TMP)                \
+       __GET_CPUID(TMP)                        \
+       sethi   %hi(trap_block), DEST;          \
+       sllx    TMP, TRAP_BLOCK_SZ_SHIFT, TMP;  \
+       or      DEST, %lo(trap_block), DEST;    \
+       add     DEST, TMP, DEST;                \
+
+/* Clobbers TMP, current address space PGD phys address into DEST.  */
+#define TRAP_LOAD_PGD_PHYS(DEST, TMP)          \
+       TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
+       ldx     [DEST + TRAP_PER_CPU_PGD_PADDR], DEST;
+
+/* Clobbers TMP, loads local processor's IRQ work area into DEST.  */
+#define TRAP_LOAD_IRQ_WORK_PA(DEST, TMP)       \
+       TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
+       add     DEST, TRAP_PER_CPU_IRQ_WORKLIST_PA, DEST;
+
+/* Clobbers TMP, loads DEST with current thread info pointer.  */
+#define TRAP_LOAD_THREAD_REG(DEST, TMP)                \
+       TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
+       ldx     [DEST + TRAP_PER_CPU_THREAD], DEST;
+
+/* Given the current thread info pointer in THR, load the per-cpu
+ * area base of the current processor into DEST.  REG1, REG2, and REG3 are
+ * clobbered.
+ *
+ * You absolutely cannot use DEST as a temporary in this code.  The
+ * reason is that traps can happen during execution, and return from
+ * trap will load the fully resolved DEST per-cpu base.  This can corrupt
+ * the calculations done by the macro mid-stream.
+ */
+#define LOAD_PER_CPU_BASE(DEST, THR, REG1, REG2, REG3) \
+       lduh    [THR + TI_CPU], REG1;                   \
+       sethi   %hi(trap_block), REG2;                  \
+       sllx    REG1, TRAP_BLOCK_SZ_SHIFT, REG1;        \
+       or      REG2, %lo(trap_block), REG2;            \
+       add     REG2, REG1, REG2;                       \
+       ldx     [REG2 + TRAP_PER_CPU_PER_CPU_BASE], DEST;
+
+#else
+
+#define TRAP_LOAD_TRAP_BLOCK(DEST, TMP)                \
+       sethi   %hi(trap_block), DEST;          \
+       or      DEST, %lo(trap_block), DEST;    \
+
+/* Uniprocessor versions, we know the cpuid is zero.  */
+#define TRAP_LOAD_PGD_PHYS(DEST, TMP)          \
+       TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
+       ldx     [DEST + TRAP_PER_CPU_PGD_PADDR], DEST;
+
+/* Clobbers TMP, loads local processor's IRQ work area into DEST.  */
+#define TRAP_LOAD_IRQ_WORK_PA(DEST, TMP)       \
+       TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
+       add     DEST, TRAP_PER_CPU_IRQ_WORKLIST_PA, DEST;
+
+#define TRAP_LOAD_THREAD_REG(DEST, TMP)                \
+       TRAP_LOAD_TRAP_BLOCK(DEST, TMP)         \
+       ldx     [DEST + TRAP_PER_CPU_THREAD], DEST;
+
+/* No per-cpu areas on uniprocessor, so no need to load DEST.  */
+#define LOAD_PER_CPU_BASE(DEST, THR, REG1, REG2, REG3)
+
+#endif /* !(CONFIG_SMP) */
+
+#endif /* _SPARC_TRAP_BLOCK_H */
index b8eb71ef31631794b3e9e2b6e4527d320d44857c..b2c406de7d4fd75e1d00aed701dd2d9807edbaa6 100644 (file)
 #define __NR_accept4           323
 #define __NR_preadv            324
 #define __NR_pwritev           325
+#define __NR_rt_tgsigqueueinfo 326
 
-#define NR_SYSCALLS            326
+#define NR_SYSCALLS            327
 
 #ifdef __32bit_syscall_numbers__
 /* Sparc 32-bit only has the "setresuid32", "getresuid32" variants,
index 54742e58831c4d78e19bad176145e8ce0bae7d6b..475ce4696acd915d90cbc2e91440cfa469dcff8b 100644 (file)
@@ -37,6 +37,7 @@ obj-y                   += una_asm_$(BITS).o
 obj-$(CONFIG_SPARC32)   += muldiv.o
 obj-y                   += prom_common.o
 obj-y                   += prom_$(BITS).o
+obj-y                   += of_device_common.o
 obj-y                   += of_device_$(BITS).o
 obj-$(CONFIG_SPARC64)   += prom_irqtrans.o
 
@@ -54,6 +55,7 @@ obj-$(CONFIG_SPARC64)   += sstate.o
 obj-$(CONFIG_SPARC64)   += mdesc.o
 obj-$(CONFIG_SPARC64)  += pcr.o
 obj-$(CONFIG_SPARC64)  += nmi.o
+obj-$(CONFIG_SPARC64_SMP) += cpumap.o
 
 # sparc32 do not use GENERIC_HARDIRQS but uses the generic devres implementation
 obj-$(CONFIG_SPARC32)     += devres.o
diff --git a/arch/sparc/kernel/cpumap.c b/arch/sparc/kernel/cpumap.c
new file mode 100644 (file)
index 0000000..7430ed0
--- /dev/null
@@ -0,0 +1,431 @@
+/* cpumap.c: used for optimizing CPU assignment
+ *
+ * Copyright (C) 2009 Hong H. Pham <hong.pham@windriver.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/cpumask.h>
+#include <linux/spinlock.h>
+#include <asm/cpudata.h>
+#include "cpumap.h"
+
+
+enum {
+       CPUINFO_LVL_ROOT = 0,
+       CPUINFO_LVL_NODE,
+       CPUINFO_LVL_CORE,
+       CPUINFO_LVL_PROC,
+       CPUINFO_LVL_MAX,
+};
+
+enum {
+       ROVER_NO_OP              = 0,
+       /* Increment rover every time level is visited */
+       ROVER_INC_ON_VISIT       = 1 << 0,
+       /* Increment parent's rover every time rover wraps around */
+       ROVER_INC_PARENT_ON_LOOP = 1 << 1,
+};
+
+struct cpuinfo_node {
+       int id;
+       int level;
+       int num_cpus;    /* Number of CPUs in this hierarchy */
+       int parent_index;
+       int child_start; /* Array index of the first child node */
+       int child_end;   /* Array index of the last child node */
+       int rover;       /* Child node iterator */
+};
+
+struct cpuinfo_level {
+       int start_index; /* Index of first node of a level in a cpuinfo tree */
+       int end_index;   /* Index of last node of a level in a cpuinfo tree */
+       int num_nodes;   /* Number of nodes in a level in a cpuinfo tree */
+};
+
+struct cpuinfo_tree {
+       int total_nodes;
+
+       /* Offsets into nodes[] for each level of the tree */
+       struct cpuinfo_level level[CPUINFO_LVL_MAX];
+       struct cpuinfo_node  nodes[0];
+};
+
+
+static struct cpuinfo_tree *cpuinfo_tree;
+
+static u16 cpu_distribution_map[NR_CPUS];
+static DEFINE_SPINLOCK(cpu_map_lock);
+
+
+/* Niagara optimized cpuinfo tree traversal. */
+static const int niagara_iterate_method[] = {
+       [CPUINFO_LVL_ROOT] = ROVER_NO_OP,
+
+       /* Strands (or virtual CPUs) within a core may not run concurrently
+        * on the Niagara, as instruction pipeline(s) are shared.  Distribute
+        * work to strands in different cores first for better concurrency.
+        * Go to next NUMA node when all cores are used.
+        */
+       [CPUINFO_LVL_NODE] = ROVER_INC_ON_VISIT|ROVER_INC_PARENT_ON_LOOP,
+
+       /* Strands are grouped together by proc_id in cpuinfo_sparc, i.e.
+        * a proc_id represents an instruction pipeline.  Distribute work to
+        * strands in different proc_id groups if the core has multiple
+        * instruction pipelines (e.g. the Niagara 2/2+ has two).
+        */
+       [CPUINFO_LVL_CORE] = ROVER_INC_ON_VISIT,
+
+       /* Pick the next strand in the proc_id group. */
+       [CPUINFO_LVL_PROC] = ROVER_INC_ON_VISIT,
+};
+
+/* Generic cpuinfo tree traversal.  Distribute work round robin across NUMA
+ * nodes.
+ */
+static const int generic_iterate_method[] = {
+       [CPUINFO_LVL_ROOT] = ROVER_INC_ON_VISIT,
+       [CPUINFO_LVL_NODE] = ROVER_NO_OP,
+       [CPUINFO_LVL_CORE] = ROVER_INC_PARENT_ON_LOOP,
+       [CPUINFO_LVL_PROC] = ROVER_INC_ON_VISIT|ROVER_INC_PARENT_ON_LOOP,
+};
+
+
+static int cpuinfo_id(int cpu, int level)
+{
+       int id;
+
+       switch (level) {
+       case CPUINFO_LVL_ROOT:
+               id = 0;
+               break;
+       case CPUINFO_LVL_NODE:
+               id = cpu_to_node(cpu);
+               break;
+       case CPUINFO_LVL_CORE:
+               id = cpu_data(cpu).core_id;
+               break;
+       case CPUINFO_LVL_PROC:
+               id = cpu_data(cpu).proc_id;
+               break;
+       default:
+               id = -EINVAL;
+       }
+       return id;
+}
+
+/*
+ * Enumerate the CPU information in __cpu_data to determine the start index,
+ * end index, and number of nodes for each level in the cpuinfo tree.  The
+ * total number of cpuinfo nodes required to build the tree is returned.
+ */
+static int enumerate_cpuinfo_nodes(struct cpuinfo_level *tree_level)
+{
+       int prev_id[CPUINFO_LVL_MAX];
+       int i, n, num_nodes;
+
+       for (i = CPUINFO_LVL_ROOT; i < CPUINFO_LVL_MAX; i++) {
+               struct cpuinfo_level *lv = &tree_level[i];
+
+               prev_id[i] = -1;
+               lv->start_index = lv->end_index = lv->num_nodes = 0;
+       }
+
+       num_nodes = 1; /* Include the root node */
+
+       for (i = 0; i < num_possible_cpus(); i++) {
+               if (!cpu_online(i))
+                       continue;
+
+               n = cpuinfo_id(i, CPUINFO_LVL_NODE);
+               if (n > prev_id[CPUINFO_LVL_NODE]) {
+                       tree_level[CPUINFO_LVL_NODE].num_nodes++;
+                       prev_id[CPUINFO_LVL_NODE] = n;
+                       num_nodes++;
+               }
+               n = cpuinfo_id(i, CPUINFO_LVL_CORE);
+               if (n > prev_id[CPUINFO_LVL_CORE]) {
+                       tree_level[CPUINFO_LVL_CORE].num_nodes++;
+                       prev_id[CPUINFO_LVL_CORE] = n;
+                       num_nodes++;
+               }
+               n = cpuinfo_id(i, CPUINFO_LVL_PROC);
+               if (n > prev_id[CPUINFO_LVL_PROC]) {
+                       tree_level[CPUINFO_LVL_PROC].num_nodes++;
+                       prev_id[CPUINFO_LVL_PROC] = n;
+                       num_nodes++;
+               }
+       }
+
+       tree_level[CPUINFO_LVL_ROOT].num_nodes = 1;
+
+       n = tree_level[CPUINFO_LVL_NODE].num_nodes;
+       tree_level[CPUINFO_LVL_NODE].start_index = 1;
+       tree_level[CPUINFO_LVL_NODE].end_index   = n;
+
+       n++;
+       tree_level[CPUINFO_LVL_CORE].start_index = n;
+       n += tree_level[CPUINFO_LVL_CORE].num_nodes;
+       tree_level[CPUINFO_LVL_CORE].end_index   = n - 1;
+
+       tree_level[CPUINFO_LVL_PROC].start_index = n;
+       n += tree_level[CPUINFO_LVL_PROC].num_nodes;
+       tree_level[CPUINFO_LVL_PROC].end_index   = n - 1;
+
+       return num_nodes;
+}
+
+/* Build a tree representation of the CPU hierarchy using the per CPU
+ * information in __cpu_data.  Entries in __cpu_data[0..NR_CPUS] are
+ * assumed to be sorted in ascending order based on node, core_id, and
+ * proc_id (in order of significance).
+ */
+static struct cpuinfo_tree *build_cpuinfo_tree(void)
+{
+       struct cpuinfo_tree *new_tree;
+       struct cpuinfo_node *node;
+       struct cpuinfo_level tmp_level[CPUINFO_LVL_MAX];
+       int num_cpus[CPUINFO_LVL_MAX];
+       int level_rover[CPUINFO_LVL_MAX];
+       int prev_id[CPUINFO_LVL_MAX];
+       int n, id, cpu, prev_cpu, last_cpu, level;
+
+       n = enumerate_cpuinfo_nodes(tmp_level);
+
+       new_tree = kzalloc(sizeof(struct cpuinfo_tree) +
+                          (sizeof(struct cpuinfo_node) * n), GFP_ATOMIC);
+       if (!new_tree)
+               return NULL;
+
+       new_tree->total_nodes = n;
+       memcpy(&new_tree->level, tmp_level, sizeof(tmp_level));
+
+       prev_cpu = cpu = first_cpu(cpu_online_map);
+
+       /* Initialize all levels in the tree with the first CPU */
+       for (level = CPUINFO_LVL_PROC; level >= CPUINFO_LVL_ROOT; level--) {
+               n = new_tree->level[level].start_index;
+
+               level_rover[level] = n;
+               node = &new_tree->nodes[n];
+
+               id = cpuinfo_id(cpu, level);
+               if (unlikely(id < 0)) {
+                       kfree(new_tree);
+                       return NULL;
+               }
+               node->id = id;
+               node->level = level;
+               node->num_cpus = 1;
+
+               node->parent_index = (level > CPUINFO_LVL_ROOT)
+                   ? new_tree->level[level - 1].start_index : -1;
+
+               node->child_start = node->child_end = node->rover =
+                   (level == CPUINFO_LVL_PROC)
+                   ? cpu : new_tree->level[level + 1].start_index;
+
+               prev_id[level] = node->id;
+               num_cpus[level] = 1;
+       }
+
+       for (last_cpu = (num_possible_cpus() - 1); last_cpu >= 0; last_cpu--) {
+               if (cpu_online(last_cpu))
+                       break;
+       }
+
+       while (++cpu <= last_cpu) {
+               if (!cpu_online(cpu))
+                       continue;
+
+               for (level = CPUINFO_LVL_PROC; level >= CPUINFO_LVL_ROOT;
+                    level--) {
+                       id = cpuinfo_id(cpu, level);
+                       if (unlikely(id < 0)) {
+                               kfree(new_tree);
+                               return NULL;
+                       }
+
+                       if ((id != prev_id[level]) || (cpu == last_cpu)) {
+                               prev_id[level] = id;
+                               node = &new_tree->nodes[level_rover[level]];
+                               node->num_cpus = num_cpus[level];
+                               num_cpus[level] = 1;
+
+                               if (cpu == last_cpu)
+                                       node->num_cpus++;
+
+                               /* Connect tree node to parent */
+                               if (level == CPUINFO_LVL_ROOT)
+                                       node->parent_index = -1;
+                               else
+                                       node->parent_index =
+                                           level_rover[level - 1];
+
+                               if (level == CPUINFO_LVL_PROC) {
+                                       node->child_end =
+                                           (cpu == last_cpu) ? cpu : prev_cpu;
+                               } else {
+                                       node->child_end =
+                                           level_rover[level + 1] - 1;
+                               }
+
+                               /* Initialize the next node in the same level */
+                               n = ++level_rover[level];
+                               if (n <= new_tree->level[level].end_index) {
+                                       node = &new_tree->nodes[n];
+                                       node->id = id;
+                                       node->level = level;
+
+                                       /* Connect node to child */
+                                       node->child_start = node->child_end =
+                                       node->rover =
+                                           (level == CPUINFO_LVL_PROC)
+                                           ? cpu : level_rover[level + 1];
+                               }
+                       } else
+                               num_cpus[level]++;
+               }
+               prev_cpu = cpu;
+       }
+
+       return new_tree;
+}
+
+static void increment_rover(struct cpuinfo_tree *t, int node_index,
+                            int root_index, const int *rover_inc_table)
+{
+       struct cpuinfo_node *node = &t->nodes[node_index];
+       int top_level, level;
+
+       top_level = t->nodes[root_index].level;
+       for (level = node->level; level >= top_level; level--) {
+               node->rover++;
+               if (node->rover <= node->child_end)
+                       return;
+
+               node->rover = node->child_start;
+               /* If parent's rover does not need to be adjusted, stop here. */
+               if ((level == top_level) ||
+                   !(rover_inc_table[level] & ROVER_INC_PARENT_ON_LOOP))
+                       return;
+
+               node = &t->nodes[node->parent_index];
+       }
+}
+
+static int iterate_cpu(struct cpuinfo_tree *t, unsigned int root_index)
+{
+       const int *rover_inc_table;
+       int level, new_index, index = root_index;
+
+       switch (sun4v_chip_type) {
+       case SUN4V_CHIP_NIAGARA1:
+       case SUN4V_CHIP_NIAGARA2:
+               rover_inc_table = niagara_iterate_method;
+               break;
+       default:
+               rover_inc_table = generic_iterate_method;
+       }
+
+       for (level = t->nodes[root_index].level; level < CPUINFO_LVL_MAX;
+            level++) {
+               new_index = t->nodes[index].rover;
+               if (rover_inc_table[level] & ROVER_INC_ON_VISIT)
+                       increment_rover(t, index, root_index, rover_inc_table);
+
+               index = new_index;
+       }
+       return index;
+}
+
+static void _cpu_map_rebuild(void)
+{
+       int i;
+
+       if (cpuinfo_tree) {
+               kfree(cpuinfo_tree);
+               cpuinfo_tree = NULL;
+       }
+
+       cpuinfo_tree = build_cpuinfo_tree();
+       if (!cpuinfo_tree)
+               return;
+
+       /* Build CPU distribution map that spans all online CPUs.  No need
+        * to check if the CPU is online, as that is done when the cpuinfo
+        * tree is being built.
+        */
+       for (i = 0; i < cpuinfo_tree->nodes[0].num_cpus; i++)
+               cpu_distribution_map[i] = iterate_cpu(cpuinfo_tree, 0);
+}
+
+/* Fallback if the cpuinfo tree could not be built.  CPU mapping is linear
+ * round robin.
+ */
+static int simple_map_to_cpu(unsigned int index)
+{
+       int i, end, cpu_rover;
+
+       cpu_rover = 0;
+       end = index % num_online_cpus();
+       for (i = 0; i < num_possible_cpus(); i++) {
+               if (cpu_online(cpu_rover)) {
+                       if (cpu_rover >= end)
+                               return cpu_rover;
+
+                       cpu_rover++;
+               }
+       }
+
+       /* Impossible, since num_online_cpus() <= num_possible_cpus() */
+       return first_cpu(cpu_online_map);
+}
+
+static int _map_to_cpu(unsigned int index)
+{
+       struct cpuinfo_node *root_node;
+
+       if (unlikely(!cpuinfo_tree)) {
+               _cpu_map_rebuild();
+               if (!cpuinfo_tree)
+                       return simple_map_to_cpu(index);
+       }
+
+       root_node = &cpuinfo_tree->nodes[0];
+#ifdef CONFIG_HOTPLUG_CPU
+       if (unlikely(root_node->num_cpus != num_online_cpus())) {
+               _cpu_map_rebuild();
+               if (!cpuinfo_tree)
+                       return simple_map_to_cpu(index);
+       }
+#endif
+       return cpu_distribution_map[index % root_node->num_cpus];
+}
+
+int map_to_cpu(unsigned int index)
+{
+       int mapped_cpu;
+       unsigned long flag;
+
+       spin_lock_irqsave(&cpu_map_lock, flag);
+       mapped_cpu = _map_to_cpu(index);
+
+#ifdef CONFIG_HOTPLUG_CPU
+       while (unlikely(!cpu_online(mapped_cpu)))
+               mapped_cpu = _map_to_cpu(index);
+#endif
+       spin_unlock_irqrestore(&cpu_map_lock, flag);
+       return mapped_cpu;
+}
+EXPORT_SYMBOL(map_to_cpu);
+
+void cpu_map_rebuild(void)
+{
+       unsigned long flag;
+
+       spin_lock_irqsave(&cpu_map_lock, flag);
+       _cpu_map_rebuild();
+       spin_unlock_irqrestore(&cpu_map_lock, flag);
+}
diff --git a/arch/sparc/kernel/cpumap.h b/arch/sparc/kernel/cpumap.h
new file mode 100644 (file)
index 0000000..e639880
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _CPUMAP_H
+#define _CPUMAP_H
+
+#ifdef CONFIG_SMP
+extern void cpu_map_rebuild(void);
+extern int  map_to_cpu(unsigned int index);
+#define cpu_map_init() cpu_map_rebuild()
+#else
+#define cpu_map_init() do {} while (0)
+static inline int map_to_cpu(unsigned int index)
+{
+       return raw_smp_processor_id();
+}
+#endif
+
+#endif
index ebc8403b035ee6b477a62254660e6db8fd48b5bc..524c32f97c555856809f3d9400d9fd76080aaa38 100644 (file)
@@ -35,8 +35,8 @@ int dma_set_mask(struct device *dev, u64 dma_mask)
 }
 EXPORT_SYMBOL(dma_set_mask);
 
-void *dma_alloc_coherent(struct device *dev, size_t size,
-                        dma_addr_t *dma_handle, gfp_t flag)
+static void *dma32_alloc_coherent(struct device *dev, size_t size,
+                                 dma_addr_t *dma_handle, gfp_t flag)
 {
 #ifdef CONFIG_PCI
        if (dev->bus == &pci_bus_type)
@@ -44,10 +44,9 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
 #endif
        return sbus_alloc_consistent(dev, size, dma_handle);
 }
-EXPORT_SYMBOL(dma_alloc_coherent);
 
-void dma_free_coherent(struct device *dev, size_t size,
-                      void *cpu_addr, dma_addr_t dma_handle)
+static void dma32_free_coherent(struct device *dev, size_t size,
+                               void *cpu_addr, dma_addr_t dma_handle)
 {
 #ifdef CONFIG_PCI
        if (dev->bus == &pci_bus_type) {
@@ -58,38 +57,10 @@ void dma_free_coherent(struct device *dev, size_t size,
 #endif
        sbus_free_consistent(dev, size, cpu_addr, dma_handle);
 }
-EXPORT_SYMBOL(dma_free_coherent);
 
-dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
-                         size_t size, enum dma_data_direction direction)
-{
-#ifdef CONFIG_PCI
-       if (dev->bus == &pci_bus_type)
-               return pci_map_single(to_pci_dev(dev), cpu_addr,
-                                     size, (int)direction);
-#endif
-       return sbus_map_single(dev, cpu_addr, size, (int)direction);
-}
-EXPORT_SYMBOL(dma_map_single);
-
-void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
-                     size_t size,
-                     enum dma_data_direction direction)
-{
-#ifdef CONFIG_PCI
-       if (dev->bus == &pci_bus_type) {
-               pci_unmap_single(to_pci_dev(dev), dma_addr,
-                                size, (int)direction);
-               return;
-       }
-#endif
-       sbus_unmap_single(dev, dma_addr, size, (int)direction);
-}
-EXPORT_SYMBOL(dma_unmap_single);
-
-dma_addr_t dma_map_page(struct device *dev, struct page *page,
-                       unsigned long offset, size_t size,
-                       enum dma_data_direction direction)
+static dma_addr_t dma32_map_page(struct device *dev, struct page *page,
+                                unsigned long offset, size_t size,
+                                enum dma_data_direction direction)
 {
 #ifdef CONFIG_PCI
        if (dev->bus == &pci_bus_type)
@@ -99,10 +70,9 @@ dma_addr_t dma_map_page(struct device *dev, struct page *page,
        return sbus_map_single(dev, page_address(page) + offset,
                               size, (int)direction);
 }
-EXPORT_SYMBOL(dma_map_page);
 
-void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
-                   size_t size, enum dma_data_direction direction)
+static void dma32_unmap_page(struct device *dev, dma_addr_t dma_address,
+                            size_t size, enum dma_data_direction direction)
 {
 #ifdef CONFIG_PCI
        if (dev->bus == &pci_bus_type) {
@@ -113,10 +83,9 @@ void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
 #endif
        sbus_unmap_single(dev, dma_address, size, (int)direction);
 }
-EXPORT_SYMBOL(dma_unmap_page);
 
-int dma_map_sg(struct device *dev, struct scatterlist *sg,
-                            int nents, enum dma_data_direction direction)
+static int dma32_map_sg(struct device *dev, struct scatterlist *sg,
+                       int nents, enum dma_data_direction direction)
 {
 #ifdef CONFIG_PCI
        if (dev->bus == &pci_bus_type)
@@ -124,10 +93,9 @@ int dma_map_sg(struct device *dev, struct scatterlist *sg,
 #endif
        return sbus_map_sg(dev, sg, nents, direction);
 }
-EXPORT_SYMBOL(dma_map_sg);
 
-void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
-                 int nents, enum dma_data_direction direction)
+void dma32_unmap_sg(struct device *dev, struct scatterlist *sg,
+                   int nents, enum dma_data_direction direction)
 {
 #ifdef CONFIG_PCI
        if (dev->bus == &pci_bus_type) {
@@ -137,10 +105,10 @@ void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
 #endif
        sbus_unmap_sg(dev, sg, nents, (int)direction);
 }
-EXPORT_SYMBOL(dma_unmap_sg);
 
-void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
-                            size_t size, enum dma_data_direction direction)
+static void dma32_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
+                                     size_t size,
+                                     enum dma_data_direction direction)
 {
 #ifdef CONFIG_PCI
        if (dev->bus == &pci_bus_type) {
@@ -151,10 +119,10 @@ void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
 #endif
        sbus_dma_sync_single_for_cpu(dev, dma_handle, size, (int) direction);
 }
-EXPORT_SYMBOL(dma_sync_single_for_cpu);
 
-void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
-                               size_t size, enum dma_data_direction direction)
+static void dma32_sync_single_for_device(struct device *dev,
+                                        dma_addr_t dma_handle, size_t size,
+                                        enum dma_data_direction direction)
 {
 #ifdef CONFIG_PCI
        if (dev->bus == &pci_bus_type) {
@@ -165,28 +133,9 @@ void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
 #endif
        sbus_dma_sync_single_for_device(dev, dma_handle, size, (int) direction);
 }
-EXPORT_SYMBOL(dma_sync_single_for_device);
-
-void dma_sync_single_range_for_cpu(struct device *dev,
-                                  dma_addr_t dma_handle,
-                                  unsigned long offset,
-                                  size_t size,
-                                  enum dma_data_direction direction)
-{
-       dma_sync_single_for_cpu(dev, dma_handle+offset, size, direction);
-}
-EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
-
-void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
-                                     unsigned long offset, size_t size,
-                                     enum dma_data_direction direction)
-{
-       dma_sync_single_for_device(dev, dma_handle+offset, size, direction);
-}
-EXPORT_SYMBOL(dma_sync_single_range_for_device);
 
-void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
-                        int nelems, enum dma_data_direction direction)
+static void dma32_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+                                 int nelems, enum dma_data_direction direction)
 {
 #ifdef CONFIG_PCI
        if (dev->bus == &pci_bus_type) {
@@ -197,11 +146,10 @@ void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
 #endif
        BUG();
 }
-EXPORT_SYMBOL(dma_sync_sg_for_cpu);
 
-void dma_sync_sg_for_device(struct device *dev,
-                           struct scatterlist *sg, int nelems,
-                           enum dma_data_direction direction)
+static void dma32_sync_sg_for_device(struct device *dev,
+                                    struct scatterlist *sg, int nelems,
+                                    enum dma_data_direction direction)
 {
 #ifdef CONFIG_PCI
        if (dev->bus == &pci_bus_type) {
@@ -212,16 +160,19 @@ void dma_sync_sg_for_device(struct device *dev,
 #endif
        BUG();
 }
-EXPORT_SYMBOL(dma_sync_sg_for_device);
 
-int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
-{
-       return (dma_addr == DMA_ERROR_CODE);
-}
-EXPORT_SYMBOL(dma_mapping_error);
-
-int dma_get_cache_alignment(void)
-{
-       return 32;
-}
-EXPORT_SYMBOL(dma_get_cache_alignment);
+static const struct dma_ops dma32_dma_ops = {
+       .alloc_coherent         = dma32_alloc_coherent,
+       .free_coherent          = dma32_free_coherent,
+       .map_page               = dma32_map_page,
+       .unmap_page             = dma32_unmap_page,
+       .map_sg                 = dma32_map_sg,
+       .unmap_sg               = dma32_unmap_sg,
+       .sync_single_for_cpu    = dma32_sync_single_for_cpu,
+       .sync_single_for_device = dma32_sync_single_for_device,
+       .sync_sg_for_cpu        = dma32_sync_sg_for_cpu,
+       .sync_sg_for_device     = dma32_sync_sg_for_device,
+};
+
+const struct dma_ops *dma_ops = &dma32_dma_ops;
+EXPORT_SYMBOL(dma_ops);
index 90350f838f05efa92a9739d4e4a03079f5f0ae55..4a700f4b79cebf068cba0c82ea22dcf6602ba74b 100644 (file)
@@ -544,7 +544,8 @@ static int __cpuinit dr_cpu_configure(struct ds_info *dp,
                             resp_len, ncpus, mask,
                             DR_CPU_STAT_CONFIGURED);
 
-       mdesc_fill_in_cpu_data(*mask);
+       mdesc_populate_present_mask(mask);
+       mdesc_fill_in_cpu_data(mask);
 
        for_each_cpu_mask(cpu, *mask) {
                int err;
index d0218e73f9820b6a478837df8dcd2869f233dcbd..d3b1a3076569890724fdc58a77fd1949ca96a684 100644 (file)
@@ -7,14 +7,10 @@
 
 #include <asm/ftrace.h>
 
+#ifdef CONFIG_DYNAMIC_FTRACE
 static const u32 ftrace_nop = 0x01000000;
 
-unsigned char *ftrace_nop_replace(void)
-{
-       return (char *)&ftrace_nop;
-}
-
-unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
+static u32 ftrace_call_replace(unsigned long ip, unsigned long addr)
 {
        static u32 call;
        s32 off;
@@ -22,15 +18,11 @@ unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
        off = ((s32)addr - (s32)ip);
        call = 0x40000000 | ((u32)off >> 2);
 
-       return (unsigned char *) &call;
+       return call;
 }
 
-int
-ftrace_modify_code(unsigned long ip, unsigned char *old_code,
-                  unsigned char *new_code)
+static int ftrace_modify_code(unsigned long ip, u32 old, u32 new)
 {
-       u32 old = *(u32 *)old_code;
-       u32 new = *(u32 *)new_code;
        u32 replaced;
        int faulted;
 
@@ -59,18 +51,43 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code,
        return faulted;
 }
 
+int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr)
+{
+       unsigned long ip = rec->ip;
+       u32 old, new;
+
+       old = ftrace_call_replace(ip, addr);
+       new = ftrace_nop;
+       return ftrace_modify_code(ip, old, new);
+}
+
+int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+       unsigned long ip = rec->ip;
+       u32 old, new;
+
+       old = ftrace_nop;
+       new = ftrace_call_replace(ip, addr);
+       return ftrace_modify_code(ip, old, new);
+}
+
 int ftrace_update_ftrace_func(ftrace_func_t func)
 {
        unsigned long ip = (unsigned long)(&ftrace_call);
-       unsigned char old[MCOUNT_INSN_SIZE], *new;
+       u32 old, new;
 
-       memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE);
+       old = *(u32 *) &ftrace_call;
        new = ftrace_call_replace(ip, (unsigned long)func);
        return ftrace_modify_code(ip, old, new);
 }
 
 int __init ftrace_dyn_arch_init(void *data)
 {
-       ftrace_mcount_set(data);
+       unsigned long *p = data;
+
+       *p = 0;
+
        return 0;
 }
+#endif
+
index 91bf4c7f79b9c6c6acc90fe0ecbb90f503e6a1d5..f8f21050448b8963bc25e23e87a3a4f816bbbea6 100644 (file)
@@ -641,28 +641,6 @@ tlb_fixup_done:
        /* Not reached... */
 
 1:
-       /* If we boot on a non-zero cpu, all of the per-cpu
-        * variable references we make before setting up the
-        * per-cpu areas will use a bogus offset.  Put a
-        * compensating factor into __per_cpu_base to handle
-        * this cleanly.
-        *
-        * What the per-cpu code calculates is:
-        *
-        *      __per_cpu_base + (cpu << __per_cpu_shift)
-        *
-        * These two variables are zero initially, so to
-        * make it all cancel out to zero we need to put
-        * "0 - (cpu << 0)" into __per_cpu_base so that the
-        * above formula evaluates to zero.
-        *
-        * We cannot even perform a printk() until this stuff
-        * is setup as that calls cpu_clock() which uses
-        * per-cpu variables.
-        */
-       sub     %g0, %o0, %o1
-       sethi   %hi(__per_cpu_base), %o2
-       stx     %o1, [%o2 + %lo(__per_cpu_base)]
 #else
        mov     0, %o0
 #endif
index f28cb8278e98abb6f2fb79c634b2e74e52cfac84..28125c5b3d3c306e216012ac7b529fa6b0f33e0a 100644 (file)
 
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-struct mm_struct init_mm = INIT_MM(init_mm);
 struct task_struct init_task = INIT_TASK(init_task);
-
-EXPORT_SYMBOL(init_mm);
 EXPORT_SYMBOL(init_task);
 
 /* .text section in head.S is aligned at 8k boundary and this gets linked
index d8900e1d5aad0cbd2253079e0ef927c9465e4fe5..0aeaefe696b9110733f2ceb6af333c7d0a33ab56 100644 (file)
@@ -351,8 +351,9 @@ static void dma_4u_free_coherent(struct device *dev, size_t size,
                free_pages((unsigned long)cpu, order);
 }
 
-static dma_addr_t dma_4u_map_single(struct device *dev, void *ptr, size_t sz,
-                                   enum dma_data_direction direction)
+static dma_addr_t dma_4u_map_page(struct device *dev, struct page *page,
+                                 unsigned long offset, size_t sz,
+                                 enum dma_data_direction direction)
 {
        struct iommu *iommu;
        struct strbuf *strbuf;
@@ -368,7 +369,7 @@ static dma_addr_t dma_4u_map_single(struct device *dev, void *ptr, size_t sz,
        if (unlikely(direction == DMA_NONE))
                goto bad_no_ctx;
 
-       oaddr = (unsigned long)ptr;
+       oaddr = (unsigned long)(page_address(page) + offset);
        npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK);
        npages >>= IO_PAGE_SHIFT;
 
@@ -472,8 +473,8 @@ do_flush_sync:
                       vaddr, ctx, npages);
 }
 
-static void dma_4u_unmap_single(struct device *dev, dma_addr_t bus_addr,
-                               size_t sz, enum dma_data_direction direction)
+static void dma_4u_unmap_page(struct device *dev, dma_addr_t bus_addr,
+                             size_t sz, enum dma_data_direction direction)
 {
        struct iommu *iommu;
        struct strbuf *strbuf;
@@ -824,8 +825,8 @@ static void dma_4u_sync_sg_for_cpu(struct device *dev,
 static const struct dma_ops sun4u_dma_ops = {
        .alloc_coherent         = dma_4u_alloc_coherent,
        .free_coherent          = dma_4u_free_coherent,
-       .map_single             = dma_4u_map_single,
-       .unmap_single           = dma_4u_unmap_single,
+       .map_page               = dma_4u_map_page,
+       .unmap_page             = dma_4u_unmap_page,
        .map_sg                 = dma_4u_map_sg,
        .unmap_sg               = dma_4u_unmap_sg,
        .sync_single_for_cpu    = dma_4u_sync_single_for_cpu,
index e5e78f9cfc95d7104ede2ab767fdd1e5401f623c..bd075054942bd900fecb66516b40d02c95becd0e 100644 (file)
@@ -45,6 +45,7 @@
 #include <asm/cacheflush.h>
 
 #include "entry.h"
+#include "cpumap.h"
 
 #define NUM_IVECS      (IMAP_INR + 1)
 
@@ -256,35 +257,13 @@ static int irq_choose_cpu(unsigned int virt_irq)
        int cpuid;
 
        cpumask_copy(&mask, irq_desc[virt_irq].affinity);
-       if (cpus_equal(mask, CPU_MASK_ALL)) {
-               static int irq_rover;
-               static DEFINE_SPINLOCK(irq_rover_lock);
-               unsigned long flags;
-
-               /* Round-robin distribution... */
-       do_round_robin:
-               spin_lock_irqsave(&irq_rover_lock, flags);
-
-               while (!cpu_online(irq_rover)) {
-                       if (++irq_rover >= nr_cpu_ids)
-                               irq_rover = 0;
-               }
-               cpuid = irq_rover;
-               do {
-                       if (++irq_rover >= nr_cpu_ids)
-                               irq_rover = 0;
-               } while (!cpu_online(irq_rover));
-
-               spin_unlock_irqrestore(&irq_rover_lock, flags);
+       if (cpus_equal(mask, cpu_online_map)) {
+               cpuid = map_to_cpu(virt_irq);
        } else {
                cpumask_t tmp;
 
                cpus_and(tmp, cpu_online_map, mask);
-
-               if (cpus_empty(tmp))
-                       goto do_round_robin;
-
-               cpuid = first_cpu(tmp);
+               cpuid = cpus_empty(tmp) ? map_to_cpu(virt_irq) : first_cpu(tmp);
        }
 
        return cpuid;
index f0e6ed23a468ec10c6b7ba78ad8d5890295f7f82..938da19dc06527d755d7ce0a9cc8171b39f654c7 100644 (file)
@@ -574,7 +574,7 @@ static void __init report_platform_properties(void)
        mdesc_release(hp);
 }
 
-static void __devinit fill_in_one_cache(cpuinfo_sparc *c,
+static void __cpuinit fill_in_one_cache(cpuinfo_sparc *c,
                                        struct mdesc_handle *hp,
                                        u64 mp)
 {
@@ -619,8 +619,7 @@ static void __devinit fill_in_one_cache(cpuinfo_sparc *c,
        }
 }
 
-static void __devinit mark_core_ids(struct mdesc_handle *hp, u64 mp,
-                                   int core_id)
+static void __cpuinit mark_core_ids(struct mdesc_handle *hp, u64 mp, int core_id)
 {
        u64 a;
 
@@ -653,7 +652,7 @@ static void __devinit mark_core_ids(struct mdesc_handle *hp, u64 mp,
        }
 }
 
-static void __devinit set_core_ids(struct mdesc_handle *hp)
+static void __cpuinit set_core_ids(struct mdesc_handle *hp)
 {
        int idx;
        u64 mp;
@@ -678,8 +677,7 @@ static void __devinit set_core_ids(struct mdesc_handle *hp)
        }
 }
 
-static void __devinit mark_proc_ids(struct mdesc_handle *hp, u64 mp,
-                                   int proc_id)
+static void __cpuinit mark_proc_ids(struct mdesc_handle *hp, u64 mp, int proc_id)
 {
        u64 a;
 
@@ -698,8 +696,7 @@ static void __devinit mark_proc_ids(struct mdesc_handle *hp, u64 mp,
        }
 }
 
-static void __devinit __set_proc_ids(struct mdesc_handle *hp,
-                                    const char *exec_unit_name)
+static void __cpuinit __set_proc_ids(struct mdesc_handle *hp, const char *exec_unit_name)
 {
        int idx;
        u64 mp;
@@ -720,13 +717,13 @@ static void __devinit __set_proc_ids(struct mdesc_handle *hp,
        }
 }
 
-static void __devinit set_proc_ids(struct mdesc_handle *hp)
+static void __cpuinit set_proc_ids(struct mdesc_handle *hp)
 {
        __set_proc_ids(hp, "exec_unit");
        __set_proc_ids(hp, "exec-unit");
 }
 
-static void __devinit get_one_mondo_bits(const u64 *p, unsigned int *mask,
+static void __cpuinit get_one_mondo_bits(const u64 *p, unsigned int *mask,
                                         unsigned char def)
 {
        u64 val;
@@ -745,7 +742,7 @@ use_default:
        *mask = ((1U << def) * 64U) - 1U;
 }
 
-static void __devinit get_mondo_data(struct mdesc_handle *hp, u64 mp,
+static void __cpuinit get_mondo_data(struct mdesc_handle *hp, u64 mp,
                                     struct trap_per_cpu *tb)
 {
        const u64 *val;
@@ -763,23 +760,15 @@ static void __devinit get_mondo_data(struct mdesc_handle *hp, u64 mp,
        get_one_mondo_bits(val, &tb->nonresum_qmask, 2);
 }
 
-void __cpuinit mdesc_fill_in_cpu_data(cpumask_t mask)
+static void * __cpuinit mdesc_iterate_over_cpus(void *(*func)(struct mdesc_handle *, u64, int, void *), void *arg, cpumask_t *mask)
 {
        struct mdesc_handle *hp = mdesc_grab();
+       void *ret = NULL;
        u64 mp;
 
-       ncpus_probed = 0;
        mdesc_for_each_node_by_name(hp, mp, "cpu") {
                const u64 *id = mdesc_get_property(hp, mp, "id", NULL);
-               const u64 *cfreq = mdesc_get_property(hp, mp, "clock-frequency", NULL);
-               struct trap_per_cpu *tb;
-               cpuinfo_sparc *c;
-               int cpuid;
-               u64 a;
-
-               ncpus_probed++;
-
-               cpuid = *id;
+               int cpuid = *id;
 
 #ifdef CONFIG_SMP
                if (cpuid >= NR_CPUS) {
@@ -788,62 +777,104 @@ void __cpuinit mdesc_fill_in_cpu_data(cpumask_t mask)
                               cpuid, NR_CPUS);
                        continue;
                }
-               if (!cpu_isset(cpuid, mask))
+               if (!cpu_isset(cpuid, *mask))
                        continue;
-#else
-               /* On uniprocessor we only want the values for the
-                * real physical cpu the kernel booted onto, however
-                * cpu_data() only has one entry at index 0.
-                */
-               if (cpuid != real_hard_smp_processor_id())
-                       continue;
-               cpuid = 0;
 #endif
 
-               c = &cpu_data(cpuid);
-               c->clock_tick = *cfreq;
+               ret = func(hp, mp, cpuid, arg);
+               if (ret)
+                       goto out;
+       }
+out:
+       mdesc_release(hp);
+       return ret;
+}
 
-               tb = &trap_block[cpuid];
-               get_mondo_data(hp, mp, tb);
+static void * __cpuinit record_one_cpu(struct mdesc_handle *hp, u64 mp, int cpuid, void *arg)
+{
+       ncpus_probed++;
+#ifdef CONFIG_SMP
+       set_cpu_present(cpuid, true);
+#endif
+       return NULL;
+}
 
-               mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) {
-                       u64 j, t = mdesc_arc_target(hp, a);
-                       const char *t_name;
+void __cpuinit mdesc_populate_present_mask(cpumask_t *mask)
+{
+       if (tlb_type != hypervisor)
+               return;
 
-                       t_name = mdesc_node_name(hp, t);
-                       if (!strcmp(t_name, "cache")) {
-                               fill_in_one_cache(c, hp, t);
-                               continue;
-                       }
+       ncpus_probed = 0;
+       mdesc_iterate_over_cpus(record_one_cpu, NULL, mask);
+}
 
-                       mdesc_for_each_arc(j, hp, t, MDESC_ARC_TYPE_FWD) {
-                               u64 n = mdesc_arc_target(hp, j);
-                               const char *n_name;
+static void * __cpuinit fill_in_one_cpu(struct mdesc_handle *hp, u64 mp, int cpuid, void *arg)
+{
+       const u64 *cfreq = mdesc_get_property(hp, mp, "clock-frequency", NULL);
+       struct trap_per_cpu *tb;
+       cpuinfo_sparc *c;
+       u64 a;
 
-                               n_name = mdesc_node_name(hp, n);
-                               if (!strcmp(n_name, "cache"))
-                                       fill_in_one_cache(c, hp, n);
-                       }
+#ifndef CONFIG_SMP
+       /* On uniprocessor we only want the values for the
+        * real physical cpu the kernel booted onto, however
+        * cpu_data() only has one entry at index 0.
+        */
+       if (cpuid != real_hard_smp_processor_id())
+               return NULL;
+       cpuid = 0;
+#endif
+
+       c = &cpu_data(cpuid);
+       c->clock_tick = *cfreq;
+
+       tb = &trap_block[cpuid];
+       get_mondo_data(hp, mp, tb);
+
+       mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) {
+               u64 j, t = mdesc_arc_target(hp, a);
+               const char *t_name;
+
+               t_name = mdesc_node_name(hp, t);
+               if (!strcmp(t_name, "cache")) {
+                       fill_in_one_cache(c, hp, t);
+                       continue;
                }
 
-#ifdef CONFIG_SMP
-               cpu_set(cpuid, cpu_present_map);
-#endif
+               mdesc_for_each_arc(j, hp, t, MDESC_ARC_TYPE_FWD) {
+                       u64 n = mdesc_arc_target(hp, j);
+                       const char *n_name;
 
-               c->core_id = 0;
-               c->proc_id = -1;
+                       n_name = mdesc_node_name(hp, n);
+                       if (!strcmp(n_name, "cache"))
+                               fill_in_one_cache(c, hp, n);
+               }
        }
 
+       c->core_id = 0;
+       c->proc_id = -1;
+
+       return NULL;
+}
+
+void __cpuinit mdesc_fill_in_cpu_data(cpumask_t *mask)
+{
+       struct mdesc_handle *hp;
+
+       mdesc_iterate_over_cpus(fill_in_one_cpu, NULL, mask);
+
 #ifdef CONFIG_SMP
        sparc64_multi_core = 1;
 #endif
 
+       hp = mdesc_grab();
+
        set_core_ids(hp);
        set_proc_ids(hp);
 
-       smp_fill_in_sib_core_maps();
-
        mdesc_release(hp);
+
+       smp_fill_in_sib_core_maps();
 }
 
 static ssize_t mdesc_read(struct file *file, char __user *buf,
@@ -887,7 +918,6 @@ void __init sun4v_mdesc_init(void)
 {
        struct mdesc_handle *hp;
        unsigned long len, real_len, status;
-       cpumask_t mask;
 
        (void) sun4v_mach_desc(0UL, 0UL, &len);
 
@@ -911,7 +941,4 @@ void __init sun4v_mdesc_init(void)
        cur_mdesc = hp;
 
        report_platform_properties();
-
-       cpus_setall(mask);
-       mdesc_fill_in_cpu_data(mask);
 }
index c8f14c1dc5214da6b99a781f0bc58d963e144fae..90396702ea2c459e75739fe7b91f8ce9557de125 100644 (file)
 #include <linux/mod_devicetable.h>
 #include <linux/slab.h>
 #include <linux/errno.h>
+#include <linux/irq.h>
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
 
-static int node_match(struct device *dev, void *data)
-{
-       struct of_device *op = to_of_device(dev);
-       struct device_node *dp = data;
-
-       return (op->node == dp);
-}
-
-struct of_device *of_find_device_by_node(struct device_node *dp)
-{
-       struct device *dev = bus_find_device(&of_platform_bus_type, NULL,
-                                            dp, node_match);
-
-       if (dev)
-               return to_of_device(dev);
-
-       return NULL;
-}
-EXPORT_SYMBOL(of_find_device_by_node);
-
-unsigned int irq_of_parse_and_map(struct device_node *node, int index)
-{
-       struct of_device *op = of_find_device_by_node(node);
-
-       if (!op || index >= op->num_irqs)
-               return 0;
-
-       return op->irqs[index];
-}
-EXPORT_SYMBOL(irq_of_parse_and_map);
-
-/* Take the archdata values for IOMMU, STC, and HOSTDATA found in
- * BUS and propagate to all child of_device objects.
- */
-void of_propagate_archdata(struct of_device *bus)
-{
-       struct dev_archdata *bus_sd = &bus->dev.archdata;
-       struct device_node *bus_dp = bus->node;
-       struct device_node *dp;
-
-       for (dp = bus_dp->child; dp; dp = dp->sibling) {
-               struct of_device *op = of_find_device_by_node(dp);
-
-               op->dev.archdata.iommu = bus_sd->iommu;
-               op->dev.archdata.stc = bus_sd->stc;
-               op->dev.archdata.host_controller = bus_sd->host_controller;
-               op->dev.archdata.numa_node = bus_sd->numa_node;
-
-               if (dp->child)
-                       of_propagate_archdata(op);
-       }
-}
-
-struct bus_type of_platform_bus_type;
-EXPORT_SYMBOL(of_platform_bus_type);
-
-static inline u64 of_read_addr(const u32 *cell, int size)
-{
-       u64 r = 0;
-       while (size--)
-               r = (r << 32) | *(cell++);
-       return r;
-}
-
-static void __init get_cells(struct device_node *dp,
-                            int *addrc, int *sizec)
-{
-       if (addrc)
-               *addrc = of_n_addr_cells(dp);
-       if (sizec)
-               *sizec = of_n_size_cells(dp);
-}
-
-/* Max address size we deal with */
-#define OF_MAX_ADDR_CELLS      4
-
-struct of_bus {
-       const char      *name;
-       const char      *addr_prop_name;
-       int             (*match)(struct device_node *parent);
-       void            (*count_cells)(struct device_node *child,
-                                      int *addrc, int *sizec);
-       int             (*map)(u32 *addr, const u32 *range,
-                              int na, int ns, int pna);
-       unsigned long   (*get_flags)(const u32 *addr, unsigned long);
-};
-
-/*
- * Default translator (generic bus)
- */
-
-static void of_bus_default_count_cells(struct device_node *dev,
-                                      int *addrc, int *sizec)
-{
-       get_cells(dev, addrc, sizec);
-}
-
-/* Make sure the least significant 64-bits are in-range.  Even
- * for 3 or 4 cell values it is a good enough approximation.
- */
-static int of_out_of_range(const u32 *addr, const u32 *base,
-                          const u32 *size, int na, int ns)
-{
-       u64 a = of_read_addr(addr, na);
-       u64 b = of_read_addr(base, na);
-
-       if (a < b)
-               return 1;
-
-       b += of_read_addr(size, ns);
-       if (a >= b)
-               return 1;
-
-       return 0;
-}
-
-static int of_bus_default_map(u32 *addr, const u32 *range,
-                             int na, int ns, int pna)
-{
-       u32 result[OF_MAX_ADDR_CELLS];
-       int i;
-
-       if (ns > 2) {
-               printk("of_device: Cannot handle size cells (%d) > 2.", ns);
-               return -EINVAL;
-       }
-
-       if (of_out_of_range(addr, range, range + na + pna, na, ns))
-               return -EINVAL;
-
-       /* Start with the parent range base.  */
-       memcpy(result, range + na, pna * 4);
-
-       /* Add in the child address offset.  */
-       for (i = 0; i < na; i++)
-               result[pna - 1 - i] +=
-                       (addr[na - 1 - i] -
-                        range[na - 1 - i]);
-
-       memcpy(addr, result, pna * 4);
-
-       return 0;
-}
-
-static unsigned long of_bus_default_get_flags(const u32 *addr, unsigned long flags)
-{
-       if (flags)
-               return flags;
-       return IORESOURCE_MEM;
-}
+#include "of_device_common.h"
 
 /*
  * PCI bus specific translator
@@ -240,47 +92,6 @@ static unsigned long of_bus_pci_get_flags(const u32 *addr, unsigned long flags)
        return flags;
 }
 
-/*
- * SBUS bus specific translator
- */
-
-static int of_bus_sbus_match(struct device_node *np)
-{
-       struct device_node *dp = np;
-
-       while (dp) {
-               if (!strcmp(dp->name, "sbus") ||
-                   !strcmp(dp->name, "sbi"))
-                       return 1;
-
-               /* Have a look at use_1to1_mapping().  We're trying
-                * to match SBUS if that's the top-level bus and we
-                * don't have some intervening real bus that provides
-                * ranges based translations.
-                */
-               if (of_find_property(dp, "ranges", NULL) != NULL)
-                       break;
-
-               dp = dp->parent;
-       }
-
-       return 0;
-}
-
-static void of_bus_sbus_count_cells(struct device_node *child,
-                                  int *addrc, int *sizec)
-{
-       if (addrc)
-               *addrc = 2;
-       if (sizec)
-               *sizec = 1;
-}
-
-static int of_bus_sbus_map(u32 *addr, const u32 *range, int na, int ns, int pna)
-{
-       return of_bus_default_map(addr, range, na, ns, pna);
-}
-
 static unsigned long of_bus_sbus_get_flags(const u32 *addr, unsigned long flags)
 {
        return IORESOURCE_MEM;
@@ -307,7 +118,7 @@ static struct of_bus of_busses[] = {
                .addr_prop_name = "reg",
                .match = of_bus_sbus_match,
                .count_cells = of_bus_sbus_count_cells,
-               .map = of_bus_sbus_map,
+               .map = of_bus_default_map,
                .get_flags = of_bus_sbus_get_flags,
        },
        /* Default */
index 5ac287ac03def46bd50d290467e76239dbfb9ef9..881947e59e955468cbc4ea0e09794a70c3c519e9 100644 (file)
@@ -10,6 +10,8 @@
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
 
+#include "of_device_common.h"
+
 void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name)
 {
        unsigned long ret = res->start + offset;
@@ -35,156 +37,6 @@ void of_iounmap(struct resource *res, void __iomem *base, unsigned long size)
 }
 EXPORT_SYMBOL(of_iounmap);
 
-static int node_match(struct device *dev, void *data)
-{
-       struct of_device *op = to_of_device(dev);
-       struct device_node *dp = data;
-
-       return (op->node == dp);
-}
-
-struct of_device *of_find_device_by_node(struct device_node *dp)
-{
-       struct device *dev = bus_find_device(&of_platform_bus_type, NULL,
-                                            dp, node_match);
-
-       if (dev)
-               return to_of_device(dev);
-
-       return NULL;
-}
-EXPORT_SYMBOL(of_find_device_by_node);
-
-unsigned int irq_of_parse_and_map(struct device_node *node, int index)
-{
-       struct of_device *op = of_find_device_by_node(node);
-
-       if (!op || index >= op->num_irqs)
-               return 0;
-
-       return op->irqs[index];
-}
-EXPORT_SYMBOL(irq_of_parse_and_map);
-
-/* Take the archdata values for IOMMU, STC, and HOSTDATA found in
- * BUS and propagate to all child of_device objects.
- */
-void of_propagate_archdata(struct of_device *bus)
-{
-       struct dev_archdata *bus_sd = &bus->dev.archdata;
-       struct device_node *bus_dp = bus->node;
-       struct device_node *dp;
-
-       for (dp = bus_dp->child; dp; dp = dp->sibling) {
-               struct of_device *op = of_find_device_by_node(dp);
-
-               op->dev.archdata.iommu = bus_sd->iommu;
-               op->dev.archdata.stc = bus_sd->stc;
-               op->dev.archdata.host_controller = bus_sd->host_controller;
-               op->dev.archdata.numa_node = bus_sd->numa_node;
-
-               if (dp->child)
-                       of_propagate_archdata(op);
-       }
-}
-
-struct bus_type of_platform_bus_type;
-EXPORT_SYMBOL(of_platform_bus_type);
-
-static inline u64 of_read_addr(const u32 *cell, int size)
-{
-       u64 r = 0;
-       while (size--)
-               r = (r << 32) | *(cell++);
-       return r;
-}
-
-static void get_cells(struct device_node *dp, int *addrc, int *sizec)
-{
-       if (addrc)
-               *addrc = of_n_addr_cells(dp);
-       if (sizec)
-               *sizec = of_n_size_cells(dp);
-}
-
-/* Max address size we deal with */
-#define OF_MAX_ADDR_CELLS      4
-
-struct of_bus {
-       const char      *name;
-       const char      *addr_prop_name;
-       int             (*match)(struct device_node *parent);
-       void            (*count_cells)(struct device_node *child,
-                                      int *addrc, int *sizec);
-       int             (*map)(u32 *addr, const u32 *range,
-                              int na, int ns, int pna);
-       unsigned long   (*get_flags)(const u32 *addr, unsigned long);
-};
-
-/*
- * Default translator (generic bus)
- */
-
-static void of_bus_default_count_cells(struct device_node *dev,
-                                      int *addrc, int *sizec)
-{
-       get_cells(dev, addrc, sizec);
-}
-
-/* Make sure the least significant 64-bits are in-range.  Even
- * for 3 or 4 cell values it is a good enough approximation.
- */
-static int of_out_of_range(const u32 *addr, const u32 *base,
-                          const u32 *size, int na, int ns)
-{
-       u64 a = of_read_addr(addr, na);
-       u64 b = of_read_addr(base, na);
-
-       if (a < b)
-               return 1;
-
-       b += of_read_addr(size, ns);
-       if (a >= b)
-               return 1;
-
-       return 0;
-}
-
-static int of_bus_default_map(u32 *addr, const u32 *range,
-                             int na, int ns, int pna)
-{
-       u32 result[OF_MAX_ADDR_CELLS];
-       int i;
-
-       if (ns > 2) {
-               printk("of_device: Cannot handle size cells (%d) > 2.", ns);
-               return -EINVAL;
-       }
-
-       if (of_out_of_range(addr, range, range + na + pna, na, ns))
-               return -EINVAL;
-
-       /* Start with the parent range base.  */
-       memcpy(result, range + na, pna * 4);
-
-       /* Add in the child address offset.  */
-       for (i = 0; i < na; i++)
-               result[pna - 1 - i] +=
-                       (addr[na - 1 - i] -
-                        range[na - 1 - i]);
-
-       memcpy(addr, result, pna * 4);
-
-       return 0;
-}
-
-static unsigned long of_bus_default_get_flags(const u32 *addr, unsigned long flags)
-{
-       if (flags)
-               return flags;
-       return IORESOURCE_MEM;
-}
-
 /*
  * PCI bus specific translator
  */
@@ -294,42 +146,6 @@ static unsigned long of_bus_pci_get_flags(const u32 *addr, unsigned long flags)
        return flags;
 }
 
-/*
- * SBUS bus specific translator
- */
-
-static int of_bus_sbus_match(struct device_node *np)
-{
-       struct device_node *dp = np;
-
-       while (dp) {
-               if (!strcmp(dp->name, "sbus") ||
-                   !strcmp(dp->name, "sbi"))
-                       return 1;
-
-               /* Have a look at use_1to1_mapping().  We're trying
-                * to match SBUS if that's the top-level bus and we
-                * don't have some intervening real bus that provides
-                * ranges based translations.
-                */
-               if (of_find_property(dp, "ranges", NULL) != NULL)
-                       break;
-
-               dp = dp->parent;
-       }
-
-       return 0;
-}
-
-static void of_bus_sbus_count_cells(struct device_node *child,
-                                  int *addrc, int *sizec)
-{
-       if (addrc)
-               *addrc = 2;
-       if (sizec)
-               *sizec = 1;
-}
-
 /*
  * FHC/Central bus specific translator.
  *
diff --git a/arch/sparc/kernel/of_device_common.c b/arch/sparc/kernel/of_device_common.c
new file mode 100644 (file)
index 0000000..cb8eb79
--- /dev/null
@@ -0,0 +1,174 @@
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/irq.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
+#include "of_device_common.h"
+
+static int node_match(struct device *dev, void *data)
+{
+       struct of_device *op = to_of_device(dev);
+       struct device_node *dp = data;
+
+       return (op->node == dp);
+}
+
+struct of_device *of_find_device_by_node(struct device_node *dp)
+{
+       struct device *dev = bus_find_device(&of_platform_bus_type, NULL,
+                                            dp, node_match);
+
+       if (dev)
+               return to_of_device(dev);
+
+       return NULL;
+}
+EXPORT_SYMBOL(of_find_device_by_node);
+
+unsigned int irq_of_parse_and_map(struct device_node *node, int index)
+{
+       struct of_device *op = of_find_device_by_node(node);
+
+       if (!op || index >= op->num_irqs)
+               return 0;
+
+       return op->irqs[index];
+}
+EXPORT_SYMBOL(irq_of_parse_and_map);
+
+/* Take the archdata values for IOMMU, STC, and HOSTDATA found in
+ * BUS and propagate to all child of_device objects.
+ */
+void of_propagate_archdata(struct of_device *bus)
+{
+       struct dev_archdata *bus_sd = &bus->dev.archdata;
+       struct device_node *bus_dp = bus->node;
+       struct device_node *dp;
+
+       for (dp = bus_dp->child; dp; dp = dp->sibling) {
+               struct of_device *op = of_find_device_by_node(dp);
+
+               op->dev.archdata.iommu = bus_sd->iommu;
+               op->dev.archdata.stc = bus_sd->stc;
+               op->dev.archdata.host_controller = bus_sd->host_controller;
+               op->dev.archdata.numa_node = bus_sd->numa_node;
+
+               if (dp->child)
+                       of_propagate_archdata(op);
+       }
+}
+
+struct bus_type of_platform_bus_type;
+EXPORT_SYMBOL(of_platform_bus_type);
+
+static void get_cells(struct device_node *dp, int *addrc, int *sizec)
+{
+       if (addrc)
+               *addrc = of_n_addr_cells(dp);
+       if (sizec)
+               *sizec = of_n_size_cells(dp);
+}
+
+/*
+ * Default translator (generic bus)
+ */
+
+void of_bus_default_count_cells(struct device_node *dev, int *addrc, int *sizec)
+{
+       get_cells(dev, addrc, sizec);
+}
+
+/* Make sure the least significant 64-bits are in-range.  Even
+ * for 3 or 4 cell values it is a good enough approximation.
+ */
+int of_out_of_range(const u32 *addr, const u32 *base,
+                   const u32 *size, int na, int ns)
+{
+       u64 a = of_read_addr(addr, na);
+       u64 b = of_read_addr(base, na);
+
+       if (a < b)
+               return 1;
+
+       b += of_read_addr(size, ns);
+       if (a >= b)
+               return 1;
+
+       return 0;
+}
+
+int of_bus_default_map(u32 *addr, const u32 *range, int na, int ns, int pna)
+{
+       u32 result[OF_MAX_ADDR_CELLS];
+       int i;
+
+       if (ns > 2) {
+               printk("of_device: Cannot handle size cells (%d) > 2.", ns);
+               return -EINVAL;
+       }
+
+       if (of_out_of_range(addr, range, range + na + pna, na, ns))
+               return -EINVAL;
+
+       /* Start with the parent range base.  */
+       memcpy(result, range + na, pna * 4);
+
+       /* Add in the child address offset.  */
+       for (i = 0; i < na; i++)
+               result[pna - 1 - i] +=
+                       (addr[na - 1 - i] -
+                        range[na - 1 - i]);
+
+       memcpy(addr, result, pna * 4);
+
+       return 0;
+}
+
+unsigned long of_bus_default_get_flags(const u32 *addr, unsigned long flags)
+{
+       if (flags)
+               return flags;
+       return IORESOURCE_MEM;
+}
+
+/*
+ * SBUS bus specific translator
+ */
+
+int of_bus_sbus_match(struct device_node *np)
+{
+       struct device_node *dp = np;
+
+       while (dp) {
+               if (!strcmp(dp->name, "sbus") ||
+                   !strcmp(dp->name, "sbi"))
+                       return 1;
+
+               /* Have a look at use_1to1_mapping().  We're trying
+                * to match SBUS if that's the top-level bus and we
+                * don't have some intervening real bus that provides
+                * ranges based translations.
+                */
+               if (of_find_property(dp, "ranges", NULL) != NULL)
+                       break;
+
+               dp = dp->parent;
+       }
+
+       return 0;
+}
+
+void of_bus_sbus_count_cells(struct device_node *child, int *addrc, int *sizec)
+{
+       if (addrc)
+               *addrc = 2;
+       if (sizec)
+               *sizec = 1;
+}
diff --git a/arch/sparc/kernel/of_device_common.h b/arch/sparc/kernel/of_device_common.h
new file mode 100644 (file)
index 0000000..cdfd239
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef _OF_DEVICE_COMMON_H
+#define _OF_DEVICE_COMMON_H
+
+static inline u64 of_read_addr(const u32 *cell, int size)
+{
+       u64 r = 0;
+       while (size--)
+               r = (r << 32) | *(cell++);
+       return r;
+}
+
+void of_bus_default_count_cells(struct device_node *dev, int *addrc,
+                               int *sizec);
+int of_out_of_range(const u32 *addr, const u32 *base,
+                   const u32 *size, int na, int ns);
+int of_bus_default_map(u32 *addr, const u32 *range, int na, int ns, int pna);
+unsigned long of_bus_default_get_flags(const u32 *addr, unsigned long flags);
+
+int of_bus_sbus_match(struct device_node *np);
+void of_bus_sbus_count_cells(struct device_node *child, int *addrc, int *sizec);
+
+/* Max address size we deal with */
+#define OF_MAX_ADDR_CELLS      4
+
+struct of_bus {
+       const char      *name;
+       const char      *addr_prop_name;
+       int             (*match)(struct device_node *parent);
+       void            (*count_cells)(struct device_node *child,
+                                      int *addrc, int *sizec);
+       int             (*map)(u32 *addr, const u32 *range,
+                              int na, int ns, int pna);
+       unsigned long   (*get_flags)(const u32 *addr, unsigned long);
+};
+
+#endif /* _OF_DEVICE_COMMON_H */
index 5db5ebed35da0083370e16a932d9478e20f4cfe1..2485eaa231019676eb1780bfe9f5ff3965394540 100644 (file)
@@ -230,8 +230,9 @@ static void dma_4v_free_coherent(struct device *dev, size_t size, void *cpu,
                free_pages((unsigned long)cpu, order);
 }
 
-static dma_addr_t dma_4v_map_single(struct device *dev, void *ptr, size_t sz,
-                                   enum dma_data_direction direction)
+static dma_addr_t dma_4v_map_page(struct device *dev, struct page *page,
+                                 unsigned long offset, size_t sz,
+                                 enum dma_data_direction direction)
 {
        struct iommu *iommu;
        unsigned long flags, npages, oaddr;
@@ -245,7 +246,7 @@ static dma_addr_t dma_4v_map_single(struct device *dev, void *ptr, size_t sz,
        if (unlikely(direction == DMA_NONE))
                goto bad;
 
-       oaddr = (unsigned long)ptr;
+       oaddr = (unsigned long)(page_address(page) + offset);
        npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK);
        npages >>= IO_PAGE_SHIFT;
 
@@ -294,8 +295,8 @@ iommu_map_fail:
        return DMA_ERROR_CODE;
 }
 
-static void dma_4v_unmap_single(struct device *dev, dma_addr_t bus_addr,
-                               size_t sz, enum dma_data_direction direction)
+static void dma_4v_unmap_page(struct device *dev, dma_addr_t bus_addr,
+                             size_t sz, enum dma_data_direction direction)
 {
        struct pci_pbm_info *pbm;
        struct iommu *iommu;
@@ -537,8 +538,8 @@ static void dma_4v_sync_sg_for_cpu(struct device *dev,
 static const struct dma_ops sun4v_dma_ops = {
        .alloc_coherent                 = dma_4v_alloc_coherent,
        .free_coherent                  = dma_4v_free_coherent,
-       .map_single                     = dma_4v_map_single,
-       .unmap_single                   = dma_4v_unmap_single,
+       .map_page                       = dma_4v_map_page,
+       .unmap_page                     = dma_4v_unmap_page,
        .map_sg                         = dma_4v_map_sg,
        .unmap_sg                       = dma_4v_unmap_sg,
        .sync_single_for_cpu            = dma_4v_sync_single_for_cpu,
index bb0f0fda6cab4a4686cbb031a0864c45e3df346a..453397fe5e14035fbc980689d844e5673312d4a3 100644 (file)
@@ -22,7 +22,6 @@ static inline int is_root_node(const struct device_node *dp)
 
 extern char *build_path_component(struct device_node *dp);
 extern void of_console_init(void);
-extern void of_fill_in_cpu_data(void);
 
 extern unsigned int prom_early_allocated;
 
index ca55c7012f7751d4338a1c6fc1153124ef0f6966..fb06ac2bd38ffbb198080dc9006775fdab0b55f1 100644 (file)
@@ -374,75 +374,26 @@ static const char *get_mid_prop(void)
        return (tlb_type == spitfire ? "upa-portid" : "portid");
 }
 
-struct device_node *of_find_node_by_cpuid(int cpuid)
-{
-       struct device_node *dp;
-       const char *mid_prop = get_mid_prop();
-
-       for_each_node_by_type(dp, "cpu") {
-               int id = of_getintprop_default(dp, mid_prop, -1);
-               const char *this_mid_prop = mid_prop;
-
-               if (id < 0) {
-                       this_mid_prop = "cpuid";
-                       id = of_getintprop_default(dp, this_mid_prop, -1);
-               }
-
-               if (id < 0) {
-                       prom_printf("OF: Serious problem, cpu lacks "
-                                   "%s property", this_mid_prop);
-                       prom_halt();
-               }
-               if (cpuid == id)
-                       return dp;
-       }
-       return NULL;
-}
-
-void __init of_fill_in_cpu_data(void)
+static void *of_iterate_over_cpus(void *(*func)(struct device_node *, int, int), int arg)
 {
        struct device_node *dp;
        const char *mid_prop;
 
-       if (tlb_type == hypervisor)
-               return;
-
        mid_prop = get_mid_prop();
-       ncpus_probed = 0;
        for_each_node_by_type(dp, "cpu") {
                int cpuid = of_getintprop_default(dp, mid_prop, -1);
                const char *this_mid_prop = mid_prop;
-               struct device_node *portid_parent;
-               int portid = -1;
+               void *ret;
 
-               portid_parent = NULL;
                if (cpuid < 0) {
                        this_mid_prop = "cpuid";
                        cpuid = of_getintprop_default(dp, this_mid_prop, -1);
-                       if (cpuid >= 0) {
-                               int limit = 2;
-
-                               portid_parent = dp;
-                               while (limit--) {
-                                       portid_parent = portid_parent->parent;
-                                       if (!portid_parent)
-                                               break;
-                                       portid = of_getintprop_default(portid_parent,
-                                                                      "portid", -1);
-                                       if (portid >= 0)
-                                               break;
-                               }
-                       }
                }
-
                if (cpuid < 0) {
                        prom_printf("OF: Serious problem, cpu lacks "
                                    "%s property", this_mid_prop);
                        prom_halt();
                }
-
-               ncpus_probed++;
-
 #ifdef CONFIG_SMP
                if (cpuid >= NR_CPUS) {
                        printk(KERN_WARNING "Ignoring CPU %d which is "
@@ -450,79 +401,142 @@ void __init of_fill_in_cpu_data(void)
                               cpuid, NR_CPUS);
                        continue;
                }
-#else
-               /* On uniprocessor we only want the values for the
-                * real physical cpu the kernel booted onto, however
-                * cpu_data() only has one entry at index 0.
-                */
-               if (cpuid != real_hard_smp_processor_id())
-                       continue;
-               cpuid = 0;
 #endif
+               ret = func(dp, cpuid, arg);
+               if (ret)
+                       return ret;
+       }
+       return NULL;
+}
 
-               cpu_data(cpuid).clock_tick =
-                       of_getintprop_default(dp, "clock-frequency", 0);
-
-               if (portid_parent) {
-                       cpu_data(cpuid).dcache_size =
-                               of_getintprop_default(dp, "l1-dcache-size",
-                                                     16 * 1024);
-                       cpu_data(cpuid).dcache_line_size =
-                               of_getintprop_default(dp, "l1-dcache-line-size",
-                                                     32);
-                       cpu_data(cpuid).icache_size =
-                               of_getintprop_default(dp, "l1-icache-size",
-                                                     8 * 1024);
-                       cpu_data(cpuid).icache_line_size =
-                               of_getintprop_default(dp, "l1-icache-line-size",
-                                                     32);
-                       cpu_data(cpuid).ecache_size =
-                               of_getintprop_default(dp, "l2-cache-size", 0);
-                       cpu_data(cpuid).ecache_line_size =
-                               of_getintprop_default(dp, "l2-cache-line-size", 0);
-                       if (!cpu_data(cpuid).ecache_size ||
-                           !cpu_data(cpuid).ecache_line_size) {
-                               cpu_data(cpuid).ecache_size =
-                                       of_getintprop_default(portid_parent,
-                                                             "l2-cache-size",
-                                                             (4 * 1024 * 1024));
-                               cpu_data(cpuid).ecache_line_size =
-                                       of_getintprop_default(portid_parent,
-                                                             "l2-cache-line-size", 64);
-                       }
-
-                       cpu_data(cpuid).core_id = portid + 1;
-                       cpu_data(cpuid).proc_id = portid;
+static void *check_cpu_node(struct device_node *dp, int cpuid, int id)
+{
+       if (id == cpuid)
+               return dp;
+       return NULL;
+}
+
+struct device_node *of_find_node_by_cpuid(int cpuid)
+{
+       return of_iterate_over_cpus(check_cpu_node, cpuid);
+}
+
+static void *record_one_cpu(struct device_node *dp, int cpuid, int arg)
+{
+       ncpus_probed++;
 #ifdef CONFIG_SMP
-                       sparc64_multi_core = 1;
+       set_cpu_present(cpuid, true);
+       set_cpu_possible(cpuid, true);
 #endif
-               } else {
-                       cpu_data(cpuid).dcache_size =
-                               of_getintprop_default(dp, "dcache-size", 16 * 1024);
-                       cpu_data(cpuid).dcache_line_size =
-                               of_getintprop_default(dp, "dcache-line-size", 32);
+       return NULL;
+}
 
-                       cpu_data(cpuid).icache_size =
-                               of_getintprop_default(dp, "icache-size", 16 * 1024);
-                       cpu_data(cpuid).icache_line_size =
-                               of_getintprop_default(dp, "icache-line-size", 32);
+void __init of_populate_present_mask(void)
+{
+       if (tlb_type == hypervisor)
+               return;
+
+       ncpus_probed = 0;
+       of_iterate_over_cpus(record_one_cpu, 0);
+}
 
+static void *fill_in_one_cpu(struct device_node *dp, int cpuid, int arg)
+{
+       struct device_node *portid_parent = NULL;
+       int portid = -1;
+
+       if (of_find_property(dp, "cpuid", NULL)) {
+               int limit = 2;
+
+               portid_parent = dp;
+               while (limit--) {
+                       portid_parent = portid_parent->parent;
+                       if (!portid_parent)
+                               break;
+                       portid = of_getintprop_default(portid_parent,
+                                                      "portid", -1);
+                       if (portid >= 0)
+                               break;
+               }
+       }
+
+#ifndef CONFIG_SMP
+       /* On uniprocessor we only want the values for the
+        * real physical cpu the kernel booted onto, however
+        * cpu_data() only has one entry at index 0.
+        */
+       if (cpuid != real_hard_smp_processor_id())
+               return NULL;
+       cpuid = 0;
+#endif
+
+       cpu_data(cpuid).clock_tick =
+               of_getintprop_default(dp, "clock-frequency", 0);
+
+       if (portid_parent) {
+               cpu_data(cpuid).dcache_size =
+                       of_getintprop_default(dp, "l1-dcache-size",
+                                             16 * 1024);
+               cpu_data(cpuid).dcache_line_size =
+                       of_getintprop_default(dp, "l1-dcache-line-size",
+                                             32);
+               cpu_data(cpuid).icache_size =
+                       of_getintprop_default(dp, "l1-icache-size",
+                                             8 * 1024);
+               cpu_data(cpuid).icache_line_size =
+                       of_getintprop_default(dp, "l1-icache-line-size",
+                                             32);
+               cpu_data(cpuid).ecache_size =
+                       of_getintprop_default(dp, "l2-cache-size", 0);
+               cpu_data(cpuid).ecache_line_size =
+                       of_getintprop_default(dp, "l2-cache-line-size", 0);
+               if (!cpu_data(cpuid).ecache_size ||
+                   !cpu_data(cpuid).ecache_line_size) {
                        cpu_data(cpuid).ecache_size =
-                               of_getintprop_default(dp, "ecache-size",
+                               of_getintprop_default(portid_parent,
+                                                     "l2-cache-size",
                                                      (4 * 1024 * 1024));
                        cpu_data(cpuid).ecache_line_size =
-                               of_getintprop_default(dp, "ecache-line-size", 64);
-
-                       cpu_data(cpuid).core_id = 0;
-                       cpu_data(cpuid).proc_id = -1;
+                               of_getintprop_default(portid_parent,
+                                                     "l2-cache-line-size", 64);
                }
 
+               cpu_data(cpuid).core_id = portid + 1;
+               cpu_data(cpuid).proc_id = portid;
 #ifdef CONFIG_SMP
-               set_cpu_present(cpuid, true);
-               set_cpu_possible(cpuid, true);
+               sparc64_multi_core = 1;
 #endif
+       } else {
+               cpu_data(cpuid).dcache_size =
+                       of_getintprop_default(dp, "dcache-size", 16 * 1024);
+               cpu_data(cpuid).dcache_line_size =
+                       of_getintprop_default(dp, "dcache-line-size", 32);
+
+               cpu_data(cpuid).icache_size =
+                       of_getintprop_default(dp, "icache-size", 16 * 1024);
+               cpu_data(cpuid).icache_line_size =
+                       of_getintprop_default(dp, "icache-line-size", 32);
+
+               cpu_data(cpuid).ecache_size =
+                       of_getintprop_default(dp, "ecache-size",
+                                             (4 * 1024 * 1024));
+               cpu_data(cpuid).ecache_line_size =
+                       of_getintprop_default(dp, "ecache-line-size", 64);
+
+               cpu_data(cpuid).core_id = 0;
+               cpu_data(cpuid).proc_id = -1;
        }
 
+       return NULL;
+}
+
+void __init of_fill_in_cpu_data(void)
+{
+       if (tlb_type == hypervisor)
+               return;
+
+       of_iterate_over_cpus(fill_in_one_cpu, 0);
+
        smp_fill_in_sib_core_maps();
 }
 
index ff7b591c8946d1ad5f849f0956e4452037f78e66..0fb5789d43c82e84977757251ad78a6fa834d9b5 100644 (file)
@@ -313,6 +313,4 @@ void __init prom_build_devicetree(void)
 
        printk("PROM: Built device tree with %u bytes of memory.\n",
               prom_early_allocated);
-
-       of_fill_in_cpu_data();
 }
index f7642e5a94dbdcd4b45d48b7391b2f01a5b14c64..fa44eaf8d897b1f110e96d7e48ce8fdea686212f 100644 (file)
@@ -20,7 +20,8 @@
 #include <linux/cache.h>
 #include <linux/jiffies.h>
 #include <linux/profile.h>
-#include <linux/lmb.h>
+#include <linux/bootmem.h>
+#include <linux/vmalloc.h>
 #include <linux/cpu.h>
 
 #include <asm/head.h>
@@ -47,6 +48,8 @@
 #include <asm/ldc.h>
 #include <asm/hypervisor.h>
 
+#include "cpumap.h"
+
 int sparc64_multi_core __read_mostly;
 
 DEFINE_PER_CPU(cpumask_t, cpu_sibling_map) = CPU_MASK_NONE;
@@ -278,7 +281,7 @@ static unsigned long kimage_addr_to_ra(void *p)
        return kern_base + (val - KERNBASE);
 }
 
-static void __cpuinit ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread_reg)
+static void __cpuinit ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread_reg, void **descrp)
 {
        extern unsigned long sparc64_ttable_tl0;
        extern unsigned long kern_locked_tte_data;
@@ -298,12 +301,12 @@ static void __cpuinit ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread
                       "hvtramp_descr.\n");
                return;
        }
+       *descrp = hdesc;
 
        hdesc->cpu = cpu;
        hdesc->num_mappings = num_kernel_image_mappings;
 
        tb = &trap_block[cpu];
-       tb->hdesc = hdesc;
 
        hdesc->fault_info_va = (unsigned long) &tb->fault_info;
        hdesc->fault_info_pa = kimage_addr_to_ra(&tb->fault_info);
@@ -341,12 +344,12 @@ static struct thread_info *cpu_new_thread = NULL;
 
 static int __cpuinit smp_boot_one_cpu(unsigned int cpu)
 {
-       struct trap_per_cpu *tb = &trap_block[cpu];
        unsigned long entry =
                (unsigned long)(&sparc64_cpu_startup);
        unsigned long cookie =
                (unsigned long)(&cpu_new_thread);
        struct task_struct *p;
+       void *descr = NULL;
        int timeout, ret;
 
        p = fork_idle(cpu);
@@ -359,7 +362,8 @@ static int __cpuinit smp_boot_one_cpu(unsigned int cpu)
 #if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU)
                if (ldom_domaining_enabled)
                        ldom_startcpu_cpuid(cpu,
-                                           (unsigned long) cpu_new_thread);
+                                           (unsigned long) cpu_new_thread,
+                                           &descr);
                else
 #endif
                        prom_startcpu_cpuid(cpu, entry, cookie);
@@ -383,10 +387,7 @@ static int __cpuinit smp_boot_one_cpu(unsigned int cpu)
        }
        cpu_new_thread = NULL;
 
-       if (tb->hdesc) {
-               kfree(tb->hdesc);
-               tb->hdesc = NULL;
-       }
+       kfree(descr);
 
        return ret;
 }
@@ -1315,6 +1316,8 @@ int __cpu_disable(void)
        cpu_clear(cpu, cpu_online_map);
        ipi_call_unlock();
 
+       cpu_map_rebuild();
+
        return 0;
 }
 
@@ -1373,36 +1376,171 @@ void smp_send_stop(void)
 {
 }
 
-unsigned long __per_cpu_base __read_mostly;
-unsigned long __per_cpu_shift __read_mostly;
+/**
+ * pcpu_alloc_bootmem - NUMA friendly alloc_bootmem wrapper for percpu
+ * @cpu: cpu to allocate for
+ * @size: size allocation in bytes
+ * @align: alignment
+ *
+ * Allocate @size bytes aligned at @align for cpu @cpu.  This wrapper
+ * does the right thing for NUMA regardless of the current
+ * configuration.
+ *
+ * RETURNS:
+ * Pointer to the allocated area on success, NULL on failure.
+ */
+static void * __init pcpu_alloc_bootmem(unsigned int cpu, unsigned long size,
+                                       unsigned long align)
+{
+       const unsigned long goal = __pa(MAX_DMA_ADDRESS);
+#ifdef CONFIG_NEED_MULTIPLE_NODES
+       int node = cpu_to_node(cpu);
+       void *ptr;
+
+       if (!node_online(node) || !NODE_DATA(node)) {
+               ptr = __alloc_bootmem(size, align, goal);
+               pr_info("cpu %d has no node %d or node-local memory\n",
+                       cpu, node);
+               pr_debug("per cpu data for cpu%d %lu bytes at %016lx\n",
+                        cpu, size, __pa(ptr));
+       } else {
+               ptr = __alloc_bootmem_node(NODE_DATA(node),
+                                          size, align, goal);
+               pr_debug("per cpu data for cpu%d %lu bytes on node%d at "
+                        "%016lx\n", cpu, size, node, __pa(ptr));
+       }
+       return ptr;
+#else
+       return __alloc_bootmem(size, align, goal);
+#endif
+}
 
-EXPORT_SYMBOL(__per_cpu_base);
-EXPORT_SYMBOL(__per_cpu_shift);
+static size_t pcpur_size __initdata;
+static void **pcpur_ptrs __initdata;
 
-void __init real_setup_per_cpu_areas(void)
+static struct page * __init pcpur_get_page(unsigned int cpu, int pageno)
 {
-       unsigned long paddr, goal, size, i;
-       char *ptr;
+       size_t off = (size_t)pageno << PAGE_SHIFT;
 
-       /* Copy section for each CPU (we discard the original) */
-       goal = PERCPU_ENOUGH_ROOM;
+       if (off >= pcpur_size)
+               return NULL;
 
-       __per_cpu_shift = PAGE_SHIFT;
-       for (size = PAGE_SIZE; size < goal; size <<= 1UL)
-               __per_cpu_shift++;
+       return virt_to_page(pcpur_ptrs[cpu] + off);
+}
+
+#define PCPU_CHUNK_SIZE (4UL * 1024UL * 1024UL)
+
+static void __init pcpu_map_range(unsigned long start, unsigned long end,
+                                 struct page *page)
+{
+       unsigned long pfn = page_to_pfn(page);
+       unsigned long pte_base;
+
+       BUG_ON((pfn<<PAGE_SHIFT)&(PCPU_CHUNK_SIZE - 1UL));
+
+       pte_base = (_PAGE_VALID | _PAGE_SZ4MB_4U |
+                   _PAGE_CP_4U | _PAGE_CV_4U |
+                   _PAGE_P_4U | _PAGE_W_4U);
+       if (tlb_type == hypervisor)
+               pte_base = (_PAGE_VALID | _PAGE_SZ4MB_4V |
+                           _PAGE_CP_4V | _PAGE_CV_4V |
+                           _PAGE_P_4V | _PAGE_W_4V);
+
+       while (start < end) {
+               pgd_t *pgd = pgd_offset_k(start);
+               unsigned long this_end;
+               pud_t *pud;
+               pmd_t *pmd;
+               pte_t *pte;
+
+               pud = pud_offset(pgd, start);
+               if (pud_none(*pud)) {
+                       pmd_t *new;
+
+                       new = __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, PAGE_SIZE);
+                       pud_populate(&init_mm, pud, new);
+               }
+
+               pmd = pmd_offset(pud, start);
+               if (!pmd_present(*pmd)) {
+                       pte_t *new;
+
+                       new = __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, PAGE_SIZE);
+                       pmd_populate_kernel(&init_mm, pmd, new);
+               }
 
-       paddr = lmb_alloc(size * NR_CPUS, PAGE_SIZE);
-       if (!paddr) {
-               prom_printf("Cannot allocate per-cpu memory.\n");
-               prom_halt();
+               pte = pte_offset_kernel(pmd, start);
+               this_end = (start + PMD_SIZE) & PMD_MASK;
+               if (this_end > end)
+                       this_end = end;
+
+               while (start < this_end) {
+                       unsigned long paddr = pfn << PAGE_SHIFT;
+
+                       pte_val(*pte) = (paddr | pte_base);
+
+                       start += PAGE_SIZE;
+                       pte++;
+                       pfn++;
+               }
+       }
+}
+
+void __init setup_per_cpu_areas(void)
+{
+       size_t dyn_size, static_size = __per_cpu_end - __per_cpu_start;
+       static struct vm_struct vm;
+       unsigned long delta, cpu;
+       size_t pcpu_unit_size;
+       size_t ptrs_size;
+
+       pcpur_size = PFN_ALIGN(static_size + PERCPU_MODULE_RESERVE +
+                              PERCPU_DYNAMIC_RESERVE);
+       dyn_size = pcpur_size - static_size - PERCPU_MODULE_RESERVE;
+
+
+       ptrs_size = PFN_ALIGN(num_possible_cpus() * sizeof(pcpur_ptrs[0]));
+       pcpur_ptrs = alloc_bootmem(ptrs_size);
+
+       for_each_possible_cpu(cpu) {
+               pcpur_ptrs[cpu] = pcpu_alloc_bootmem(cpu, PCPU_CHUNK_SIZE,
+                                                    PCPU_CHUNK_SIZE);
+
+               free_bootmem(__pa(pcpur_ptrs[cpu] + pcpur_size),
+                            PCPU_CHUNK_SIZE - pcpur_size);
+
+               memcpy(pcpur_ptrs[cpu], __per_cpu_load, static_size);
        }
 
-       ptr = __va(paddr);
-       __per_cpu_base = ptr - __per_cpu_start;
+       /* allocate address and map */
+       vm.flags = VM_ALLOC;
+       vm.size = num_possible_cpus() * PCPU_CHUNK_SIZE;
+       vm_area_register_early(&vm, PCPU_CHUNK_SIZE);
+
+       for_each_possible_cpu(cpu) {
+               unsigned long start = (unsigned long) vm.addr;
+               unsigned long end;
+
+               start += cpu * PCPU_CHUNK_SIZE;
+               end = start + PCPU_CHUNK_SIZE;
+               pcpu_map_range(start, end, virt_to_page(pcpur_ptrs[cpu]));
+       }
 
-       for (i = 0; i < NR_CPUS; i++, ptr += size)
-               memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
+       pcpu_unit_size = pcpu_setup_first_chunk(pcpur_get_page, static_size,
+                                               PERCPU_MODULE_RESERVE, dyn_size,
+                                               PCPU_CHUNK_SIZE, vm.addr, NULL);
+
+       free_bootmem(__pa(pcpur_ptrs), ptrs_size);
+
+       delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start;
+       for_each_possible_cpu(cpu) {
+               __per_cpu_offset(cpu) = delta + cpu * pcpu_unit_size;
+       }
 
        /* Setup %g5 for the boot cpu.  */
        __local_per_cpu_offset = __per_cpu_offset(smp_processor_id());
+
+       of_fill_in_cpu_data();
+       if (tlb_type == hypervisor)
+               mdesc_fill_in_cpu_data(cpu_all_mask);
 }
index 00ec3b15f38ceb4e53332b085bd437cdedab5ba8..690901657291db9f641bc17a9c45cd26f542c8fa 100644 (file)
@@ -81,4 +81,6 @@ sys_call_table:
 /*305*/        .long sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
 /*310*/        .long sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate
 /*315*/        .long sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1
-/*320*/        .long sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv, sys_pwritev
+/*320*/        .long sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv
+/*325*/        .long sys_pwritev, sys_rt_tgsigqueueinfo
+
index 82b5bf85b9d2b2137bcaedda89ffe472dd06650e..6b3ee88e253c22035d5d0f80f39c472e59219dd1 100644 (file)
@@ -82,7 +82,8 @@ sys_call_table32:
        .word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait
 /*310*/        .word compat_sys_utimensat, compat_sys_signalfd, sys_timerfd_create, sys_eventfd, compat_sys_fallocate
        .word compat_sys_timerfd_settime, compat_sys_timerfd_gettime, compat_sys_signalfd4, sys_eventfd2, sys_epoll_create1
-/*320*/        .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, compat_sys_preadv, compat_sys_pwritev
+/*320*/        .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, compat_sys_preadv
+       .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo
 
 #endif /* CONFIG_COMPAT */
 
@@ -156,4 +157,5 @@ sys_call_table:
        .word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
 /*310*/        .word sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate
        .word sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1
-/*320*/        .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv, sys_pwritev
+/*320*/        .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv
+       .word sys_pwritev, sys_rt_tgsigqueueinfo
index d809c4ebb48f44120f682272e00664bfbfd7cea6..10f7bb9fc1404e77a6eb542dec98285e98762162 100644 (file)
@@ -2509,6 +2509,7 @@ void do_getpsr(struct pt_regs *regs)
 }
 
 struct trap_per_cpu trap_block[NR_CPUS];
+EXPORT_SYMBOL(trap_block);
 
 /* This can get invoked before sched_init() so play it super safe
  * and use hard_smp_processor_id().
@@ -2530,84 +2531,97 @@ extern void tsb_config_offsets_are_bolixed_dave(void);
 void __init trap_init(void)
 {
        /* Compile time sanity check. */
-       if (TI_TASK != offsetof(struct thread_info, task) ||
-           TI_FLAGS != offsetof(struct thread_info, flags) ||
-           TI_CPU != offsetof(struct thread_info, cpu) ||
-           TI_FPSAVED != offsetof(struct thread_info, fpsaved) ||
-           TI_KSP != offsetof(struct thread_info, ksp) ||
-           TI_FAULT_ADDR != offsetof(struct thread_info, fault_address) ||
-           TI_KREGS != offsetof(struct thread_info, kregs) ||
-           TI_UTRAPS != offsetof(struct thread_info, utraps) ||
-           TI_EXEC_DOMAIN != offsetof(struct thread_info, exec_domain) ||
-           TI_REG_WINDOW != offsetof(struct thread_info, reg_window) ||
-           TI_RWIN_SPTRS != offsetof(struct thread_info, rwbuf_stkptrs) ||
-           TI_GSR != offsetof(struct thread_info, gsr) ||
-           TI_XFSR != offsetof(struct thread_info, xfsr) ||
-           TI_USER_CNTD0 != offsetof(struct thread_info, user_cntd0) ||
-           TI_USER_CNTD1 != offsetof(struct thread_info, user_cntd1) ||
-           TI_KERN_CNTD0 != offsetof(struct thread_info, kernel_cntd0) ||
-           TI_KERN_CNTD1 != offsetof(struct thread_info, kernel_cntd1) ||
-           TI_PCR != offsetof(struct thread_info, pcr_reg) ||
-           TI_PRE_COUNT != offsetof(struct thread_info, preempt_count) ||
-           TI_NEW_CHILD != offsetof(struct thread_info, new_child) ||
-           TI_SYS_NOERROR != offsetof(struct thread_info, syscall_noerror) ||
-           TI_RESTART_BLOCK != offsetof(struct thread_info, restart_block) ||
-           TI_KUNA_REGS != offsetof(struct thread_info, kern_una_regs) ||
-           TI_KUNA_INSN != offsetof(struct thread_info, kern_una_insn) ||
-           TI_FPREGS != offsetof(struct thread_info, fpregs) ||
-           (TI_FPREGS & (64 - 1)))
-               thread_info_offsets_are_bolixed_dave();
-
-       if (TRAP_PER_CPU_THREAD != offsetof(struct trap_per_cpu, thread) ||
-           (TRAP_PER_CPU_PGD_PADDR !=
-            offsetof(struct trap_per_cpu, pgd_paddr)) ||
-           (TRAP_PER_CPU_CPU_MONDO_PA !=
-            offsetof(struct trap_per_cpu, cpu_mondo_pa)) ||
-           (TRAP_PER_CPU_DEV_MONDO_PA !=
-            offsetof(struct trap_per_cpu, dev_mondo_pa)) ||
-           (TRAP_PER_CPU_RESUM_MONDO_PA !=
-            offsetof(struct trap_per_cpu, resum_mondo_pa)) ||
-           (TRAP_PER_CPU_RESUM_KBUF_PA !=
-            offsetof(struct trap_per_cpu, resum_kernel_buf_pa)) ||
-           (TRAP_PER_CPU_NONRESUM_MONDO_PA !=
-            offsetof(struct trap_per_cpu, nonresum_mondo_pa)) ||
-           (TRAP_PER_CPU_NONRESUM_KBUF_PA !=
-            offsetof(struct trap_per_cpu, nonresum_kernel_buf_pa)) ||
-           (TRAP_PER_CPU_FAULT_INFO !=
-            offsetof(struct trap_per_cpu, fault_info)) ||
-           (TRAP_PER_CPU_CPU_MONDO_BLOCK_PA !=
-            offsetof(struct trap_per_cpu, cpu_mondo_block_pa)) ||
-           (TRAP_PER_CPU_CPU_LIST_PA !=
-            offsetof(struct trap_per_cpu, cpu_list_pa)) ||
-           (TRAP_PER_CPU_TSB_HUGE !=
-            offsetof(struct trap_per_cpu, tsb_huge)) ||
-           (TRAP_PER_CPU_TSB_HUGE_TEMP !=
-            offsetof(struct trap_per_cpu, tsb_huge_temp)) ||
-           (TRAP_PER_CPU_IRQ_WORKLIST_PA !=
-            offsetof(struct trap_per_cpu, irq_worklist_pa)) ||
-           (TRAP_PER_CPU_CPU_MONDO_QMASK !=
-            offsetof(struct trap_per_cpu, cpu_mondo_qmask)) ||
-           (TRAP_PER_CPU_DEV_MONDO_QMASK !=
-            offsetof(struct trap_per_cpu, dev_mondo_qmask)) ||
-           (TRAP_PER_CPU_RESUM_QMASK !=
-            offsetof(struct trap_per_cpu, resum_qmask)) ||
-           (TRAP_PER_CPU_NONRESUM_QMASK !=
-            offsetof(struct trap_per_cpu, nonresum_qmask)))
-               trap_per_cpu_offsets_are_bolixed_dave();
-
-       if ((TSB_CONFIG_TSB !=
-            offsetof(struct tsb_config, tsb)) ||
-           (TSB_CONFIG_RSS_LIMIT !=
-            offsetof(struct tsb_config, tsb_rss_limit)) ||
-           (TSB_CONFIG_NENTRIES !=
-            offsetof(struct tsb_config, tsb_nentries)) ||
-           (TSB_CONFIG_REG_VAL !=
-            offsetof(struct tsb_config, tsb_reg_val)) ||
-           (TSB_CONFIG_MAP_VADDR !=
-            offsetof(struct tsb_config, tsb_map_vaddr)) ||
-           (TSB_CONFIG_MAP_PTE !=
-            offsetof(struct tsb_config, tsb_map_pte)))
-               tsb_config_offsets_are_bolixed_dave();
+       BUILD_BUG_ON(TI_TASK != offsetof(struct thread_info, task) ||
+                    TI_FLAGS != offsetof(struct thread_info, flags) ||
+                    TI_CPU != offsetof(struct thread_info, cpu) ||
+                    TI_FPSAVED != offsetof(struct thread_info, fpsaved) ||
+                    TI_KSP != offsetof(struct thread_info, ksp) ||
+                    TI_FAULT_ADDR != offsetof(struct thread_info,
+                                              fault_address) ||
+                    TI_KREGS != offsetof(struct thread_info, kregs) ||
+                    TI_UTRAPS != offsetof(struct thread_info, utraps) ||
+                    TI_EXEC_DOMAIN != offsetof(struct thread_info,
+                                               exec_domain) ||
+                    TI_REG_WINDOW != offsetof(struct thread_info,
+                                              reg_window) ||
+                    TI_RWIN_SPTRS != offsetof(struct thread_info,
+                                              rwbuf_stkptrs) ||
+                    TI_GSR != offsetof(struct thread_info, gsr) ||
+                    TI_XFSR != offsetof(struct thread_info, xfsr) ||
+                    TI_USER_CNTD0 != offsetof(struct thread_info,
+                                              user_cntd0) ||
+                    TI_USER_CNTD1 != offsetof(struct thread_info,
+                                              user_cntd1) ||
+                    TI_KERN_CNTD0 != offsetof(struct thread_info,
+                                              kernel_cntd0) ||
+                    TI_KERN_CNTD1 != offsetof(struct thread_info,
+                                              kernel_cntd1) ||
+                    TI_PCR != offsetof(struct thread_info, pcr_reg) ||
+                    TI_PRE_COUNT != offsetof(struct thread_info,
+                                             preempt_count) ||
+                    TI_NEW_CHILD != offsetof(struct thread_info, new_child) ||
+                    TI_SYS_NOERROR != offsetof(struct thread_info,
+                                               syscall_noerror) ||
+                    TI_RESTART_BLOCK != offsetof(struct thread_info,
+                                                 restart_block) ||
+                    TI_KUNA_REGS != offsetof(struct thread_info,
+                                             kern_una_regs) ||
+                    TI_KUNA_INSN != offsetof(struct thread_info,
+                                             kern_una_insn) ||
+                    TI_FPREGS != offsetof(struct thread_info, fpregs) ||
+                    (TI_FPREGS & (64 - 1)));
+
+       BUILD_BUG_ON(TRAP_PER_CPU_THREAD != offsetof(struct trap_per_cpu,
+                                                    thread) ||
+                    (TRAP_PER_CPU_PGD_PADDR !=
+                     offsetof(struct trap_per_cpu, pgd_paddr)) ||
+                    (TRAP_PER_CPU_CPU_MONDO_PA !=
+                     offsetof(struct trap_per_cpu, cpu_mondo_pa)) ||
+                    (TRAP_PER_CPU_DEV_MONDO_PA !=
+                     offsetof(struct trap_per_cpu, dev_mondo_pa)) ||
+                    (TRAP_PER_CPU_RESUM_MONDO_PA !=
+                     offsetof(struct trap_per_cpu, resum_mondo_pa)) ||
+                    (TRAP_PER_CPU_RESUM_KBUF_PA !=
+                     offsetof(struct trap_per_cpu, resum_kernel_buf_pa)) ||
+                    (TRAP_PER_CPU_NONRESUM_MONDO_PA !=
+                     offsetof(struct trap_per_cpu, nonresum_mondo_pa)) ||
+                    (TRAP_PER_CPU_NONRESUM_KBUF_PA !=
+                     offsetof(struct trap_per_cpu, nonresum_kernel_buf_pa)) ||
+                    (TRAP_PER_CPU_FAULT_INFO !=
+                     offsetof(struct trap_per_cpu, fault_info)) ||
+                    (TRAP_PER_CPU_CPU_MONDO_BLOCK_PA !=
+                     offsetof(struct trap_per_cpu, cpu_mondo_block_pa)) ||
+                    (TRAP_PER_CPU_CPU_LIST_PA !=
+                     offsetof(struct trap_per_cpu, cpu_list_pa)) ||
+                    (TRAP_PER_CPU_TSB_HUGE !=
+                     offsetof(struct trap_per_cpu, tsb_huge)) ||
+                    (TRAP_PER_CPU_TSB_HUGE_TEMP !=
+                     offsetof(struct trap_per_cpu, tsb_huge_temp)) ||
+                    (TRAP_PER_CPU_IRQ_WORKLIST_PA !=
+                     offsetof(struct trap_per_cpu, irq_worklist_pa)) ||
+                    (TRAP_PER_CPU_CPU_MONDO_QMASK !=
+                     offsetof(struct trap_per_cpu, cpu_mondo_qmask)) ||
+                    (TRAP_PER_CPU_DEV_MONDO_QMASK !=
+                     offsetof(struct trap_per_cpu, dev_mondo_qmask)) ||
+                    (TRAP_PER_CPU_RESUM_QMASK !=
+                     offsetof(struct trap_per_cpu, resum_qmask)) ||
+                    (TRAP_PER_CPU_NONRESUM_QMASK !=
+                     offsetof(struct trap_per_cpu, nonresum_qmask)) ||
+                    (TRAP_PER_CPU_PER_CPU_BASE !=
+                     offsetof(struct trap_per_cpu, __per_cpu_base)));
+
+       BUILD_BUG_ON((TSB_CONFIG_TSB !=
+                     offsetof(struct tsb_config, tsb)) ||
+                    (TSB_CONFIG_RSS_LIMIT !=
+                     offsetof(struct tsb_config, tsb_rss_limit)) ||
+                    (TSB_CONFIG_NENTRIES !=
+                     offsetof(struct tsb_config, tsb_nentries)) ||
+                    (TSB_CONFIG_REG_VAL !=
+                     offsetof(struct tsb_config, tsb_reg_val)) ||
+                    (TSB_CONFIG_MAP_VADDR !=
+                     offsetof(struct tsb_config, tsb_map_vaddr)) ||
+                    (TSB_CONFIG_MAP_PTE !=
+                     offsetof(struct tsb_config, tsb_map_pte)));
 
        /* Attach to the address space of init_task.  On SMP we
         * do this in smp.c:smp_callin for other cpus.
index cbb282dab5a7e5d82ac386730d6b3e1244ee08e4..26bb3919ff1fe216eda103883b9ee0aec2f8208e 100644 (file)
@@ -358,6 +358,7 @@ void __init paging_init(void)
        protection_map[15] = PAGE_SHARED;
        btfixup();
        prom_build_devicetree();
+       of_fill_in_cpu_data();
        device_scan();
 }
 
index f26a352c08a068b0b915ddc0d309c394cb2fc966..ca92e2f54e4d5bd5f3e2f663ce2056eecb853c7e 100644 (file)
@@ -1679,11 +1679,6 @@ pgd_t swapper_pg_dir[2048];
 static void sun4u_pgprot_init(void);
 static void sun4v_pgprot_init(void);
 
-/* Dummy function */
-void __init setup_per_cpu_areas(void)
-{
-}
-
 void __init paging_init(void)
 {
        unsigned long end_pfn, shift, phys_base;
@@ -1799,16 +1794,13 @@ void __init paging_init(void)
        if (tlb_type == hypervisor)
                sun4v_ktsb_register();
 
-       /* We must setup the per-cpu areas before we pull in the
-        * PROM and the MDESC.  The code there fills in cpu and
-        * other information into per-cpu data structures.
-        */
-       real_setup_per_cpu_areas();
-
        prom_build_devicetree();
+       of_populate_present_mask();
 
-       if (tlb_type == hypervisor)
+       if (tlb_type == hypervisor) {
                sun4v_mdesc_init();
+               mdesc_populate_present_mask(cpu_all_mask);
+       }
 
        /* Once the OF device tree and MDESC have been setup, we know
         * the list of possible cpus.  Therefore we can allocate the
index 06c9a7d98206f0256c23a281381bf2d6ab7ca441..ade4eb373bddc2e9d6c85472d26a90e62d457e2b 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/fs.h>
 #include <linux/seq_file.h>
 #include <linux/kdebug.h>
+#include <linux/log2.h>
 
 #include <asm/bitext.h>
 #include <asm/page.h>
@@ -349,7 +350,7 @@ static void srmmu_free_nocache(unsigned long vaddr, int size)
                    vaddr, srmmu_nocache_end);
                BUG();
        }
-       if (size & (size-1)) {
+       if (!is_power_of_2(size)) {
                printk("Size 0x%x is not a power of 2\n", size);
                BUG();
        }
index 434ba121e3c59a30009117fd6f1c146f516270a6..3b44b47c7e1d4615dbf73dd6f2e92997b9fa29c3 100644 (file)
@@ -360,7 +360,7 @@ static struct platform_driver uml_net_driver = {
 
 static void net_device_release(struct device *dev)
 {
-       struct uml_net *device = dev->driver_data;
+       struct uml_net *device = dev_get_drvdata(dev);
        struct net_device *netdev = device->dev;
        struct uml_net_private *lp = netdev_priv(netdev);
 
@@ -440,7 +440,7 @@ static void eth_configure(int n, void *init, char *mac,
        device->pdev.id = n;
        device->pdev.name = DRIVER_NAME;
        device->pdev.dev.release = net_device_release;
-       device->pdev.dev.driver_data = device;
+       dev_set_drvdata(&device->pdev.dev, device);
        if (platform_device_register(&device->pdev))
                goto out_free_netdev;
        SET_NETDEV_DEV(dev,&device->pdev.dev);
index aa9e926e13d73dca17015a5bd5f8e5eb76842c63..8f05d4d9da128788d0b5b7d5f39ac5fe2741bd61 100644 (file)
@@ -778,7 +778,7 @@ static int ubd_open_dev(struct ubd *ubd_dev)
 
 static void ubd_device_release(struct device *dev)
 {
-       struct ubd *ubd_dev = dev->driver_data;
+       struct ubd *ubd_dev = dev_get_drvdata(dev);
 
        blk_cleanup_queue(ubd_dev->queue);
        *ubd_dev = ((struct ubd) DEFAULT_UBD);
@@ -807,7 +807,7 @@ static int ubd_disk_register(int major, u64 size, int unit,
                ubd_devs[unit].pdev.id   = unit;
                ubd_devs[unit].pdev.name = DRIVER_NAME;
                ubd_devs[unit].pdev.dev.release = ubd_device_release;
-               ubd_devs[unit].pdev.dev.driver_data = &ubd_devs[unit];
+               dev_set_drvdata(&ubd_devs[unit].pdev.dev, &ubd_devs[unit]);
                platform_device_register(&ubd_devs[unit].pdev);
                disk->driverfs_dev = &ubd_devs[unit].pdev.dev;
        }
index 37dd097c16c07131282b8ddd484d52e1cb6fd369..b3906f860a87e31189c0824d3df1edc2a6c0378c 100644 (file)
@@ -27,7 +27,7 @@
  * sign followed by value, e.g.:
  *
  * static int init_variable __initdata = 0;
- * static char linux_logo[] __initdata = { 0x32, 0x36, ... };
+ * static const char linux_logo[] __initconst = { 0x32, 0x36, ... };
  *
  * Don't forget to initialize data not at file scope, i.e. within a function,
  * as gcc otherwise puts the data into the bss section and not into the init
index 63bee158cd8efbe2639f5a293c741ca5af1623ef..3dabbe128e40b0186538f9b4389a1311f2b738f2 100644 (file)
@@ -8,7 +8,7 @@
 
 #define ETH_ADDR_LEN (6)
 #define ETH_HEADER_ETHERTAP (16)
-#define ETH_HEADER_OTHER (14)
+#define ETH_HEADER_OTHER (26) /* 14 for ethernet + VLAN + MPLS for crazy people */
 #define ETH_MAX_PACKET (1500)
 
 #define UML_NET_VERSION (4)
index 806d381947bf1c704dc584e5b29360abb7b40a88..b25121b537d8dfb6d0588d1aaf4ebc9b915cc663 100644 (file)
 #include "linux/mqueue.h"
 #include "asm/uaccess.h"
 
-struct mm_struct init_mm = INIT_MM(init_mm);
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-EXPORT_SYMBOL(init_mm);
-
 /*
  * Initial task structure.
  *
index 336b61569072be6958ccb74c22e6c87abbb7c9b2..454cdb43e351a93fbb6ea50db791f726a8fb2733 100644 (file)
@@ -358,7 +358,7 @@ EXPORT_SYMBOL(um_request_irq);
 EXPORT_SYMBOL(reactivate_fd);
 
 /*
- * hw_interrupt_type must define (startup || enable) &&
+ * irq_chip must define (startup || enable) &&
  * (shutdown || disable) && end
  */
 static void dummy(unsigned int irq)
@@ -366,7 +366,7 @@ static void dummy(unsigned int irq)
 }
 
 /* This is used for everything else than the timer. */
-static struct hw_interrupt_type normal_irq_type = {
+static struct irq_chip normal_irq_type = {
        .typename = "SIGIO",
        .release = free_irq_by_irq_and_dev,
        .disable = dummy,
@@ -375,7 +375,7 @@ static struct hw_interrupt_type normal_irq_type = {
        .end = dummy
 };
 
-static struct hw_interrupt_type SIGVTALRM_irq_type = {
+static struct irq_chip SIGVTALRM_irq_type = {
        .typename = "SIGVTALRM",
        .release = free_irq_by_irq_and_dev,
        .shutdown = dummy, /* never called */
index c41b04bf5fa005399183176935a683dbfe92d3ce..54a36ec20cb75c32b65a7e0e28043a8c19c6a6f0 100644 (file)
@@ -1,7 +1,7 @@
 #include "as-layout.h"
 
        .globl syscall_stub
-.section .__syscall_stub, "x"
+.section .__syscall_stub, "ax"
 
        .globl batch_syscall_stub
 batch_syscall_stub:
index 6e8a9195e95266ff55276e7de633782e970a646b..04b9e87c8dadd38f5f0ebc60ae72b190e63c7920 100644 (file)
@@ -66,28 +66,28 @@ typedef struct user_i387_struct elf_fpregset_t;
        PT_REGS_R15(regs) = 0; \
 } while (0)
 
-#define ELF_CORE_COPY_REGS(pr_reg, regs)               \
-       (pr_reg)[0] = (regs)->regs.gp[0];                       \
-       (pr_reg)[1] = (regs)->regs.gp[1];                       \
-       (pr_reg)[2] = (regs)->regs.gp[2];                       \
-       (pr_reg)[3] = (regs)->regs.gp[3];                       \
-       (pr_reg)[4] = (regs)->regs.gp[4];                       \
-       (pr_reg)[5] = (regs)->regs.gp[5];                       \
-       (pr_reg)[6] = (regs)->regs.gp[6];                       \
-       (pr_reg)[7] = (regs)->regs.gp[7];                       \
-       (pr_reg)[8] = (regs)->regs.gp[8];                       \
-       (pr_reg)[9] = (regs)->regs.gp[9];                       \
-       (pr_reg)[10] = (regs)->regs.gp[10];                     \
-       (pr_reg)[11] = (regs)->regs.gp[11];                     \
-       (pr_reg)[12] = (regs)->regs.gp[12];                     \
-       (pr_reg)[13] = (regs)->regs.gp[13];                     \
-       (pr_reg)[14] = (regs)->regs.gp[14];                     \
-       (pr_reg)[15] = (regs)->regs.gp[15];                     \
-       (pr_reg)[16] = (regs)->regs.gp[16];                     \
-       (pr_reg)[17] = (regs)->regs.gp[17];                     \
-       (pr_reg)[18] = (regs)->regs.gp[18];                     \
-       (pr_reg)[19] = (regs)->regs.gp[19];                     \
-       (pr_reg)[20] = (regs)->regs.gp[20];                     \
+#define ELF_CORE_COPY_REGS(pr_reg, _regs)              \
+       (pr_reg)[0] = (_regs)->regs.gp[0];                      \
+       (pr_reg)[1] = (_regs)->regs.gp[1];                      \
+       (pr_reg)[2] = (_regs)->regs.gp[2];                      \
+       (pr_reg)[3] = (_regs)->regs.gp[3];                      \
+       (pr_reg)[4] = (_regs)->regs.gp[4];                      \
+       (pr_reg)[5] = (_regs)->regs.gp[5];                      \
+       (pr_reg)[6] = (_regs)->regs.gp[6];                      \
+       (pr_reg)[7] = (_regs)->regs.gp[7];                      \
+       (pr_reg)[8] = (_regs)->regs.gp[8];                      \
+       (pr_reg)[9] = (_regs)->regs.gp[9];                      \
+       (pr_reg)[10] = (_regs)->regs.gp[10];                    \
+       (pr_reg)[11] = (_regs)->regs.gp[11];                    \
+       (pr_reg)[12] = (_regs)->regs.gp[12];                    \
+       (pr_reg)[13] = (_regs)->regs.gp[13];                    \
+       (pr_reg)[14] = (_regs)->regs.gp[14];                    \
+       (pr_reg)[15] = (_regs)->regs.gp[15];                    \
+       (pr_reg)[16] = (_regs)->regs.gp[16];                    \
+       (pr_reg)[17] = (_regs)->regs.gp[17];                    \
+       (pr_reg)[18] = (_regs)->regs.gp[18];                    \
+       (pr_reg)[19] = (_regs)->regs.gp[19];                    \
+       (pr_reg)[20] = (_regs)->regs.gp[20];                    \
        (pr_reg)[21] = current->thread.arch.fs;                 \
        (pr_reg)[22] = 0;                                       \
        (pr_reg)[23] = 0;                                       \
index 6d9edf9fabce15d4dac536ae8ce18e70b301822e..20e4a96a6dcbe064ddc99f719e7ffdb506fa4cdc 100644 (file)
@@ -1,7 +1,7 @@
 #include "as-layout.h"
 
        .globl syscall_stub
-.section .__syscall_stub, "x"
+.section .__syscall_stub, "ax"
 syscall_stub:
        syscall
        /* We don't have 64-bit constants, so this constructs the address
index 356d2ec8e2fbbf0a4e0ccee99c1f261226ed4cde..cf42fc305419873d2816f2989bb01f23711d74ed 100644 (file)
@@ -46,6 +46,7 @@ config X86
        select HAVE_KERNEL_GZIP
        select HAVE_KERNEL_BZIP2
        select HAVE_KERNEL_LZMA
+       select HAVE_ARCH_KMEMCHECK
 
 config OUTPUT_FORMAT
        string
index edbd0ca620678fd6627c60d4849a07852a823b11..1b68659c41b4c4ce91a3ad7bee7aa8c532fc2168 100644 (file)
@@ -81,6 +81,11 @@ ifdef CONFIG_CC_STACKPROTECTOR
         endif
 endif
 
+# Don't unroll struct assignments with kmemcheck enabled
+ifeq ($(CONFIG_KMEMCHECK),y)
+       KBUILD_CFLAGS += $(call cc-option,-fno-builtin-memcpy)
+endif
+
 # Stackpointer is addressed different for 32 bit and 64 bit x86
 sp-$(CONFIG_X86_32) := esp
 sp-$(CONFIG_X86_64) := rsp
index f82fdc412c64b9d3371fb1a9df65f38ba141bb52..b93405b228b47868dba489944324a147852f90cc 100644 (file)
@@ -6,6 +6,7 @@
  * Documentation/DMA-API.txt for documentation.
  */
 
+#include <linux/kmemcheck.h>
 #include <linux/scatterlist.h>
 #include <linux/dma-debug.h>
 #include <linux/dma-attrs.h>
@@ -60,6 +61,7 @@ dma_map_single(struct device *hwdev, void *ptr, size_t size,
        dma_addr_t addr;
 
        BUG_ON(!valid_dma_direction(dir));
+       kmemcheck_mark_initialized(ptr, size);
        addr = ops->map_page(hwdev, virt_to_page(ptr),
                             (unsigned long)ptr & ~PAGE_MASK, size,
                             dir, NULL);
@@ -87,8 +89,12 @@ dma_map_sg(struct device *hwdev, struct scatterlist *sg,
 {
        struct dma_map_ops *ops = get_dma_ops(hwdev);
        int ents;
+       struct scatterlist *s;
+       int i;
 
        BUG_ON(!valid_dma_direction(dir));
+       for_each_sg(sg, s, nents, i)
+               kmemcheck_mark_initialized(sg_virt(s), s->length);
        ents = ops->map_sg(hwdev, sg, nents, dir, NULL);
        debug_dma_map_sg(hwdev, sg, nents, ents, dir);
 
@@ -200,6 +206,7 @@ static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
        dma_addr_t addr;
 
        BUG_ON(!valid_dma_direction(dir));
+       kmemcheck_mark_initialized(page_address(page) + offset, size);
        addr = ops->map_page(dev, page, offset, size, dir, NULL);
        debug_dma_map_page(dev, page, offset, size, dir, addr, false);
 
index 5759c165a5cf5516adc32d6cc6d841451cf55aaa..9e00a731a7fbaad71b252d3779a54b04311407fd 100644 (file)
@@ -2,28 +2,11 @@
 #define _ASM_X86_KMAP_TYPES_H
 
 #if defined(CONFIG_X86_32) && defined(CONFIG_DEBUG_HIGHMEM)
-# define D(n) __KM_FENCE_##n ,
-#else
-# define D(n)
+#define  __WITH_KM_FENCE
 #endif
 
-enum km_type {
-D(0)   KM_BOUNCE_READ,
-D(1)   KM_SKB_SUNRPC_DATA,
-D(2)   KM_SKB_DATA_SOFTIRQ,
-D(3)   KM_USER0,
-D(4)   KM_USER1,
-D(5)   KM_BIO_SRC_IRQ,
-D(6)   KM_BIO_DST_IRQ,
-D(7)   KM_PTE0,
-D(8)   KM_PTE1,
-D(9)   KM_IRQ0,
-D(10)  KM_IRQ1,
-D(11)  KM_SOFTIRQ0,
-D(12)  KM_SOFTIRQ1,
-D(13)  KM_TYPE_NR
-};
+#include <asm-generic/kmap_types.h>
 
-#undef D
+#undef __WITH_KM_FENCE
 
 #endif /* _ASM_X86_KMAP_TYPES_H */
diff --git a/arch/x86/include/asm/kmemcheck.h b/arch/x86/include/asm/kmemcheck.h
new file mode 100644 (file)
index 0000000..ed01518
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef ASM_X86_KMEMCHECK_H
+#define ASM_X86_KMEMCHECK_H
+
+#include <linux/types.h>
+#include <asm/ptrace.h>
+
+#ifdef CONFIG_KMEMCHECK
+bool kmemcheck_active(struct pt_regs *regs);
+
+void kmemcheck_show(struct pt_regs *regs);
+void kmemcheck_hide(struct pt_regs *regs);
+
+bool kmemcheck_fault(struct pt_regs *regs,
+       unsigned long address, unsigned long error_code);
+bool kmemcheck_trap(struct pt_regs *regs);
+#else
+static inline bool kmemcheck_active(struct pt_regs *regs)
+{
+       return false;
+}
+
+static inline void kmemcheck_show(struct pt_regs *regs)
+{
+}
+
+static inline void kmemcheck_hide(struct pt_regs *regs)
+{
+}
+
+static inline bool kmemcheck_fault(struct pt_regs *regs,
+       unsigned long address, unsigned long error_code)
+{
+       return false;
+}
+
+static inline bool kmemcheck_trap(struct pt_regs *regs)
+{
+       return false;
+}
+#endif /* CONFIG_KMEMCHECK */
+
+#endif
index 18ef7ebf2631709dad4f26a681fdbf5dff5a8b2b..3cc06e3fceb8e8ba2b9a7d72b7608c520aa5b81f 100644 (file)
@@ -317,6 +317,11 @@ static inline int pte_present(pte_t a)
        return pte_flags(a) & (_PAGE_PRESENT | _PAGE_PROTNONE);
 }
 
+static inline int pte_hidden(pte_t pte)
+{
+       return pte_flags(pte) & _PAGE_HIDDEN;
+}
+
 static inline int pmd_present(pmd_t pmd)
 {
        return pmd_flags(pmd) & _PAGE_PRESENT;
index 4d258ad76a0fc04925ac484c1fa9b0bfc47a1cb9..54cb697f4900e03f1934f784196dc4d167bdd366 100644 (file)
@@ -18,7 +18,7 @@
 #define _PAGE_BIT_GLOBAL       8       /* Global TLB entry PPro+ */
 #define _PAGE_BIT_UNUSED1      9       /* available for programmer */
 #define _PAGE_BIT_IOMAP                10      /* flag used to indicate IO mapping */
-#define _PAGE_BIT_UNUSED3      11
+#define _PAGE_BIT_HIDDEN       11      /* hidden by kmemcheck */
 #define _PAGE_BIT_PAT_LARGE    12      /* On 2MB or 1GB pages */
 #define _PAGE_BIT_SPECIAL      _PAGE_BIT_UNUSED1
 #define _PAGE_BIT_CPA_TEST     _PAGE_BIT_UNUSED1
 #define _PAGE_GLOBAL   (_AT(pteval_t, 1) << _PAGE_BIT_GLOBAL)
 #define _PAGE_UNUSED1  (_AT(pteval_t, 1) << _PAGE_BIT_UNUSED1)
 #define _PAGE_IOMAP    (_AT(pteval_t, 1) << _PAGE_BIT_IOMAP)
-#define _PAGE_UNUSED3  (_AT(pteval_t, 1) << _PAGE_BIT_UNUSED3)
 #define _PAGE_PAT      (_AT(pteval_t, 1) << _PAGE_BIT_PAT)
 #define _PAGE_PAT_LARGE (_AT(pteval_t, 1) << _PAGE_BIT_PAT_LARGE)
 #define _PAGE_SPECIAL  (_AT(pteval_t, 1) << _PAGE_BIT_SPECIAL)
 #define _PAGE_CPA_TEST (_AT(pteval_t, 1) << _PAGE_BIT_CPA_TEST)
 #define __HAVE_ARCH_PTE_SPECIAL
 
+#ifdef CONFIG_KMEMCHECK
+#define _PAGE_HIDDEN   (_AT(pteval_t, 1) << _PAGE_BIT_HIDDEN)
+#else
+#define _PAGE_HIDDEN   (_AT(pteval_t, 0))
+#endif
+
 #if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
 #define _PAGE_NX       (_AT(pteval_t, 1) << _PAGE_BIT_NX)
 #else
index 0e0e3ba827f74dcad11f51f898bf1f1311afa805..c86f452256de935492dae82c0256f8040791f9c8 100644 (file)
@@ -177,10 +177,18 @@ static inline void *__memcpy3d(void *to, const void *from, size_t len)
  *     No 3D Now!
  */
 
+#ifndef CONFIG_KMEMCHECK
 #define memcpy(t, f, n)                                \
        (__builtin_constant_p((n))              \
         ? __constant_memcpy((t), (f), (n))     \
         : __memcpy((t), (f), (n)))
+#else
+/*
+ * kmemcheck becomes very happy if we use the REP instructions unconditionally,
+ * because it means that we know both memory operands in advance.
+ */
+#define memcpy(t, f, n) __memcpy((t), (f), (n))
+#endif
 
 #endif
 
index 2afe164bf1e67a73f622c751adaeed870e12075f..19e2c468fc2c8045469ac2a704947cd07ea81100 100644 (file)
@@ -27,6 +27,7 @@ static __always_inline void *__inline_memcpy(void *to, const void *from, size_t
    function. */
 
 #define __HAVE_ARCH_MEMCPY 1
+#ifndef CONFIG_KMEMCHECK
 #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4
 extern void *memcpy(void *to, const void *from, size_t len);
 #else
@@ -42,6 +43,13 @@ extern void *__memcpy(void *to, const void *from, size_t len);
        __ret;                                                  \
 })
 #endif
+#else
+/*
+ * kmemcheck becomes very happy if we use the REP instructions unconditionally,
+ * because it means that we know both memory operands in advance.
+ */
+#define memcpy(dst, src, len) __inline_memcpy((dst), (src), (len))
+#endif
 
 #define __HAVE_ARCH_MEMSET
 void *memset(void *s, int c, size_t n);
index 602c769fc98ca7340f5388fe21e57ce5431b376e..b0783520988b8bba544ad79dc38d4ea4580876f6 100644 (file)
@@ -154,9 +154,9 @@ struct thread_info {
 
 /* thread information allocation */
 #ifdef CONFIG_DEBUG_STACK_USAGE
-#define THREAD_FLAGS (GFP_KERNEL | __GFP_ZERO)
+#define THREAD_FLAGS (GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO)
 #else
-#define THREAD_FLAGS GFP_KERNEL
+#define THREAD_FLAGS (GFP_KERNEL | __GFP_NOTRACK)
 #endif
 
 #define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
index b5c9d45c981fa7a51b9429aff281a9a595fcb370..1375cfc93960e1054dcaa3d8a7f41cacaaee028a 100644 (file)
@@ -4,9 +4,7 @@
 #include <asm/processor.h>
 #include <asm/tsc.h>
 
-/* The PIT ticks at this frequency (in HZ): */
-#define PIT_TICK_RATE          1193182
-
+/* Assume we use the PIT time source for the clock tick */
 #define CLOCK_TICK_RATE                PIT_TICK_RATE
 
 #define ARCH_HAS_READ_CURRENT_TIMER
index 11b3bb86e17bc06e579a0d4e1493c30903a845a6..7fcf6f3dbcc37af7e45b3ffaa38f7b6a02f25f26 100644 (file)
@@ -1,5 +1,10 @@
+#ifdef CONFIG_KMEMCHECK
+/* kmemcheck doesn't handle MMX/SSE/SSE2 instructions */
+# include <asm-generic/xor.h>
+#else
 #ifdef CONFIG_X86_32
 # include "xor_32.h"
 #else
 # include "xor_64.h"
 #endif
+#endif
index 3ffdcfa9abdf07accfa466518b8ac1adf16a9c05..9fa33886c0d791a2a6aad25b42accb1e5a978a34 100644 (file)
@@ -487,7 +487,6 @@ out:
 static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c)
 {
        char *v = c->x86_vendor_id;
-       static int printed;
        int i;
 
        for (i = 0; i < X86_VENDOR_NUM; i++) {
@@ -504,13 +503,9 @@ static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c)
                }
        }
 
-       if (!printed) {
-               printed++;
-               printk(KERN_ERR
-                   "CPU: vendor_id '%s' unknown, using generic init.\n", v);
-
-               printk(KERN_ERR "CPU: Your system may be unstable.\n");
-       }
+       printk_once(KERN_ERR
+                       "CPU: vendor_id '%s' unknown, using generic init.\n" \
+                       "CPU: Your system may be unstable.\n", v);
 
        c->x86_vendor = X86_VENDOR_UNKNOWN;
        this_cpu = &default_cpu;
index daed39ba2614dbcad31e4725b343d56d0912f05d..3260ab04499610d603ca5809758844c025dfaa19 100644 (file)
@@ -86,6 +86,29 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c)
         */
        if (c->x86 == 6 && c->x86_model < 15)
                clear_cpu_cap(c, X86_FEATURE_PAT);
+
+#ifdef CONFIG_KMEMCHECK
+       /*
+        * P4s have a "fast strings" feature which causes single-
+        * stepping REP instructions to only generate a #DB on
+        * cache-line boundaries.
+        *
+        * Ingo Molnar reported a Pentium D (model 6) and a Xeon
+        * (model 2) with the same problem.
+        */
+       if (c->x86 == 15) {
+               u64 misc_enable;
+
+               rdmsrl(MSR_IA32_MISC_ENABLE, misc_enable);
+
+               if (misc_enable & MSR_IA32_MISC_ENABLE_FAST_STRING) {
+                       printk(KERN_INFO "kmemcheck: Disabling fast string operations\n");
+
+                       misc_enable &= ~MSR_IA32_MISC_ENABLE_FAST_STRING;
+                       wrmsrl(MSR_IA32_MISC_ENABLE, misc_enable);
+               }
+       }
+#endif
 }
 
 #ifdef CONFIG_X86_32
index 2ac1f0c2beb3ba54088d4e0c4e89622dbc03094d..b07af8861244cd4f108181c061a3fab787a724b2 100644 (file)
@@ -182,6 +182,11 @@ static struct notifier_block __refdata cpuid_class_cpu_notifier =
        .notifier_call = cpuid_class_cpu_callback,
 };
 
+static char *cpuid_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "cpu/%u/cpuid", MINOR(dev->devt));
+}
+
 static int __init cpuid_init(void)
 {
        int i, err = 0;
@@ -198,6 +203,7 @@ static int __init cpuid_init(void)
                err = PTR_ERR(cpuid_class);
                goto out_chrdev;
        }
+       cpuid_class->nodename = cpuid_nodename;
        for_each_online_cpu(i) {
                err = cpuid_device_create(i);
                if (err != 0)
index c2e0bb0890d4a17d652f1710a4df8ab948dec7a5..5cf36c053ac401a08a9e1ced6679e7f59c09d782 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/spinlock.h>
 #include <linux/jiffies.h>
 #include <linux/module.h>
+#include <linux/timex.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/io.h>
index df3bf269beab96466785764b619bc737fd0f5d55..270ff83efc11d8dc27089a3fec085fdec9074b5b 100644 (file)
@@ -12,7 +12,6 @@
 
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-struct mm_struct init_mm = INIT_MM(init_mm);
 
 /*
  * Initial thread structure.
index 9c4461501fcbb9618ac3ce12fef93f990b8f3955..9371448290ac3c4f3a3489b0d9edbe55a5dd689b 100644 (file)
@@ -236,6 +236,7 @@ static const struct file_operations microcode_fops = {
 static struct miscdevice microcode_dev = {
        .minor                  = MICROCODE_MINOR,
        .name                   = "microcode",
+       .devnode                = "cpu/microcode",
        .fops                   = &microcode_fops,
 };
 
index 3cf3413ec626936f334c309f9a20f2a32a36de96..98fd6cd4e3a479e8e1cea7a4ccfad7063f921850 100644 (file)
@@ -196,6 +196,11 @@ static struct notifier_block __refdata msr_class_cpu_notifier = {
        .notifier_call = msr_class_cpu_callback,
 };
 
+static char *msr_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "cpu/%u/msr", MINOR(dev->devt));
+}
+
 static int __init msr_init(void)
 {
        int i, err = 0;
@@ -212,6 +217,7 @@ static int __init msr_init(void)
                err = PTR_ERR(msr_class);
                goto out_chrdev;
        }
+       msr_class->nodename = msr_nodename;
        for_each_online_cpu(i) {
                err = msr_device_create(i);
                if (err != 0)
index 3bb2be1649bddb5b3ba9870553b72ce73e41b460..994dd6a4a2a004bcb5d91955fb921ac8c303eb3d 100644 (file)
@@ -63,7 +63,7 @@ void arch_task_cache_init(void)
         task_xstate_cachep =
                kmem_cache_create("task_xstate", xstate_size,
                                  __alignof__(union thread_xstate),
-                                 SLAB_PANIC, NULL);
+                                 SLAB_PANIC | SLAB_NOTRACK, NULL);
 }
 
 /*
index 4aaf7e48394fb562343f27d811e7a9f329be2b76..c3eb207181feeef5be791127b61798b432935cc4 100644 (file)
@@ -77,6 +77,13 @@ void save_stack_trace(struct stack_trace *trace)
 }
 EXPORT_SYMBOL_GPL(save_stack_trace);
 
+void save_stack_trace_bp(struct stack_trace *trace, unsigned long bp)
+{
+       dump_trace(current, NULL, NULL, bp, &save_stack_ops, trace);
+       if (trace->nr_entries < trace->max_entries)
+               trace->entries[trace->nr_entries++] = ULONG_MAX;
+}
+
 void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
 {
        dump_trace(tsk, NULL, NULL, 0, &save_stack_ops_nosched, trace);
index 1e1e27b7d438c4106e23f719335f2aa8f3f6ef5c..5f935f0d5861c625b3ffa6811846e4a480c91282 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/edac.h>
 #endif
 
+#include <asm/kmemcheck.h>
 #include <asm/stacktrace.h>
 #include <asm/processor.h>
 #include <asm/debugreg.h>
@@ -534,6 +535,10 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
 
        get_debugreg(condition, 6);
 
+       /* Catch kmemcheck conditions first of all! */
+       if (condition & DR_STEP && kmemcheck_trap(regs))
+               return;
+
        /*
         * The processor cleared BTF, so don't mark that we need it set.
         */
index 3e1c057e98fe039325eed2056d8960fa52f023c4..ae3180c506a6ba47163ff621b46b1814f55cdd8e 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/delay.h>
 #include <linux/clocksource.h>
 #include <linux/percpu.h>
+#include <linux/timex.h>
 
 #include <asm/hpet.h>
 #include <asm/timer.h>
index 32d6ae8fb60e339eba6b85968676776d44293c8b..e770bf349ec4f7f473f8639dabf4068188a4b3b5 100644 (file)
@@ -1277,7 +1277,7 @@ static struct vmcs *alloc_vmcs_cpu(int cpu)
        struct page *pages;
        struct vmcs *vmcs;
 
-       pages = alloc_pages_node(node, GFP_KERNEL, vmcs_config.order);
+       pages = alloc_pages_exact_node(node, GFP_KERNEL, vmcs_config.order);
        if (!pages)
                return NULL;
        vmcs = page_address(pages);
index fdd30d08ab524a24ca3e2c27a07e1b0b326d88a4..eefdeee8a871175d49a8a7f10bdebd37ed90265c 100644 (file)
@@ -10,6 +10,8 @@ obj-$(CONFIG_X86_PTDUMP)      += dump_pagetables.o
 
 obj-$(CONFIG_HIGHMEM)          += highmem_32.o
 
+obj-$(CONFIG_KMEMCHECK)                += kmemcheck/
+
 obj-$(CONFIG_MMIOTRACE)                += mmiotrace.o
 mmiotrace-y                    := kmmio.o pf_in.o mmio-mod.o
 obj-$(CONFIG_MMIOTRACE_TEST)   += testmmiotrace.o
index c6acc632637417c193394da4881fa19112ace761..baa0e86adfbc65325baa07c60cd31be67ed046cc 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <asm/traps.h>                 /* dotraplinkage, ...           */
 #include <asm/pgalloc.h>               /* pgd_*(), ...                 */
+#include <asm/kmemcheck.h>             /* kmemcheck_*(), ...           */
 
 /*
  * Page fault error code bits:
@@ -956,6 +957,13 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code)
        /* Get the faulting address: */
        address = read_cr2();
 
+       /*
+        * Detect and handle instructions that would cause a page fault for
+        * both a tracked kernel page and a userspace page.
+        */
+       if (kmemcheck_active(regs))
+               kmemcheck_hide(regs);
+
        if (unlikely(kmmio_fault(regs, address)))
                return;
 
@@ -973,9 +981,13 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code)
         * protection error (error_code & 9) == 0.
         */
        if (unlikely(fault_in_kernel_space(address))) {
-               if (!(error_code & (PF_RSVD|PF_USER|PF_PROT)) &&
-                   vmalloc_fault(address) >= 0)
-                       return;
+               if (!(error_code & (PF_RSVD | PF_USER | PF_PROT))) {
+                       if (vmalloc_fault(address) >= 0)
+                               return;
+
+                       if (kmemcheck_fault(regs, address, error_code))
+                               return;
+               }
 
                /* Can handle a stale RO->RW TLB: */
                if (spurious_fault(error_code, address))
index 34c1bfb64f1ca07d80838f363b514caf07acf4db..f53b57e4086fffde114e8c153c67b76a7a857554 100644 (file)
@@ -213,7 +213,7 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
        if (!after_bootmem)
                init_gbpages();
 
-#ifdef CONFIG_DEBUG_PAGEALLOC
+#if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_KMEMCHECK)
        /*
         * For CONFIG_DEBUG_PAGEALLOC, identity mapping will use small pages.
         * This will simplify cpa(), which otherwise needs to support splitting
index 9ff3c0816d158e33c168e4c11a64e511c236705f..3cd7711bb94940d0f19ffb4bac4f4b5f9f6a1a5f 100644 (file)
@@ -111,7 +111,7 @@ static pte_t * __init one_page_table_init(pmd_t *pmd)
                pte_t *page_table = NULL;
 
                if (after_bootmem) {
-#ifdef CONFIG_DEBUG_PAGEALLOC
+#if defined(CONFIG_DEBUG_PAGEALLOC) || defined(CONFIG_KMEMCHECK)
                        page_table = (pte_t *) alloc_bootmem_pages(PAGE_SIZE);
 #endif
                        if (!page_table)
index 52bb9519bb86b4ec778d613939ea658adb1052a6..9c543290a813837f4a5f6140511a305424e480ba 100644 (file)
@@ -104,7 +104,7 @@ static __ref void *spp_getpage(void)
        void *ptr;
 
        if (after_bootmem)
-               ptr = (void *) get_zeroed_page(GFP_ATOMIC);
+               ptr = (void *) get_zeroed_page(GFP_ATOMIC | __GFP_NOTRACK);
        else
                ptr = alloc_bootmem_pages(PAGE_SIZE);
 
@@ -281,7 +281,7 @@ static __ref void *alloc_low_page(unsigned long *phys)
        void *adr;
 
        if (after_bootmem) {
-               adr = (void *)get_zeroed_page(GFP_ATOMIC);
+               adr = (void *)get_zeroed_page(GFP_ATOMIC | __GFP_NOTRACK);
                *phys = __pa(adr);
 
                return adr;
diff --git a/arch/x86/mm/kmemcheck/Makefile b/arch/x86/mm/kmemcheck/Makefile
new file mode 100644 (file)
index 0000000..520b3bc
--- /dev/null
@@ -0,0 +1 @@
+obj-y := error.o kmemcheck.o opcode.o pte.o selftest.o shadow.o
diff --git a/arch/x86/mm/kmemcheck/error.c b/arch/x86/mm/kmemcheck/error.c
new file mode 100644 (file)
index 0000000..4901d0d
--- /dev/null
@@ -0,0 +1,228 @@
+#include <linux/interrupt.h>
+#include <linux/kdebug.h>
+#include <linux/kmemcheck.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/stacktrace.h>
+#include <linux/string.h>
+
+#include "error.h"
+#include "shadow.h"
+
+enum kmemcheck_error_type {
+       KMEMCHECK_ERROR_INVALID_ACCESS,
+       KMEMCHECK_ERROR_BUG,
+};
+
+#define SHADOW_COPY_SIZE (1 << CONFIG_KMEMCHECK_SHADOW_COPY_SHIFT)
+
+struct kmemcheck_error {
+       enum kmemcheck_error_type type;
+
+       union {
+               /* KMEMCHECK_ERROR_INVALID_ACCESS */
+               struct {
+                       /* Kind of access that caused the error */
+                       enum kmemcheck_shadow state;
+                       /* Address and size of the erroneous read */
+                       unsigned long   address;
+                       unsigned int    size;
+               };
+       };
+
+       struct pt_regs          regs;
+       struct stack_trace      trace;
+       unsigned long           trace_entries[32];
+
+       /* We compress it to a char. */
+       unsigned char           shadow_copy[SHADOW_COPY_SIZE];
+       unsigned char           memory_copy[SHADOW_COPY_SIZE];
+};
+
+/*
+ * Create a ring queue of errors to output. We can't call printk() directly
+ * from the kmemcheck traps, since this may call the console drivers and
+ * result in a recursive fault.
+ */
+static struct kmemcheck_error error_fifo[CONFIG_KMEMCHECK_QUEUE_SIZE];
+static unsigned int error_count;
+static unsigned int error_rd;
+static unsigned int error_wr;
+static unsigned int error_missed_count;
+
+static struct kmemcheck_error *error_next_wr(void)
+{
+       struct kmemcheck_error *e;
+
+       if (error_count == ARRAY_SIZE(error_fifo)) {
+               ++error_missed_count;
+               return NULL;
+       }
+
+       e = &error_fifo[error_wr];
+       if (++error_wr == ARRAY_SIZE(error_fifo))
+               error_wr = 0;
+       ++error_count;
+       return e;
+}
+
+static struct kmemcheck_error *error_next_rd(void)
+{
+       struct kmemcheck_error *e;
+
+       if (error_count == 0)
+               return NULL;
+
+       e = &error_fifo[error_rd];
+       if (++error_rd == ARRAY_SIZE(error_fifo))
+               error_rd = 0;
+       --error_count;
+       return e;
+}
+
+void kmemcheck_error_recall(void)
+{
+       static const char *desc[] = {
+               [KMEMCHECK_SHADOW_UNALLOCATED]          = "unallocated",
+               [KMEMCHECK_SHADOW_UNINITIALIZED]        = "uninitialized",
+               [KMEMCHECK_SHADOW_INITIALIZED]          = "initialized",
+               [KMEMCHECK_SHADOW_FREED]                = "freed",
+       };
+
+       static const char short_desc[] = {
+               [KMEMCHECK_SHADOW_UNALLOCATED]          = 'a',
+               [KMEMCHECK_SHADOW_UNINITIALIZED]        = 'u',
+               [KMEMCHECK_SHADOW_INITIALIZED]          = 'i',
+               [KMEMCHECK_SHADOW_FREED]                = 'f',
+       };
+
+       struct kmemcheck_error *e;
+       unsigned int i;
+
+       e = error_next_rd();
+       if (!e)
+               return;
+
+       switch (e->type) {
+       case KMEMCHECK_ERROR_INVALID_ACCESS:
+               printk(KERN_ERR  "WARNING: kmemcheck: Caught %d-bit read "
+                       "from %s memory (%p)\n",
+                       8 * e->size, e->state < ARRAY_SIZE(desc) ?
+                               desc[e->state] : "(invalid shadow state)",
+                       (void *) e->address);
+
+               printk(KERN_INFO);
+               for (i = 0; i < SHADOW_COPY_SIZE; ++i)
+                       printk("%02x", e->memory_copy[i]);
+               printk("\n");
+
+               printk(KERN_INFO);
+               for (i = 0; i < SHADOW_COPY_SIZE; ++i) {
+                       if (e->shadow_copy[i] < ARRAY_SIZE(short_desc))
+                               printk(" %c", short_desc[e->shadow_copy[i]]);
+                       else
+                               printk(" ?");
+               }
+               printk("\n");
+               printk(KERN_INFO "%*c\n", 2 + 2
+                       * (int) (e->address & (SHADOW_COPY_SIZE - 1)), '^');
+               break;
+       case KMEMCHECK_ERROR_BUG:
+               printk(KERN_EMERG "ERROR: kmemcheck: Fatal error\n");
+               break;
+       }
+
+       __show_regs(&e->regs, 1);
+       print_stack_trace(&e->trace, 0);
+}
+
+static void do_wakeup(unsigned long data)
+{
+       while (error_count > 0)
+               kmemcheck_error_recall();
+
+       if (error_missed_count > 0) {
+               printk(KERN_WARNING "kmemcheck: Lost %d error reports because "
+                       "the queue was too small\n", error_missed_count);
+               error_missed_count = 0;
+       }
+}
+
+static DECLARE_TASKLET(kmemcheck_tasklet, &do_wakeup, 0);
+
+/*
+ * Save the context of an error report.
+ */
+void kmemcheck_error_save(enum kmemcheck_shadow state,
+       unsigned long address, unsigned int size, struct pt_regs *regs)
+{
+       static unsigned long prev_ip;
+
+       struct kmemcheck_error *e;
+       void *shadow_copy;
+       void *memory_copy;
+
+       /* Don't report several adjacent errors from the same EIP. */
+       if (regs->ip == prev_ip)
+               return;
+       prev_ip = regs->ip;
+
+       e = error_next_wr();
+       if (!e)
+               return;
+
+       e->type = KMEMCHECK_ERROR_INVALID_ACCESS;
+
+       e->state = state;
+       e->address = address;
+       e->size = size;
+
+       /* Save regs */
+       memcpy(&e->regs, regs, sizeof(*regs));
+
+       /* Save stack trace */
+       e->trace.nr_entries = 0;
+       e->trace.entries = e->trace_entries;
+       e->trace.max_entries = ARRAY_SIZE(e->trace_entries);
+       e->trace.skip = 0;
+       save_stack_trace_bp(&e->trace, regs->bp);
+
+       /* Round address down to nearest 16 bytes */
+       shadow_copy = kmemcheck_shadow_lookup(address
+               & ~(SHADOW_COPY_SIZE - 1));
+       BUG_ON(!shadow_copy);
+
+       memcpy(e->shadow_copy, shadow_copy, SHADOW_COPY_SIZE);
+
+       kmemcheck_show_addr(address);
+       memory_copy = (void *) (address & ~(SHADOW_COPY_SIZE - 1));
+       memcpy(e->memory_copy, memory_copy, SHADOW_COPY_SIZE);
+       kmemcheck_hide_addr(address);
+
+       tasklet_hi_schedule_first(&kmemcheck_tasklet);
+}
+
+/*
+ * Save the context of a kmemcheck bug.
+ */
+void kmemcheck_error_save_bug(struct pt_regs *regs)
+{
+       struct kmemcheck_error *e;
+
+       e = error_next_wr();
+       if (!e)
+               return;
+
+       e->type = KMEMCHECK_ERROR_BUG;
+
+       memcpy(&e->regs, regs, sizeof(*regs));
+
+       e->trace.nr_entries = 0;
+       e->trace.entries = e->trace_entries;
+       e->trace.max_entries = ARRAY_SIZE(e->trace_entries);
+       e->trace.skip = 1;
+       save_stack_trace(&e->trace);
+
+       tasklet_hi_schedule_first(&kmemcheck_tasklet);
+}
diff --git a/arch/x86/mm/kmemcheck/error.h b/arch/x86/mm/kmemcheck/error.h
new file mode 100644 (file)
index 0000000..0efc2e8
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef ARCH__X86__MM__KMEMCHECK__ERROR_H
+#define ARCH__X86__MM__KMEMCHECK__ERROR_H
+
+#include <linux/ptrace.h>
+
+#include "shadow.h"
+
+void kmemcheck_error_save(enum kmemcheck_shadow state,
+       unsigned long address, unsigned int size, struct pt_regs *regs);
+
+void kmemcheck_error_save_bug(struct pt_regs *regs);
+
+void kmemcheck_error_recall(void);
+
+#endif
diff --git a/arch/x86/mm/kmemcheck/kmemcheck.c b/arch/x86/mm/kmemcheck/kmemcheck.c
new file mode 100644 (file)
index 0000000..2c55ed0
--- /dev/null
@@ -0,0 +1,640 @@
+/**
+ * kmemcheck - a heavyweight memory checker for the linux kernel
+ * Copyright (C) 2007, 2008  Vegard Nossum <vegardno@ifi.uio.no>
+ * (With a lot of help from Ingo Molnar and Pekka Enberg.)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License (version 2) as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kallsyms.h>
+#include <linux/kernel.h>
+#include <linux/kmemcheck.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/page-flags.h>
+#include <linux/percpu.h>
+#include <linux/ptrace.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <asm/cacheflush.h>
+#include <asm/kmemcheck.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+
+#include "error.h"
+#include "opcode.h"
+#include "pte.h"
+#include "selftest.h"
+#include "shadow.h"
+
+
+#ifdef CONFIG_KMEMCHECK_DISABLED_BY_DEFAULT
+#  define KMEMCHECK_ENABLED 0
+#endif
+
+#ifdef CONFIG_KMEMCHECK_ENABLED_BY_DEFAULT
+#  define KMEMCHECK_ENABLED 1
+#endif
+
+#ifdef CONFIG_KMEMCHECK_ONESHOT_BY_DEFAULT
+#  define KMEMCHECK_ENABLED 2
+#endif
+
+int kmemcheck_enabled = KMEMCHECK_ENABLED;
+
+int __init kmemcheck_init(void)
+{
+#ifdef CONFIG_SMP
+       /*
+        * Limit SMP to use a single CPU. We rely on the fact that this code
+        * runs before SMP is set up.
+        */
+       if (setup_max_cpus > 1) {
+               printk(KERN_INFO
+                       "kmemcheck: Limiting number of CPUs to 1.\n");
+               setup_max_cpus = 1;
+       }
+#endif
+
+       if (!kmemcheck_selftest()) {
+               printk(KERN_INFO "kmemcheck: self-tests failed; disabling\n");
+               kmemcheck_enabled = 0;
+               return -EINVAL;
+       }
+
+       printk(KERN_INFO "kmemcheck: Initialized\n");
+       return 0;
+}
+
+early_initcall(kmemcheck_init);
+
+/*
+ * We need to parse the kmemcheck= option before any memory is allocated.
+ */
+static int __init param_kmemcheck(char *str)
+{
+       if (!str)
+               return -EINVAL;
+
+       sscanf(str, "%d", &kmemcheck_enabled);
+       return 0;
+}
+
+early_param("kmemcheck", param_kmemcheck);
+
+int kmemcheck_show_addr(unsigned long address)
+{
+       pte_t *pte;
+
+       pte = kmemcheck_pte_lookup(address);
+       if (!pte)
+               return 0;
+
+       set_pte(pte, __pte(pte_val(*pte) | _PAGE_PRESENT));
+       __flush_tlb_one(address);
+       return 1;
+}
+
+int kmemcheck_hide_addr(unsigned long address)
+{
+       pte_t *pte;
+
+       pte = kmemcheck_pte_lookup(address);
+       if (!pte)
+               return 0;
+
+       set_pte(pte, __pte(pte_val(*pte) & ~_PAGE_PRESENT));
+       __flush_tlb_one(address);
+       return 1;
+}
+
+struct kmemcheck_context {
+       bool busy;
+       int balance;
+
+       /*
+        * There can be at most two memory operands to an instruction, but
+        * each address can cross a page boundary -- so we may need up to
+        * four addresses that must be hidden/revealed for each fault.
+        */
+       unsigned long addr[4];
+       unsigned long n_addrs;
+       unsigned long flags;
+
+       /* Data size of the instruction that caused a fault. */
+       unsigned int size;
+};
+
+static DEFINE_PER_CPU(struct kmemcheck_context, kmemcheck_context);
+
+bool kmemcheck_active(struct pt_regs *regs)
+{
+       struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context);
+
+       return data->balance > 0;
+}
+
+/* Save an address that needs to be shown/hidden */
+static void kmemcheck_save_addr(unsigned long addr)
+{
+       struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context);
+
+       BUG_ON(data->n_addrs >= ARRAY_SIZE(data->addr));
+       data->addr[data->n_addrs++] = addr;
+}
+
+static unsigned int kmemcheck_show_all(void)
+{
+       struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context);
+       unsigned int i;
+       unsigned int n;
+
+       n = 0;
+       for (i = 0; i < data->n_addrs; ++i)
+               n += kmemcheck_show_addr(data->addr[i]);
+
+       return n;
+}
+
+static unsigned int kmemcheck_hide_all(void)
+{
+       struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context);
+       unsigned int i;
+       unsigned int n;
+
+       n = 0;
+       for (i = 0; i < data->n_addrs; ++i)
+               n += kmemcheck_hide_addr(data->addr[i]);
+
+       return n;
+}
+
+/*
+ * Called from the #PF handler.
+ */
+void kmemcheck_show(struct pt_regs *regs)
+{
+       struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context);
+
+       BUG_ON(!irqs_disabled());
+
+       if (unlikely(data->balance != 0)) {
+               kmemcheck_show_all();
+               kmemcheck_error_save_bug(regs);
+               data->balance = 0;
+               return;
+       }
+
+       /*
+        * None of the addresses actually belonged to kmemcheck. Note that
+        * this is not an error.
+        */
+       if (kmemcheck_show_all() == 0)
+               return;
+
+       ++data->balance;
+
+       /*
+        * The IF needs to be cleared as well, so that the faulting
+        * instruction can run "uninterrupted". Otherwise, we might take
+        * an interrupt and start executing that before we've had a chance
+        * to hide the page again.
+        *
+        * NOTE: In the rare case of multiple faults, we must not override
+        * the original flags:
+        */
+       if (!(regs->flags & X86_EFLAGS_TF))
+               data->flags = regs->flags;
+
+       regs->flags |= X86_EFLAGS_TF;
+       regs->flags &= ~X86_EFLAGS_IF;
+}
+
+/*
+ * Called from the #DB handler.
+ */
+void kmemcheck_hide(struct pt_regs *regs)
+{
+       struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context);
+       int n;
+
+       BUG_ON(!irqs_disabled());
+
+       if (data->balance == 0)
+               return;
+
+       if (unlikely(data->balance != 1)) {
+               kmemcheck_show_all();
+               kmemcheck_error_save_bug(regs);
+               data->n_addrs = 0;
+               data->balance = 0;
+
+               if (!(data->flags & X86_EFLAGS_TF))
+                       regs->flags &= ~X86_EFLAGS_TF;
+               if (data->flags & X86_EFLAGS_IF)
+                       regs->flags |= X86_EFLAGS_IF;
+               return;
+       }
+
+       if (kmemcheck_enabled)
+               n = kmemcheck_hide_all();
+       else
+               n = kmemcheck_show_all();
+
+       if (n == 0)
+               return;
+
+       --data->balance;
+
+       data->n_addrs = 0;
+
+       if (!(data->flags & X86_EFLAGS_TF))
+               regs->flags &= ~X86_EFLAGS_TF;
+       if (data->flags & X86_EFLAGS_IF)
+               regs->flags |= X86_EFLAGS_IF;
+}
+
+void kmemcheck_show_pages(struct page *p, unsigned int n)
+{
+       unsigned int i;
+
+       for (i = 0; i < n; ++i) {
+               unsigned long address;
+               pte_t *pte;
+               unsigned int level;
+
+               address = (unsigned long) page_address(&p[i]);
+               pte = lookup_address(address, &level);
+               BUG_ON(!pte);
+               BUG_ON(level != PG_LEVEL_4K);
+
+               set_pte(pte, __pte(pte_val(*pte) | _PAGE_PRESENT));
+               set_pte(pte, __pte(pte_val(*pte) & ~_PAGE_HIDDEN));
+               __flush_tlb_one(address);
+       }
+}
+
+bool kmemcheck_page_is_tracked(struct page *p)
+{
+       /* This will also check the "hidden" flag of the PTE. */
+       return kmemcheck_pte_lookup((unsigned long) page_address(p));
+}
+
+void kmemcheck_hide_pages(struct page *p, unsigned int n)
+{
+       unsigned int i;
+
+       for (i = 0; i < n; ++i) {
+               unsigned long address;
+               pte_t *pte;
+               unsigned int level;
+
+               address = (unsigned long) page_address(&p[i]);
+               pte = lookup_address(address, &level);
+               BUG_ON(!pte);
+               BUG_ON(level != PG_LEVEL_4K);
+
+               set_pte(pte, __pte(pte_val(*pte) & ~_PAGE_PRESENT));
+               set_pte(pte, __pte(pte_val(*pte) | _PAGE_HIDDEN));
+               __flush_tlb_one(address);
+       }
+}
+
+/* Access may NOT cross page boundary */
+static void kmemcheck_read_strict(struct pt_regs *regs,
+       unsigned long addr, unsigned int size)
+{
+       void *shadow;
+       enum kmemcheck_shadow status;
+
+       shadow = kmemcheck_shadow_lookup(addr);
+       if (!shadow)
+               return;
+
+       kmemcheck_save_addr(addr);
+       status = kmemcheck_shadow_test(shadow, size);
+       if (status == KMEMCHECK_SHADOW_INITIALIZED)
+               return;
+
+       if (kmemcheck_enabled)
+               kmemcheck_error_save(status, addr, size, regs);
+
+       if (kmemcheck_enabled == 2)
+               kmemcheck_enabled = 0;
+
+       /* Don't warn about it again. */
+       kmemcheck_shadow_set(shadow, size);
+}
+
+/* Access may cross page boundary */
+static void kmemcheck_read(struct pt_regs *regs,
+       unsigned long addr, unsigned int size)
+{
+       unsigned long page = addr & PAGE_MASK;
+       unsigned long next_addr = addr + size - 1;
+       unsigned long next_page = next_addr & PAGE_MASK;
+
+       if (likely(page == next_page)) {
+               kmemcheck_read_strict(regs, addr, size);
+               return;
+       }
+
+       /*
+        * What we do is basically to split the access across the
+        * two pages and handle each part separately. Yes, this means
+        * that we may now see reads that are 3 + 5 bytes, for
+        * example (and if both are uninitialized, there will be two
+        * reports), but it makes the code a lot simpler.
+        */
+       kmemcheck_read_strict(regs, addr, next_page - addr);
+       kmemcheck_read_strict(regs, next_page, next_addr - next_page);
+}
+
+static void kmemcheck_write_strict(struct pt_regs *regs,
+       unsigned long addr, unsigned int size)
+{
+       void *shadow;
+
+       shadow = kmemcheck_shadow_lookup(addr);
+       if (!shadow)
+               return;
+
+       kmemcheck_save_addr(addr);
+       kmemcheck_shadow_set(shadow, size);
+}
+
+static void kmemcheck_write(struct pt_regs *regs,
+       unsigned long addr, unsigned int size)
+{
+       unsigned long page = addr & PAGE_MASK;
+       unsigned long next_addr = addr + size - 1;
+       unsigned long next_page = next_addr & PAGE_MASK;
+
+       if (likely(page == next_page)) {
+               kmemcheck_write_strict(regs, addr, size);
+               return;
+       }
+
+       /* See comment in kmemcheck_read(). */
+       kmemcheck_write_strict(regs, addr, next_page - addr);
+       kmemcheck_write_strict(regs, next_page, next_addr - next_page);
+}
+
+/*
+ * Copying is hard. We have two addresses, each of which may be split across
+ * a page (and each page will have different shadow addresses).
+ */
+static void kmemcheck_copy(struct pt_regs *regs,
+       unsigned long src_addr, unsigned long dst_addr, unsigned int size)
+{
+       uint8_t shadow[8];
+       enum kmemcheck_shadow status;
+
+       unsigned long page;
+       unsigned long next_addr;
+       unsigned long next_page;
+
+       uint8_t *x;
+       unsigned int i;
+       unsigned int n;
+
+       BUG_ON(size > sizeof(shadow));
+
+       page = src_addr & PAGE_MASK;
+       next_addr = src_addr + size - 1;
+       next_page = next_addr & PAGE_MASK;
+
+       if (likely(page == next_page)) {
+               /* Same page */
+               x = kmemcheck_shadow_lookup(src_addr);
+               if (x) {
+                       kmemcheck_save_addr(src_addr);
+                       for (i = 0; i < size; ++i)
+                               shadow[i] = x[i];
+               } else {
+                       for (i = 0; i < size; ++i)
+                               shadow[i] = KMEMCHECK_SHADOW_INITIALIZED;
+               }
+       } else {
+               n = next_page - src_addr;
+               BUG_ON(n > sizeof(shadow));
+
+               /* First page */
+               x = kmemcheck_shadow_lookup(src_addr);
+               if (x) {
+                       kmemcheck_save_addr(src_addr);
+                       for (i = 0; i < n; ++i)
+                               shadow[i] = x[i];
+               } else {
+                       /* Not tracked */
+                       for (i = 0; i < n; ++i)
+                               shadow[i] = KMEMCHECK_SHADOW_INITIALIZED;
+               }
+
+               /* Second page */
+               x = kmemcheck_shadow_lookup(next_page);
+               if (x) {
+                       kmemcheck_save_addr(next_page);
+                       for (i = n; i < size; ++i)
+                               shadow[i] = x[i - n];
+               } else {
+                       /* Not tracked */
+                       for (i = n; i < size; ++i)
+                               shadow[i] = KMEMCHECK_SHADOW_INITIALIZED;
+               }
+       }
+
+       page = dst_addr & PAGE_MASK;
+       next_addr = dst_addr + size - 1;
+       next_page = next_addr & PAGE_MASK;
+
+       if (likely(page == next_page)) {
+               /* Same page */
+               x = kmemcheck_shadow_lookup(dst_addr);
+               if (x) {
+                       kmemcheck_save_addr(dst_addr);
+                       for (i = 0; i < size; ++i) {
+                               x[i] = shadow[i];
+                               shadow[i] = KMEMCHECK_SHADOW_INITIALIZED;
+                       }
+               }
+       } else {
+               n = next_page - dst_addr;
+               BUG_ON(n > sizeof(shadow));
+
+               /* First page */
+               x = kmemcheck_shadow_lookup(dst_addr);
+               if (x) {
+                       kmemcheck_save_addr(dst_addr);
+                       for (i = 0; i < n; ++i) {
+                               x[i] = shadow[i];
+                               shadow[i] = KMEMCHECK_SHADOW_INITIALIZED;
+                       }
+               }
+
+               /* Second page */
+               x = kmemcheck_shadow_lookup(next_page);
+               if (x) {
+                       kmemcheck_save_addr(next_page);
+                       for (i = n; i < size; ++i) {
+                               x[i - n] = shadow[i];
+                               shadow[i] = KMEMCHECK_SHADOW_INITIALIZED;
+                       }
+               }
+       }
+
+       status = kmemcheck_shadow_test(shadow, size);
+       if (status == KMEMCHECK_SHADOW_INITIALIZED)
+               return;
+
+       if (kmemcheck_enabled)
+               kmemcheck_error_save(status, src_addr, size, regs);
+
+       if (kmemcheck_enabled == 2)
+               kmemcheck_enabled = 0;
+}
+
+enum kmemcheck_method {
+       KMEMCHECK_READ,
+       KMEMCHECK_WRITE,
+};
+
+static void kmemcheck_access(struct pt_regs *regs,
+       unsigned long fallback_address, enum kmemcheck_method fallback_method)
+{
+       const uint8_t *insn;
+       const uint8_t *insn_primary;
+       unsigned int size;
+
+       struct kmemcheck_context *data = &__get_cpu_var(kmemcheck_context);
+
+       /* Recursive fault -- ouch. */
+       if (data->busy) {
+               kmemcheck_show_addr(fallback_address);
+               kmemcheck_error_save_bug(regs);
+               return;
+       }
+
+       data->busy = true;
+
+       insn = (const uint8_t *) regs->ip;
+       insn_primary = kmemcheck_opcode_get_primary(insn);
+
+       kmemcheck_opcode_decode(insn, &size);
+
+       switch (insn_primary[0]) {
+#ifdef CONFIG_KMEMCHECK_BITOPS_OK
+               /* AND, OR, XOR */
+               /*
+                * Unfortunately, these instructions have to be excluded from
+                * our regular checking since they access only some (and not
+                * all) bits. This clears out "bogus" bitfield-access warnings.
+                */
+       case 0x80:
+       case 0x81:
+       case 0x82:
+       case 0x83:
+               switch ((insn_primary[1] >> 3) & 7) {
+                       /* OR */
+               case 1:
+                       /* AND */
+               case 4:
+                       /* XOR */
+               case 6:
+                       kmemcheck_write(regs, fallback_address, size);
+                       goto out;
+
+                       /* ADD */
+               case 0:
+                       /* ADC */
+               case 2:
+                       /* SBB */
+               case 3:
+                       /* SUB */
+               case 5:
+                       /* CMP */
+               case 7:
+                       break;
+               }
+               break;
+#endif
+
+               /* MOVS, MOVSB, MOVSW, MOVSD */
+       case 0xa4:
+       case 0xa5:
+               /*
+                * These instructions are special because they take two
+                * addresses, but we only get one page fault.
+                */
+               kmemcheck_copy(regs, regs->si, regs->di, size);
+               goto out;
+
+               /* CMPS, CMPSB, CMPSW, CMPSD */
+       case 0xa6:
+       case 0xa7:
+               kmemcheck_read(regs, regs->si, size);
+               kmemcheck_read(regs, regs->di, size);
+               goto out;
+       }
+
+       /*
+        * If the opcode isn't special in any way, we use the data from the
+        * page fault handler to determine the address and type of memory
+        * access.
+        */
+       switch (fallback_method) {
+       case KMEMCHECK_READ:
+               kmemcheck_read(regs, fallback_address, size);
+               goto out;
+       case KMEMCHECK_WRITE:
+               kmemcheck_write(regs, fallback_address, size);
+               goto out;
+       }
+
+out:
+       data->busy = false;
+}
+
+bool kmemcheck_fault(struct pt_regs *regs, unsigned long address,
+       unsigned long error_code)
+{
+       pte_t *pte;
+
+       /*
+        * XXX: Is it safe to assume that memory accesses from virtual 86
+        * mode or non-kernel code segments will _never_ access kernel
+        * memory (e.g. tracked pages)? For now, we need this to avoid
+        * invoking kmemcheck for PnP BIOS calls.
+        */
+       if (regs->flags & X86_VM_MASK)
+               return false;
+       if (regs->cs != __KERNEL_CS)
+               return false;
+
+       pte = kmemcheck_pte_lookup(address);
+       if (!pte)
+               return false;
+
+       if (error_code & 2)
+               kmemcheck_access(regs, address, KMEMCHECK_WRITE);
+       else
+               kmemcheck_access(regs, address, KMEMCHECK_READ);
+
+       kmemcheck_show(regs);
+       return true;
+}
+
+bool kmemcheck_trap(struct pt_regs *regs)
+{
+       if (!kmemcheck_active(regs))
+               return false;
+
+       /* We're done. */
+       kmemcheck_hide(regs);
+       return true;
+}
diff --git a/arch/x86/mm/kmemcheck/opcode.c b/arch/x86/mm/kmemcheck/opcode.c
new file mode 100644 (file)
index 0000000..63c19e2
--- /dev/null
@@ -0,0 +1,106 @@
+#include <linux/types.h>
+
+#include "opcode.h"
+
+static bool opcode_is_prefix(uint8_t b)
+{
+       return
+               /* Group 1 */
+               b == 0xf0 || b == 0xf2 || b == 0xf3
+               /* Group 2 */
+               || b == 0x2e || b == 0x36 || b == 0x3e || b == 0x26
+               || b == 0x64 || b == 0x65 || b == 0x2e || b == 0x3e
+               /* Group 3 */
+               || b == 0x66
+               /* Group 4 */
+               || b == 0x67;
+}
+
+#ifdef CONFIG_X86_64
+static bool opcode_is_rex_prefix(uint8_t b)
+{
+       return (b & 0xf0) == 0x40;
+}
+#else
+static bool opcode_is_rex_prefix(uint8_t b)
+{
+       return false;
+}
+#endif
+
+#define REX_W (1 << 3)
+
+/*
+ * This is a VERY crude opcode decoder. We only need to find the size of the
+ * load/store that caused our #PF and this should work for all the opcodes
+ * that we care about. Moreover, the ones who invented this instruction set
+ * should be shot.
+ */
+void kmemcheck_opcode_decode(const uint8_t *op, unsigned int *size)
+{
+       /* Default operand size */
+       int operand_size_override = 4;
+
+       /* prefixes */
+       for (; opcode_is_prefix(*op); ++op) {
+               if (*op == 0x66)
+                       operand_size_override = 2;
+       }
+
+       /* REX prefix */
+       if (opcode_is_rex_prefix(*op)) {
+               uint8_t rex = *op;
+
+               ++op;
+               if (rex & REX_W) {
+                       switch (*op) {
+                       case 0x63:
+                               *size = 4;
+                               return;
+                       case 0x0f:
+                               ++op;
+
+                               switch (*op) {
+                               case 0xb6:
+                               case 0xbe:
+                                       *size = 1;
+                                       return;
+                               case 0xb7:
+                               case 0xbf:
+                                       *size = 2;
+                                       return;
+                               }
+
+                               break;
+                       }
+
+                       *size = 8;
+                       return;
+               }
+       }
+
+       /* escape opcode */
+       if (*op == 0x0f) {
+               ++op;
+
+               /*
+                * This is move with zero-extend and sign-extend, respectively;
+                * we don't have to think about 0xb6/0xbe, because this is
+                * already handled in the conditional below.
+                */
+               if (*op == 0xb7 || *op == 0xbf)
+                       operand_size_override = 2;
+       }
+
+       *size = (*op & 1) ? operand_size_override : 1;
+}
+
+const uint8_t *kmemcheck_opcode_get_primary(const uint8_t *op)
+{
+       /* skip prefixes */
+       while (opcode_is_prefix(*op))
+               ++op;
+       if (opcode_is_rex_prefix(*op))
+               ++op;
+       return op;
+}
diff --git a/arch/x86/mm/kmemcheck/opcode.h b/arch/x86/mm/kmemcheck/opcode.h
new file mode 100644 (file)
index 0000000..6956aad
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef ARCH__X86__MM__KMEMCHECK__OPCODE_H
+#define ARCH__X86__MM__KMEMCHECK__OPCODE_H
+
+#include <linux/types.h>
+
+void kmemcheck_opcode_decode(const uint8_t *op, unsigned int *size);
+const uint8_t *kmemcheck_opcode_get_primary(const uint8_t *op);
+
+#endif
diff --git a/arch/x86/mm/kmemcheck/pte.c b/arch/x86/mm/kmemcheck/pte.c
new file mode 100644 (file)
index 0000000..4ead26e
--- /dev/null
@@ -0,0 +1,22 @@
+#include <linux/mm.h>
+
+#include <asm/pgtable.h>
+
+#include "pte.h"
+
+pte_t *kmemcheck_pte_lookup(unsigned long address)
+{
+       pte_t *pte;
+       unsigned int level;
+
+       pte = lookup_address(address, &level);
+       if (!pte)
+               return NULL;
+       if (level != PG_LEVEL_4K)
+               return NULL;
+       if (!pte_hidden(*pte))
+               return NULL;
+
+       return pte;
+}
+
diff --git a/arch/x86/mm/kmemcheck/pte.h b/arch/x86/mm/kmemcheck/pte.h
new file mode 100644 (file)
index 0000000..9f59664
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef ARCH__X86__MM__KMEMCHECK__PTE_H
+#define ARCH__X86__MM__KMEMCHECK__PTE_H
+
+#include <linux/mm.h>
+
+#include <asm/pgtable.h>
+
+pte_t *kmemcheck_pte_lookup(unsigned long address);
+
+#endif
diff --git a/arch/x86/mm/kmemcheck/selftest.c b/arch/x86/mm/kmemcheck/selftest.c
new file mode 100644 (file)
index 0000000..036efbe
--- /dev/null
@@ -0,0 +1,69 @@
+#include <linux/kernel.h>
+
+#include "opcode.h"
+#include "selftest.h"
+
+struct selftest_opcode {
+       unsigned int expected_size;
+       const uint8_t *insn;
+       const char *desc;
+};
+
+static const struct selftest_opcode selftest_opcodes[] = {
+       /* REP MOVS */
+       {1, "\xf3\xa4",                 "rep movsb <mem8>, <mem8>"},
+       {4, "\xf3\xa5",                 "rep movsl <mem32>, <mem32>"},
+
+       /* MOVZX / MOVZXD */
+       {1, "\x66\x0f\xb6\x51\xf8",     "movzwq <mem8>, <reg16>"},
+       {1, "\x0f\xb6\x51\xf8",         "movzwq <mem8>, <reg32>"},
+
+       /* MOVSX / MOVSXD */
+       {1, "\x66\x0f\xbe\x51\xf8",     "movswq <mem8>, <reg16>"},
+       {1, "\x0f\xbe\x51\xf8",         "movswq <mem8>, <reg32>"},
+
+#ifdef CONFIG_X86_64
+       /* MOVZX / MOVZXD */
+       {1, "\x49\x0f\xb6\x51\xf8",     "movzbq <mem8>, <reg64>"},
+       {2, "\x49\x0f\xb7\x51\xf8",     "movzbq <mem16>, <reg64>"},
+
+       /* MOVSX / MOVSXD */
+       {1, "\x49\x0f\xbe\x51\xf8",     "movsbq <mem8>, <reg64>"},
+       {2, "\x49\x0f\xbf\x51\xf8",     "movsbq <mem16>, <reg64>"},
+       {4, "\x49\x63\x51\xf8",         "movslq <mem32>, <reg64>"},
+#endif
+};
+
+static bool selftest_opcode_one(const struct selftest_opcode *op)
+{
+       unsigned size;
+
+       kmemcheck_opcode_decode(op->insn, &size);
+
+       if (size == op->expected_size)
+               return true;
+
+       printk(KERN_WARNING "kmemcheck: opcode %s: expected size %d, got %d\n",
+               op->desc, op->expected_size, size);
+       return false;
+}
+
+static bool selftest_opcodes_all(void)
+{
+       bool pass = true;
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(selftest_opcodes); ++i)
+               pass = pass && selftest_opcode_one(&selftest_opcodes[i]);
+
+       return pass;
+}
+
+bool kmemcheck_selftest(void)
+{
+       bool pass = true;
+
+       pass = pass && selftest_opcodes_all();
+
+       return pass;
+}
diff --git a/arch/x86/mm/kmemcheck/selftest.h b/arch/x86/mm/kmemcheck/selftest.h
new file mode 100644 (file)
index 0000000..8fed4fe
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef ARCH_X86_MM_KMEMCHECK_SELFTEST_H
+#define ARCH_X86_MM_KMEMCHECK_SELFTEST_H
+
+bool kmemcheck_selftest(void);
+
+#endif
diff --git a/arch/x86/mm/kmemcheck/shadow.c b/arch/x86/mm/kmemcheck/shadow.c
new file mode 100644 (file)
index 0000000..e773b6b
--- /dev/null
@@ -0,0 +1,162 @@
+#include <linux/kmemcheck.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#include "pte.h"
+#include "shadow.h"
+
+/*
+ * Return the shadow address for the given address. Returns NULL if the
+ * address is not tracked.
+ *
+ * We need to be extremely careful not to follow any invalid pointers,
+ * because this function can be called for *any* possible address.
+ */
+void *kmemcheck_shadow_lookup(unsigned long address)
+{
+       pte_t *pte;
+       struct page *page;
+
+       if (!virt_addr_valid(address))
+               return NULL;
+
+       pte = kmemcheck_pte_lookup(address);
+       if (!pte)
+               return NULL;
+
+       page = virt_to_page(address);
+       if (!page->shadow)
+               return NULL;
+       return page->shadow + (address & (PAGE_SIZE - 1));
+}
+
+static void mark_shadow(void *address, unsigned int n,
+       enum kmemcheck_shadow status)
+{
+       unsigned long addr = (unsigned long) address;
+       unsigned long last_addr = addr + n - 1;
+       unsigned long page = addr & PAGE_MASK;
+       unsigned long last_page = last_addr & PAGE_MASK;
+       unsigned int first_n;
+       void *shadow;
+
+       /* If the memory range crosses a page boundary, stop there. */
+       if (page == last_page)
+               first_n = n;
+       else
+               first_n = page + PAGE_SIZE - addr;
+
+       shadow = kmemcheck_shadow_lookup(addr);
+       if (shadow)
+               memset(shadow, status, first_n);
+
+       addr += first_n;
+       n -= first_n;
+
+       /* Do full-page memset()s. */
+       while (n >= PAGE_SIZE) {
+               shadow = kmemcheck_shadow_lookup(addr);
+               if (shadow)
+                       memset(shadow, status, PAGE_SIZE);
+
+               addr += PAGE_SIZE;
+               n -= PAGE_SIZE;
+       }
+
+       /* Do the remaining page, if any. */
+       if (n > 0) {
+               shadow = kmemcheck_shadow_lookup(addr);
+               if (shadow)
+                       memset(shadow, status, n);
+       }
+}
+
+void kmemcheck_mark_unallocated(void *address, unsigned int n)
+{
+       mark_shadow(address, n, KMEMCHECK_SHADOW_UNALLOCATED);
+}
+
+void kmemcheck_mark_uninitialized(void *address, unsigned int n)
+{
+       mark_shadow(address, n, KMEMCHECK_SHADOW_UNINITIALIZED);
+}
+
+/*
+ * Fill the shadow memory of the given address such that the memory at that
+ * address is marked as being initialized.
+ */
+void kmemcheck_mark_initialized(void *address, unsigned int n)
+{
+       mark_shadow(address, n, KMEMCHECK_SHADOW_INITIALIZED);
+}
+EXPORT_SYMBOL_GPL(kmemcheck_mark_initialized);
+
+void kmemcheck_mark_freed(void *address, unsigned int n)
+{
+       mark_shadow(address, n, KMEMCHECK_SHADOW_FREED);
+}
+
+void kmemcheck_mark_unallocated_pages(struct page *p, unsigned int n)
+{
+       unsigned int i;
+
+       for (i = 0; i < n; ++i)
+               kmemcheck_mark_unallocated(page_address(&p[i]), PAGE_SIZE);
+}
+
+void kmemcheck_mark_uninitialized_pages(struct page *p, unsigned int n)
+{
+       unsigned int i;
+
+       for (i = 0; i < n; ++i)
+               kmemcheck_mark_uninitialized(page_address(&p[i]), PAGE_SIZE);
+}
+
+void kmemcheck_mark_initialized_pages(struct page *p, unsigned int n)
+{
+       unsigned int i;
+
+       for (i = 0; i < n; ++i)
+               kmemcheck_mark_initialized(page_address(&p[i]), PAGE_SIZE);
+}
+
+enum kmemcheck_shadow kmemcheck_shadow_test(void *shadow, unsigned int size)
+{
+       uint8_t *x;
+       unsigned int i;
+
+       x = shadow;
+
+#ifdef CONFIG_KMEMCHECK_PARTIAL_OK
+       /*
+        * Make sure _some_ bytes are initialized. Gcc frequently generates
+        * code to access neighboring bytes.
+        */
+       for (i = 0; i < size; ++i) {
+               if (x[i] == KMEMCHECK_SHADOW_INITIALIZED)
+                       return x[i];
+       }
+#else
+       /* All bytes must be initialized. */
+       for (i = 0; i < size; ++i) {
+               if (x[i] != KMEMCHECK_SHADOW_INITIALIZED)
+                       return x[i];
+       }
+#endif
+
+       return x[0];
+}
+
+void kmemcheck_shadow_set(void *shadow, unsigned int size)
+{
+       uint8_t *x;
+       unsigned int i;
+
+       x = shadow;
+       for (i = 0; i < size; ++i)
+               x[i] = KMEMCHECK_SHADOW_INITIALIZED;
+}
diff --git a/arch/x86/mm/kmemcheck/shadow.h b/arch/x86/mm/kmemcheck/shadow.h
new file mode 100644 (file)
index 0000000..af46d9a
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef ARCH__X86__MM__KMEMCHECK__SHADOW_H
+#define ARCH__X86__MM__KMEMCHECK__SHADOW_H
+
+enum kmemcheck_shadow {
+       KMEMCHECK_SHADOW_UNALLOCATED,
+       KMEMCHECK_SHADOW_UNINITIALIZED,
+       KMEMCHECK_SHADOW_INITIALIZED,
+       KMEMCHECK_SHADOW_FREED,
+};
+
+void *kmemcheck_shadow_lookup(unsigned long address);
+
+enum kmemcheck_shadow kmemcheck_shadow_test(void *shadow, unsigned int size);
+void kmemcheck_shadow_set(void *shadow, unsigned int size);
+
+#endif
index 6ce9518fe2acb6457db7d6c19c1739e6f48f2c9b..3cfe9ced8a4c6e500b6df519dceadc7534a5730a 100644 (file)
@@ -470,7 +470,7 @@ static int split_large_page(pte_t *kpte, unsigned long address)
 
        if (!debug_pagealloc)
                spin_unlock(&cpa_lock);
-       base = alloc_pages(GFP_KERNEL, 0);
+       base = alloc_pages(GFP_KERNEL | __GFP_NOTRACK, 0);
        if (!debug_pagealloc)
                spin_lock(&cpa_lock);
        if (!base)
index 7aa03a5389f53ea635b9d553fac783e879c14535..8e43bdd45456017cd431c2cf9b4678c5b7e9f65d 100644 (file)
@@ -4,9 +4,11 @@
 #include <asm/tlb.h>
 #include <asm/fixmap.h>
 
+#define PGALLOC_GFP GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO
+
 pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
 {
-       return (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO);
+       return (pte_t *)__get_free_page(PGALLOC_GFP);
 }
 
 pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address)
@@ -14,9 +16,9 @@ pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address)
        struct page *pte;
 
 #ifdef CONFIG_HIGHPTE
-       pte = alloc_pages(GFP_KERNEL|__GFP_HIGHMEM|__GFP_REPEAT|__GFP_ZERO, 0);
+       pte = alloc_pages(PGALLOC_GFP | __GFP_HIGHMEM, 0);
 #else
-       pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, 0);
+       pte = alloc_pages(PGALLOC_GFP, 0);
 #endif
        if (pte)
                pgtable_page_ctor(pte);
@@ -161,7 +163,7 @@ static int preallocate_pmds(pmd_t *pmds[])
        bool failed = false;
 
        for(i = 0; i < PREALLOCATED_PMDS; i++) {
-               pmd_t *pmd = (pmd_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
+               pmd_t *pmd = (pmd_t *)__get_free_page(PGALLOC_GFP);
                if (pmd == NULL)
                        failed = true;
                pmds[i] = pmd;
@@ -228,7 +230,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
        pmd_t *pmds[PREALLOCATED_PMDS];
        unsigned long flags;
 
-       pgd = (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
+       pgd = (pgd_t *)__get_free_page(PGALLOC_GFP);
 
        if (pgd == NULL)
                goto out;
index 9e822d2e3bcecf69871eb65acdf81655c02e1124..11c687e527f101137188089b30b762b5c93f55e4 100644 (file)
@@ -1,31 +1,6 @@
-/*
- * include/asm-xtensa/kmap_types.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_KMAP_TYPES_H
 #define _XTENSA_KMAP_TYPES_H
 
-enum km_type {
-  KM_BOUNCE_READ,
-  KM_SKB_SUNRPC_DATA,
-  KM_SKB_DATA_SOFTIRQ,
-  KM_USER0,
-  KM_USER1,
-  KM_BIO_SRC_IRQ,
-  KM_BIO_DST_IRQ,
-  KM_PTE0,
-  KM_PTE1,
-  KM_IRQ0,
-  KM_IRQ1,
-  KM_SOFTIRQ0,
-  KM_SOFTIRQ1,
-  KM_TYPE_NR
-};
+#include <asm-generic/kmap_types.h>
 
 #endif /* _XTENSA_KMAP_TYPES_H */
index e07f5c9fcd3500727efdd0a734b4cfcf654412fc..c4302f0e4ba08a66b39023d13986dda288a4f487 100644 (file)
 
 static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
 static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-struct mm_struct init_mm = INIT_MM(init_mm);
-
-EXPORT_SYMBOL(init_mm);
-
 union thread_union init_thread_union
        __attribute__((__section__(".data.init_task"))) =
 { INIT_THREAD_INFO(init_task) };
index f6452f692501a00f13684a73fd74248e878d79cd..b06cf5c2a829c49a17dc4a23ab4421d8933b3401 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/swap.h>
 #include <linux/writeback.h>
 #include <linux/task_io_accounting_ops.h>
-#include <linux/blktrace_api.h>
 #include <linux/fault-inject.h>
 
 #define CREATE_TRACE_POINTS
@@ -498,6 +497,11 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
 
        q->backing_dev_info.unplug_io_fn = blk_backing_dev_unplug;
        q->backing_dev_info.unplug_io_data = q;
+       q->backing_dev_info.ra_pages =
+                       (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
+       q->backing_dev_info.state = 0;
+       q->backing_dev_info.capabilities = BDI_CAP_MAP_COPY;
+
        err = bdi_init(&q->backing_dev_info);
        if (err) {
                kmem_cache_free(blk_requestq_cachep, q);
index d71cedc09c4e237f05f99753ffe0f1f4cb5557f5..7541ea4bf9fe8bf62c5f85cc1b17b60d08e9a19a 100644 (file)
@@ -95,6 +95,31 @@ void blk_queue_lld_busy(struct request_queue *q, lld_busy_fn *fn)
 }
 EXPORT_SYMBOL_GPL(blk_queue_lld_busy);
 
+/**
+ * blk_set_default_limits - reset limits to default values
+ * @limits:  the queue_limits structure to reset
+ *
+ * Description:
+ *   Returns a queue_limit struct to its default state.  Can be used by
+ *   stacking drivers like DM that stage table swaps and reuse an
+ *   existing device queue.
+ */
+void blk_set_default_limits(struct queue_limits *lim)
+{
+       lim->max_phys_segments = MAX_PHYS_SEGMENTS;
+       lim->max_hw_segments = MAX_HW_SEGMENTS;
+       lim->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK;
+       lim->max_segment_size = MAX_SEGMENT_SIZE;
+       lim->max_sectors = lim->max_hw_sectors = SAFE_MAX_SECTORS;
+       lim->logical_block_size = lim->physical_block_size = lim->io_min = 512;
+       lim->bounce_pfn = BLK_BOUNCE_ANY;
+       lim->alignment_offset = 0;
+       lim->io_opt = 0;
+       lim->misaligned = 0;
+       lim->no_cluster = 0;
+}
+EXPORT_SYMBOL(blk_set_default_limits);
+
 /**
  * blk_queue_make_request - define an alternate make_request function for a device
  * @q:  the request queue for the device to be affected
@@ -123,18 +148,8 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
         * set defaults
         */
        q->nr_requests = BLKDEV_MAX_RQ;
-       blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS);
-       blk_queue_max_hw_segments(q, MAX_HW_SEGMENTS);
-       blk_queue_segment_boundary(q, BLK_SEG_BOUNDARY_MASK);
-       blk_queue_max_segment_size(q, MAX_SEGMENT_SIZE);
 
        q->make_request_fn = mfn;
-       q->backing_dev_info.ra_pages =
-                       (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
-       q->backing_dev_info.state = 0;
-       q->backing_dev_info.capabilities = BDI_CAP_MAP_COPY;
-       blk_queue_max_sectors(q, SAFE_MAX_SECTORS);
-       blk_queue_logical_block_size(q, 512);
        blk_queue_dma_alignment(q, 511);
        blk_queue_congestion_threshold(q);
        q->nr_batching = BLK_BATCH_REQ;
@@ -147,6 +162,8 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
        q->unplug_timer.function = blk_unplug_timeout;
        q->unplug_timer.data = (unsigned long)q;
 
+       blk_set_default_limits(&q->limits);
+
        /*
         * by default assume old behaviour and bounce for any highmem page
         */
index 5358f9ae13c1797b7eda131c7033c73a0c525162..54106f052f707bde6c4b89530d53a585c06366ce 100644 (file)
@@ -1065,6 +1065,11 @@ EXPORT_SYMBOL_GPL(bsg_register_queue);
 
 static struct cdev bsg_cdev;
 
+static char *bsg_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "bsg/%s", dev_name(dev));
+}
+
 static int __init bsg_init(void)
 {
        int ret, i;
@@ -1085,6 +1090,7 @@ static int __init bsg_init(void)
                ret = PTR_ERR(bsg_class);
                goto destroy_kmemcache;
        }
+       bsg_class->nodename = bsg_nodename;
 
        ret = alloc_chrdev_region(&devid, 0, BSG_MAX_DEVS, "bsg");
        if (ret)
index ef2f72d4243407ccfec220c867028f28b013b751..833ec18eaa63e2a20b847797c99511e41314b474 100644 (file)
@@ -122,7 +122,6 @@ struct cfq_data {
        struct cfq_queue *async_idle_cfqq;
 
        sector_t last_position;
-       unsigned long last_end_request;
 
        /*
         * tunables, see top of file
@@ -1253,7 +1252,7 @@ static int cfq_forced_dispatch(struct cfq_data *cfqd)
 
        BUG_ON(cfqd->busy_queues);
 
-       cfq_log(cfqd, "forced_dispatch=%d\n", dispatched);
+       cfq_log(cfqd, "forced_dispatch=%d", dispatched);
        return dispatched;
 }
 
@@ -2164,9 +2163,6 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
        if (cfq_cfqq_sync(cfqq))
                cfqd->sync_flight--;
 
-       if (!cfq_class_idle(cfqq))
-               cfqd->last_end_request = now;
-
        if (sync)
                RQ_CIC(rq)->last_end_request = now;
 
@@ -2479,7 +2475,6 @@ static void *cfq_init_queue(struct request_queue *q)
 
        INIT_WORK(&cfqd->unplug_work, cfq_kick_queue);
 
-       cfqd->last_end_request = jiffies;
        cfqd->cfq_quantum = cfq_quantum;
        cfqd->cfq_fifo_expire[0] = cfq_fifo_expire[0];
        cfqd->cfq_fifo_expire[1] = cfq_fifo_expire[1];
index fe7ccc0a618f35e21ed7fbbe19ae49665270d498..f4c64c2b303a33e2f46bd10b01d36c2cd931b4d6 100644 (file)
@@ -996,10 +996,20 @@ struct class block_class = {
        .name           = "block",
 };
 
+static char *block_nodename(struct device *dev)
+{
+       struct gendisk *disk = dev_to_disk(dev);
+
+       if (disk->nodename)
+               return disk->nodename(disk);
+       return NULL;
+}
+
 static struct device_type disk_type = {
        .name           = "disk",
        .groups         = disk_attr_groups,
        .release        = disk_release,
+       .nodename       = block_nodename,
 };
 
 #ifdef CONFIG_PROC_FS
index 996b6ee57d9e3fb3ff48251ea9ee01d405b648ad..fc5b836f343084f74b76f516133adbe455e04ab7 100644 (file)
@@ -101,7 +101,12 @@ calibrate_xor_blocks(void)
        void *b1, *b2;
        struct xor_block_template *f, *fastest;
 
-       b1 = (void *) __get_free_pages(GFP_KERNEL, 2);
+       /*
+        * Note: Since the memory is not actually used for _anything_ but to
+        * test the XOR speed, we don't really want kmemcheck to warn about
+        * reading uninitialized bytes here.
+        */
+       b1 = (void *) __get_free_pages(GFP_KERNEL | __GFP_NOTRACK, 2);
        if (!b1) {
                printk(KERN_WARNING "xor: Yikes!  No memory available.\n");
                return -ENOMEM;
index 00cf9553f74065291612b0971337f79995933a06..a442c8f29fc1e697d71394fed73bb1d81db0150d 100644 (file)
@@ -104,6 +104,8 @@ source "drivers/auxdisplay/Kconfig"
 
 source "drivers/uio/Kconfig"
 
+source "drivers/vlynq/Kconfig"
+
 source "drivers/xen/Kconfig"
 
 source "drivers/staging/Kconfig"
index 9e7d4e56c85ba2747a0463daefef1aa7fef1ac40..00b44f4ccf03836eca44bbcad29d9cd9546f6ffb 100644 (file)
@@ -105,6 +105,7 @@ obj-$(CONFIG_PPC_PS3)               += ps3/
 obj-$(CONFIG_OF)               += of/
 obj-$(CONFIG_SSB)              += ssb/
 obj-$(CONFIG_VIRTIO)           += virtio/
+obj-$(CONFIG_VLYNQ)            += vlynq/
 obj-$(CONFIG_STAGING)          += staging/
 obj-y                          += platform/
 obj-y                          += ieee802154/
index 07e20135f01b30873d1f4aca495d7278a81962cd..0bba148a2c61fc084d52a58df1b1498b20ef6034 100644 (file)
@@ -139,7 +139,7 @@ acpi_status acpi_ev_initialize_op_regions(void);
 acpi_status
 acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
                               u32 function,
-                              acpi_physical_address address,
+                              u32 region_offset,
                               u32 bit_width, acpi_integer * value);
 
 acpi_status
index 16e5210ae936288c17a76b0c7f82e93873b658fa..3d87362d17ed163851c3f5790fb4ecc4976e5c30 100644 (file)
@@ -362,9 +362,6 @@ extern u8 acpi_gbl_method_executing;
 extern u8 acpi_gbl_abort_method;
 extern u8 acpi_gbl_db_terminate_threads;
 
-ACPI_EXTERN int optind;
-ACPI_EXTERN char *optarg;
-
 ACPI_EXTERN u8 acpi_gbl_db_opt_tables;
 ACPI_EXTERN u8 acpi_gbl_db_opt_stats;
 ACPI_EXTERN u8 acpi_gbl_db_opt_ini_methods;
index 2ec394a328e95fea0f15d2e94aef9c32fda507dd..ee986edfa0da32704133b949624aa6ff75f3bea2 100644 (file)
@@ -205,6 +205,7 @@ struct acpi_namespace_node {
 #define ANOBJ_METHOD_LOCAL              0x08   /* Node is a method local */
 #define ANOBJ_SUBTREE_HAS_INI           0x10   /* Used to optimize device initialization */
 #define ANOBJ_EVALUATED                 0x20   /* Set on first evaluation of node */
+#define ANOBJ_ALLOCATED_BUFFER          0x40   /* Method AML buffer is dynamic (install_method) */
 
 #define ANOBJ_IS_EXTERNAL               0x08   /* i_aSL only: This object created via External() */
 #define ANOBJ_METHOD_NO_RETVAL          0x10   /* i_aSL only: Method has no return value */
@@ -788,11 +789,14 @@ struct acpi_bit_register_info {
 /* For control registers, both ignored and reserved bits must be preserved */
 
 /*
- * The ACPI spec says to ignore PM1_CTL.SCI_EN (bit 0)
- * but we need to be able to write ACPI_BITREG_SCI_ENABLE directly
- * as a BIOS workaround on some machines.
+ * For PM1 control, the SCI enable bit (bit 0, SCI_EN) is defined by the
+ * ACPI specification to be a "preserved" bit - "OSPM always preserves this
+ * bit position", section 4.7.3.2.1. However, on some machines the OS must
+ * write a one to this bit after resume for the machine to work properly.
+ * To enable this, we no longer attempt to preserve this bit. No machines
+ * are known to fail if the bit is not preserved. (May 2009)
  */
-#define ACPI_PM1_CONTROL_IGNORED_BITS           0x0200 /* Bits 9 */
+#define ACPI_PM1_CONTROL_IGNORED_BITS           0x0200 /* Bit 9 */
 #define ACPI_PM1_CONTROL_RESERVED_BITS          0xC1F8 /* Bits 14-15, 3-8 */
 #define ACPI_PM1_CONTROL_PRESERVED_BITS \
               (ACPI_PM1_CONTROL_IGNORED_BITS | ACPI_PM1_CONTROL_RESERVED_BITS)
index 46cb5b46d2803fd43bf7691bf0ee065fcf039dfc..94cdc2b8cb9385d6814005933810afd6d81e8d72 100644 (file)
@@ -99,10 +99,19 @@ acpi_ns_walk_namespace(acpi_object_type type,
                       acpi_walk_callback user_function,
                       void *context, void **return_value);
 
-struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct acpi_namespace_node
-                                                 *parent, struct acpi_namespace_node
+struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node
+                                                 *parent,
+                                                 struct acpi_namespace_node
                                                  *child);
 
+struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type,
+                                                       struct
+                                                       acpi_namespace_node
+                                                       *parent,
+                                                       struct
+                                                       acpi_namespace_node
+                                                       *child);
+
 /*
  * nsparse - table parsing
  */
index ff851c5df698a465a3c5e3d730b0a00d7d14ea07..067f967eb389cf720b2ee7d9a25b840ca3477443 100644 (file)
@@ -483,7 +483,7 @@ typedef enum {
 
 #define AML_METHOD_ARG_COUNT        0x07
 #define AML_METHOD_SERIALIZED       0x08
-#define AML_METHOD_SYNCH_LEVEL      0xF0
+#define AML_METHOD_SYNC_LEVEL       0xF0
 
 /* METHOD_FLAGS_ARG_COUNT is not used internally, define additional flags */
 
index dab3f48f0b42938066b145c58a7b1c231139944d..02e6caad4a7610718bb4d52df924a86ef5bf10e4 100644 (file)
@@ -734,7 +734,8 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
 
                        /* Local ID (0-7) is (AML opcode - base AML_LOCAL_OP) */
 
-                       obj_desc->reference.value = opcode - AML_LOCAL_OP;
+                       obj_desc->reference.value =
+                           ((u32)opcode) - AML_LOCAL_OP;
                        obj_desc->reference.class = ACPI_REFCLASS_LOCAL;
 
 #ifndef ACPI_NO_METHOD_EXECUTION
@@ -754,7 +755,7 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
 
                        /* Arg ID (0-6) is (AML opcode - base AML_ARG_OP) */
 
-                       obj_desc->reference.value = opcode - AML_ARG_OP;
+                       obj_desc->reference.value = ((u32)opcode) - AML_ARG_OP;
                        obj_desc->reference.class = ACPI_REFCLASS_ARG;
 
 #ifndef ACPI_NO_METHOD_EXECUTION
index b4c87b5053e6d1c6daeff5d68013672466061378..584d766e6f124248c1b496731df225fd94fa0099 100644 (file)
@@ -1386,14 +1386,19 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state,
 
        case AML_BREAK_POINT_OP:
 
-               /* Call up to the OS service layer to handle this */
-
-               status =
-                   acpi_os_signal(ACPI_SIGNAL_BREAKPOINT,
-                                  "Executed AML Breakpoint opcode");
+               /*
+                * Set the single-step flag. This will cause the debugger (if present)
+                * to break to the console within the AML debugger at the start of the
+                * next AML instruction.
+                */
+               ACPI_DEBUGGER_EXEC(acpi_gbl_cm_single_step = TRUE);
+               ACPI_DEBUGGER_EXEC(acpi_os_printf
+                                  ("**break** Executed AML BreakPoint opcode\n"));
 
-               /* If and when it returns, all done. */
+               /* Call to the OSL in case OS wants a piece of the action */
 
+               status = acpi_os_signal(ACPI_SIGNAL_BREAKPOINT,
+                                       "Executed AML Breakpoint opcode");
                break;
 
        case AML_BREAK_OP:
index 40f92bf7dce5cc2e7bf33cd5fd83013d544d4328..e46c821cf57295b7064bd58a333d1692e373451e 100644 (file)
@@ -102,7 +102,7 @@ acpi_ds_result_pop(union acpi_operand_object **object,
        /* Return object of the top element and clean that top element result stack */
 
        walk_state->result_count--;
-       index = walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM;
+       index = (u32)walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM;
 
        *object = state->results.obj_desc[index];
        if (!*object) {
@@ -186,7 +186,7 @@ acpi_ds_result_push(union acpi_operand_object * object,
 
        /* Assign the address of object to the top free element of result stack */
 
-       index = walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM;
+       index = (u32)walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM;
        state->results.obj_desc[index] = object;
        walk_state->result_count++;
 
index 538d63264555b321d473ef95942f8602d9fe4a51..98c7f9c626531f00e2bb9933c02ff61c8c0d42df 100644 (file)
@@ -275,7 +275,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
  *
  * PARAMETERS:  region_obj          - Internal region object
  *              Function            - Read or Write operation
- *              Address             - Where in the space to read or write
+ *              region_offset       - Where in the region to read or write
  *              bit_width           - Field width in bits (8, 16, 32, or 64)
  *              Value               - Pointer to in or out value, must be
  *                                    full 64-bit acpi_integer
@@ -290,7 +290,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
 acpi_status
 acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
                               u32 function,
-                              acpi_physical_address address,
+                              u32 region_offset,
                               u32 bit_width, acpi_integer * value)
 {
        acpi_status status;
@@ -396,7 +396,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
        ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
                          "Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
                          &region_obj->region.handler->address_space, handler,
-                         ACPI_FORMAT_NATIVE_UINT(address),
+                         ACPI_FORMAT_NATIVE_UINT(region_obj->region.address +
+                                                 region_offset),
                          acpi_ut_get_region_name(region_obj->region.
                                                  space_id)));
 
@@ -412,8 +413,9 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
 
        /* Call the handler */
 
-       status = handler(function, address, bit_width, value,
-                        handler_desc->address_space.context,
+       status = handler(function,
+                        (region_obj->region.address + region_offset),
+                        bit_width, value, handler_desc->address_space.context,
                         region_obj2->extra.region_context);
 
        if (ACPI_FAILURE(status)) {
index d0a080747ec35cf6c2754ca3c534cb618401800c..4721f58fe42c0653d6a6c14aee384ffbab2e708a 100644 (file)
@@ -51,7 +51,7 @@
 ACPI_MODULE_NAME("evxfevnt")
 
 /* Local prototypes */
-acpi_status
+static acpi_status
 acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
                       struct acpi_gpe_block_info *gpe_block, void *context);
 
@@ -785,7 +785,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_gpe_device)
  *              block device. NULL if the GPE is one of the FADT-defined GPEs.
  *
  ******************************************************************************/
-acpi_status
+static acpi_status
 acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
                       struct acpi_gpe_block_info *gpe_block, void *context)
 {
index 3deb20a126b215d706b162ea761fa8eb3ead0344..277fd609611aec1a92eb5717c21724425ce4f61a 100644 (file)
@@ -47,6 +47,7 @@
 #include "acnamesp.h"
 #include "actables.h"
 #include "acdispat.h"
+#include "acevents.h"
 
 #define _COMPONENT          ACPI_EXECUTER
 ACPI_MODULE_NAME("exconfig")
@@ -57,6 +58,10 @@ acpi_ex_add_table(u32 table_index,
                  struct acpi_namespace_node *parent_node,
                  union acpi_operand_object **ddb_handle);
 
+static acpi_status
+acpi_ex_region_read(union acpi_operand_object *obj_desc,
+                   u32 length, u8 *buffer);
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ex_add_table
@@ -91,6 +96,7 @@ acpi_ex_add_table(u32 table_index,
 
        /* Init the table handle */
 
+       obj_desc->common.flags |= AOPOBJ_DATA_VALID;
        obj_desc->reference.class = ACPI_REFCLASS_TABLE;
        *ddb_handle = obj_desc;
 
@@ -229,6 +235,8 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
                                       walk_state);
                if (ACPI_FAILURE(status)) {
                        (void)acpi_ex_unload_table(ddb_handle);
+
+                       acpi_ut_remove_reference(ddb_handle);
                        return_ACPI_STATUS(status);
                }
        }
@@ -252,6 +260,47 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
        return_ACPI_STATUS(status);
 }
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ex_region_read
+ *
+ * PARAMETERS:  obj_desc        - Region descriptor
+ *              Length          - Number of bytes to read
+ *              Buffer          - Pointer to where to put the data
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Read data from an operation region. The read starts from the
+ *              beginning of the region.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ex_region_read(union acpi_operand_object *obj_desc, u32 length, u8 *buffer)
+{
+       acpi_status status;
+       acpi_integer value;
+       u32 region_offset = 0;
+       u32 i;
+
+       /* Bytewise reads */
+
+       for (i = 0; i < length; i++) {
+               status = acpi_ev_address_space_dispatch(obj_desc, ACPI_READ,
+                                                       region_offset, 8,
+                                                       &value);
+               if (ACPI_FAILURE(status)) {
+                       return status;
+               }
+
+               *buffer = (u8)value;
+               buffer++;
+               region_offset++;
+       }
+
+       return AE_OK;
+}
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ex_load_op
@@ -314,18 +363,23 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
                        }
                }
 
-               /*
-                * Map the table header and get the actual table length. The region
-                * length is not guaranteed to be the same as the table length.
-                */
-               table = acpi_os_map_memory(obj_desc->region.address,
-                                          sizeof(struct acpi_table_header));
+               /* Get the table header first so we can get the table length */
+
+               table = ACPI_ALLOCATE(sizeof(struct acpi_table_header));
                if (!table) {
                        return_ACPI_STATUS(AE_NO_MEMORY);
                }
 
+               status =
+                   acpi_ex_region_read(obj_desc,
+                                       sizeof(struct acpi_table_header),
+                                       ACPI_CAST_PTR(u8, table));
                length = table->length;
-               acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
+               ACPI_FREE(table);
+
+               if (ACPI_FAILURE(status)) {
+                       return_ACPI_STATUS(status);
+               }
 
                /* Must have at least an ACPI table header */
 
@@ -334,10 +388,19 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
                }
 
                /*
-                * The memory region is not guaranteed to remain stable and we must
-                * copy the table to a local buffer. For example, the memory region
-                * is corrupted after suspend on some machines. Dynamically loaded
-                * tables are usually small, so this overhead is minimal.
+                * The original implementation simply mapped the table, with no copy.
+                * However, the memory region is not guaranteed to remain stable and
+                * we must copy the table to a local buffer. For example, the memory
+                * region is corrupted after suspend on some machines. Dynamically
+                * loaded tables are usually small, so this overhead is minimal.
+                *
+                * The latest implementation (5/2009) does not use a mapping at all.
+                * We use the low-level operation region interface to read the table
+                * instead of the obvious optimization of using a direct mapping.
+                * This maintains a consistent use of operation regions across the
+                * entire subsystem. This is important if additional processing must
+                * be performed in the (possibly user-installed) operation region
+                * handler. For example, acpi_exec and ASLTS depend on this.
                 */
 
                /* Allocate a buffer for the table */
@@ -347,17 +410,16 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
                        return_ACPI_STATUS(AE_NO_MEMORY);
                }
 
-               /* Map the entire table and copy it */
+               /* Read the entire table */
 
-               table = acpi_os_map_memory(obj_desc->region.address, length);
-               if (!table) {
+               status = acpi_ex_region_read(obj_desc, length,
+                                            ACPI_CAST_PTR(u8,
+                                                          table_desc.pointer));
+               if (ACPI_FAILURE(status)) {
                        ACPI_FREE(table_desc.pointer);
-                       return_ACPI_STATUS(AE_NO_MEMORY);
+                       return_ACPI_STATUS(status);
                }
 
-               ACPI_MEMCPY(table_desc.pointer, table, length);
-               acpi_os_unmap_memory(table, length);
-
                table_desc.address = obj_desc->region.address;
                break;
 
@@ -454,6 +516,10 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
                return_ACPI_STATUS(status);
        }
 
+       /* Remove the reference by added by acpi_ex_store above */
+
+       acpi_ut_remove_reference(ddb_handle);
+
        /* Invoke table handler if present */
 
        if (acpi_gbl_table_handler) {
@@ -495,13 +561,18 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
 
        /*
         * Validate the handle
-        * Although the handle is partially validated in acpi_ex_reconfiguration(),
+        * Although the handle is partially validated in acpi_ex_reconfiguration()
         * when it calls acpi_ex_resolve_operands(), the handle is more completely
         * validated here.
+        *
+        * Handle must be a valid operand object of type reference. Also, the
+        * ddb_handle must still be marked valid (table has not been previously
+        * unloaded)
         */
        if ((!ddb_handle) ||
            (ACPI_GET_DESCRIPTOR_TYPE(ddb_handle) != ACPI_DESC_TYPE_OPERAND) ||
-           (ddb_handle->common.type != ACPI_TYPE_LOCAL_REFERENCE)) {
+           (ddb_handle->common.type != ACPI_TYPE_LOCAL_REFERENCE) ||
+           (!(ddb_handle->common.flags & AOPOBJ_DATA_VALID))) {
                return_ACPI_STATUS(AE_BAD_PARAMETER);
        }
 
@@ -509,6 +580,12 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
 
        table_index = table_desc->reference.value;
 
+       /* Ensure the table is still loaded */
+
+       if (!acpi_tb_is_table_loaded(table_index)) {
+               return_ACPI_STATUS(AE_NOT_EXIST);
+       }
+
        /* Invoke table handler if present */
 
        if (acpi_gbl_table_handler) {
@@ -530,8 +607,10 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
        (void)acpi_tb_release_owner_id(table_index);
        acpi_tb_set_table_loaded_flag(table_index, FALSE);
 
-       /* Table unloaded, remove a reference to the ddb_handle object */
-
-       acpi_ut_remove_reference(ddb_handle);
+       /*
+        * Invalidate the handle. We do this because the handle may be stored
+        * in a named object and may not be actually deleted until much later.
+        */
+       ddb_handle->common.flags &= ~AOPOBJ_DATA_VALID;
        return_ACPI_STATUS(AE_OK);
 }
index a57ad2564ab0c7c66a1594601efcf161971dd4be..02b25d233d994523323e673f3f7eb8e99efb4da4 100644 (file)
@@ -502,7 +502,7 @@ acpi_ex_create_method(u8 * aml_start,
                 * ACPI 2.0: sync_level = sync_level in method declaration
                 */
                obj_desc->method.sync_level = (u8)
-                   ((method_flags & AML_METHOD_SYNCH_LEVEL) >> 4);
+                   ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4);
        }
 
        /* Attach the new object to the method Node */
index 89d141fdae0b463eb650d6224219ba2b42fd6ba6..ec524614e7087c42e3337614b319e2a2f67278ca 100644 (file)
@@ -120,9 +120,11 @@ static struct acpi_exdump_info acpi_ex_dump_event[2] = {
        {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(event.os_semaphore), "OsSemaphore"}
 };
 
-static struct acpi_exdump_info acpi_ex_dump_method[8] = {
+static struct acpi_exdump_info acpi_ex_dump_method[9] = {
        {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_method), NULL},
-       {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.param_count), "ParamCount"},
+       {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.method_flags), "Method Flags"},
+       {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.param_count),
+        "Parameter Count"},
        {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.sync_level), "Sync Level"},
        {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(method.mutex), "Mutex"},
        {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.owner_id), "Owner Id"},
index 99cee61e655d7ddae24b2e73061a119244826e80..d4075b8210217ecc5c503b54b4831aabe7ad83c2 100644 (file)
@@ -222,7 +222,7 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc,
 {
        acpi_status status;
        union acpi_operand_object *rgn_desc;
-       acpi_physical_address address;
+       u32 region_offset;
 
        ACPI_FUNCTION_TRACE(ex_access_region);
 
@@ -243,7 +243,7 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc,
         * 3) The current offset into the field
         */
        rgn_desc = obj_desc->common_field.region_obj;
-       address = rgn_desc->region.address +
+       region_offset =
            obj_desc->common_field.base_byte_offset + field_datum_byte_offset;
 
        if ((function & ACPI_IO_MASK) == ACPI_READ) {
@@ -260,16 +260,18 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc,
                              obj_desc->common_field.access_byte_width,
                              obj_desc->common_field.base_byte_offset,
                              field_datum_byte_offset, ACPI_CAST_PTR(void,
-                                                                    address)));
+                                                                    (rgn_desc->
+                                                                     region.
+                                                                     address +
+                                                                     region_offset))));
 
        /* Invoke the appropriate address_space/op_region handler */
 
-       status = acpi_ev_address_space_dispatch(rgn_desc, function,
-                                               address,
-                                               ACPI_MUL_8(obj_desc->
-                                                          common_field.
-                                                          access_byte_width),
-                                               value);
+       status =
+           acpi_ev_address_space_dispatch(rgn_desc, function, region_offset,
+                                          ACPI_MUL_8(obj_desc->common_field.
+                                                     access_byte_width),
+                                          value);
 
        if (ACPI_FAILURE(status)) {
                if (status == AE_NOT_IMPLEMENTED) {
index d301c1f363ef0fceb3749ee679d8f1366ec7fb32..2f0114202b05dc8a86e77b31075d3e930e96718f 100644 (file)
@@ -83,6 +83,15 @@ void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc)
 
        if (obj_desc->mutex.prev) {
                (obj_desc->mutex.prev)->mutex.next = obj_desc->mutex.next;
+
+               /*
+                * Migrate the previous sync level associated with this mutex to the
+                * previous mutex on the list so that it may be preserved. This handles
+                * the case where several mutexes have been acquired at the same level,
+                * but are not released in opposite order.
+                */
+               (obj_desc->mutex.prev)->mutex.original_sync_level =
+                   obj_desc->mutex.original_sync_level;
        } else {
                thread->acquired_mutex_list = obj_desc->mutex.next;
        }
@@ -349,6 +358,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
                      struct acpi_walk_state *walk_state)
 {
        acpi_status status = AE_OK;
+       u8 previous_sync_level;
 
        ACPI_FUNCTION_TRACE(ex_release_mutex);
 
@@ -373,11 +383,12 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
             walk_state->thread->thread_id)
            && (obj_desc != acpi_gbl_global_lock_mutex)) {
                ACPI_ERROR((AE_INFO,
-                           "Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX",
-                           (unsigned long)walk_state->thread->thread_id,
+                           "Thread %p cannot release Mutex [%4.4s] acquired by thread %p",
+                           ACPI_CAST_PTR(void, walk_state->thread->thread_id),
                            acpi_ut_get_node_name(obj_desc->mutex.node),
-                           (unsigned long)obj_desc->mutex.owner_thread->
-                           thread_id));
+                           ACPI_CAST_PTR(void,
+                                         obj_desc->mutex.owner_thread->
+                                         thread_id)));
                return_ACPI_STATUS(AE_AML_NOT_OWNER);
        }
 
@@ -391,10 +402,14 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
        }
 
        /*
-        * The sync level of the mutex must be less than or equal to the current
-        * sync level
+        * The sync level of the mutex must be equal to the current sync level. In
+        * other words, the current level means that at least one mutex at that
+        * level is currently being held. Attempting to release a mutex of a
+        * different level can only mean that the mutex ordering rule is being
+        * violated. This behavior is clarified in ACPI 4.0 specification.
         */
-       if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) {
+       if (obj_desc->mutex.sync_level !=
+           walk_state->thread->current_sync_level) {
                ACPI_ERROR((AE_INFO,
                            "Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %d current %d",
                            acpi_ut_get_node_name(obj_desc->mutex.node),
@@ -403,14 +418,24 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
                return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
        }
 
+       /*
+        * Get the previous sync_level from the head of the acquired mutex list.
+        * This handles the case where several mutexes at the same level have been
+        * acquired, but are not released in reverse order.
+        */
+       previous_sync_level =
+           walk_state->thread->acquired_mutex_list->mutex.original_sync_level;
+
        status = acpi_ex_release_mutex_object(obj_desc);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
 
        if (obj_desc->mutex.acquisition_depth == 0) {
 
-               /* Restore the original sync_level */
+               /* Restore the previous sync_level */
 
-               walk_state->thread->current_sync_level =
-                   obj_desc->mutex.original_sync_level;
+               walk_state->thread->current_sync_level = previous_sync_level;
        }
        return_ACPI_STATUS(status);
 }
index 90d606196c99595f871f249c33d931442e7610f0..6efd07a4f779c5975b864eb81989f60a9f84019f 100644 (file)
@@ -193,10 +193,12 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc,
 
                case ACPI_REFCLASS_TABLE:
 
+                       /* Case for ddb_handle */
+
                        ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT,
                                              "Table Index 0x%X\n",
                                              source_desc->reference.value));
-                       break;
+                       return;
 
                default:
                        break;
index 7b2fb602b5cbf59a441a98950078e34a6d7f862b..23d5505cb1f779cf551730065e36e84580852975 100644 (file)
@@ -81,9 +81,9 @@ acpi_status acpi_hw_clear_acpi_status(void)
 
        ACPI_FUNCTION_TRACE(hw_clear_acpi_status);
 
-       ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %0llX\n",
+       ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n",
                          ACPI_BITMASK_ALL_FIXED_STATUS,
-                         acpi_gbl_xpm1a_status.address));
+                         ACPI_FORMAT_UINT64(acpi_gbl_xpm1a_status.address)));
 
        lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
 
index aceb93111967f35a7f0a335c4bcb2798c4d56304..efc971ab7d6512dbc47607bd25d6d976f28ddff6 100644 (file)
@@ -334,9 +334,7 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node)
 
                /* Get the next node in this scope (NULL if none) */
 
-               child_node =
-                   acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node,
-                                         child_node);
+               child_node = acpi_ns_get_next_node(parent_node, child_node);
                if (child_node) {
 
                        /* Found a child node - detach any attached object */
@@ -345,8 +343,7 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node)
 
                        /* Check if this node has any children */
 
-                       if (acpi_ns_get_next_node
-                           (ACPI_TYPE_ANY, child_node, NULL)) {
+                       if (child_node->child) {
                                /*
                                 * There is at least one child of this node,
                                 * visit the node
@@ -432,9 +429,7 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id)
                 * Get the next child of this parent node. When child_node is NULL,
                 * the first child of the parent is returned
                 */
-               child_node =
-                   acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node,
-                                         child_node);
+               child_node = acpi_ns_get_next_node(parent_node, child_node);
 
                if (deletion_node) {
                        acpi_ns_delete_children(deletion_node);
@@ -452,8 +447,7 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id)
 
                        /* Check if this node has any children */
 
-                       if (acpi_ns_get_next_node
-                           (ACPI_TYPE_ANY, child_node, NULL)) {
+                       if (child_node->child) {
                                /*
                                 * There is at least one child of this node,
                                 * visit the node
index ae3dc10a7e817c4c9f11d7c5d6549e7cff2e0f61..af8e6bcee07e5544112299df765c540a7b4c0602 100644 (file)
@@ -149,7 +149,7 @@ char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node)
 
        name_buffer = ACPI_ALLOCATE_ZEROED(size);
        if (!name_buffer) {
-               ACPI_ERROR((AE_INFO, "Allocation failure"));
+               ACPI_ERROR((AE_INFO, "Could not allocate %u bytes", (u32)size));
                return_PTR(NULL);
        }
 
index 3eb20bfda9d81a079c606d2e91ac85aa5dd8a859..60f3af08d28c3955fdee04607e99ce95befda017 100644 (file)
@@ -213,6 +213,15 @@ void acpi_ns_detach_object(struct acpi_namespace_node *node)
                return_VOID;
        }
 
+       if (node->flags & ANOBJ_ALLOCATED_BUFFER) {
+
+               /* Free the dynamic aml buffer */
+
+               if (obj_desc->common.type == ACPI_TYPE_METHOD) {
+                       ACPI_FREE(obj_desc->method.aml_start);
+               }
+       }
+
        /* Clear the entry in all cases */
 
        node->object = NULL;
index d9e8cbc6e679732d9a362d71f604a51d1683d223..7f8e066b12a3d20b79a986a7e771d65eef3a332c 100644 (file)
@@ -144,7 +144,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
 
        pathname = acpi_ns_get_external_pathname(node);
        if (!pathname) {
-               pathname = ACPI_CAST_PTR(char, predefined->info.name);
+               return AE_OK;   /* Could not get pathname, ignore */
        }
 
        /*
@@ -230,10 +230,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
        }
 
       exit:
-       if (pathname != predefined->info.name) {
-               ACPI_FREE(pathname);
-       }
-
+       ACPI_FREE(pathname);
        return (status);
 }
 
index f9b4f51bf8f2445fb7a48879b9d7298874a776ee..7e865639a928746abb4d94039dc771d8d40245fa 100644 (file)
 #include "accommon.h"
 #include "acnamesp.h"
 
+#ifdef ACPI_ASL_COMPILER
+#include "amlcode.h"
+#endif
+
 #define _COMPONENT          ACPI_NAMESPACE
 ACPI_MODULE_NAME("nssearch")
 
index 83e3aa6d4b9b65ddcec28881939908007ae39698..35539df5c75dc965800e555bd1432d8ef11c9767 100644 (file)
@@ -52,8 +52,7 @@ ACPI_MODULE_NAME("nswalk")
  *
  * FUNCTION:    acpi_ns_get_next_node
  *
- * PARAMETERS:  Type                - Type of node to be searched for
- *              parent_node         - Parent node whose children we are
+ * PARAMETERS:  parent_node         - Parent node whose children we are
  *                                    getting
  *              child_node          - Previous child that was found.
  *                                    The NEXT child will be returned
@@ -66,27 +65,68 @@ ACPI_MODULE_NAME("nswalk")
  *              within Scope is returned.
  *
  ******************************************************************************/
-struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct acpi_namespace_node
-                                                 *parent_node, struct acpi_namespace_node
+struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node
+                                                 *parent_node,
+                                                 struct acpi_namespace_node
                                                  *child_node)
 {
-       struct acpi_namespace_node *next_node = NULL;
-
        ACPI_FUNCTION_ENTRY();
 
        if (!child_node) {
 
                /* It's really the parent's _scope_ that we want */
 
-               next_node = parent_node->child;
+               return parent_node->child;
        }
 
-       else {
-               /* Start search at the NEXT node */
-
-               next_node = acpi_ns_get_next_valid_node(child_node);
+       /*
+        * Get the next node.
+        *
+        * If we are at the end of this peer list, return NULL
+        */
+       if (child_node->flags & ANOBJ_END_OF_PEER_LIST) {
+               return NULL;
        }
 
+       /* Otherwise just return the next peer */
+
+       return child_node->peer;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ns_get_next_node_typed
+ *
+ * PARAMETERS:  Type                - Type of node to be searched for
+ *              parent_node         - Parent node whose children we are
+ *                                    getting
+ *              child_node          - Previous child that was found.
+ *                                    The NEXT child will be returned
+ *
+ * RETURN:      struct acpi_namespace_node - Pointer to the NEXT child or NULL if
+ *                                    none is found.
+ *
+ * DESCRIPTION: Return the next peer node within the namespace.  If Handle
+ *              is valid, Scope is ignored.  Otherwise, the first node
+ *              within Scope is returned.
+ *
+ ******************************************************************************/
+
+struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type,
+                                                       struct
+                                                       acpi_namespace_node
+                                                       *parent_node,
+                                                       struct
+                                                       acpi_namespace_node
+                                                       *child_node)
+{
+       struct acpi_namespace_node *next_node = NULL;
+
+       ACPI_FUNCTION_ENTRY();
+
+       next_node = acpi_ns_get_next_node(parent_node, child_node);
+
+
        /* If any type is OK, we are done */
 
        if (type == ACPI_TYPE_ANY) {
@@ -186,9 +226,7 @@ acpi_ns_walk_namespace(acpi_object_type type,
                /* Get the next node in this scope.  Null if not found */
 
                status = AE_OK;
-               child_node =
-                   acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node,
-                                         child_node);
+               child_node = acpi_ns_get_next_node(parent_node, child_node);
                if (child_node) {
 
                        /* Found next child, get the type if we are not searching for ANY */
@@ -269,8 +307,7 @@ acpi_ns_walk_namespace(acpi_object_type type,
                         * function has specified that the maximum depth has been reached.
                         */
                        if ((level < max_depth) && (status != AE_CTRL_DEPTH)) {
-                               if (acpi_ns_get_next_node
-                                   (ACPI_TYPE_ANY, child_node, NULL)) {
+                               if (child_node->child) {
 
                                        /* There is at least one child of this node, visit it */
 
index 9589fea2499790bc4fc989baeb3700d49137390e..f23593d6add4857f146527e29b130fed13c47ff9 100644 (file)
@@ -45,6 +45,8 @@
 #include <acpi/acpi.h>
 #include "accommon.h"
 #include "acnamesp.h"
+#include "acparser.h"
+#include "amlcode.h"
 
 #define _COMPONENT          ACPI_NAMESPACE
 ACPI_MODULE_NAME("nsxfname")
@@ -358,3 +360,151 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer)
 }
 
 ACPI_EXPORT_SYMBOL(acpi_get_object_info)
+
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_install_method
+ *
+ * PARAMETERS:  Buffer         - An ACPI table containing one control method
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Install a control method into the namespace. If the method
+ *              name already exists in the namespace, it is overwritten. The
+ *              input buffer must contain a valid DSDT or SSDT containing a
+ *              single control method.
+ *
+ ******************************************************************************/
+acpi_status acpi_install_method(u8 *buffer)
+{
+       struct acpi_table_header *table =
+           ACPI_CAST_PTR(struct acpi_table_header, buffer);
+       u8 *aml_buffer;
+       u8 *aml_start;
+       char *path;
+       struct acpi_namespace_node *node;
+       union acpi_operand_object *method_obj;
+       struct acpi_parse_state parser_state;
+       u32 aml_length;
+       u16 opcode;
+       u8 method_flags;
+       acpi_status status;
+
+       /* Parameter validation */
+
+       if (!buffer) {
+               return AE_BAD_PARAMETER;
+       }
+
+       /* Table must be a DSDT or SSDT */
+
+       if (!ACPI_COMPARE_NAME(table->signature, ACPI_SIG_DSDT) &&
+           !ACPI_COMPARE_NAME(table->signature, ACPI_SIG_SSDT)) {
+               return AE_BAD_HEADER;
+       }
+
+       /* First AML opcode in the table must be a control method */
+
+       parser_state.aml = buffer + sizeof(struct acpi_table_header);
+       opcode = acpi_ps_peek_opcode(&parser_state);
+       if (opcode != AML_METHOD_OP) {
+               return AE_BAD_PARAMETER;
+       }
+
+       /* Extract method information from the raw AML */
+
+       parser_state.aml += acpi_ps_get_opcode_size(opcode);
+       parser_state.pkg_end = acpi_ps_get_next_package_end(&parser_state);
+       path = acpi_ps_get_next_namestring(&parser_state);
+       method_flags = *parser_state.aml++;
+       aml_start = parser_state.aml;
+       aml_length = ACPI_PTR_DIFF(parser_state.pkg_end, aml_start);
+
+       /*
+        * Allocate resources up-front. We don't want to have to delete a new
+        * node from the namespace if we cannot allocate memory.
+        */
+       aml_buffer = ACPI_ALLOCATE(aml_length);
+       if (!aml_buffer) {
+               return AE_NO_MEMORY;
+       }
+
+       method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD);
+       if (!method_obj) {
+               ACPI_FREE(aml_buffer);
+               return AE_NO_MEMORY;
+       }
+
+       /* Lock namespace for acpi_ns_lookup, we may be creating a new node */
+
+       status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+       if (ACPI_FAILURE(status)) {
+               goto error_exit;
+       }
+
+       /* The lookup either returns an existing node or creates a new one */
+
+       status =
+           acpi_ns_lookup(NULL, path, ACPI_TYPE_METHOD, ACPI_IMODE_LOAD_PASS1,
+                          ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND,
+                          NULL, &node);
+
+       (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+
+       if (ACPI_FAILURE(status)) {     /* ns_lookup */
+               if (status != AE_ALREADY_EXISTS) {
+                       goto error_exit;
+               }
+
+               /* Node existed previously, make sure it is a method node */
+
+               if (node->type != ACPI_TYPE_METHOD) {
+                       status = AE_TYPE;
+                       goto error_exit;
+               }
+       }
+
+       /* Copy the method AML to the local buffer */
+
+       ACPI_MEMCPY(aml_buffer, aml_start, aml_length);
+
+       /* Initialize the method object with the new method's information */
+
+       method_obj->method.aml_start = aml_buffer;
+       method_obj->method.aml_length = aml_length;
+
+       method_obj->method.param_count = (u8)
+           (method_flags & AML_METHOD_ARG_COUNT);
+
+       method_obj->method.method_flags = (u8)
+           (method_flags & ~AML_METHOD_ARG_COUNT);
+
+       if (method_flags & AML_METHOD_SERIALIZED) {
+               method_obj->method.sync_level = (u8)
+                   ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4);
+       }
+
+       /*
+        * Now that it is complete, we can attach the new method object to
+        * the method Node (detaches/deletes any existing object)
+        */
+       status = acpi_ns_attach_object(node, method_obj, ACPI_TYPE_METHOD);
+
+       /*
+        * Flag indicates AML buffer is dynamic, must be deleted later.
+        * Must be set only after attach above.
+        */
+       node->flags |= ANOBJ_ALLOCATED_BUFFER;
+
+       /* Remove local reference to the method object */
+
+       acpi_ut_remove_reference(method_obj);
+       return status;
+
+error_exit:
+
+       ACPI_FREE(aml_buffer);
+       ACPI_FREE(method_obj);
+       return status;
+}
+ACPI_EXPORT_SYMBOL(acpi_install_method)
index 1c7efc15225f6a63dcf4fc5e8ff763bbe8f7e327..4071bad4458ed7d229bc04e30cb02abcb8efe26b 100644 (file)
@@ -162,6 +162,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_type)
 acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle)
 {
        struct acpi_namespace_node *node;
+       struct acpi_namespace_node *parent_node;
        acpi_status status;
 
        if (!ret_handle) {
@@ -189,12 +190,12 @@ acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle)
 
        /* Get the parent entry */
 
-       *ret_handle =
-           acpi_ns_convert_entry_to_handle(acpi_ns_get_parent_node(node));
+       parent_node = acpi_ns_get_parent_node(node);
+       *ret_handle = acpi_ns_convert_entry_to_handle(parent_node);
 
        /* Return exception if parent is null */
 
-       if (!acpi_ns_get_parent_node(node)) {
+       if (!parent_node) {
                status = AE_NULL_ENTRY;
        }
 
@@ -268,7 +269,7 @@ acpi_get_next_object(acpi_object_type type,
 
        /* Internal function does the real work */
 
-       node = acpi_ns_get_next_node(type, parent_node, child_node);
+       node = acpi_ns_get_next_node_typed(type, parent_node, child_node);
        if (!node) {
                status = AE_NOT_FOUND;
                goto unlock_and_exit;
index 88b5a2c4814d0423f60a02e1c994d5cb6c9e9775..3c4dcc3d1069097f4255b92d5b2eaa68119b8424 100644 (file)
@@ -547,7 +547,7 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object,
 
                if (!package_element ||
                    (package_element->common.type != ACPI_TYPE_PACKAGE)) {
-                       return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+                       return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
                }
 
                /*
@@ -593,9 +593,6 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object,
                        } else {
                                temp_size_needed +=
                                    acpi_ns_get_pathname_length((*sub_object_list)->reference.node);
-                               if (!temp_size_needed) {
-                                       return_ACPI_STATUS(AE_BAD_PARAMETER);
-                               }
                        }
                } else {
                        /*
index 69a2aa5b5d831ae83ac0ba901732a121f918ad16..395212bcd19b470d756efa5328dfc9d21464c603 100644 (file)
@@ -338,13 +338,17 @@ acpi_resource_to_address64(struct acpi_resource *resource,
        switch (resource->type) {
        case ACPI_RESOURCE_TYPE_ADDRESS16:
 
-               address16 = (struct acpi_resource_address16 *)&resource->data;
+               address16 =
+                   ACPI_CAST_PTR(struct acpi_resource_address16,
+                                 &resource->data);
                ACPI_COPY_ADDRESS(out, address16);
                break;
 
        case ACPI_RESOURCE_TYPE_ADDRESS32:
 
-               address32 = (struct acpi_resource_address32 *)&resource->data;
+               address32 =
+                   ACPI_CAST_PTR(struct acpi_resource_address32,
+                                 &resource->data);
                ACPI_COPY_ADDRESS(out, address32);
                break;
 
index 71e655d14cb0759a71fff3da12188f6c8a0f0679..82b02dcb942e75f9cfe3871464da16dc839cfc6e 100644 (file)
@@ -284,9 +284,9 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
        if (length > sizeof(struct acpi_table_fadt)) {
                ACPI_WARNING((AE_INFO,
                              "FADT (revision %u) is longer than ACPI 2.0 version, "
-                             "truncating length 0x%X to 0x%zX",
-                             table->revision, (unsigned)length,
-                             sizeof(struct acpi_table_fadt)));
+                             "truncating length 0x%X to 0x%X",
+                             table->revision, length,
+                             (u32)sizeof(struct acpi_table_fadt)));
        }
 
        /* Clear the entire local FADT */
@@ -441,7 +441,7 @@ static void acpi_tb_convert_fadt(void)
                                                                   &acpi_gbl_FADT,
                                                                   fadt_info_table
                                                                   [i].length),
-                                                    address32);
+                                                    (u64) address32);
                }
        }
 }
@@ -469,7 +469,6 @@ static void acpi_tb_convert_fadt(void)
 static void acpi_tb_validate_fadt(void)
 {
        char *name;
-       u32 *address32;
        struct acpi_generic_address *address64;
        u8 length;
        u32 i;
@@ -505,15 +504,12 @@ static void acpi_tb_validate_fadt(void)
 
        for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
                /*
-                * Generate pointers to the 32-bit and 64-bit addresses, get the
-                * register length (width), and the register name
+                * Generate pointer to the 64-bit address, get the register
+                * length (width) and the register name
                 */
                address64 = ACPI_ADD_PTR(struct acpi_generic_address,
                                         &acpi_gbl_FADT,
                                         fadt_info_table[i].address64);
-               address32 =
-                   ACPI_ADD_PTR(u32, &acpi_gbl_FADT,
-                                fadt_info_table[i].address32);
                length =
                    *ACPI_ADD_PTR(u8, &acpi_gbl_FADT,
                                  fadt_info_table[i].length);
index f865d5a096de28e2ab57bb2c9c5d295f7e354243..63e82329a9e858ca81e1169daf1bf0f4f40e0e14 100644 (file)
@@ -472,7 +472,7 @@ acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index)
         * lock may block, and also since the execution of a namespace walk
         * must be allowed to use the interpreter.
         */
-       acpi_ut_release_mutex(ACPI_MTX_INTERPRETER);
+       (void)acpi_ut_release_mutex(ACPI_MTX_INTERPRETER);
        status = acpi_ut_acquire_write_lock(&acpi_gbl_namespace_rw_lock);
 
        acpi_ns_delete_namespace_by_owner(owner_id);
index 919624f123d5ab4e6cb65b8ec23702c0d6d538ab..0f0c64bf8ac98d1cae2da0bdb073405d5f08d9e5 100644 (file)
@@ -676,6 +676,7 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc,
 {
        u16 reference_count;
        union acpi_operand_object *next_object;
+       acpi_status status;
 
        /* Save fields from destination that we don't want to overwrite */
 
@@ -768,6 +769,28 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc,
                }
                break;
 
+               /*
+                * For Mutex and Event objects, we cannot simply copy the underlying
+                * OS object. We must create a new one.
+                */
+       case ACPI_TYPE_MUTEX:
+
+               status = acpi_os_create_mutex(&dest_desc->mutex.os_mutex);
+               if (ACPI_FAILURE(status)) {
+                       return status;
+               }
+               break;
+
+       case ACPI_TYPE_EVENT:
+
+               status = acpi_os_create_semaphore(ACPI_NO_UNIT_LIMIT, 0,
+                                                 &dest_desc->event.
+                                                 os_semaphore);
+               if (ACPI_FAILURE(status)) {
+                       return status;
+               }
+               break;
+
        default:
                /* Nothing to do for other simple objects */
                break;
index 38821f53042c34c215d6776ba6599434b3273f5f..527d729f681506d160c0e93611f60439c0dcb740 100644 (file)
@@ -179,9 +179,9 @@ acpi_debug_print(u32 requested_debug_level,
        if (thread_id != acpi_gbl_prev_thread_id) {
                if (ACPI_LV_THREADS & acpi_dbg_level) {
                        acpi_os_printf
-                           ("\n**** Context Switch from TID %lX to TID %lX ****\n\n",
-                            (unsigned long)acpi_gbl_prev_thread_id,
-                            (unsigned long)thread_id);
+                           ("\n**** Context Switch from TID %p to TID %p ****\n\n",
+                            ACPI_CAST_PTR(void, acpi_gbl_prev_thread_id),
+                            ACPI_CAST_PTR(void, thread_id));
                }
 
                acpi_gbl_prev_thread_id = thread_id;
@@ -194,7 +194,7 @@ acpi_debug_print(u32 requested_debug_level,
        acpi_os_printf("%8s-%04ld ", module_name, line_number);
 
        if (ACPI_LV_THREADS & acpi_dbg_level) {
-               acpi_os_printf("[%04lX] ", (unsigned long)thread_id);
+               acpi_os_printf("[%p] ", ACPI_CAST_PTR(void, thread_id));
        }
 
        acpi_os_printf("[%02ld] %-22.22s: ",
index a5ee23bc4f5563bcece4fe2a628016cf7a8c4208..bc1710315088a7304cfaa86bc9237f7ca0afd75f 100644 (file)
@@ -75,6 +75,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
        union acpi_operand_object *handler_desc;
        union acpi_operand_object *second_desc;
        union acpi_operand_object *next_desc;
+       union acpi_operand_object **last_obj_ptr;
 
        ACPI_FUNCTION_TRACE_PTR(ut_delete_internal_obj, object);
 
@@ -223,6 +224,26 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
                         */
                        handler_desc = object->region.handler;
                        if (handler_desc) {
+                               next_desc =
+                                   handler_desc->address_space.region_list;
+                               last_obj_ptr =
+                                   &handler_desc->address_space.region_list;
+
+                               /* Remove the region object from the handler's list */
+
+                               while (next_desc) {
+                                       if (next_desc == object) {
+                                               *last_obj_ptr =
+                                                   next_desc->region.next;
+                                               break;
+                                       }
+
+                                       /* Walk the linked list of handler */
+
+                                       last_obj_ptr = &next_desc->region.next;
+                                       next_desc = next_desc->region.next;
+                               }
+
                                if (handler_desc->address_space.handler_flags &
                                    ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) {
 
index 1c9e250caefb0c0eb57809c543514b227bf89557..fbe782348b0bcf0111971398ac0dc752b2f6e92d 100644 (file)
@@ -1033,11 +1033,12 @@ acpi_error(const char *module_name, u32 line_number, const char *format, ...)
 {
        va_list args;
 
-       acpi_os_printf("ACPI Error (%s-%04d): ", module_name, line_number);
+       acpi_os_printf("ACPI Error: ");
 
        va_start(args, format);
        acpi_os_vprintf(format, args);
-       acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
+       acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name,
+                      line_number);
        va_end(args);
 }
 
@@ -1047,12 +1048,12 @@ acpi_exception(const char *module_name,
 {
        va_list args;
 
-       acpi_os_printf("ACPI Exception (%s-%04d): %s, ", module_name,
-                      line_number, acpi_format_exception(status));
+       acpi_os_printf("ACPI Exception: %s, ", acpi_format_exception(status));
 
        va_start(args, format);
        acpi_os_vprintf(format, args);
-       acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
+       acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name,
+                      line_number);
        va_end(args);
 }
 
@@ -1061,11 +1062,12 @@ acpi_warning(const char *module_name, u32 line_number, const char *format, ...)
 {
        va_list args;
 
-       acpi_os_printf("ACPI Warning (%s-%04d): ", module_name, line_number);
+       acpi_os_printf("ACPI Warning: ");
 
        va_start(args, format);
        acpi_os_vprintf(format, args);
-       acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
+       acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name,
+                      line_number);
        va_end(args);
 }
 
@@ -1074,10 +1076,6 @@ acpi_info(const char *module_name, u32 line_number, const char *format, ...)
 {
        va_list args;
 
-       /*
-        * Removed module_name, line_number, and acpica version, not needed
-        * for info output
-        */
        acpi_os_printf("ACPI: ");
 
        va_start(args, format);
index 26c93a748e64b10795e61eaf61991a980ceabc2f..80bb6515411791898cacbee2c3c71c92bcc85180 100644 (file)
@@ -230,17 +230,18 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
                        if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) {
                                if (i == mutex_id) {
                                        ACPI_ERROR((AE_INFO,
-                                                   "Mutex [%s] already acquired by this thread [%X]",
+                                                   "Mutex [%s] already acquired by this thread [%p]",
                                                    acpi_ut_get_mutex_name
                                                    (mutex_id),
-                                                   this_thread_id));
+                                                   ACPI_CAST_PTR(void,
+                                                                 this_thread_id)));
 
                                        return (AE_ALREADY_ACQUIRED);
                                }
 
                                ACPI_ERROR((AE_INFO,
-                                           "Invalid acquire order: Thread %X owns [%s], wants [%s]",
-                                           this_thread_id,
+                                           "Invalid acquire order: Thread %p owns [%s], wants [%s]",
+                                           ACPI_CAST_PTR(void, this_thread_id),
                                            acpi_ut_get_mutex_name(i),
                                            acpi_ut_get_mutex_name(mutex_id)));
 
@@ -251,24 +252,24 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
 #endif
 
        ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
-                         "Thread %lX attempting to acquire Mutex [%s]\n",
-                         (unsigned long)this_thread_id,
+                         "Thread %p attempting to acquire Mutex [%s]\n",
+                         ACPI_CAST_PTR(void, this_thread_id),
                          acpi_ut_get_mutex_name(mutex_id)));
 
        status = acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex,
                                       ACPI_WAIT_FOREVER);
        if (ACPI_SUCCESS(status)) {
                ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
-                                 "Thread %lX acquired Mutex [%s]\n",
-                                 (unsigned long)this_thread_id,
+                                 "Thread %p acquired Mutex [%s]\n",
+                                 ACPI_CAST_PTR(void, this_thread_id),
                                  acpi_ut_get_mutex_name(mutex_id)));
 
                acpi_gbl_mutex_info[mutex_id].use_count++;
                acpi_gbl_mutex_info[mutex_id].thread_id = this_thread_id;
        } else {
                ACPI_EXCEPTION((AE_INFO, status,
-                               "Thread %lX could not acquire Mutex [%X]",
-                               (unsigned long)this_thread_id, mutex_id));
+                               "Thread %p could not acquire Mutex [%X]",
+                               ACPI_CAST_PTR(void, this_thread_id), mutex_id));
        }
 
        return (status);
@@ -293,9 +294,8 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id)
        ACPI_FUNCTION_NAME(ut_release_mutex);
 
        this_thread_id = acpi_os_get_thread_id();
-       ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
-                         "Thread %lX releasing Mutex [%s]\n",
-                         (unsigned long)this_thread_id,
+       ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %p releasing Mutex [%s]\n",
+                         ACPI_CAST_PTR(void, this_thread_id),
                          acpi_ut_get_mutex_name(mutex_id)));
 
        if (mutex_id > ACPI_MAX_MUTEX) {
index 1977d4beb89e0012290a567c850f6a59dd3da1b0..7ecb1938e590f34526beaaeda2a3f6683f4024ce 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/kallsyms.h>
 #include <linux/semaphore.h>
 #include <linux/mutex.h>
+#include <linux/async.h>
 
 #include "base.h"
 #include "power/power.h"
@@ -161,10 +162,18 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj,
        struct device *dev = to_dev(kobj);
        int retval = 0;
 
-       /* add the major/minor if present */
+       /* add device node properties if present */
        if (MAJOR(dev->devt)) {
+               const char *tmp;
+               const char *name;
+
                add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt));
                add_uevent_var(env, "MINOR=%u", MINOR(dev->devt));
+               name = device_get_nodename(dev, &tmp);
+               if (name) {
+                       add_uevent_var(env, "DEVNAME=%s", name);
+                       kfree(tmp);
+               }
        }
 
        if (dev->type && dev->type->name)
@@ -874,7 +883,7 @@ int device_add(struct device *dev)
         * the name, and force the use of dev_name()
         */
        if (dev->init_name) {
-               dev_set_name(dev, dev->init_name);
+               dev_set_name(dev, "%s", dev->init_name);
                dev->init_name = NULL;
        }
 
@@ -1127,6 +1136,47 @@ static struct device *next_device(struct klist_iter *i)
        return dev;
 }
 
+/**
+ * device_get_nodename - path of device node file
+ * @dev: device
+ * @tmp: possibly allocated string
+ *
+ * Return the relative path of a possible device node.
+ * Non-default names may need to allocate a memory to compose
+ * a name. This memory is returned in tmp and needs to be
+ * freed by the caller.
+ */
+const char *device_get_nodename(struct device *dev, const char **tmp)
+{
+       char *s;
+
+       *tmp = NULL;
+
+       /* the device type may provide a specific name */
+       if (dev->type && dev->type->nodename)
+               *tmp = dev->type->nodename(dev);
+       if (*tmp)
+               return *tmp;
+
+       /* the class may provide a specific name */
+       if (dev->class && dev->class->nodename)
+               *tmp = dev->class->nodename(dev);
+       if (*tmp)
+               return *tmp;
+
+       /* return name without allocation, tmp == NULL */
+       if (strchr(dev_name(dev), '!') == NULL)
+               return dev_name(dev);
+
+       /* replace '!' in the name with '/' */
+       *tmp = kstrdup(dev_name(dev), GFP_KERNEL);
+       if (!*tmp)
+               return NULL;
+       while ((s = strchr(*tmp, '!')))
+               s[0] = '/';
+       return *tmp;
+}
+
 /**
  * device_for_each_child - device child iterator.
  * @parent: parent struct device.
@@ -1271,7 +1321,7 @@ struct device *__root_device_register(const char *name, struct module *owner)
        if (!root)
                return ERR_PTR(err);
 
-       err = dev_set_name(&root->dev, name);
+       err = dev_set_name(&root->dev, "%s", name);
        if (err) {
                kfree(root);
                return ERR_PTR(err);
@@ -1665,4 +1715,5 @@ void device_shutdown(void)
        kobject_put(sysfs_dev_char_kobj);
        kobject_put(sysfs_dev_block_kobj);
        kobject_put(dev_kobj);
+       async_synchronize_full();
 }
index 742cbe6b042bbf711054e2cd7f02cdcc66354752..f0106875f01da48f9fb70afb6b2a68ac7259e37a 100644 (file)
@@ -226,7 +226,7 @@ static int __device_attach(struct device_driver *drv, void *data)
  * pair is found, break out and return.
  *
  * Returns 1 if the device was bound to a driver;
- * 0 if no matching device was found;
+ * 0 if no matching driver was found;
  * -ENODEV if the device is not registered.
  *
  * When called for a USB interface, @dev->parent->sem must be held.
@@ -320,6 +320,10 @@ static void __device_release_driver(struct device *dev)
                devres_release_all(dev);
                dev->driver = NULL;
                klist_remove(&dev->p->knode_driver);
+               if (dev->bus)
+                       blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
+                                                    BUS_NOTIFY_UNBOUND_DRIVER,
+                                                    dev);
        }
 }
 
index 8a267c4276291bb775e2590a6935825ae35e9305..ddeb819c8f878a3cf07c18ed9d6d2c3ffe082e46 100644 (file)
@@ -40,7 +40,7 @@ static int loading_timeout = 60;      /* In seconds */
 static DEFINE_MUTEX(fw_lock);
 
 struct firmware_priv {
-       char fw_id[FIRMWARE_NAME_MAX];
+       char *fw_id;
        struct completion completion;
        struct bin_attribute attr_data;
        struct firmware *fw;
@@ -355,8 +355,9 @@ static void fw_dev_release(struct device *dev)
        for (i = 0; i < fw_priv->nr_pages; i++)
                __free_page(fw_priv->pages[i]);
        kfree(fw_priv->pages);
+       kfree(fw_priv->fw_id);
        kfree(fw_priv);
-       kfree(dev);
+       put_device(dev);
 
        module_put(THIS_MODULE);
 }
@@ -386,13 +387,19 @@ static int fw_register_device(struct device **dev_p, const char *fw_name,
 
        init_completion(&fw_priv->completion);
        fw_priv->attr_data = firmware_attr_data_tmpl;
-       strlcpy(fw_priv->fw_id, fw_name, FIRMWARE_NAME_MAX);
+       fw_priv->fw_id = kstrdup(fw_name, GFP_KERNEL);
+       if (!fw_priv->fw_id) {
+               dev_err(device, "%s: Firmware name allocation failed\n",
+                       __func__);
+               retval = -ENOMEM;
+               goto error_kfree;
+       }
 
        fw_priv->timeout.function = firmware_class_timeout;
        fw_priv->timeout.data = (u_long) fw_priv;
        init_timer(&fw_priv->timeout);
 
-       dev_set_name(f_dev, dev_name(device));
+       dev_set_name(f_dev, "%s", dev_name(device));
        f_dev->parent = device;
        f_dev->class = &firmware_class;
        dev_set_drvdata(f_dev, fw_priv);
@@ -400,14 +407,17 @@ static int fw_register_device(struct device **dev_p, const char *fw_name,
        retval = device_register(f_dev);
        if (retval) {
                dev_err(device, "%s: device_register failed\n", __func__);
-               goto error_kfree;
+               put_device(f_dev);
+               goto error_kfree_fw_id;
        }
        *dev_p = f_dev;
        return 0;
 
+error_kfree_fw_id:
+       kfree(fw_priv->fw_id);
 error_kfree:
-       kfree(fw_priv);
        kfree(f_dev);
+       kfree(fw_priv);
        return retval;
 }
 
@@ -615,8 +625,9 @@ request_firmware_work_func(void *arg)
  * @cont: function will be called asynchronously when the firmware
  *     request is over.
  *
- *     Asynchronous variant of request_firmware() for contexts where
- *     it is not possible to sleep.
+ *     Asynchronous variant of request_firmware() for user contexts where
+ *     it is not possible to sleep for long time. It can't be called
+ *     in atomic contexts.
  **/
 int
 request_firmware_nowait(
index 40b809742a1c3ecf3b42a0e55b8130059d7d6e8e..91d4087b4039490a844d23e909ffe34eaa0ff0f9 100644 (file)
@@ -72,10 +72,8 @@ static ssize_t node_read_meminfo(struct sys_device * dev,
                       "Node %d Inactive(anon): %8lu kB\n"
                       "Node %d Active(file):   %8lu kB\n"
                       "Node %d Inactive(file): %8lu kB\n"
-#ifdef CONFIG_UNEVICTABLE_LRU
                       "Node %d Unevictable:    %8lu kB\n"
                       "Node %d Mlocked:        %8lu kB\n"
-#endif
 #ifdef CONFIG_HIGHMEM
                       "Node %d HighTotal:      %8lu kB\n"
                       "Node %d HighFree:       %8lu kB\n"
@@ -105,10 +103,8 @@ static ssize_t node_read_meminfo(struct sys_device * dev,
                       nid, K(node_page_state(nid, NR_INACTIVE_ANON)),
                       nid, K(node_page_state(nid, NR_ACTIVE_FILE)),
                       nid, K(node_page_state(nid, NR_INACTIVE_FILE)),
-#ifdef CONFIG_UNEVICTABLE_LRU
                       nid, K(node_page_state(nid, NR_UNEVICTABLE)),
                       nid, K(node_page_state(nid, NR_MLOCK)),
-#endif
 #ifdef CONFIG_HIGHMEM
                       nid, K(i.totalhigh),
                       nid, K(i.freehigh),
index ead3f64c41d0506774788860f0f2232f22c9ce0a..81cb01bfc356294865a4e04721d77d5a9c64ffff 100644 (file)
@@ -69,7 +69,8 @@ EXPORT_SYMBOL_GPL(platform_get_irq);
  * @name: resource name
  */
 struct resource *platform_get_resource_byname(struct platform_device *dev,
-                                             unsigned int type, char *name)
+                                             unsigned int type,
+                                             const char *name)
 {
        int i;
 
@@ -88,7 +89,7 @@ EXPORT_SYMBOL_GPL(platform_get_resource_byname);
  * @dev: platform device
  * @name: IRQ name
  */
-int platform_get_irq_byname(struct platform_device *dev, char *name)
+int platform_get_irq_byname(struct platform_device *dev, const char *name)
 {
        struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ,
                                                          name);
@@ -244,7 +245,7 @@ int platform_device_add(struct platform_device *pdev)
        if (pdev->id != -1)
                dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
        else
-               dev_set_name(&pdev->dev, pdev->name);
+               dev_set_name(&pdev->dev, "%s", pdev->name);
 
        for (i = 0; i < pdev->num_resources; i++) {
                struct resource *p, *r = &pdev->resource[i];
index 9742a78c9fe42a043bfa0c57e89ead65e4f6fc2f..79a9ae5238acc1b9fa06a2fed1ed70d2440a9416 100644 (file)
@@ -131,6 +131,8 @@ static struct kset *system_kset;
 
 int sysdev_class_register(struct sysdev_class *cls)
 {
+       int retval;
+
        pr_debug("Registering sysdev class '%s'\n", cls->name);
 
        INIT_LIST_HEAD(&cls->drivers);
@@ -138,7 +140,11 @@ int sysdev_class_register(struct sysdev_class *cls)
        cls->kset.kobj.parent = &system_kset->kobj;
        cls->kset.kobj.ktype = &ktype_sysdev_class;
        cls->kset.kobj.kset = system_kset;
-       kobject_set_name(&cls->kset.kobj, cls->name);
+
+       retval = kobject_set_name(&cls->kset.kobj, "%s", cls->name);
+       if (retval)
+               return retval;
+
        return kset_register(&cls->kset);
 }
 
index 200efc4d2c1e756cd9a7182709bbfb2328a57140..19888354188f7f4c4afb0f1c37050cc1d06805fc 100644 (file)
@@ -266,6 +266,11 @@ static const struct file_operations aoe_fops = {
        .owner = THIS_MODULE,
 };
 
+static char *aoe_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "etherd/%s", dev_name(dev));
+}
+
 int __init
 aoechr_init(void)
 {
@@ -283,6 +288,8 @@ aoechr_init(void)
                unregister_chrdev(AOE_MAJOR, "aoechr");
                return PTR_ERR(aoe_class);
        }
+       aoe_class->nodename = aoe_nodename;
+
        for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
                device_create(aoe_class, NULL,
                              MKDEV(AOE_MAJOR, chardevs[i].minor), NULL,
index b22cec97ea194e148427f998a5c310bc3eedf262..c7a527c08a0980d542c1fffbd30687bbc95289d0 100644 (file)
@@ -38,7 +38,6 @@
 #include <linux/hdreg.h>
 #include <linux/spinlock.h>
 #include <linux/compat.h>
-#include <linux/blktrace_api.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
index 60de5a01e71e6ecd67b15eee29fef7d567265872..f703f54782469e2ae9491cbd6d6dd89708fb8a55 100644 (file)
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
+#include <linux/mg_disk.h>
 
 #define MG_RES_SEC (CONFIG_MG_DISK_RES << 1)
 
 /* name for block device */
 #define MG_DISK_NAME "mgd"
-/* name for platform device */
-#define MG_DEV_NAME "mg_disk"
 
 #define MG_DISK_MAJ 0
 #define MG_DISK_MAX_PART 16
 #define MG_TMAX_SWRST_TO_RDY   500
 #define MG_TMAX_RSTOUT         3000
 
-/* device attribution */
-/* use mflash as boot device */
-#define MG_BOOT_DEV            (1 << 0)
-/* use mflash as storage device */
-#define MG_STORAGE_DEV         (1 << 1)
-/* same as MG_STORAGE_DEV, but bootloader already done reset sequence */
-#define MG_STORAGE_DEV_SKIP_RST        (1 << 2)
-
 #define MG_DEV_MASK (MG_BOOT_DEV | MG_STORAGE_DEV | MG_STORAGE_DEV_SKIP_RST)
 
-/* names of GPIO resource */
-#define MG_RST_PIN     "mg_rst"
-/* except MG_BOOT_DEV, reset-out pin should be assigned */
-#define MG_RSTOUT_PIN  "mg_rstout"
-
-/* private driver data */
-struct mg_drv_data {
-       /* disk resource */
-       u32 use_polling;
-
-       /* device attribution */
-       u32 dev_attr;
-
-       /* internally used */
-       struct mg_host *host;
-};
-
 /* main structure for mflash driver */
 struct mg_host {
        struct device *dev;
index d57f11759480c1c2874922e773cee62ac6571472..83650e00632d80b6837678355fbac3c50c6d9a94 100644 (file)
@@ -430,7 +430,7 @@ static void pkt_sysfs_cleanup(void)
 /********************************************************************
   entries in debugfs
 
-  /debugfs/pktcdvd[0-7]/
+  /sys/kernel/debug/pktcdvd[0-7]/
                        info
 
  *******************************************************************/
@@ -2855,6 +2855,11 @@ static struct block_device_operations pktcdvd_ops = {
        .media_changed =        pkt_media_changed,
 };
 
+static char *pktcdvd_nodename(struct gendisk *gd)
+{
+       return kasprintf(GFP_KERNEL, "pktcdvd/%s", gd->disk_name);
+}
+
 /*
  * Set up mapping from pktcdvd device to CD-ROM device.
  */
@@ -2907,6 +2912,7 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
        disk->fops = &pktcdvd_ops;
        disk->flags = GENHD_FL_REMOVABLE;
        strcpy(disk->disk_name, pd->name);
+       disk->nodename = pktcdvd_nodename;
        disk->private_data = pd;
        disk->queue = blk_alloc_queue(GFP_KERNEL);
        if (!disk->queue)
@@ -3062,6 +3068,7 @@ static const struct file_operations pkt_ctl_fops = {
 static struct miscdevice pkt_misc = {
        .minor          = MISC_DYNAMIC_MINOR,
        .name           = DRIVER_NAME,
+       .name           = "pktcdvd/control",
        .fops           = &pkt_ctl_fops
 };
 
index aaeeb544228a322efc790482f206f48afdf829a8..34cbb7f3efa89e5504920d547b081c86fe9ca4e9 100644 (file)
@@ -120,7 +120,7 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev,
 static int ps3disk_submit_request_sg(struct ps3_storage_device *dev,
                                     struct request *req)
 {
-       struct ps3disk_private *priv = dev->sbd.core.driver_data;
+       struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
        int write = rq_data_dir(req), res;
        const char *op = write ? "write" : "read";
        u64 start_sector, sectors;
@@ -168,7 +168,7 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev,
 static int ps3disk_submit_flush_request(struct ps3_storage_device *dev,
                                        struct request *req)
 {
-       struct ps3disk_private *priv = dev->sbd.core.driver_data;
+       struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
        u64 res;
 
        dev_dbg(&dev->sbd.core, "%s:%u: flush request\n", __func__, __LINE__);
@@ -213,7 +213,7 @@ static void ps3disk_do_request(struct ps3_storage_device *dev,
 static void ps3disk_request(struct request_queue *q)
 {
        struct ps3_storage_device *dev = q->queuedata;
-       struct ps3disk_private *priv = dev->sbd.core.driver_data;
+       struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
 
        if (priv->req) {
                dev_dbg(&dev->sbd.core, "%s:%u busy\n", __func__, __LINE__);
@@ -245,7 +245,7 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data)
                return IRQ_HANDLED;
        }
 
-       priv = dev->sbd.core.driver_data;
+       priv = ps3_system_bus_get_drvdata(&dev->sbd);
        req = priv->req;
        if (!req) {
                dev_dbg(&dev->sbd.core,
@@ -364,7 +364,7 @@ static void ata_id_c_string(const u16 *id, unsigned char *s, unsigned int ofs,
 
 static int ps3disk_identify(struct ps3_storage_device *dev)
 {
-       struct ps3disk_private *priv = dev->sbd.core.driver_data;
+       struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
        struct lv1_ata_cmnd_block ata_cmnd;
        u16 *id = dev->bounce_buf;
        u64 res;
@@ -445,7 +445,7 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev)
                goto fail;
        }
 
-       dev->sbd.core.driver_data = priv;
+       ps3_system_bus_set_drvdata(_dev, priv);
        spin_lock_init(&priv->lock);
 
        dev->bounce_size = BOUNCE_SIZE;
@@ -523,7 +523,7 @@ fail_free_bounce:
        kfree(dev->bounce_buf);
 fail_free_priv:
        kfree(priv);
-       dev->sbd.core.driver_data = NULL;
+       ps3_system_bus_set_drvdata(_dev, NULL);
 fail:
        mutex_lock(&ps3disk_mask_mutex);
        __clear_bit(devidx, &ps3disk_mask);
@@ -534,7 +534,7 @@ fail:
 static int ps3disk_remove(struct ps3_system_bus_device *_dev)
 {
        struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
-       struct ps3disk_private *priv = dev->sbd.core.driver_data;
+       struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
 
        mutex_lock(&ps3disk_mask_mutex);
        __clear_bit(MINOR(disk_devt(priv->gendisk)) / PS3DISK_MINORS,
@@ -548,7 +548,7 @@ static int ps3disk_remove(struct ps3_system_bus_device *_dev)
        ps3stor_teardown(dev);
        kfree(dev->bounce_buf);
        kfree(priv);
-       dev->sbd.core.driver_data = NULL;
+       ps3_system_bus_set_drvdata(_dev, NULL);
        return 0;
 }
 
index 8eddef373a9197d9db8834d5ba15d1f743b85ee2..095f97e6066562671eaad46eed57478aa3bafaf7 100644 (file)
 #include <linux/seq_file.h>
 
 #include <asm/firmware.h>
+#include <asm/iommu.h>
 #include <asm/lv1call.h>
 #include <asm/ps3.h>
+#include <asm/ps3gpu.h>
 
 
 #define DEVICE_NAME            "ps3vram"
@@ -45,8 +47,6 @@
 #define NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN   0x0000030c
 #define NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY      0x00000104
 
-#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601
-
 #define CACHE_PAGE_PRESENT 1
 #define CACHE_PAGE_DIRTY   2
 
@@ -72,8 +72,7 @@ struct ps3vram_priv {
        u64 memory_handle;
        u64 context_handle;
        u32 *ctrl;
-       u32 *reports;
-       u8 __iomem *ddr_base;
+       void *reports;
        u8 *xdr_buf;
 
        u32 *fifo_base;
@@ -81,8 +80,8 @@ struct ps3vram_priv {
 
        struct ps3vram_cache cache;
 
-       /* Used to serialize cache/DMA operations */
-       struct mutex lock;
+       spinlock_t lock;        /* protecting list of bios */
+       struct bio_list list;
 };
 
 
@@ -103,15 +102,15 @@ static char *size = "256M";
 module_param(size, charp, 0);
 MODULE_PARM_DESC(size, "memory size");
 
-static u32 *ps3vram_get_notifier(u32 *reports, int notifier)
+static u32 *ps3vram_get_notifier(void *reports, int notifier)
 {
-       return (void *)reports + DMA_NOTIFIER_OFFSET_BASE +
+       return reports + DMA_NOTIFIER_OFFSET_BASE +
               DMA_NOTIFIER_SIZE * notifier;
 }
 
 static void ps3vram_notifier_reset(struct ps3_system_bus_device *dev)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER);
        int i;
 
@@ -122,7 +121,7 @@ static void ps3vram_notifier_reset(struct ps3_system_bus_device *dev)
 static int ps3vram_notifier_wait(struct ps3_system_bus_device *dev,
                                 unsigned int timeout_ms)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER);
        unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
 
@@ -137,7 +136,7 @@ static int ps3vram_notifier_wait(struct ps3_system_bus_device *dev,
 
 static void ps3vram_init_ring(struct ps3_system_bus_device *dev)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
 
        priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET;
        priv->ctrl[CTRL_GET] = FIFO_BASE + FIFO_OFFSET;
@@ -146,7 +145,7 @@ static void ps3vram_init_ring(struct ps3_system_bus_device *dev)
 static int ps3vram_wait_ring(struct ps3_system_bus_device *dev,
                             unsigned int timeout_ms)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
 
        do {
@@ -175,7 +174,7 @@ static void ps3vram_begin_ring(struct ps3vram_priv *priv, u32 chan, u32 tag,
 
 static void ps3vram_rewind_ring(struct ps3_system_bus_device *dev)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        int status;
 
        ps3vram_out_ring(priv, 0x20000000 | (FIFO_BASE + FIFO_OFFSET));
@@ -183,20 +182,17 @@ static void ps3vram_rewind_ring(struct ps3_system_bus_device *dev)
        priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET;
 
        /* asking the HV for a blit will kick the FIFO */
-       status = lv1_gpu_context_attribute(priv->context_handle,
-                                          L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, 0,
-                                          0, 0, 0);
+       status = lv1_gpu_fb_blit(priv->context_handle, 0, 0, 0, 0);
        if (status)
-               dev_err(&dev->core,
-                       "%s: lv1_gpu_context_attribute failed %d\n", __func__,
-                       status);
+               dev_err(&dev->core, "%s: lv1_gpu_fb_blit failed %d\n",
+                       __func__, status);
 
        priv->fifo_ptr = priv->fifo_base;
 }
 
 static void ps3vram_fire_ring(struct ps3_system_bus_device *dev)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        int status;
 
        mutex_lock(&ps3_gpu_mutex);
@@ -205,13 +201,10 @@ static void ps3vram_fire_ring(struct ps3_system_bus_device *dev)
                               (priv->fifo_ptr - priv->fifo_base) * sizeof(u32);
 
        /* asking the HV for a blit will kick the FIFO */
-       status = lv1_gpu_context_attribute(priv->context_handle,
-                                          L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, 0,
-                                          0, 0, 0);
+       status = lv1_gpu_fb_blit(priv->context_handle, 0, 0, 0, 0);
        if (status)
-               dev_err(&dev->core,
-                       "%s: lv1_gpu_context_attribute failed %d\n", __func__,
-                       status);
+               dev_err(&dev->core, "%s: lv1_gpu_fb_blit failed %d\n",
+                       __func__, status);
 
        if ((priv->fifo_ptr - priv->fifo_base) * sizeof(u32) >
            FIFO_SIZE - 1024) {
@@ -225,7 +218,7 @@ static void ps3vram_fire_ring(struct ps3_system_bus_device *dev)
 
 static void ps3vram_bind(struct ps3_system_bus_device *dev)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
 
        ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0, 1);
        ps3vram_out_ring(priv, 0x31337303);
@@ -248,7 +241,7 @@ static int ps3vram_upload(struct ps3_system_bus_device *dev,
                          unsigned int src_offset, unsigned int dst_offset,
                          int len, int count)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
 
        ps3vram_begin_ring(priv, UPLOAD_SUBCH,
                           NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
@@ -280,7 +273,7 @@ static int ps3vram_download(struct ps3_system_bus_device *dev,
                            unsigned int src_offset, unsigned int dst_offset,
                            int len, int count)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
 
        ps3vram_begin_ring(priv, DOWNLOAD_SUBCH,
                           NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
@@ -310,7 +303,7 @@ static int ps3vram_download(struct ps3_system_bus_device *dev,
 
 static void ps3vram_cache_evict(struct ps3_system_bus_device *dev, int entry)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        struct ps3vram_cache *cache = &priv->cache;
 
        if (!(cache->tags[entry].flags & CACHE_PAGE_DIRTY))
@@ -332,7 +325,7 @@ static void ps3vram_cache_evict(struct ps3_system_bus_device *dev, int entry)
 static void ps3vram_cache_load(struct ps3_system_bus_device *dev, int entry,
                               unsigned int address)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        struct ps3vram_cache *cache = &priv->cache;
 
        dev_dbg(&dev->core, "Fetching %d: 0x%08x\n", entry, address);
@@ -352,7 +345,7 @@ static void ps3vram_cache_load(struct ps3_system_bus_device *dev, int entry,
 
 static void ps3vram_cache_flush(struct ps3_system_bus_device *dev)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        struct ps3vram_cache *cache = &priv->cache;
        int i;
 
@@ -366,7 +359,7 @@ static void ps3vram_cache_flush(struct ps3_system_bus_device *dev)
 static unsigned int ps3vram_cache_match(struct ps3_system_bus_device *dev,
                                        loff_t address)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        struct ps3vram_cache *cache = &priv->cache;
        unsigned int base;
        unsigned int offset;
@@ -400,7 +393,7 @@ static unsigned int ps3vram_cache_match(struct ps3_system_bus_device *dev,
 
 static int ps3vram_cache_init(struct ps3_system_bus_device *dev)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
 
        priv->cache.page_count = CACHE_PAGE_COUNT;
        priv->cache.page_size = CACHE_PAGE_SIZE;
@@ -419,7 +412,7 @@ static int ps3vram_cache_init(struct ps3_system_bus_device *dev)
 
 static void ps3vram_cache_cleanup(struct ps3_system_bus_device *dev)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
 
        ps3vram_cache_flush(dev);
        kfree(priv->cache.tags);
@@ -428,7 +421,7 @@ static void ps3vram_cache_cleanup(struct ps3_system_bus_device *dev)
 static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from,
                        size_t len, size_t *retlen, u_char *buf)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        unsigned int cached, count;
 
        dev_dbg(&dev->core, "%s: from=0x%08x len=0x%zx\n", __func__,
@@ -449,8 +442,6 @@ static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from,
                offset = (unsigned int) (from & (priv->cache.page_size - 1));
                avail  = priv->cache.page_size - offset;
 
-               mutex_lock(&priv->lock);
-
                entry = ps3vram_cache_match(dev, from);
                cached = CACHE_OFFSET + entry * priv->cache.page_size + offset;
 
@@ -462,8 +453,6 @@ static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from,
                        avail = count;
                memcpy(buf, priv->xdr_buf + cached, avail);
 
-               mutex_unlock(&priv->lock);
-
                buf += avail;
                count -= avail;
                from += avail;
@@ -476,7 +465,7 @@ static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from,
 static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to,
                         size_t len, size_t *retlen, const u_char *buf)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        unsigned int cached, count;
 
        if (to >= priv->size)
@@ -494,8 +483,6 @@ static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to,
                offset = (unsigned int) (to & (priv->cache.page_size - 1));
                avail  = priv->cache.page_size - offset;
 
-               mutex_lock(&priv->lock);
-
                entry = ps3vram_cache_match(dev, to);
                cached = CACHE_OFFSET + entry * priv->cache.page_size + offset;
 
@@ -509,8 +496,6 @@ static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to,
 
                priv->cache.tags[entry].flags |= CACHE_PAGE_DIRTY;
 
-               mutex_unlock(&priv->lock);
-
                buf += avail;
                count -= avail;
                to += avail;
@@ -543,28 +528,26 @@ static const struct file_operations ps3vram_proc_fops = {
 
 static void __devinit ps3vram_proc_init(struct ps3_system_bus_device *dev)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        struct proc_dir_entry *pde;
 
-       pde = proc_create(DEVICE_NAME, 0444, NULL, &ps3vram_proc_fops);
-       if (!pde) {
+       pde = proc_create_data(DEVICE_NAME, 0444, NULL, &ps3vram_proc_fops,
+                              priv);
+       if (!pde)
                dev_warn(&dev->core, "failed to create /proc entry\n");
-               return;
-       }
-       pde->data = priv;
 }
 
-static int ps3vram_make_request(struct request_queue *q, struct bio *bio)
+static struct bio *ps3vram_do_bio(struct ps3_system_bus_device *dev,
+                                 struct bio *bio)
 {
-       struct ps3_system_bus_device *dev = q->queuedata;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        int write = bio_data_dir(bio) == WRITE;
        const char *op = write ? "write" : "read";
        loff_t offset = bio->bi_sector << 9;
        int error = 0;
        struct bio_vec *bvec;
        unsigned int i;
-
-       dev_dbg(&dev->core, "%s\n", __func__);
+       struct bio *next;
 
        bio_for_each_segment(bvec, bio, i) {
                /* PS3 is ppc64, so we don't handle highmem */
@@ -585,6 +568,7 @@ static int ps3vram_make_request(struct request_queue *q, struct bio *bio)
 
                if (retlen != len) {
                        dev_err(&dev->core, "Short %s\n", op);
+                       error = -EIO;
                        goto out;
                }
 
@@ -594,7 +578,35 @@ static int ps3vram_make_request(struct request_queue *q, struct bio *bio)
        dev_dbg(&dev->core, "%s completed\n", op);
 
 out:
+       spin_lock_irq(&priv->lock);
+       bio_list_pop(&priv->list);
+       next = bio_list_peek(&priv->list);
+       spin_unlock_irq(&priv->lock);
+
        bio_endio(bio, error);
+       return next;
+}
+
+static int ps3vram_make_request(struct request_queue *q, struct bio *bio)
+{
+       struct ps3_system_bus_device *dev = q->queuedata;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
+       int busy;
+
+       dev_dbg(&dev->core, "%s\n", __func__);
+
+       spin_lock_irq(&priv->lock);
+       busy = !bio_list_empty(&priv->list);
+       bio_list_add(&priv->list, bio);
+       spin_unlock_irq(&priv->lock);
+
+       if (busy)
+               return 0;
+
+       do {
+               bio = ps3vram_do_bio(dev, bio);
+       } while (bio);
+
        return 0;
 }
 
@@ -604,8 +616,8 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
        int error, status;
        struct request_queue *queue;
        struct gendisk *gendisk;
-       u64 ddr_lpar, ctrl_lpar, info_lpar, reports_lpar, ddr_size,
-           reports_size;
+       u64 ddr_size, ddr_lpar, ctrl_lpar, info_lpar, reports_lpar,
+           reports_size, xdr_lpar;
        char *rest;
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
@@ -614,10 +626,9 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
                goto fail;
        }
 
-       mutex_init(&priv->lock);
-       dev->core.driver_data = priv;
-
-       priv = dev->core.driver_data;
+       spin_lock_init(&priv->lock);
+       bio_list_init(&priv->list);
+       ps3_system_bus_set_drvdata(dev, priv);
 
        /* Allocate XDR buffer (1MiB aligned) */
        priv->xdr_buf = (void *)__get_free_pages(GFP_KERNEL,
@@ -636,7 +647,7 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
        if (ps3_open_hv_device(dev)) {
                dev_err(&dev->core, "ps3_open_hv_device failed\n");
                error = -EAGAIN;
-               goto out_close_gpu;
+               goto out_free_xdr_buf;
        }
 
        /* Request memory */
@@ -660,7 +671,7 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
                dev_err(&dev->core, "lv1_gpu_memory_allocate failed %d\n",
                        status);
                error = -ENOMEM;
-               goto out_free_xdr_buf;
+               goto out_close_gpu;
        }
 
        /* Request context */
@@ -676,9 +687,11 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
        }
 
        /* Map XDR buffer to RSX */
+       xdr_lpar = ps3_mm_phys_to_lpar(__pa(priv->xdr_buf));
        status = lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF,
-                                      ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)),
-                                      XDR_BUF_SIZE, 0);
+                                      xdr_lpar, XDR_BUF_SIZE,
+                                      CBE_IOPTE_PP_W | CBE_IOPTE_PP_R |
+                                      CBE_IOPTE_M);
        if (status) {
                dev_err(&dev->core, "lv1_gpu_context_iomap failed %d\n",
                        status);
@@ -686,19 +699,11 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
                goto out_free_context;
        }
 
-       priv->ddr_base = ioremap_flags(ddr_lpar, ddr_size, _PAGE_NO_CACHE);
-
-       if (!priv->ddr_base) {
-               dev_err(&dev->core, "ioremap DDR failed\n");
-               error = -ENOMEM;
-               goto out_free_context;
-       }
-
        priv->ctrl = ioremap(ctrl_lpar, 64 * 1024);
        if (!priv->ctrl) {
                dev_err(&dev->core, "ioremap CTRL failed\n");
                error = -ENOMEM;
-               goto out_unmap_vram;
+               goto out_unmap_context;
        }
 
        priv->reports = ioremap(reports_lpar, reports_size);
@@ -775,8 +780,9 @@ out_unmap_reports:
        iounmap(priv->reports);
 out_unmap_ctrl:
        iounmap(priv->ctrl);
-out_unmap_vram:
-       iounmap(priv->ddr_base);
+out_unmap_context:
+       lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF, xdr_lpar,
+                             XDR_BUF_SIZE, CBE_IOPTE_M);
 out_free_context:
        lv1_gpu_context_free(priv->context_handle);
 out_free_memory:
@@ -787,14 +793,14 @@ out_free_xdr_buf:
        free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE));
 fail_free_priv:
        kfree(priv);
-       dev->core.driver_data = NULL;
+       ps3_system_bus_set_drvdata(dev, NULL);
 fail:
        return error;
 }
 
 static int ps3vram_remove(struct ps3_system_bus_device *dev)
 {
-       struct ps3vram_priv *priv = dev->core.driver_data;
+       struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
 
        del_gendisk(priv->gendisk);
        put_disk(priv->gendisk);
@@ -803,13 +809,15 @@ static int ps3vram_remove(struct ps3_system_bus_device *dev)
        ps3vram_cache_cleanup(dev);
        iounmap(priv->reports);
        iounmap(priv->ctrl);
-       iounmap(priv->ddr_base);
+       lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF,
+                             ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)),
+                             XDR_BUF_SIZE, CBE_IOPTE_M);
        lv1_gpu_context_free(priv->context_handle);
        lv1_gpu_memory_free(priv->memory_handle);
        ps3_close_hv_device(dev);
        free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE));
        kfree(priv);
-       dev->core.driver_data = NULL;
+       ps3_system_bus_set_drvdata(dev, NULL);
        return 0;
 }
 
index c1996829d5ecb92231042afd0cdc90ee7b4ad186..e53284767f7c9e59b89c6fe1611487526dee081c 100644 (file)
@@ -753,12 +753,12 @@ static int blkfront_probe(struct xenbus_device *dev,
 
        /* Front end dir is a number, which is used as the id. */
        info->handle = simple_strtoul(strrchr(dev->nodename, '/')+1, NULL, 0);
-       dev->dev.driver_data = info;
+       dev_set_drvdata(&dev->dev, info);
 
        err = talk_to_backend(dev, info);
        if (err) {
                kfree(info);
-               dev->dev.driver_data = NULL;
+               dev_set_drvdata(&dev->dev, NULL);
                return err;
        }
 
@@ -843,7 +843,7 @@ static int blkif_recover(struct blkfront_info *info)
  */
 static int blkfront_resume(struct xenbus_device *dev)
 {
-       struct blkfront_info *info = dev->dev.driver_data;
+       struct blkfront_info *info = dev_get_drvdata(&dev->dev);
        int err;
 
        dev_dbg(&dev->dev, "blkfront_resume: %s\n", dev->nodename);
@@ -922,7 +922,7 @@ static void blkfront_connect(struct blkfront_info *info)
  */
 static void blkfront_closing(struct xenbus_device *dev)
 {
-       struct blkfront_info *info = dev->dev.driver_data;
+       struct blkfront_info *info = dev_get_drvdata(&dev->dev);
        unsigned long flags;
 
        dev_dbg(&dev->dev, "blkfront_closing: %s removed\n", dev->nodename);
@@ -957,7 +957,7 @@ static void blkfront_closing(struct xenbus_device *dev)
 static void backend_changed(struct xenbus_device *dev,
                            enum xenbus_state backend_state)
 {
-       struct blkfront_info *info = dev->dev.driver_data;
+       struct blkfront_info *info = dev_get_drvdata(&dev->dev);
        struct block_device *bd;
 
        dev_dbg(&dev->dev, "blkfront:backend_changed.\n");
@@ -997,7 +997,7 @@ static void backend_changed(struct xenbus_device *dev,
 
 static int blkfront_remove(struct xenbus_device *dev)
 {
-       struct blkfront_info *info = dev->dev.driver_data;
+       struct blkfront_info *info = dev_get_drvdata(&dev->dev);
 
        dev_dbg(&dev->dev, "blkfront_remove: %s removed\n", dev->nodename);
 
@@ -1010,7 +1010,7 @@ static int blkfront_remove(struct xenbus_device *dev)
 
 static int blkfront_is_ready(struct xenbus_device *dev)
 {
-       struct blkfront_info *info = dev->dev.driver_data;
+       struct blkfront_info *info = dev_get_drvdata(&dev->dev);
 
        return info->is_ready;
 }
index 54481a8877699d40d22d3afceded64d70365cbe0..86105efb4eb6cb948314a69b3b754ffdc290771a 100644 (file)
@@ -4,7 +4,7 @@
  * This HVC device driver provides terminal access using
  * z/VM IUCV communication paths.
  *
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008, 2009
  *
  * Author(s):  Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
  */
@@ -15,6 +15,7 @@
 #include <asm/ebcdic.h>
 #include <linux/ctype.h>
 #include <linux/delay.h>
+#include <linux/device.h>
 #include <linux/init.h>
 #include <linux/mempool.h>
 #include <linux/moduleparam.h>
@@ -74,6 +75,7 @@ struct hvc_iucv_private {
        wait_queue_head_t       sndbuf_waitq;   /* wait for send completion */
        struct list_head        tty_outqueue;   /* outgoing IUCV messages */
        struct list_head        tty_inqueue;    /* incoming IUCV messages */
+       struct device           *dev;           /* device structure */
 };
 
 struct iucv_tty_buffer {
@@ -542,7 +544,68 @@ static void flush_sndbuf_sync(struct hvc_iucv_private *priv)
 
        if (sync_wait)
                wait_event_timeout(priv->sndbuf_waitq,
-                                  tty_outqueue_empty(priv), HZ);
+                                  tty_outqueue_empty(priv), HZ/10);
+}
+
+/**
+ * hvc_iucv_hangup() - Sever IUCV path and schedule hvc tty hang up
+ * @priv:      Pointer to hvc_iucv_private structure
+ *
+ * This routine severs an existing IUCV communication path and hangs
+ * up the underlying HVC terminal device.
+ * The hang-up occurs only if an IUCV communication path is established;
+ * otherwise there is no need to hang up the terminal device.
+ *
+ * The IUCV HVC hang-up is separated into two steps:
+ * 1. After the IUCV path has been severed, the iucv_state is set to
+ *    IUCV_SEVERED.
+ * 2. Later, when the HVC thread calls hvc_iucv_get_chars(), the
+ *    IUCV_SEVERED state causes the tty hang-up in the HVC layer.
+ *
+ * If the tty has not yet been opened, clean up the hvc_iucv_private
+ * structure to allow re-connects.
+ * If the tty has been opened, let get_chars() return -EPIPE to signal
+ * the HVC layer to hang up the tty and, if so, wake up the HVC thread
+ * to call get_chars()...
+ *
+ * Special notes on hanging up a HVC terminal instantiated as console:
+ * Hang-up:    1. do_tty_hangup() replaces file ops (= hung_up_tty_fops)
+ *             2. do_tty_hangup() calls tty->ops->close() for console_filp
+ *                     => no hangup notifier is called by HVC (default)
+ *             2. hvc_close() returns because of tty_hung_up_p(filp)
+ *                     => no delete notifier is called!
+ * Finally, the back-end is not being notified, thus, the tty session is
+ * kept active (TTY_OPEN) to be ready for re-connects.
+ *
+ * Locking:    spin_lock(&priv->lock) w/o disabling bh
+ */
+static void hvc_iucv_hangup(struct hvc_iucv_private *priv)
+{
+       struct iucv_path *path;
+
+       path = NULL;
+       spin_lock(&priv->lock);
+       if (priv->iucv_state == IUCV_CONNECTED) {
+               path = priv->path;
+               priv->path = NULL;
+               priv->iucv_state = IUCV_SEVERED;
+               if (priv->tty_state == TTY_CLOSED)
+                       hvc_iucv_cleanup(priv);
+               else
+                       /* console is special (see above) */
+                       if (priv->is_console) {
+                               hvc_iucv_cleanup(priv);
+                               priv->tty_state = TTY_OPENED;
+                       } else
+                               hvc_kick();
+       }
+       spin_unlock(&priv->lock);
+
+       /* finally sever path (outside of priv->lock due to lock ordering) */
+       if (path) {
+               iucv_path_sever(path, NULL);
+               iucv_path_free(path);
+       }
 }
 
 /**
@@ -735,11 +798,8 @@ out_path_handled:
  * @ipuser:    User specified data for this path
  *             (AF_IUCV: port/service name and originator port)
  *
- * The function also severs the path (as required by the IUCV protocol) and
- * sets the iucv state to IUCV_SEVERED for the associated struct
- * hvc_iucv_private instance. Later, the IUCV_SEVERED state triggers a tty
- * hangup (hvc_iucv_get_chars() / hvc_iucv_write()).
- * If tty portion of the HVC is closed, clean up the outqueue.
+ * This function calls the hvc_iucv_hangup() function for the
+ * respective IUCV HVC terminal.
  *
  * Locking:    struct hvc_iucv_private->lock
  */
@@ -747,33 +807,7 @@ static void hvc_iucv_path_severed(struct iucv_path *path, u8 ipuser[16])
 {
        struct hvc_iucv_private *priv = path->private;
 
-       spin_lock(&priv->lock);
-       priv->iucv_state = IUCV_SEVERED;
-
-       /* If the tty has not yet been opened, clean up the hvc_iucv_private
-        * structure to allow re-connects.
-        * This is also done for our console device because console hangups
-        * are handled specially and no notifier is called by HVC.
-        * The tty session is active (TTY_OPEN) and ready for re-connects...
-        *
-        * If it has been opened, let get_chars() return -EPIPE to signal the
-        * HVC layer to hang up the tty.
-        * If so, we need to wake up the HVC thread to call get_chars()...
-        */
-       priv->path = NULL;
-       if (priv->tty_state == TTY_CLOSED)
-               hvc_iucv_cleanup(priv);
-       else
-               if (priv->is_console) {
-                       hvc_iucv_cleanup(priv);
-                       priv->tty_state = TTY_OPENED;
-               } else
-                       hvc_kick();
-       spin_unlock(&priv->lock);
-
-       /* finally sever path (outside of priv->lock due to lock ordering) */
-       iucv_path_sever(path, ipuser);
-       iucv_path_free(path);
+       hvc_iucv_hangup(priv);
 }
 
 /**
@@ -853,6 +887,37 @@ static void hvc_iucv_msg_complete(struct iucv_path *path,
        destroy_tty_buffer_list(&list_remove);
 }
 
+/**
+ * hvc_iucv_pm_freeze() - Freeze PM callback
+ * @dev:       IUVC HVC terminal device
+ *
+ * Sever an established IUCV communication path and
+ * trigger a hang-up of the underlying HVC terminal.
+ */
+static int hvc_iucv_pm_freeze(struct device *dev)
+{
+       struct hvc_iucv_private *priv = dev_get_drvdata(dev);
+
+       local_bh_disable();
+       hvc_iucv_hangup(priv);
+       local_bh_enable();
+
+       return 0;
+}
+
+/**
+ * hvc_iucv_pm_restore_thaw() - Thaw and restore PM callback
+ * @dev:       IUVC HVC terminal device
+ *
+ * Wake up the HVC thread to trigger hang-up and respective
+ * HVC back-end notifier invocations.
+ */
+static int hvc_iucv_pm_restore_thaw(struct device *dev)
+{
+       hvc_kick();
+       return 0;
+}
+
 
 /* HVC operations */
 static struct hv_ops hvc_iucv_ops = {
@@ -863,6 +928,20 @@ static struct hv_ops hvc_iucv_ops = {
        .notifier_hangup = hvc_iucv_notifier_hangup,
 };
 
+/* Suspend / resume device operations */
+static struct dev_pm_ops hvc_iucv_pm_ops = {
+       .freeze   = hvc_iucv_pm_freeze,
+       .thaw     = hvc_iucv_pm_restore_thaw,
+       .restore  = hvc_iucv_pm_restore_thaw,
+};
+
+/* IUCV HVC device driver */
+static struct device_driver hvc_iucv_driver = {
+       .name = KMSG_COMPONENT,
+       .bus  = &iucv_bus,
+       .pm   = &hvc_iucv_pm_ops,
+};
+
 /**
  * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance
  * @id:                        hvc_iucv_table index
@@ -897,14 +976,12 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console)
        /* set console flag */
        priv->is_console = is_console;
 
-       /* finally allocate hvc */
+       /* allocate hvc device */
        priv->hvc = hvc_alloc(HVC_IUCV_MAGIC + id, /*             PAGE_SIZE */
                              HVC_IUCV_MAGIC + id, &hvc_iucv_ops, 256);
        if (IS_ERR(priv->hvc)) {
                rc = PTR_ERR(priv->hvc);
-               free_page((unsigned long) priv->sndbuf);
-               kfree(priv);
-               return rc;
+               goto out_error_hvc;
        }
 
        /* notify HVC thread instead of using polling */
@@ -915,8 +992,45 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console)
        memcpy(priv->srv_name, name, 8);
        ASCEBC(priv->srv_name, 8);
 
+       /* create and setup device */
+       priv->dev = kzalloc(sizeof(*priv->dev), GFP_KERNEL);
+       if (!priv->dev) {
+               rc = -ENOMEM;
+               goto out_error_dev;
+       }
+       dev_set_name(priv->dev, "hvc_iucv%d", id);
+       dev_set_drvdata(priv->dev, priv);
+       priv->dev->bus = &iucv_bus;
+       priv->dev->parent = iucv_root;
+       priv->dev->driver = &hvc_iucv_driver;
+       priv->dev->release = (void (*)(struct device *)) kfree;
+       rc = device_register(priv->dev);
+       if (rc) {
+               kfree(priv->dev);
+               goto out_error_dev;
+       }
+
        hvc_iucv_table[id] = priv;
        return 0;
+
+out_error_dev:
+       hvc_remove(priv->hvc);
+out_error_hvc:
+       free_page((unsigned long) priv->sndbuf);
+       kfree(priv);
+
+       return rc;
+}
+
+/**
+ * hvc_iucv_destroy() - Destroy and free hvc_iucv_private instances
+ */
+static void __init hvc_iucv_destroy(struct hvc_iucv_private *priv)
+{
+       hvc_remove(priv->hvc);
+       device_unregister(priv->dev);
+       free_page((unsigned long) priv->sndbuf);
+       kfree(priv);
 }
 
 /**
@@ -1109,6 +1223,11 @@ static int __init hvc_iucv_init(void)
                goto out_error;
        }
 
+       /* register IUCV HVC device driver */
+       rc = driver_register(&hvc_iucv_driver);
+       if (rc)
+               goto out_error;
+
        /* parse hvc_iucv_allow string and create z/VM user ID filter list */
        if (hvc_iucv_filter_string) {
                rc = hvc_iucv_setup_filter(hvc_iucv_filter_string);
@@ -1183,15 +1302,14 @@ out_error_iucv:
        iucv_unregister(&hvc_iucv_handler, 0);
 out_error_hvc:
        for (i = 0; i < hvc_iucv_devices; i++)
-               if (hvc_iucv_table[i]) {
-                       if (hvc_iucv_table[i]->hvc)
-                               hvc_remove(hvc_iucv_table[i]->hvc);
-                       kfree(hvc_iucv_table[i]);
-               }
+               if (hvc_iucv_table[i])
+                       hvc_iucv_destroy(hvc_iucv_table[i]);
 out_error_memory:
        mempool_destroy(hvc_iucv_mempool);
        kmem_cache_destroy(hvc_iucv_buffer_cache);
 out_error:
+       if (hvc_iucv_filter)
+               kfree(hvc_iucv_filter);
        hvc_iucv_devices = 0; /* ensure that we do not provide any device */
        return rc;
 }
index c76bccf5354dc77f1b97bdb3ea22266d8154faa5..7d64e4230e661ebaac5aeff1383c6967cf963f7b 100644 (file)
@@ -347,7 +347,7 @@ static void __exit hvcs_module_exit(void);
 
 static inline struct hvcs_struct *from_vio_dev(struct vio_dev *viod)
 {
-       return viod->dev.driver_data;
+       return dev_get_drvdata(&viod->dev);
 }
 /* The sysfs interface for the driver and devices */
 
@@ -785,7 +785,7 @@ static int __devinit hvcs_probe(
        kref_init(&hvcsd->kref);
 
        hvcsd->vdev = dev;
-       dev->dev.driver_data = hvcsd;
+       dev_set_drvdata(&dev->dev, hvcsd);
 
        hvcsd->index = index;
 
@@ -831,7 +831,7 @@ static int __devinit hvcs_probe(
 
 static int __devexit hvcs_remove(struct vio_dev *dev)
 {
-       struct hvcs_struct *hvcsd = dev->dev.driver_data;
+       struct hvcs_struct *hvcsd = dev_get_drvdata(&dev->dev);
        unsigned long flags;
        struct tty_struct *tty;
 
index e5d583c84e4f864ae31cb95534bd5befe6291ed6..fc93e2fc7c71220d02e31acbaf67d40eda7b3133 100644 (file)
@@ -153,6 +153,7 @@ static const struct file_operations rng_chrdev_ops = {
 static struct miscdevice rng_miscdev = {
        .minor          = RNG_MISCDEV_MINOR,
        .name           = RNG_MODULE_NAME,
+       .devnode        = "hwrng",
        .fops           = &rng_chrdev_ops,
 };
 
index 259644646b82e88ea2f120b1f73eb3563c627aa4..d2e698096ace182698152e2366d7c2dc2cf91342 100644 (file)
@@ -2375,14 +2375,14 @@ static int __devinit ipmi_of_probe(struct of_device *dev,
                info->io.addr_data, info->io.regsize, info->io.regspacing,
                info->irq);
 
-       dev->dev.driver_data = (void *) info;
+       dev_set_drvdata(&dev->dev, info);
 
        return try_smi_init(info);
 }
 
 static int __devexit ipmi_of_remove(struct of_device *dev)
 {
-       cleanup_one_si(dev->dev.driver_data);
+       cleanup_one_si(dev_get_drvdata(&dev->dev));
        return 0;
 }
 
index a5e0db9d7662d4a060ff167260753b193a64ee9f..62c99fa59e2b5bf09ee792652648eab4760f37bc 100644 (file)
@@ -168,7 +168,6 @@ static const struct file_operations misc_fops = {
        .open           = misc_open,
 };
 
-
 /**
  *     misc_register   -       register a miscellaneous device
  *     @misc: device structure
@@ -217,8 +216,8 @@ int misc_register(struct miscdevice * misc)
                misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7);
        dev = MKDEV(MISC_MAJOR, misc->minor);
 
-       misc->this_device = device_create(misc_class, misc->parent, dev, NULL,
-                                         "%s", misc->name);
+       misc->this_device = device_create(misc_class, misc->parent, dev,
+                                         misc, "%s", misc->name);
        if (IS_ERR(misc->this_device)) {
                err = PTR_ERR(misc->this_device);
                goto out;
@@ -264,6 +263,15 @@ int misc_deregister(struct miscdevice *misc)
 EXPORT_SYMBOL(misc_register);
 EXPORT_SYMBOL(misc_deregister);
 
+static char *misc_nodename(struct device *dev)
+{
+       struct miscdevice *c = dev_get_drvdata(dev);
+
+       if (c->devnode)
+               return kstrdup(c->devnode, GFP_KERNEL);
+       return NULL;
+}
+
 static int __init misc_init(void)
 {
        int err;
@@ -279,6 +287,7 @@ static int __init misc_init(void)
        err = -EIO;
        if (register_chrdev(MISC_MAJOR,"misc",&misc_fops))
                goto fail_printk;
+       misc_class->nodename = misc_nodename;
        return 0;
 
 fail_printk:
index afbe45676d71c8f064e5102b0e8460dbde0119a3..f424d394a286415e82c8aafdc634073f916f6521 100644 (file)
 
 struct ps3flash_private {
        struct mutex mutex;     /* Bounce buffer mutex */
+       u64 chunk_sectors;
+       int tag;                /* Start sector of buffer, -1 if invalid */
+       bool dirty;
 };
 
 static struct ps3_storage_device *ps3flash_dev;
 
-static ssize_t ps3flash_read_write_sectors(struct ps3_storage_device *dev,
-                                          u64 lpar, u64 start_sector,
-                                          u64 sectors, int write)
+static int ps3flash_read_write_sectors(struct ps3_storage_device *dev,
+                                      u64 start_sector, int write)
 {
-       u64 res = ps3stor_read_write_sectors(dev, lpar, start_sector, sectors,
+       struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
+       u64 res = ps3stor_read_write_sectors(dev, dev->bounce_lpar,
+                                            start_sector, priv->chunk_sectors,
                                             write);
        if (res) {
                dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__,
                        __LINE__, write ? "write" : "read", res);
                return -EIO;
        }
-       return sectors;
+       return 0;
 }
 
-static ssize_t ps3flash_read_sectors(struct ps3_storage_device *dev,
-                                    u64 start_sector, u64 sectors,
-                                    unsigned int sector_offset)
+static int ps3flash_writeback(struct ps3_storage_device *dev)
 {
-       u64 max_sectors, lpar;
+       struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
+       int res;
 
-       max_sectors = dev->bounce_size / dev->blk_size;
-       if (sectors > max_sectors) {
-               dev_dbg(&dev->sbd.core, "%s:%u Limiting sectors to %llu\n",
-                       __func__, __LINE__, max_sectors);
-               sectors = max_sectors;
-       }
+       if (!priv->dirty || priv->tag < 0)
+               return 0;
 
-       lpar = dev->bounce_lpar + sector_offset * dev->blk_size;
-       return ps3flash_read_write_sectors(dev, lpar, start_sector, sectors,
-                                          0);
+       res = ps3flash_read_write_sectors(dev, priv->tag, 1);
+       if (res)
+               return res;
+
+       priv->dirty = false;
+       return 0;
 }
 
-static ssize_t ps3flash_write_chunk(struct ps3_storage_device *dev,
-                                   u64 start_sector)
+static int ps3flash_fetch(struct ps3_storage_device *dev, u64 start_sector)
 {
-       u64 sectors = dev->bounce_size / dev->blk_size;
-       return ps3flash_read_write_sectors(dev, dev->bounce_lpar, start_sector,
-                                         sectors, 1);
+       struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
+       int res;
+
+       if (start_sector == priv->tag)
+               return 0;
+
+       res = ps3flash_writeback(dev);
+       if (res)
+               return res;
+
+       priv->tag = -1;
+
+       res = ps3flash_read_write_sectors(dev, start_sector, 0);
+       if (res)
+               return res;
+
+       priv->tag = start_sector;
+       return 0;
 }
 
 static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin)
@@ -104,18 +120,19 @@ out:
        return res;
 }
 
-static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count,
-                            loff_t *pos)
+static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf,
+                            size_t count, loff_t *pos)
 {
        struct ps3_storage_device *dev = ps3flash_dev;
-       struct ps3flash_private *priv = dev->sbd.core.driver_data;
-       u64 size, start_sector, end_sector, offset;
-       ssize_t sectors_read;
+       struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
+       u64 size, sector, offset;
+       int res;
        size_t remaining, n;
+       const void *src;
 
        dev_dbg(&dev->sbd.core,
-               "%s:%u: Reading %zu bytes at position %lld to user 0x%p\n",
-               __func__, __LINE__, count, *pos, buf);
+               "%s:%u: Reading %zu bytes at position %lld to U0x%p/K0x%p\n",
+               __func__, __LINE__, count, *pos, userbuf, kernelbuf);
 
        size = dev->regions[dev->region_idx].size*dev->blk_size;
        if (*pos >= size || !count)
@@ -128,61 +145,63 @@ static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count,
                count = size - *pos;
        }
 
-       start_sector = *pos / dev->blk_size;
-       offset = *pos % dev->blk_size;
-       end_sector = DIV_ROUND_UP(*pos + count, dev->blk_size);
+       sector = *pos / dev->bounce_size * priv->chunk_sectors;
+       offset = *pos % dev->bounce_size;
 
        remaining = count;
        do {
+               n = min_t(u64, remaining, dev->bounce_size - offset);
+               src = dev->bounce_buf + offset;
+
                mutex_lock(&priv->mutex);
 
-               sectors_read = ps3flash_read_sectors(dev, start_sector,
-                                                    end_sector-start_sector,
-                                                    0);
-               if (sectors_read < 0) {
-                       mutex_unlock(&priv->mutex);
+               res = ps3flash_fetch(dev, sector);
+               if (res)
                        goto fail;
-               }
 
-               n = min_t(u64, remaining, sectors_read*dev->blk_size-offset);
                dev_dbg(&dev->sbd.core,
-                       "%s:%u: copy %lu bytes from 0x%p to user 0x%p\n",
-                       __func__, __LINE__, n, dev->bounce_buf+offset, buf);
-               if (copy_to_user(buf, dev->bounce_buf+offset, n)) {
-                       mutex_unlock(&priv->mutex);
-                       sectors_read = -EFAULT;
-                       goto fail;
+                       "%s:%u: copy %lu bytes from 0x%p to U0x%p/K0x%p\n",
+                       __func__, __LINE__, n, src, userbuf, kernelbuf);
+               if (userbuf) {
+                       if (copy_to_user(userbuf, src, n)) {
+                               res = -EFAULT;
+                               goto fail;
+                       }
+                       userbuf += n;
+               }
+               if (kernelbuf) {
+                       memcpy(kernelbuf, src, n);
+                       kernelbuf += n;
                }
 
                mutex_unlock(&priv->mutex);
 
                *pos += n;
-               buf += n;
                remaining -= n;
-               start_sector += sectors_read;
+               sector += priv->chunk_sectors;
                offset = 0;
        } while (remaining > 0);
 
        return count;
 
 fail:
-       return sectors_read;
+       mutex_unlock(&priv->mutex);
+       return res;
 }
 
-static ssize_t ps3flash_write(struct file *file, const char __user *buf,
-                             size_t count, loff_t *pos)
+static ssize_t ps3flash_write(const char __user *userbuf,
+                             const void *kernelbuf, size_t count, loff_t *pos)
 {
        struct ps3_storage_device *dev = ps3flash_dev;
-       struct ps3flash_private *priv = dev->sbd.core.driver_data;
-       u64 size, chunk_sectors, start_write_sector, end_write_sector,
-           end_read_sector, start_read_sector, head, tail, offset;
-       ssize_t res;
+       struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
+       u64 size, sector, offset;
+       int res = 0;
        size_t remaining, n;
-       unsigned int sec_off;
+       void *dst;
 
        dev_dbg(&dev->sbd.core,
-               "%s:%u: Writing %zu bytes at position %lld from user 0x%p\n",
-               __func__, __LINE__, count, *pos, buf);
+               "%s:%u: Writing %zu bytes at position %lld from U0x%p/K0x%p\n",
+               __func__, __LINE__, count, *pos, userbuf, kernelbuf);
 
        size = dev->regions[dev->region_idx].size*dev->blk_size;
        if (*pos >= size || !count)
@@ -195,89 +214,46 @@ static ssize_t ps3flash_write(struct file *file, const char __user *buf,
                count = size - *pos;
        }
 
-       chunk_sectors = dev->bounce_size / dev->blk_size;
-
-       start_write_sector = *pos / dev->bounce_size * chunk_sectors;
+       sector = *pos / dev->bounce_size * priv->chunk_sectors;
        offset = *pos % dev->bounce_size;
-       end_write_sector = DIV_ROUND_UP(*pos + count, dev->bounce_size) *
-                          chunk_sectors;
-
-       end_read_sector = DIV_ROUND_UP(*pos, dev->blk_size);
-       start_read_sector = (*pos + count) / dev->blk_size;
-
-       /*
-        * As we have to write in 256 KiB chunks, while we can read in blk_size
-        * (usually 512 bytes) chunks, we perform the following steps:
-        *   1. Read from start_write_sector to end_read_sector ("head")
-        *   2. Read from start_read_sector to end_write_sector ("tail")
-        *   3. Copy data to buffer
-        *   4. Write from start_write_sector to end_write_sector
-        * All of this is complicated by using only one 256 KiB bounce buffer.
-        */
-
-       head = end_read_sector - start_write_sector;
-       tail = end_write_sector - start_read_sector;
 
        remaining = count;
        do {
+               n = min_t(u64, remaining, dev->bounce_size - offset);
+               dst = dev->bounce_buf + offset;
+
                mutex_lock(&priv->mutex);
 
-               if (end_read_sector >= start_read_sector) {
-                       /* Merge head and tail */
-                       dev_dbg(&dev->sbd.core,
-                               "Merged head and tail: %llu sectors at %llu\n",
-                               chunk_sectors, start_write_sector);
-                       res = ps3flash_read_sectors(dev, start_write_sector,
-                                                   chunk_sectors, 0);
-                       if (res < 0)
+               if (n != dev->bounce_size)
+                       res = ps3flash_fetch(dev, sector);
+               else if (sector != priv->tag)
+                       res = ps3flash_writeback(dev);
+               if (res)
+                       goto fail;
+
+               dev_dbg(&dev->sbd.core,
+                       "%s:%u: copy %lu bytes from U0x%p/K0x%p to 0x%p\n",
+                       __func__, __LINE__, n, userbuf, kernelbuf, dst);
+               if (userbuf) {
+                       if (copy_from_user(dst, userbuf, n)) {
+                               res = -EFAULT;
                                goto fail;
-               } else {
-                       if (head) {
-                               /* Read head */
-                               dev_dbg(&dev->sbd.core,
-                                       "head: %llu sectors at %llu\n", head,
-                                       start_write_sector);
-                               res = ps3flash_read_sectors(dev,
-                                                           start_write_sector,
-                                                           head, 0);
-                               if (res < 0)
-                                       goto fail;
-                       }
-                       if (start_read_sector <
-                           start_write_sector+chunk_sectors) {
-                               /* Read tail */
-                               dev_dbg(&dev->sbd.core,
-                                       "tail: %llu sectors at %llu\n", tail,
-                                       start_read_sector);
-                               sec_off = start_read_sector-start_write_sector;
-                               res = ps3flash_read_sectors(dev,
-                                                           start_read_sector,
-                                                           tail, sec_off);
-                               if (res < 0)
-                                       goto fail;
                        }
+                       userbuf += n;
                }
-
-               n = min_t(u64, remaining, dev->bounce_size-offset);
-               dev_dbg(&dev->sbd.core,
-                       "%s:%u: copy %lu bytes from user 0x%p to 0x%p\n",
-                       __func__, __LINE__, n, buf, dev->bounce_buf+offset);
-               if (copy_from_user(dev->bounce_buf+offset, buf, n)) {
-                       res = -EFAULT;
-                       goto fail;
+               if (kernelbuf) {
+                       memcpy(dst, kernelbuf, n);
+                       kernelbuf += n;
                }
 
-               res = ps3flash_write_chunk(dev, start_write_sector);
-               if (res < 0)
-                       goto fail;
+               priv->tag = sector;
+               priv->dirty = true;
 
                mutex_unlock(&priv->mutex);
 
                *pos += n;
-               buf += n;
                remaining -= n;
-               start_write_sector += chunk_sectors;
-               head = 0;
+               sector += priv->chunk_sectors;
                offset = 0;
        } while (remaining > 0);
 
@@ -288,6 +264,51 @@ fail:
        return res;
 }
 
+static ssize_t ps3flash_user_read(struct file *file, char __user *buf,
+                                 size_t count, loff_t *pos)
+{
+       return ps3flash_read(buf, NULL, count, pos);
+}
+
+static ssize_t ps3flash_user_write(struct file *file, const char __user *buf,
+                                  size_t count, loff_t *pos)
+{
+       return ps3flash_write(buf, NULL, count, pos);
+}
+
+static ssize_t ps3flash_kernel_read(void *buf, size_t count, loff_t pos)
+{
+       return ps3flash_read(NULL, buf, count, &pos);
+}
+
+static ssize_t ps3flash_kernel_write(const void *buf, size_t count,
+                                    loff_t pos)
+{
+       ssize_t res;
+       int wb;
+
+       res = ps3flash_write(NULL, buf, count, &pos);
+       if (res < 0)
+               return res;
+
+       /* Make kernel writes synchronous */
+       wb = ps3flash_writeback(ps3flash_dev);
+       if (wb)
+               return wb;
+
+       return res;
+}
+
+static int ps3flash_flush(struct file *file, fl_owner_t id)
+{
+       return ps3flash_writeback(ps3flash_dev);
+}
+
+static int ps3flash_fsync(struct file *file, struct dentry *dentry,
+                         int datasync)
+{
+       return ps3flash_writeback(ps3flash_dev);
+}
 
 static irqreturn_t ps3flash_interrupt(int irq, void *data)
 {
@@ -312,12 +333,18 @@ static irqreturn_t ps3flash_interrupt(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-
 static const struct file_operations ps3flash_fops = {
        .owner  = THIS_MODULE,
        .llseek = ps3flash_llseek,
-       .read   = ps3flash_read,
-       .write  = ps3flash_write,
+       .read   = ps3flash_user_read,
+       .write  = ps3flash_user_write,
+       .flush  = ps3flash_flush,
+       .fsync  = ps3flash_fsync,
+};
+
+static const struct ps3_os_area_flash_ops ps3flash_kernel_ops = {
+       .read   = ps3flash_kernel_read,
+       .write  = ps3flash_kernel_write,
 };
 
 static struct miscdevice ps3flash_misc = {
@@ -366,11 +393,13 @@ static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev)
                goto fail;
        }
 
-       dev->sbd.core.driver_data = priv;
+       ps3_system_bus_set_drvdata(&dev->sbd, priv);
        mutex_init(&priv->mutex);
+       priv->tag = -1;
 
        dev->bounce_size = ps3flash_bounce_buffer.size;
        dev->bounce_buf = ps3flash_bounce_buffer.address;
+       priv->chunk_sectors = dev->bounce_size / dev->blk_size;
 
        error = ps3stor_setup(dev, ps3flash_interrupt);
        if (error)
@@ -386,13 +415,15 @@ static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev)
 
        dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n",
                 __func__, __LINE__, ps3flash_misc.minor);
+
+       ps3_os_area_flash_register(&ps3flash_kernel_ops);
        return 0;
 
 fail_teardown:
        ps3stor_teardown(dev);
 fail_free_priv:
        kfree(priv);
-       dev->sbd.core.driver_data = NULL;
+       ps3_system_bus_set_drvdata(&dev->sbd, NULL);
 fail:
        ps3flash_dev = NULL;
        return error;
@@ -402,10 +433,11 @@ static int ps3flash_remove(struct ps3_system_bus_device *_dev)
 {
        struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
 
+       ps3_os_area_flash_register(NULL);
        misc_deregister(&ps3flash_misc);
        ps3stor_teardown(dev);
-       kfree(dev->sbd.core.driver_data);
-       dev->sbd.core.driver_data = NULL;
+       kfree(ps3_system_bus_get_drvdata(&dev->sbd));
+       ps3_system_bus_set_drvdata(&dev->sbd, NULL);
        ps3flash_dev = NULL;
        return 0;
 }
index 5acd29e6e0430ee6bc16f3b4757a4fc76eb5cc06..daebe1ba43d42ad0f3a4053cea80e6c411e8968a 100644 (file)
@@ -95,23 +95,34 @@ static void pty_unthrottle(struct tty_struct *tty)
  * a count.
  *
  * FIXME: Our pty_write method is called with our ldisc lock held but
- * not our partners. We can't just take the other one blindly without
- * risking deadlocks.
+ * not our partners. We can't just wait on the other one blindly without
+ * risking deadlocks. At some point when everything has settled down we need
+ * to look into making pty_write at least able to sleep over an ldisc change.
+ *
+ * The return on no ldisc is a bit counter intuitive but the logic works
+ * like this. During an ldisc change the other end will flush its buffers. We
+ * thus return the full length which is identical to the case where we had
+ * proper locking and happened to queue the bytes just before the flush during
+ * the ldisc change.
  */
 static int pty_write(struct tty_struct *tty, const unsigned char *buf,
                                                                int count)
 {
        struct tty_struct *to = tty->link;
-       int     c;
+       struct tty_ldisc *ld;
+       int c = count;
 
        if (!to || tty->stopped)
                return 0;
-
-       c = to->receive_room;
-       if (c > count)
-               c = count;
-       to->ldisc->ops->receive_buf(to, buf, NULL, c);
-
+       ld = tty_ldisc_ref(to);
+
+       if (ld) {
+               c = to->receive_room;
+               if (c > count)
+                       c = count;
+               ld->ops->receive_buf(to, buf, NULL, c);
+               tty_ldisc_deref(ld);
+       }
        return c;
 }
 
@@ -145,14 +156,23 @@ static int pty_write_room(struct tty_struct *tty)
 static int pty_chars_in_buffer(struct tty_struct *tty)
 {
        struct tty_struct *to = tty->link;
-       int count;
+       struct tty_ldisc *ld;
+       int count = 0;
 
        /* We should get the line discipline lock for "tty->link" */
-       if (!to || !to->ldisc->ops->chars_in_buffer)
+       if (!to)
+               return 0;
+       /* We cannot take a sleeping reference here without deadlocking with
+          an ldisc change - but it doesn't really matter */
+       ld = tty_ldisc_ref(to);
+       if (ld == NULL)
                return 0;
 
        /* The ldisc must report 0 if no characters available to be read */
-       count = to->ldisc->ops->chars_in_buffer(to);
+       if (ld->ops->chars_in_buffer)
+               count = ld->ops->chars_in_buffer(to);
+
+       tty_ldisc_deref(ld);
 
        if (tty->driver->subtype == PTY_TYPE_SLAVE)
                return count;
@@ -182,12 +202,19 @@ static void pty_flush_buffer(struct tty_struct *tty)
 {
        struct tty_struct *to = tty->link;
        unsigned long flags;
+       struct tty_ldisc *ld;
 
        if (!to)
                return;
+       ld = tty_ldisc_ref(to);
+
+       /* The other end is changing discipline */
+       if (!ld)
+               return;
 
-       if (to->ldisc->ops->flush_buffer)
+       if (ld->ops->flush_buffer)
                to->ldisc->ops->flush_buffer(to);
+       tty_ldisc_deref(ld);
 
        if (to->packet) {
                spin_lock_irqsave(&tty->ctrl_lock, flags);
index db32f0e4c7dd48aaef0f1022627a4bebaded6f39..05f9d18b9361227e7cff39946e2d3de41faf8609 100644 (file)
@@ -261,6 +261,11 @@ static const struct file_operations raw_ctl_fops = {
 
 static struct cdev raw_cdev;
 
+static char *raw_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "raw/%s", dev_name(dev));
+}
+
 static int __init raw_init(void)
 {
        dev_t dev = MKDEV(RAW_MAJOR, 0);
@@ -284,6 +289,7 @@ static int __init raw_init(void)
                ret = PTR_ERR(raw_class);
                goto error_region;
        }
+       raw_class->nodename = raw_nodename;
        device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), NULL, "rawctl");
 
        return 0;
index 939e198d7670adfdad2068b4036a8d9348779444..a3afa0c387cdeb79c9dc9a406eb70935ceaf50d4 100644 (file)
@@ -1263,7 +1263,9 @@ static int tty_reopen(struct tty_struct *tty)
        tty->count++;
        tty->driver = driver; /* N.B. why do this every time?? */
 
+       mutex_lock(&tty->ldisc_mutex);
        WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
+       mutex_unlock(&tty->ldisc_mutex);
 
        return 0;
 }
index 8116bb1c8f801c505816b0eec531bed441ff0842..b24f6c6a1ea317c1ccf399eaf2842f281175d70d 100644 (file)
@@ -947,7 +947,6 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
        void __user *p = (void __user *)arg;
        int ret = 0;
        struct ktermios kterm;
-       struct termiox ktermx;
 
        if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
            tty->driver->subtype == PTY_TYPE_MASTER)
@@ -1049,7 +1048,8 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
                return ret;
 #endif
 #ifdef TCGETX
-       case TCGETX:
+       case TCGETX: {
+               struct termiox ktermx;
                if (real_tty->termiox == NULL)
                        return -EINVAL;
                mutex_lock(&real_tty->termios_mutex);
@@ -1058,6 +1058,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
                if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
                        ret = -EFAULT;
                return ret;
+       }
        case TCSETX:
                return set_termiox(real_tty, p, 0);
        case TCSETXW:
index 39c8f86dedd49c9e60ebe1e4e218225416bf0375..a19e935847b0a14e9740184e32d6e099efc26955 100644 (file)
@@ -148,8 +148,10 @@ static struct tty_ldisc *tty_ldisc_try_get(int disc)
                }
        }
        spin_unlock_irqrestore(&tty_ldisc_lock, flags);
-       if (err)
+       if (err) {
+               kfree(ld);
                return ERR_PTR(err);
+       }
        return ld;
 }
 
@@ -205,6 +207,7 @@ static void tty_ldisc_put(struct tty_ldisc *ld)
        ldo->refcount--;
        module_put(ldo->owner);
        spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+       WARN_ON(ld->refcount);
        kfree(ld);
 }
 
@@ -262,7 +265,7 @@ const struct file_operations tty_ldiscs_proc_fops = {
  *     @ld: line discipline
  *
  *     Install an instance of a line discipline into a tty structure. The
- *     ldisc must have a reference count above zero to ensure it remains/
+ *     ldisc must have a reference count above zero to ensure it remains.
  *     The tty instance refcount starts at zero.
  *
  *     Locking:
@@ -791,6 +794,8 @@ void tty_ldisc_hangup(struct tty_struct *tty)
                /* Avoid racing set_ldisc */
                mutex_lock(&tty->ldisc_mutex);
                /* Switch back to N_TTY */
+               tty_ldisc_halt(tty);
+               tty_ldisc_wait_idle(tty);
                tty_ldisc_reinit(tty);
                /* At this point we have a closed ldisc and we want to
                   reopen it. We could defer this to the next open but
index c796a86ab7f36bbff85998425b31d78fb2417d32..d9113b4c76e370bad289b19558958448846a6064 100644 (file)
@@ -171,8 +171,9 @@ int do_poke_blanked_console;
 int console_blanked;
 
 static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
-static int blankinterval = 10*60*HZ;
 static int vesa_off_interval;
+static int blankinterval = 10*60;
+core_param(consoleblank, blankinterval, int, 0444);
 
 static DECLARE_WORK(console_work, console_callback);
 
@@ -1485,7 +1486,7 @@ static void setterm_command(struct vc_data *vc)
                        update_attr(vc);
                        break;
                case 9: /* set blanking interval */
-                       blankinterval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60 * HZ;
+                       blankinterval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60;
                        poke_blanked_console();
                        break;
                case 10: /* set bell frequency in Hz */
@@ -2871,7 +2872,7 @@ static int __init con_init(void)
 
        if (blankinterval) {
                blank_state = blank_normal_wait;
-               mod_timer(&console_timer, jiffies + blankinterval);
+               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
        }
 
        for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
@@ -3677,7 +3678,7 @@ void do_unblank_screen(int leaving_gfx)
                return; /* but leave console_blanked != 0 */
 
        if (blankinterval) {
-               mod_timer(&console_timer, jiffies + blankinterval);
+               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
                blank_state = blank_normal_wait;
        }
 
@@ -3711,7 +3712,7 @@ void unblank_screen(void)
 static void blank_screen_t(unsigned long dummy)
 {
        if (unlikely(!keventd_up())) {
-               mod_timer(&console_timer, jiffies + blankinterval);
+               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
                return;
        }
        blank_timer_expired = 1;
@@ -3741,7 +3742,7 @@ void poke_blanked_console(void)
        if (console_blanked)
                unblank_screen();
        else if (blankinterval) {
-               mod_timer(&console_timer, jiffies + blankinterval);
+               mod_timer(&console_timer, jiffies + (blankinterval * HZ));
                blank_state = blank_normal_wait;
        }
 }
index 40bd8c61c7d7c5ead10f794ad52b1250bf9e33bd..72a633a6ec982e74153235e8f015ddba65d84af4 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <linux/acpi_pmtmr.h>
 #include <linux/clocksource.h>
+#include <linux/timex.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/pci.h>
index cf56a2af5fe111b3cbb15db3a1edb27a23d207de..2964f5f4a7ef3348104044f008992d22b08b55b1 100644 (file)
@@ -184,6 +184,9 @@ static void sh_cmt_disable(struct sh_cmt_priv *p)
        /* disable channel */
        sh_cmt_start_stop_ch(p, 0);
 
+       /* disable interrupts in CMT block */
+       sh_cmt_write(p, CMCSR, 0);
+
        /* stop clock */
        clk_disable(p->clk);
 }
@@ -599,7 +602,6 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
        p->irqaction.handler = sh_cmt_interrupt;
        p->irqaction.dev_id = p;
        p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL;
-       p->irqaction.mask = CPU_MASK_NONE;
        ret = setup_irq(irq, &p->irqaction);
        if (ret) {
                pr_err("sh_cmt: failed to request irq %d\n", irq);
index d1ae75454d10ef111f71c3b24e9e5b15ff83df8d..973e714d605147d7e2110eaae48a25b780d32bc7 100644 (file)
@@ -283,7 +283,6 @@ static int sh_mtu2_setup(struct sh_mtu2_priv *p, struct platform_device *pdev)
        p->irqaction.dev_id = p;
        p->irqaction.irq = irq;
        p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL;
-       p->irqaction.mask = CPU_MASK_NONE;
 
        /* get hold of clock */
        p->clk = clk_get(&p->pdev->dev, cfg->clk);
index d6ea4398bf6237782a333e46163d5be75cfbb02c..9ffb05f4095d7598c6b8fc8e37bc55cae96ae2b6 100644 (file)
@@ -138,6 +138,9 @@ static void sh_tmu_disable(struct sh_tmu_priv *p)
        /* disable channel */
        sh_tmu_start_stop_ch(p, 0);
 
+       /* disable interrupts in TMU block */
+       sh_tmu_write(p, TCR, 0x0000);
+
        /* stop clock */
        clk_disable(p->clk);
 }
@@ -385,7 +388,6 @@ static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev)
        p->irqaction.dev_id = p;
        p->irqaction.irq = irq;
        p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL;
-       p->irqaction.mask = CPU_MASK_NONE;
 
        /* get hold of clock */
        p->clk = clk_get(&p->pdev->dev, cfg->clk);
index ed69837d8b746edf376c42857992f60433191c03..6cbb7a514436fd0b355e38a2d6138a65254f147d 100644 (file)
@@ -1140,6 +1140,11 @@ NON0301 "c't Universale Graphic Adapter"
 NON0401 "c't Universal Ethernet Adapter"
 NON0501 "c't Universal 16-Bit Sound Adapter"
 NON0601 "c't Universal 8-Bit Adapter"
+NPI0120 "Network Peripherals NP-EISA-1 FDDI Interface"
+NPI0221 "Network Peripherals NP-EISA-2 FDDI Interface"
+NPI0223 "Network Peripherals NP-EISA-2E Enhanced FDDI Interface"
+NPI0301 "Network Peripherals NP-EISA-3 FDDI Interface"
+NPI0303 "Network Peripherals NP-EISA-3E Enhanced FDDI Interface"
 NSS0011 "Newport Systems Solutions WNIC Adapter"
 NVL0701 "Novell NE3200 Bus Master Ethernet"
 NVL0702 "Novell NE3200T Bus Master Ethernet"
index 74edb1d0110f7675f2635d26f5dc4ade609a96ac..0dd0f633b18ddabbcfb55f095b7631eeee177fea 100644 (file)
@@ -31,11 +31,11 @@ static int __init pci_eisa_init(struct pci_dev *pdev,
        }
 
        pci_eisa_root.dev              = &pdev->dev;
-       pci_eisa_root.dev->driver_data = &pci_eisa_root;
        pci_eisa_root.res              = pdev->bus->resource[0];
        pci_eisa_root.bus_base_addr    = pdev->bus->resource[0]->start;
        pci_eisa_root.slots            = EISA_MAX_SLOTS;
        pci_eisa_root.dma_mask         = pdev->dma_mask;
+       dev_set_drvdata(pci_eisa_root.dev, &pci_eisa_root);
 
        if (eisa_root_register (&pci_eisa_root)) {
                printk (KERN_ERR "pci_eisa : Could not register EISA root\n");
index 3074879f231f26d9df3b5219e69a49bfcf8704d5..535e4f9c83f4fed09ca3c00e085b53c60e0cee62 100644 (file)
@@ -57,7 +57,7 @@ static int __init virtual_eisa_root_init (void)
 
        eisa_bus_root.force_probe = force_probe;
        
-       eisa_root_dev.dev.driver_data = &eisa_bus_root;
+       dev_set_drvdata(&eisa_root_dev.dev, &eisa_bus_root);
 
        if (eisa_root_register (&eisa_bus_root)) {
                /* A real bridge may have been registered before
index a7c31e9039c14c0912554ed981c1fa390ce7606d..bc3b9bf822bf1e15c661944edae679406e673a0e 100644 (file)
@@ -2,10 +2,10 @@
 # Makefile for the Linux IEEE 1394 implementation
 #
 
-firewire-core-y += fw-card.o fw-topology.o fw-transaction.o fw-iso.o \
-                   fw-device.o fw-cdev.o
-firewire-ohci-y += fw-ohci.o
-firewire-sbp2-y += fw-sbp2.o
+firewire-core-y += core-card.o core-cdev.o core-device.o \
+                   core-iso.o core-topology.o core-transaction.o
+firewire-ohci-y += ohci.o
+firewire-sbp2-y += sbp2.o
 
 obj-$(CONFIG_FIREWIRE) += firewire-core.o
 obj-$(CONFIG_FIREWIRE_OHCI) += firewire-ohci.o
similarity index 97%
rename from drivers/firewire/fw-card.c
rename to drivers/firewire/core-card.c
index 8b8c8c22f0fce384229eab085210a1aea4353cc8..4c1be64fdddd458a93bc8dd9ae0c156f7a5abf89 100644 (file)
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+#include <linux/bug.h>
 #include <linux/completion.h>
 #include <linux/crc-itu-t.h>
-#include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/errno.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
 #include <linux/kref.h>
+#include <linux/list.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
 
-#include "fw-transaction.h"
-#include "fw-topology.h"
-#include "fw-device.h"
+#include <asm/atomic.h>
+#include <asm/byteorder.h>
+
+#include "core.h"
 
 int fw_compute_block_crc(u32 *block)
 {
@@ -181,12 +190,6 @@ void fw_core_remove_descriptor(struct fw_descriptor *desc)
        mutex_unlock(&card_mutex);
 }
 
-static int set_broadcast_channel(struct device *dev, void *data)
-{
-       fw_device_set_broadcast_channel(fw_device(dev), (long)data);
-       return 0;
-}
-
 static void allocate_broadcast_channel(struct fw_card *card, int generation)
 {
        int channel, bandwidth = 0;
@@ -196,7 +199,7 @@ static void allocate_broadcast_channel(struct fw_card *card, int generation)
        if (channel == 31) {
                card->broadcast_channel_allocated = true;
                device_for_each_child(card->device, (void *)(long)generation,
-                                     set_broadcast_channel);
+                                     fw_device_set_broadcast_channel);
        }
 }
 
similarity index 99%
rename from drivers/firewire/fw-cdev.c
rename to drivers/firewire/core-cdev.c
index 7eb6594cc3e5b92e9891773ada1898a4f0831c38..d1d30c615b0f191c7fb33a313e64bfd37b2835d5 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/errno.h>
+#include <linux/firewire.h>
 #include <linux/firewire-cdev.h>
 #include <linux/idr.h>
 #include <linux/jiffies.h>
 #include <linux/preempt.h>
 #include <linux/spinlock.h>
 #include <linux/time.h>
+#include <linux/uaccess.h>
 #include <linux/vmalloc.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
 
 #include <asm/system.h>
-#include <asm/uaccess.h>
 
-#include "fw-device.h"
-#include "fw-topology.h"
-#include "fw-transaction.h"
+#include "core.h"
 
 struct client {
        u32 version;
@@ -739,15 +738,11 @@ static void release_descriptor(struct client *client,
 static int ioctl_add_descriptor(struct client *client, void *buffer)
 {
        struct fw_cdev_add_descriptor *request = buffer;
-       struct fw_card *card = client->device->card;
        struct descriptor_resource *r;
        int ret;
 
        /* Access policy: Allow this ioctl only on local nodes' device files. */
-       spin_lock_irq(&card->lock);
-       ret = client->device->node_id != card->local_node->node_id;
-       spin_unlock_irq(&card->lock);
-       if (ret)
+       if (!client->device->is_local)
                return -ENOSYS;
 
        if (request->length > 256)
similarity index 88%
rename from drivers/firewire/fw-device.c
rename to drivers/firewire/core-device.c
index a47e2129d83d3a5f99aa7165a6600f3bea9b5383..97e656af2d22800e03d7c2302747ed7573ff71a7 100644 (file)
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/errno.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
 #include <linux/idr.h>
 #include <linux/jiffies.h>
 #include <linux/kobject.h>
 #include <linux/list.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/rwsem.h>
 #include <linux/semaphore.h>
 #include <linux/string.h>
 #include <linux/workqueue.h>
 
+#include <asm/atomic.h>
+#include <asm/byteorder.h>
 #include <asm/system.h>
 
-#include "fw-device.h"
-#include "fw-topology.h"
-#include "fw-transaction.h"
+#include "core.h"
 
 void fw_csr_iterator_init(struct fw_csr_iterator *ci, u32 * p)
 {
@@ -55,9 +59,10 @@ int fw_csr_iterator_next(struct fw_csr_iterator *ci, int *key, int *value)
 }
 EXPORT_SYMBOL(fw_csr_iterator_next);
 
-static int is_fw_unit(struct device *dev);
+static bool is_fw_unit(struct device *dev);
 
-static int match_unit_directory(u32 * directory, const struct fw_device_id *id)
+static int match_unit_directory(u32 *directory, u32 match_flags,
+                               const struct ieee1394_device_id *id)
 {
        struct fw_csr_iterator ci;
        int key, value, match;
@@ -65,31 +70,42 @@ static int match_unit_directory(u32 * directory, const struct fw_device_id *id)
        match = 0;
        fw_csr_iterator_init(&ci, directory);
        while (fw_csr_iterator_next(&ci, &key, &value)) {
-               if (key == CSR_VENDOR && value == id->vendor)
-                       match |= FW_MATCH_VENDOR;
-               if (key == CSR_MODEL && value == id->model)
-                       match |= FW_MATCH_MODEL;
+               if (key == CSR_VENDOR && value == id->vendor_id)
+                       match |= IEEE1394_MATCH_VENDOR_ID;
+               if (key == CSR_MODEL && value == id->model_id)
+                       match |= IEEE1394_MATCH_MODEL_ID;
                if (key == CSR_SPECIFIER_ID && value == id->specifier_id)
-                       match |= FW_MATCH_SPECIFIER_ID;
+                       match |= IEEE1394_MATCH_SPECIFIER_ID;
                if (key == CSR_VERSION && value == id->version)
-                       match |= FW_MATCH_VERSION;
+                       match |= IEEE1394_MATCH_VERSION;
        }
 
-       return (match & id->match_flags) == id->match_flags;
+       return (match & match_flags) == match_flags;
 }
 
 static int fw_unit_match(struct device *dev, struct device_driver *drv)
 {
        struct fw_unit *unit = fw_unit(dev);
-       struct fw_driver *driver = fw_driver(drv);
-       int i;
+       struct fw_device *device;
+       const struct ieee1394_device_id *id;
 
        /* We only allow binding to fw_units. */
        if (!is_fw_unit(dev))
                return 0;
 
-       for (i = 0; driver->id_table[i].match_flags != 0; i++) {
-               if (match_unit_directory(unit->directory, &driver->id_table[i]))
+       device = fw_parent_device(unit);
+       id = container_of(drv, struct fw_driver, driver)->id_table;
+
+       for (; id->match_flags != 0; id++) {
+               if (match_unit_directory(unit->directory, id->match_flags, id))
+                       return 1;
+
+               /* Also check vendor ID in the root directory. */
+               if ((id->match_flags & IEEE1394_MATCH_VENDOR_ID) &&
+                   match_unit_directory(&device->config_rom[5],
+                               IEEE1394_MATCH_VENDOR_ID, id) &&
+                   match_unit_directory(unit->directory, id->match_flags
+                               & ~IEEE1394_MATCH_VENDOR_ID, id))
                        return 1;
        }
 
@@ -98,7 +114,7 @@ static int fw_unit_match(struct device *dev, struct device_driver *drv)
 
 static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size)
 {
-       struct fw_device *device = fw_device(unit->device.parent);
+       struct fw_device *device = fw_parent_device(unit);
        struct fw_csr_iterator ci;
 
        int key, value;
@@ -292,8 +308,7 @@ static void init_fw_attribute_group(struct device *dev,
                group->attrs[j++] = &attr->attr;
        }
 
-       BUG_ON(j >= ARRAY_SIZE(group->attrs));
-       group->attrs[j++] = NULL;
+       group->attrs[j] = NULL;
        group->groups[0] = &group->group;
        group->groups[1] = NULL;
        group->group.attrs = group->attrs;
@@ -356,9 +371,56 @@ static ssize_t guid_show(struct device *dev,
        return ret;
 }
 
+static int units_sprintf(char *buf, u32 *directory)
+{
+       struct fw_csr_iterator ci;
+       int key, value;
+       int specifier_id = 0;
+       int version = 0;
+
+       fw_csr_iterator_init(&ci, directory);
+       while (fw_csr_iterator_next(&ci, &key, &value)) {
+               switch (key) {
+               case CSR_SPECIFIER_ID:
+                       specifier_id = value;
+                       break;
+               case CSR_VERSION:
+                       version = value;
+                       break;
+               }
+       }
+
+       return sprintf(buf, "0x%06x:0x%06x ", specifier_id, version);
+}
+
+static ssize_t units_show(struct device *dev,
+                         struct device_attribute *attr, char *buf)
+{
+       struct fw_device *device = fw_device(dev);
+       struct fw_csr_iterator ci;
+       int key, value, i = 0;
+
+       down_read(&fw_device_rwsem);
+       fw_csr_iterator_init(&ci, &device->config_rom[5]);
+       while (fw_csr_iterator_next(&ci, &key, &value)) {
+               if (key != (CSR_UNIT | CSR_DIRECTORY))
+                       continue;
+               i += units_sprintf(&buf[i], ci.p + value - 1);
+               if (i >= PAGE_SIZE - (8 + 1 + 8 + 1))
+                       break;
+       }
+       up_read(&fw_device_rwsem);
+
+       if (i)
+               buf[i - 1] = '\n';
+
+       return i;
+}
+
 static struct device_attribute fw_device_attributes[] = {
        __ATTR_RO(config_rom),
        __ATTR_RO(guid),
+       __ATTR_RO(units),
        __ATTR_NULL,
 };
 
@@ -518,7 +580,9 @@ static int read_bus_info_block(struct fw_device *device, int generation)
 
        kfree(old_rom);
        ret = 0;
-       device->cmc = rom[2] >> 30 & 1;
+       device->max_rec = rom[2] >> 12 & 0xf;
+       device->cmc     = rom[2] >> 30 & 1;
+       device->irmc    = rom[2] >> 31 & 1;
  out:
        kfree(rom);
 
@@ -537,7 +601,7 @@ static struct device_type fw_unit_type = {
        .release        = fw_unit_release,
 };
 
-static int is_fw_unit(struct device *dev)
+static bool is_fw_unit(struct device *dev)
 {
        return dev->type == &fw_unit_type;
 }
@@ -570,9 +634,13 @@ static void create_units(struct fw_device *device)
                unit->device.parent = &device->device;
                dev_set_name(&unit->device, "%s.%d", dev_name(&device->device), i++);
 
+               BUILD_BUG_ON(ARRAY_SIZE(unit->attribute_group.attrs) <
+                               ARRAY_SIZE(fw_unit_attributes) +
+                               ARRAY_SIZE(config_rom_attributes));
                init_fw_attribute_group(&unit->device,
                                        fw_unit_attributes,
                                        &unit->attribute_group);
+
                if (device_register(&unit->device) < 0)
                        goto skip_unit;
 
@@ -683,6 +751,11 @@ static struct device_type fw_device_type = {
        .release = fw_device_release,
 };
 
+static bool is_fw_device(struct device *dev)
+{
+       return dev->type == &fw_device_type;
+}
+
 static int update_unit(struct device *dev, void *data)
 {
        struct fw_unit *unit = fw_unit(dev);
@@ -719,6 +792,9 @@ static int lookup_existing_device(struct device *dev, void *data)
        struct fw_card *card = new->card;
        int match = 0;
 
+       if (!is_fw_device(dev))
+               return 0;
+
        down_read(&fw_device_rwsem); /* serialize config_rom access */
        spin_lock_irq(&card->lock);  /* serialize node access */
 
@@ -758,7 +834,7 @@ static int lookup_existing_device(struct device *dev, void *data)
 
 enum { BC_UNKNOWN = 0, BC_UNIMPLEMENTED, BC_IMPLEMENTED, };
 
-void fw_device_set_broadcast_channel(struct fw_device *device, int generation)
+static void set_broadcast_channel(struct fw_device *device, int generation)
 {
        struct fw_card *card = device->card;
        __be32 data;
@@ -767,6 +843,20 @@ void fw_device_set_broadcast_channel(struct fw_device *device, int generation)
        if (!card->broadcast_channel_allocated)
                return;
 
+       /*
+        * The Broadcast_Channel Valid bit is required by nodes which want to
+        * transmit on this channel.  Such transmissions are practically
+        * exclusive to IP over 1394 (RFC 2734).  IP capable nodes are required
+        * to be IRM capable and have a max_rec of 8 or more.  We use this fact
+        * to narrow down to which nodes we send Broadcast_Channel updates.
+        */
+       if (!device->irmc || device->max_rec < 8)
+               return;
+
+       /*
+        * Some 1394-1995 nodes crash if this 1394a-2000 register is written.
+        * Perform a read test first.
+        */
        if (device->bc_implemented == BC_UNKNOWN) {
                rcode = fw_run_transaction(card, TCODE_READ_QUADLET_REQUEST,
                                device->node_id, generation, device->max_speed,
@@ -794,6 +884,14 @@ void fw_device_set_broadcast_channel(struct fw_device *device, int generation)
        }
 }
 
+int fw_device_set_broadcast_channel(struct device *dev, void *gen)
+{
+       if (is_fw_device(dev))
+               set_broadcast_channel(fw_device(dev), (long)gen);
+
+       return 0;
+}
+
 static void fw_device_init(struct work_struct *work)
 {
        struct fw_device *device =
@@ -849,9 +947,13 @@ static void fw_device_init(struct work_struct *work)
        device->device.devt = MKDEV(fw_cdev_major, minor);
        dev_set_name(&device->device, "fw%d", minor);
 
+       BUILD_BUG_ON(ARRAY_SIZE(device->attribute_group.attrs) <
+                       ARRAY_SIZE(fw_device_attributes) +
+                       ARRAY_SIZE(config_rom_attributes));
        init_fw_attribute_group(&device->device,
                                fw_device_attributes,
                                &device->attribute_group);
+
        if (device_add(&device->device)) {
                fw_error("Failed to add device.\n");
                goto error_with_cdev;
@@ -888,7 +990,7 @@ static void fw_device_init(struct work_struct *work)
                                  1 << device->max_speed);
                device->config_rom_retries = 0;
 
-               fw_device_set_broadcast_channel(device, device->generation);
+               set_broadcast_channel(device, device->generation);
        }
 
        /*
@@ -993,6 +1095,9 @@ static void fw_device_refresh(struct work_struct *work)
 
        create_units(device);
 
+       /* Userspace may want to re-read attributes. */
+       kobject_uevent(&device->device.kobj, KOBJ_CHANGE);
+
        if (atomic_cmpxchg(&device->state,
                           FW_DEVICE_INITIALIZING,
                           FW_DEVICE_RUNNING) == FW_DEVICE_GONE)
@@ -1042,6 +1147,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
                device->node = fw_node_get(node);
                device->node_id = node->node_id;
                device->generation = card->generation;
+               device->is_local = node == card->local_node;
                mutex_init(&device->client_list_mutex);
                INIT_LIST_HEAD(&device->client_list);
 
@@ -1075,7 +1181,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
                            FW_DEVICE_INITIALIZING) == FW_DEVICE_RUNNING) {
                        PREPARE_DELAYED_WORK(&device->work, fw_device_refresh);
                        schedule_delayed_work(&device->work,
-                               node == card->local_node ? 0 : INITIAL_DELAY);
+                               device->is_local ? 0 : INITIAL_DELAY);
                }
                break;
 
similarity index 99%
rename from drivers/firewire/fw-iso.c
rename to drivers/firewire/core-iso.c
index 2baf1007253e66a972b357d37b62b1e245d26bcd..28076c892d7e8320d38b9f61c5f78163148b6a01 100644 (file)
 
 #include <linux/dma-mapping.h>
 #include <linux/errno.h>
+#include <linux/firewire.h>
 #include <linux/firewire-constants.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/spinlock.h>
 #include <linux/vmalloc.h>
 
-#include "fw-topology.h"
-#include "fw-transaction.h"
+#include <asm/byteorder.h>
+
+#include "core.h"
 
 /*
  * Isochronous DMA context management
similarity index 97%
rename from drivers/firewire/fw-topology.c
rename to drivers/firewire/core-topology.c
index d0deecc4de938440c99c1c6778ca0917e71491d0..fddf2b358936bd7b223a79bea5b4bd41147291d8 100644 (file)
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-#include <linux/module.h>
-#include <linux/wait.h>
+#include <linux/bug.h>
 #include <linux/errno.h>
-#include <asm/bug.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+
+#include <asm/atomic.h>
 #include <asm/system.h>
-#include "fw-transaction.h"
-#include "fw-topology.h"
+
+#include "core.h"
 
 #define SELF_ID_PHY_ID(q)              (((q) >> 24) & 0x3f)
 #define SELF_ID_EXTENDED(q)            (((q) >> 23) & 0x01)
 
 #define SELF_ID_EXT_SEQUENCE(q)                (((q) >> 20) & 0x07)
 
+#define SELFID_PORT_CHILD      0x3
+#define SELFID_PORT_PARENT     0x2
+#define SELFID_PORT_NCONN      0x1
+#define SELFID_PORT_NONE       0x0
+
 static u32 *count_ports(u32 *sid, int *total_port_count, int *child_port_count)
 {
        u32 q;
similarity index 97%
rename from drivers/firewire/fw-transaction.c
rename to drivers/firewire/core-transaction.c
index 283dac6d327db100853c1768be00f37dbc346b10..479b22f5a1eb7889162643741357fdd6cd8948b4 100644 (file)
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
+#include <linux/bug.h>
 #include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/fs.h>
+#include <linux/init.h>
 #include <linux/idr.h>
+#include <linux/jiffies.h>
 #include <linux/kernel.h>
-#include <linux/kref.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/poll.h>
 #include <linux/list.h>
-#include <linux/kthread.h>
-#include <asm/uaccess.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/types.h>
 
-#include "fw-transaction.h"
-#include "fw-topology.h"
-#include "fw-device.h"
+#include <asm/byteorder.h>
+
+#include "core.h"
 
 #define HEADER_PRI(pri)                        ((pri) << 0)
 #define HEADER_TCODE(tcode)            ((tcode) << 4)
 #define HEADER_DESTINATION_IS_BROADCAST(q) \
        (((q) & HEADER_DESTINATION(0x3f)) == HEADER_DESTINATION(0x3f))
 
+#define PHY_PACKET_CONFIG      0x0
+#define PHY_PACKET_LINK_ON     0x1
+#define PHY_PACKET_SELF_ID     0x2
+
 #define PHY_CONFIG_GAP_COUNT(gap_count)        (((gap_count) << 16) | (1 << 22))
 #define PHY_CONFIG_ROOT_ID(node_id)    ((((node_id) & 0x3f) << 24) | (1 << 23))
 #define PHY_IDENTIFIER(id)             ((id) << 30)
@@ -74,7 +82,7 @@ static int close_transaction(struct fw_transaction *transaction,
        list_for_each_entry(t, &card->transaction_list, link) {
                if (t == transaction) {
                        list_del(&t->link);
-                       card->tlabel_mask &= ~(1 << t->tlabel);
+                       card->tlabel_mask &= ~(1ULL << t->tlabel);
                        break;
                }
        }
@@ -280,14 +288,14 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
        spin_lock_irqsave(&card->lock, flags);
 
        tlabel = card->current_tlabel;
-       if (card->tlabel_mask & (1 << tlabel)) {
+       if (card->tlabel_mask & (1ULL << tlabel)) {
                spin_unlock_irqrestore(&card->lock, flags);
                callback(card, RCODE_SEND_ERROR, NULL, 0, callback_data);
                return;
        }
 
-       card->current_tlabel = (card->current_tlabel + 1) & 0x1f;
-       card->tlabel_mask |= (1 << tlabel);
+       card->current_tlabel = (card->current_tlabel + 1) & 0x3f;
+       card->tlabel_mask |= (1ULL << tlabel);
 
        t->node_id = destination_id;
        t->tlabel = tlabel;
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h
new file mode 100644 (file)
index 0000000..0a25a7b
--- /dev/null
@@ -0,0 +1,293 @@
+#ifndef _FIREWIRE_CORE_H
+#define _FIREWIRE_CORE_H
+
+#include <linux/dma-mapping.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/idr.h>
+#include <linux/mm_types.h>
+#include <linux/rwsem.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <asm/atomic.h>
+
+struct device;
+struct fw_card;
+struct fw_device;
+struct fw_iso_buffer;
+struct fw_iso_context;
+struct fw_iso_packet;
+struct fw_node;
+struct fw_packet;
+
+
+/* -card */
+
+/* bitfields within the PHY registers */
+#define PHY_LINK_ACTIVE                0x80
+#define PHY_CONTENDER          0x40
+#define PHY_BUS_RESET          0x40
+#define PHY_BUS_SHORT_RESET    0x40
+
+#define BANDWIDTH_AVAILABLE_INITIAL    4915
+#define BROADCAST_CHANNEL_INITIAL      (1 << 31 | 31)
+#define BROADCAST_CHANNEL_VALID                (1 << 30)
+
+struct fw_card_driver {
+       /*
+        * Enable the given card with the given initial config rom.
+        * This function is expected to activate the card, and either
+        * enable the PHY or set the link_on bit and initiate a bus
+        * reset.
+        */
+       int (*enable)(struct fw_card *card, u32 *config_rom, size_t length);
+
+       int (*update_phy_reg)(struct fw_card *card, int address,
+                             int clear_bits, int set_bits);
+
+       /*
+        * Update the config rom for an enabled card.  This function
+        * should change the config rom that is presented on the bus
+        * an initiate a bus reset.
+        */
+       int (*set_config_rom)(struct fw_card *card,
+                             u32 *config_rom, size_t length);
+
+       void (*send_request)(struct fw_card *card, struct fw_packet *packet);
+       void (*send_response)(struct fw_card *card, struct fw_packet *packet);
+       /* Calling cancel is valid once a packet has been submitted. */
+       int (*cancel_packet)(struct fw_card *card, struct fw_packet *packet);
+
+       /*
+        * Allow the specified node ID to do direct DMA out and in of
+        * host memory.  The card will disable this for all node when
+        * a bus reset happens, so driver need to reenable this after
+        * bus reset.  Returns 0 on success, -ENODEV if the card
+        * doesn't support this, -ESTALE if the generation doesn't
+        * match.
+        */
+       int (*enable_phys_dma)(struct fw_card *card,
+                              int node_id, int generation);
+
+       u64 (*get_bus_time)(struct fw_card *card);
+
+       struct fw_iso_context *
+       (*allocate_iso_context)(struct fw_card *card,
+                               int type, int channel, size_t header_size);
+       void (*free_iso_context)(struct fw_iso_context *ctx);
+
+       int (*start_iso)(struct fw_iso_context *ctx,
+                        s32 cycle, u32 sync, u32 tags);
+
+       int (*queue_iso)(struct fw_iso_context *ctx,
+                        struct fw_iso_packet *packet,
+                        struct fw_iso_buffer *buffer,
+                        unsigned long payload);
+
+       int (*stop_iso)(struct fw_iso_context *ctx);
+};
+
+void fw_card_initialize(struct fw_card *card,
+               const struct fw_card_driver *driver, struct device *device);
+int fw_card_add(struct fw_card *card,
+               u32 max_receive, u32 link_speed, u64 guid);
+void fw_core_remove_card(struct fw_card *card);
+int fw_core_initiate_bus_reset(struct fw_card *card, int short_reset);
+int fw_compute_block_crc(u32 *block);
+void fw_schedule_bm_work(struct fw_card *card, unsigned long delay);
+
+struct fw_descriptor {
+       struct list_head link;
+       size_t length;
+       u32 immediate;
+       u32 key;
+       const u32 *data;
+};
+
+int fw_core_add_descriptor(struct fw_descriptor *desc);
+void fw_core_remove_descriptor(struct fw_descriptor *desc);
+
+
+/* -cdev */
+
+extern const struct file_operations fw_device_ops;
+
+void fw_device_cdev_update(struct fw_device *device);
+void fw_device_cdev_remove(struct fw_device *device);
+
+
+/* -device */
+
+extern struct rw_semaphore fw_device_rwsem;
+extern struct idr fw_device_idr;
+extern int fw_cdev_major;
+
+struct fw_device *fw_device_get_by_devt(dev_t devt);
+int fw_device_set_broadcast_channel(struct device *dev, void *gen);
+void fw_node_event(struct fw_card *card, struct fw_node *node, int event);
+
+
+/* -iso */
+
+/*
+ * The iso packet format allows for an immediate header/payload part
+ * stored in 'header' immediately after the packet info plus an
+ * indirect payload part that is pointer to by the 'payload' field.
+ * Applications can use one or the other or both to implement simple
+ * low-bandwidth streaming (e.g. audio) or more advanced
+ * scatter-gather streaming (e.g. assembling video frame automatically).
+ */
+struct fw_iso_packet {
+       u16 payload_length;     /* Length of indirect payload. */
+       u32 interrupt:1;        /* Generate interrupt on this packet */
+       u32 skip:1;             /* Set to not send packet at all. */
+       u32 tag:2;
+       u32 sy:4;
+       u32 header_length:8;    /* Length of immediate header. */
+       u32 header[0];
+};
+
+#define FW_ISO_CONTEXT_TRANSMIT        0
+#define FW_ISO_CONTEXT_RECEIVE 1
+
+#define FW_ISO_CONTEXT_MATCH_TAG0       1
+#define FW_ISO_CONTEXT_MATCH_TAG1       2
+#define FW_ISO_CONTEXT_MATCH_TAG2       4
+#define FW_ISO_CONTEXT_MATCH_TAG3       8
+#define FW_ISO_CONTEXT_MATCH_ALL_TAGS  15
+
+/*
+ * An iso buffer is just a set of pages mapped for DMA in the
+ * specified direction.  Since the pages are to be used for DMA, they
+ * are not mapped into the kernel virtual address space.  We store the
+ * DMA address in the page private. The helper function
+ * fw_iso_buffer_map() will map the pages into a given vma.
+ */
+struct fw_iso_buffer {
+       enum dma_data_direction direction;
+       struct page **pages;
+       int page_count;
+};
+
+typedef void (*fw_iso_callback_t)(struct fw_iso_context *context,
+                                 u32 cycle, size_t header_length,
+                                 void *header, void *data);
+
+struct fw_iso_context {
+       struct fw_card *card;
+       int type;
+       int channel;
+       int speed;
+       size_t header_size;
+       fw_iso_callback_t callback;
+       void *callback_data;
+};
+
+int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
+                      int page_count, enum dma_data_direction direction);
+int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma);
+void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, struct fw_card *card);
+
+struct fw_iso_context *fw_iso_context_create(struct fw_card *card,
+               int type, int channel, int speed, size_t header_size,
+               fw_iso_callback_t callback, void *callback_data);
+int fw_iso_context_queue(struct fw_iso_context *ctx,
+                        struct fw_iso_packet *packet,
+                        struct fw_iso_buffer *buffer,
+                        unsigned long payload);
+int fw_iso_context_start(struct fw_iso_context *ctx,
+                        int cycle, int sync, int tags);
+int fw_iso_context_stop(struct fw_iso_context *ctx);
+void fw_iso_context_destroy(struct fw_iso_context *ctx);
+
+void fw_iso_resource_manage(struct fw_card *card, int generation,
+               u64 channels_mask, int *channel, int *bandwidth, bool allocate);
+
+
+/* -topology */
+
+enum {
+       FW_NODE_CREATED,
+       FW_NODE_UPDATED,
+       FW_NODE_DESTROYED,
+       FW_NODE_LINK_ON,
+       FW_NODE_LINK_OFF,
+       FW_NODE_INITIATED_RESET,
+};
+
+struct fw_node {
+       u16 node_id;
+       u8 color;
+       u8 port_count;
+       u8 link_on:1;
+       u8 initiated_reset:1;
+       u8 b_path:1;
+       u8 phy_speed:2; /* As in the self ID packet. */
+       u8 max_speed:2; /* Minimum of all phy-speeds on the path from the
+                        * local node to this node. */
+       u8 max_depth:4; /* Maximum depth to any leaf node */
+       u8 max_hops:4;  /* Max hops in this sub tree */
+       atomic_t ref_count;
+
+       /* For serializing node topology into a list. */
+       struct list_head link;
+
+       /* Upper layer specific data. */
+       void *data;
+
+       struct fw_node *ports[0];
+};
+
+static inline struct fw_node *fw_node_get(struct fw_node *node)
+{
+       atomic_inc(&node->ref_count);
+
+       return node;
+}
+
+static inline void fw_node_put(struct fw_node *node)
+{
+       if (atomic_dec_and_test(&node->ref_count))
+               kfree(node);
+}
+
+void fw_core_handle_bus_reset(struct fw_card *card, int node_id,
+                             int generation, int self_id_count, u32 *self_ids);
+void fw_destroy_nodes(struct fw_card *card);
+
+/*
+ * Check whether new_generation is the immediate successor of old_generation.
+ * Take counter roll-over at 255 (as per OHCI) into account.
+ */
+static inline bool is_next_generation(int new_generation, int old_generation)
+{
+       return (new_generation & 0xff) == ((old_generation + 1) & 0xff);
+}
+
+
+/* -transaction */
+
+#define TCODE_IS_READ_REQUEST(tcode)   (((tcode) & ~1) == 4)
+#define TCODE_IS_BLOCK_PACKET(tcode)   (((tcode) &  1) != 0)
+#define TCODE_IS_REQUEST(tcode)                (((tcode) &  2) == 0)
+#define TCODE_IS_RESPONSE(tcode)       (((tcode) &  2) != 0)
+#define TCODE_HAS_REQUEST_DATA(tcode)  (((tcode) & 12) != 4)
+#define TCODE_HAS_RESPONSE_DATA(tcode) (((tcode) & 12) != 0)
+
+#define LOCAL_BUS 0xffc0
+
+void fw_core_handle_request(struct fw_card *card, struct fw_packet *request);
+void fw_core_handle_response(struct fw_card *card, struct fw_packet *packet);
+void fw_fill_response(struct fw_packet *response, u32 *request_header,
+                     int rcode, void *payload, size_t length);
+void fw_flush_transactions(struct fw_card *card);
+void fw_send_phy_config(struct fw_card *card,
+                       int node_id, int generation, int gap_count);
+
+static inline int fw_stream_packet_destination_id(int tag, int channel, int sy)
+{
+       return tag << 14 | channel << 8 | sy;
+}
+
+#endif /* _FIREWIRE_CORE_H */
diff --git a/drivers/firewire/fw-device.h b/drivers/firewire/fw-device.h
deleted file mode 100644 (file)
index 9758893..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2005-2006  Kristian Hoegsberg <krh@bitplanet.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef __fw_device_h
-#define __fw_device_h
-
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/idr.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/mutex.h>
-#include <linux/rwsem.h>
-#include <linux/sysfs.h>
-#include <linux/types.h>
-#include <linux/workqueue.h>
-
-#include <asm/atomic.h>
-
-enum fw_device_state {
-       FW_DEVICE_INITIALIZING,
-       FW_DEVICE_RUNNING,
-       FW_DEVICE_GONE,
-       FW_DEVICE_SHUTDOWN,
-};
-
-struct fw_attribute_group {
-       struct attribute_group *groups[2];
-       struct attribute_group group;
-       struct attribute *attrs[11];
-};
-
-struct fw_node;
-struct fw_card;
-
-/*
- * Note, fw_device.generation always has to be read before fw_device.node_id.
- * Use SMP memory barriers to ensure this.  Otherwise requests will be sent
- * to an outdated node_id if the generation was updated in the meantime due
- * to a bus reset.
- *
- * Likewise, fw-core will take care to update .node_id before .generation so
- * that whenever fw_device.generation is current WRT the actual bus generation,
- * fw_device.node_id is guaranteed to be current too.
- *
- * The same applies to fw_device.card->node_id vs. fw_device.generation.
- *
- * fw_device.config_rom and fw_device.config_rom_length may be accessed during
- * the lifetime of any fw_unit belonging to the fw_device, before device_del()
- * was called on the last fw_unit.  Alternatively, they may be accessed while
- * holding fw_device_rwsem.
- */
-struct fw_device {
-       atomic_t state;
-       struct fw_node *node;
-       int node_id;
-       int generation;
-       unsigned max_speed;
-       struct fw_card *card;
-       struct device device;
-
-       struct mutex client_list_mutex;
-       struct list_head client_list;
-
-       u32 *config_rom;
-       size_t config_rom_length;
-       int config_rom_retries;
-       unsigned cmc:1;
-       unsigned bc_implemented:2;
-
-       struct delayed_work work;
-       struct fw_attribute_group attribute_group;
-};
-
-static inline struct fw_device *fw_device(struct device *dev)
-{
-       return container_of(dev, struct fw_device, device);
-}
-
-static inline int fw_device_is_shutdown(struct fw_device *device)
-{
-       return atomic_read(&device->state) == FW_DEVICE_SHUTDOWN;
-}
-
-static inline struct fw_device *fw_device_get(struct fw_device *device)
-{
-       get_device(&device->device);
-
-       return device;
-}
-
-static inline void fw_device_put(struct fw_device *device)
-{
-       put_device(&device->device);
-}
-
-struct fw_device *fw_device_get_by_devt(dev_t devt);
-int fw_device_enable_phys_dma(struct fw_device *device);
-void fw_device_set_broadcast_channel(struct fw_device *device, int generation);
-
-void fw_device_cdev_update(struct fw_device *device);
-void fw_device_cdev_remove(struct fw_device *device);
-
-extern struct rw_semaphore fw_device_rwsem;
-extern struct idr fw_device_idr;
-extern int fw_cdev_major;
-
-/*
- * fw_unit.directory must not be accessed after device_del(&fw_unit.device).
- */
-struct fw_unit {
-       struct device device;
-       u32 *directory;
-       struct fw_attribute_group attribute_group;
-};
-
-static inline struct fw_unit *fw_unit(struct device *dev)
-{
-       return container_of(dev, struct fw_unit, device);
-}
-
-static inline struct fw_unit *fw_unit_get(struct fw_unit *unit)
-{
-       get_device(&unit->device);
-
-       return unit;
-}
-
-static inline void fw_unit_put(struct fw_unit *unit)
-{
-       put_device(&unit->device);
-}
-
-#define CSR_OFFSET     0x40
-#define CSR_LEAF       0x80
-#define CSR_DIRECTORY  0xc0
-
-#define CSR_DESCRIPTOR         0x01
-#define CSR_VENDOR             0x03
-#define CSR_HARDWARE_VERSION   0x04
-#define CSR_NODE_CAPABILITIES  0x0c
-#define CSR_UNIT               0x11
-#define CSR_SPECIFIER_ID       0x12
-#define CSR_VERSION            0x13
-#define CSR_DEPENDENT_INFO     0x14
-#define CSR_MODEL              0x17
-#define CSR_INSTANCE           0x18
-#define CSR_DIRECTORY_ID       0x20
-
-struct fw_csr_iterator {
-       u32 *p;
-       u32 *end;
-};
-
-void fw_csr_iterator_init(struct fw_csr_iterator *ci, u32 *p);
-int fw_csr_iterator_next(struct fw_csr_iterator *ci,
-                        int *key, int *value);
-
-#define FW_MATCH_VENDOR                0x0001
-#define FW_MATCH_MODEL         0x0002
-#define FW_MATCH_SPECIFIER_ID  0x0004
-#define FW_MATCH_VERSION       0x0008
-
-struct fw_device_id {
-       u32 match_flags;
-       u32 vendor;
-       u32 model;
-       u32 specifier_id;
-       u32 version;
-       void *driver_data;
-};
-
-struct fw_driver {
-       struct device_driver driver;
-       /* Called when the parent device sits through a bus reset. */
-       void (*update) (struct fw_unit *unit);
-       const struct fw_device_id *id_table;
-};
-
-static inline struct fw_driver *fw_driver(struct device_driver *drv)
-{
-       return container_of(drv, struct fw_driver, driver);
-}
-
-extern const struct file_operations fw_device_ops;
-
-#endif /* __fw_device_h */
diff --git a/drivers/firewire/fw-topology.h b/drivers/firewire/fw-topology.h
deleted file mode 100644 (file)
index 3c497bb..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2003-2006 Kristian Hoegsberg <krh@bitplanet.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef __fw_topology_h
-#define __fw_topology_h
-
-#include <linux/list.h>
-#include <linux/slab.h>
-
-#include <asm/atomic.h>
-
-enum {
-       FW_NODE_CREATED,
-       FW_NODE_UPDATED,
-       FW_NODE_DESTROYED,
-       FW_NODE_LINK_ON,
-       FW_NODE_LINK_OFF,
-       FW_NODE_INITIATED_RESET,
-};
-
-struct fw_node {
-       u16 node_id;
-       u8 color;
-       u8 port_count;
-       u8 link_on : 1;
-       u8 initiated_reset : 1;
-       u8 b_path : 1;
-       u8 phy_speed : 2; /* As in the self ID packet. */
-       u8 max_speed : 2; /* Minimum of all phy-speeds on the path from the
-                          * local node to this node. */
-       u8 max_depth : 4; /* Maximum depth to any leaf node */
-       u8 max_hops : 4;  /* Max hops in this sub tree */
-       atomic_t ref_count;
-
-       /* For serializing node topology into a list. */
-       struct list_head link;
-
-       /* Upper layer specific data. */
-       void *data;
-
-       struct fw_node *ports[0];
-};
-
-static inline struct fw_node *fw_node_get(struct fw_node *node)
-{
-       atomic_inc(&node->ref_count);
-
-       return node;
-}
-
-static inline void fw_node_put(struct fw_node *node)
-{
-       if (atomic_dec_and_test(&node->ref_count))
-               kfree(node);
-}
-
-struct fw_card;
-void fw_destroy_nodes(struct fw_card *card);
-
-int fw_compute_block_crc(u32 *block);
-
-#endif /* __fw_topology_h */
diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h
deleted file mode 100644 (file)
index dfa7990..0000000
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * Copyright (C) 2003-2006 Kristian Hoegsberg <krh@bitplanet.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef __fw_transaction_h
-#define __fw_transaction_h
-
-#include <linux/completion.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/firewire-constants.h>
-#include <linux/kref.h>
-#include <linux/list.h>
-#include <linux/spinlock_types.h>
-#include <linux/timer.h>
-#include <linux/types.h>
-#include <linux/workqueue.h>
-
-#define TCODE_IS_READ_REQUEST(tcode)   (((tcode) & ~1) == 4)
-#define TCODE_IS_BLOCK_PACKET(tcode)   (((tcode) &  1) != 0)
-#define TCODE_IS_REQUEST(tcode)                (((tcode) &  2) == 0)
-#define TCODE_IS_RESPONSE(tcode)       (((tcode) &  2) != 0)
-#define TCODE_HAS_REQUEST_DATA(tcode)  (((tcode) & 12) != 4)
-#define TCODE_HAS_RESPONSE_DATA(tcode) (((tcode) & 12) != 0)
-
-#define LOCAL_BUS 0xffc0
-
-#define SELFID_PORT_CHILD      0x3
-#define SELFID_PORT_PARENT     0x2
-#define SELFID_PORT_NCONN      0x1
-#define SELFID_PORT_NONE       0x0
-
-#define PHY_PACKET_CONFIG      0x0
-#define PHY_PACKET_LINK_ON     0x1
-#define PHY_PACKET_SELF_ID     0x2
-
-/* Bit fields _within_ the PHY registers. */
-#define PHY_LINK_ACTIVE                0x80
-#define PHY_CONTENDER          0x40
-#define PHY_BUS_RESET          0x40
-#define PHY_BUS_SHORT_RESET    0x40
-
-#define CSR_REGISTER_BASE              0xfffff0000000ULL
-
-/* register offsets relative to CSR_REGISTER_BASE */
-#define CSR_STATE_CLEAR                        0x0
-#define CSR_STATE_SET                  0x4
-#define CSR_NODE_IDS                   0x8
-#define CSR_RESET_START                        0xc
-#define CSR_SPLIT_TIMEOUT_HI           0x18
-#define CSR_SPLIT_TIMEOUT_LO           0x1c
-#define CSR_CYCLE_TIME                 0x200
-#define CSR_BUS_TIME                   0x204
-#define CSR_BUSY_TIMEOUT               0x210
-#define CSR_BUS_MANAGER_ID             0x21c
-#define CSR_BANDWIDTH_AVAILABLE                0x220
-#define CSR_CHANNELS_AVAILABLE         0x224
-#define CSR_CHANNELS_AVAILABLE_HI      0x224
-#define CSR_CHANNELS_AVAILABLE_LO      0x228
-#define CSR_BROADCAST_CHANNEL          0x234
-#define CSR_CONFIG_ROM                 0x400
-#define CSR_CONFIG_ROM_END             0x800
-#define CSR_FCP_COMMAND                        0xB00
-#define CSR_FCP_RESPONSE               0xD00
-#define CSR_FCP_END                    0xF00
-#define CSR_TOPOLOGY_MAP               0x1000
-#define CSR_TOPOLOGY_MAP_END           0x1400
-#define CSR_SPEED_MAP                  0x2000
-#define CSR_SPEED_MAP_END              0x3000
-
-#define BANDWIDTH_AVAILABLE_INITIAL    4915
-#define BROADCAST_CHANNEL_INITIAL      (1 << 31 | 31)
-#define BROADCAST_CHANNEL_VALID                (1 << 30)
-
-#define fw_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, ## args)
-#define fw_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args)
-
-static inline void fw_memcpy_from_be32(void *_dst, void *_src, size_t size)
-{
-       u32    *dst = _dst;
-       __be32 *src = _src;
-       int i;
-
-       for (i = 0; i < size / 4; i++)
-               dst[i] = be32_to_cpu(src[i]);
-}
-
-static inline void fw_memcpy_to_be32(void *_dst, void *_src, size_t size)
-{
-       fw_memcpy_from_be32(_dst, _src, size);
-}
-
-struct fw_card;
-struct fw_packet;
-struct fw_node;
-struct fw_request;
-
-struct fw_descriptor {
-       struct list_head link;
-       size_t length;
-       u32 immediate;
-       u32 key;
-       const u32 *data;
-};
-
-int fw_core_add_descriptor(struct fw_descriptor *desc);
-void fw_core_remove_descriptor(struct fw_descriptor *desc);
-
-typedef void (*fw_packet_callback_t)(struct fw_packet *packet,
-                                    struct fw_card *card, int status);
-
-typedef void (*fw_transaction_callback_t)(struct fw_card *card, int rcode,
-                                         void *data, size_t length,
-                                         void *callback_data);
-
-/*
- * Important note:  The callback must guarantee that either fw_send_response()
- * or kfree() is called on the @request.
- */
-typedef void (*fw_address_callback_t)(struct fw_card *card,
-                                     struct fw_request *request,
-                                     int tcode, int destination, int source,
-                                     int generation, int speed,
-                                     unsigned long long offset,
-                                     void *data, size_t length,
-                                     void *callback_data);
-
-struct fw_packet {
-       int speed;
-       int generation;
-       u32 header[4];
-       size_t header_length;
-       void *payload;
-       size_t payload_length;
-       dma_addr_t payload_bus;
-       u32 timestamp;
-
-       /*
-        * This callback is called when the packet transmission has
-        * completed; for successful transmission, the status code is
-        * the ack received from the destination, otherwise it's a
-        * negative errno: ENOMEM, ESTALE, ETIMEDOUT, ENODEV, EIO.
-        * The callback can be called from tasklet context and thus
-        * must never block.
-        */
-       fw_packet_callback_t callback;
-       int ack;
-       struct list_head link;
-       void *driver_data;
-};
-
-struct fw_transaction {
-       int node_id; /* The generation is implied; it is always the current. */
-       int tlabel;
-       int timestamp;
-       struct list_head link;
-
-       struct fw_packet packet;
-
-       /*
-        * The data passed to the callback is valid only during the
-        * callback.
-        */
-       fw_transaction_callback_t callback;
-       void *callback_data;
-};
-
-struct fw_address_handler {
-       u64 offset;
-       size_t length;
-       fw_address_callback_t address_callback;
-       void *callback_data;
-       struct list_head link;
-};
-
-struct fw_address_region {
-       u64 start;
-       u64 end;
-};
-
-extern const struct fw_address_region fw_high_memory_region;
-
-int fw_core_add_address_handler(struct fw_address_handler *handler,
-                               const struct fw_address_region *region);
-void fw_core_remove_address_handler(struct fw_address_handler *handler);
-void fw_fill_response(struct fw_packet *response, u32 *request_header,
-                     int rcode, void *payload, size_t length);
-void fw_send_response(struct fw_card *card,
-                     struct fw_request *request, int rcode);
-
-extern struct bus_type fw_bus_type;
-
-struct fw_card {
-       const struct fw_card_driver *driver;
-       struct device *device;
-       struct kref kref;
-       struct completion done;
-
-       int node_id;
-       int generation;
-       int current_tlabel, tlabel_mask;
-       struct list_head transaction_list;
-       struct timer_list flush_timer;
-       unsigned long reset_jiffies;
-
-       unsigned long long guid;
-       unsigned max_receive;
-       int link_speed;
-       int config_rom_generation;
-
-       spinlock_t lock; /* Take this lock when handling the lists in
-                         * this struct. */
-       struct fw_node *local_node;
-       struct fw_node *root_node;
-       struct fw_node *irm_node;
-       u8 color; /* must be u8 to match the definition in struct fw_node */
-       int gap_count;
-       bool beta_repeaters_present;
-
-       int index;
-
-       struct list_head link;
-
-       /* Work struct for BM duties. */
-       struct delayed_work work;
-       int bm_retries;
-       int bm_generation;
-
-       bool broadcast_channel_allocated;
-       u32 broadcast_channel;
-       u32 topology_map[(CSR_TOPOLOGY_MAP_END - CSR_TOPOLOGY_MAP) / 4];
-};
-
-static inline struct fw_card *fw_card_get(struct fw_card *card)
-{
-       kref_get(&card->kref);
-
-       return card;
-}
-
-void fw_card_release(struct kref *kref);
-
-static inline void fw_card_put(struct fw_card *card)
-{
-       kref_put(&card->kref, fw_card_release);
-}
-
-extern void fw_schedule_bm_work(struct fw_card *card, unsigned long delay);
-
-/*
- * Check whether new_generation is the immediate successor of old_generation.
- * Take counter roll-over at 255 (as per to OHCI) into account.
- */
-static inline bool is_next_generation(int new_generation, int old_generation)
-{
-       return (new_generation & 0xff) == ((old_generation + 1) & 0xff);
-}
-
-/*
- * The iso packet format allows for an immediate header/payload part
- * stored in 'header' immediately after the packet info plus an
- * indirect payload part that is pointer to by the 'payload' field.
- * Applications can use one or the other or both to implement simple
- * low-bandwidth streaming (e.g. audio) or more advanced
- * scatter-gather streaming (e.g. assembling video frame automatically).
- */
-
-struct fw_iso_packet {
-       u16 payload_length;     /* Length of indirect payload. */
-       u32 interrupt : 1;      /* Generate interrupt on this packet */
-       u32 skip : 1;           /* Set to not send packet at all. */
-       u32 tag : 2;
-       u32 sy : 4;
-       u32 header_length : 8;  /* Length of immediate header. */
-       u32 header[0];
-};
-
-#define FW_ISO_CONTEXT_TRANSMIT        0
-#define FW_ISO_CONTEXT_RECEIVE 1
-
-#define FW_ISO_CONTEXT_MATCH_TAG0       1
-#define FW_ISO_CONTEXT_MATCH_TAG1       2
-#define FW_ISO_CONTEXT_MATCH_TAG2       4
-#define FW_ISO_CONTEXT_MATCH_TAG3       8
-#define FW_ISO_CONTEXT_MATCH_ALL_TAGS  15
-
-struct fw_iso_context;
-
-typedef void (*fw_iso_callback_t)(struct fw_iso_context *context,
-                                 u32 cycle, size_t header_length,
-                                 void *header, void *data);
-
-/*
- * An iso buffer is just a set of pages mapped for DMA in the
- * specified direction.  Since the pages are to be used for DMA, they
- * are not mapped into the kernel virtual address space.  We store the
- * DMA address in the page private. The helper function
- * fw_iso_buffer_map() will map the pages into a given vma.
- */
-
-struct fw_iso_buffer {
-       enum dma_data_direction direction;
-       struct page **pages;
-       int page_count;
-};
-
-struct fw_iso_context {
-       struct fw_card *card;
-       int type;
-       int channel;
-       int speed;
-       size_t header_size;
-       fw_iso_callback_t callback;
-       void *callback_data;
-};
-
-int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
-                      int page_count, enum dma_data_direction direction);
-int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma);
-void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, struct fw_card *card);
-
-struct fw_iso_context *fw_iso_context_create(struct fw_card *card,
-               int type, int channel, int speed, size_t header_size,
-               fw_iso_callback_t callback, void *callback_data);
-int fw_iso_context_queue(struct fw_iso_context *ctx,
-                        struct fw_iso_packet *packet,
-                        struct fw_iso_buffer *buffer,
-                        unsigned long payload);
-int fw_iso_context_start(struct fw_iso_context *ctx,
-                        int cycle, int sync, int tags);
-int fw_iso_context_stop(struct fw_iso_context *ctx);
-void fw_iso_context_destroy(struct fw_iso_context *ctx);
-
-void fw_iso_resource_manage(struct fw_card *card, int generation,
-               u64 channels_mask, int *channel, int *bandwidth, bool allocate);
-
-struct fw_card_driver {
-       /*
-        * Enable the given card with the given initial config rom.
-        * This function is expected to activate the card, and either
-        * enable the PHY or set the link_on bit and initiate a bus
-        * reset.
-        */
-       int (*enable)(struct fw_card *card, u32 *config_rom, size_t length);
-
-       int (*update_phy_reg)(struct fw_card *card, int address,
-                             int clear_bits, int set_bits);
-
-       /*
-        * Update the config rom for an enabled card.  This function
-        * should change the config rom that is presented on the bus
-        * an initiate a bus reset.
-        */
-       int (*set_config_rom)(struct fw_card *card,
-                             u32 *config_rom, size_t length);
-
-       void (*send_request)(struct fw_card *card, struct fw_packet *packet);
-       void (*send_response)(struct fw_card *card, struct fw_packet *packet);
-       /* Calling cancel is valid once a packet has been submitted. */
-       int (*cancel_packet)(struct fw_card *card, struct fw_packet *packet);
-
-       /*
-        * Allow the specified node ID to do direct DMA out and in of
-        * host memory.  The card will disable this for all node when
-        * a bus reset happens, so driver need to reenable this after
-        * bus reset.  Returns 0 on success, -ENODEV if the card
-        * doesn't support this, -ESTALE if the generation doesn't
-        * match.
-        */
-       int (*enable_phys_dma)(struct fw_card *card,
-                              int node_id, int generation);
-
-       u64 (*get_bus_time)(struct fw_card *card);
-
-       struct fw_iso_context *
-       (*allocate_iso_context)(struct fw_card *card,
-                               int type, int channel, size_t header_size);
-       void (*free_iso_context)(struct fw_iso_context *ctx);
-
-       int (*start_iso)(struct fw_iso_context *ctx,
-                        s32 cycle, u32 sync, u32 tags);
-
-       int (*queue_iso)(struct fw_iso_context *ctx,
-                        struct fw_iso_packet *packet,
-                        struct fw_iso_buffer *buffer,
-                        unsigned long payload);
-
-       int (*stop_iso)(struct fw_iso_context *ctx);
-};
-
-int fw_core_initiate_bus_reset(struct fw_card *card, int short_reset);
-
-void fw_send_request(struct fw_card *card, struct fw_transaction *t,
-               int tcode, int destination_id, int generation, int speed,
-               unsigned long long offset, void *payload, size_t length,
-               fw_transaction_callback_t callback, void *callback_data);
-int fw_cancel_transaction(struct fw_card *card,
-                         struct fw_transaction *transaction);
-void fw_flush_transactions(struct fw_card *card);
-int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
-                      int generation, int speed, unsigned long long offset,
-                      void *payload, size_t length);
-void fw_send_phy_config(struct fw_card *card,
-                       int node_id, int generation, int gap_count);
-
-static inline int fw_stream_packet_destination_id(int tag, int channel, int sy)
-{
-       return tag << 14 | channel << 8 | sy;
-}
-
-/*
- * Called by the topology code to inform the device code of node
- * activity; found, lost, or updated nodes.
- */
-void fw_node_event(struct fw_card *card, struct fw_node *node, int event);
-
-/* API used by card level drivers */
-
-void fw_card_initialize(struct fw_card *card,
-               const struct fw_card_driver *driver, struct device *device);
-int fw_card_add(struct fw_card *card,
-               u32 max_receive, u32 link_speed, u64 guid);
-void fw_core_remove_card(struct fw_card *card);
-void fw_core_handle_bus_reset(struct fw_card *card, int node_id,
-               int generation, int self_id_count, u32 *self_ids);
-void fw_core_handle_request(struct fw_card *card, struct fw_packet *request);
-void fw_core_handle_response(struct fw_card *card, struct fw_packet *packet);
-
-extern int fw_irm_set_broadcast_channel_register(struct device *dev,
-                                                void *data);
-
-#endif /* __fw_transaction_h */
similarity index 99%
rename from drivers/firewire/fw-ohci.c
rename to drivers/firewire/ohci.c
index 1180d0be0bb4c0536cd7917cbd68910518f67450..ecddd11b797a366d105763656dd4eda2c2273add 100644 (file)
 
 #include <linux/compiler.h>
 #include <linux/delay.h>
+#include <linux/device.h>
 #include <linux/dma-mapping.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
 #include <linux/gfp.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
+#include <linux/list.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/pci.h>
 #include <linux/spinlock.h>
+#include <linux/string.h>
 
+#include <asm/atomic.h>
+#include <asm/byteorder.h>
 #include <asm/page.h>
 #include <asm/system.h>
 
@@ -38,8 +46,8 @@
 #include <asm/pmac_feature.h>
 #endif
 
-#include "fw-ohci.h"
-#include "fw-transaction.h"
+#include "core.h"
+#include "ohci.h"
 
 #define DESCRIPTOR_OUTPUT_MORE         0
 #define DESCRIPTOR_OUTPUT_LAST         (1 << 12)
@@ -178,7 +186,7 @@ struct fw_ohci {
        int node_id;
        int generation;
        int request_generation; /* for timestamping incoming requests */
-       u32 bus_seconds;
+       atomic_t bus_seconds;
 
        bool use_dualbuffer;
        bool old_uninorth;
@@ -231,7 +239,6 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card)
 #define OHCI1394_MAX_AT_RESP_RETRIES   0x2
 #define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8
 
-#define FW_OHCI_MAJOR                  240
 #define OHCI1394_REGISTER_SIZE         0x800
 #define OHCI_LOOP_COUNT                        500
 #define OHCI1394_PCI_HCI_Control       0x40
@@ -1434,7 +1441,7 @@ static irqreturn_t irq_handler(int irq, void *data)
        if (event & OHCI1394_cycle64Seconds) {
                cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
                if ((cycle_time & 0x80000000) == 0)
-                       ohci->bus_seconds++;
+                       atomic_inc(&ohci->bus_seconds);
        }
 
        return IRQ_HANDLED;
@@ -1770,7 +1777,7 @@ static u64 ohci_get_bus_time(struct fw_card *card)
        u64 bus_time;
 
        cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
-       bus_time = ((u64) ohci->bus_seconds << 32) | cycle_time;
+       bus_time = ((u64)atomic_read(&ohci->bus_seconds) << 32) | cycle_time;
 
        return bus_time;
 }
similarity index 98%
rename from drivers/firewire/fw-ohci.h
rename to drivers/firewire/ohci.h
index a2fbb6240ca75033e683edafd56b934856d2613b..ba492d85c516260c33339c953296408e23437e16 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef __fw_ohci_h
-#define __fw_ohci_h
+#ifndef _FIREWIRE_OHCI_H
+#define _FIREWIRE_OHCI_H
 
 /* OHCI register map */
 
 
 #define OHCI1394_phy_tcode             0xe
 
-#endif /* __fw_ohci_h */
+#endif /* _FIREWIRE_OHCI_H */
similarity index 96%
rename from drivers/firewire/fw-sbp2.c
rename to drivers/firewire/sbp2.c
index 2bcf51557c72ae8300ae844106ed0d052f9eb068..24c45635376a746ba9ae3e69ef53cfa7da1ab514 100644 (file)
 
 #include <linux/blkdev.h>
 #include <linux/bug.h>
+#include <linux/completion.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
 #include <linux/kernel.h>
+#include <linux/kref.h>
+#include <linux/list.h>
 #include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/stringify.h>
-#include <linux/timer.h>
 #include <linux/workqueue.h>
+
+#include <asm/byteorder.h>
 #include <asm/system.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 
-#include "fw-device.h"
-#include "fw-topology.h"
-#include "fw-transaction.h"
-
 /*
  * So far only bridges from Oxford Semiconductor are known to support
  * concurrent logins. Depending on firmware, four or two concurrent logins
@@ -174,6 +180,11 @@ struct sbp2_target {
        int blocked;    /* ditto */
 };
 
+static struct fw_device *target_device(struct sbp2_target *tgt)
+{
+       return fw_parent_device(tgt->unit);
+}
+
 /* Impossible login_id, to detect logout attempt before successful login */
 #define INVALID_LOGIN_ID 0x10000
 
@@ -482,7 +493,7 @@ static void complete_transaction(struct fw_card *card, int rcode,
 static void sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu,
                          int node_id, int generation, u64 offset)
 {
-       struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
+       struct fw_device *device = target_device(lu->tgt);
        unsigned long flags;
 
        orb->pointer.high = 0;
@@ -504,7 +515,7 @@ static void sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu,
 
 static int sbp2_cancel_orbs(struct sbp2_logical_unit *lu)
 {
-       struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
+       struct fw_device *device = target_device(lu->tgt);
        struct sbp2_orb *orb, *next;
        struct list_head list;
        unsigned long flags;
@@ -542,7 +553,7 @@ static int sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id,
                                    int generation, int function,
                                    int lun_or_login_id, void *response)
 {
-       struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
+       struct fw_device *device = target_device(lu->tgt);
        struct sbp2_management_orb *orb;
        unsigned int timeout;
        int retval = -ENOMEM;
@@ -638,7 +649,7 @@ static int sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id,
 
 static void sbp2_agent_reset(struct sbp2_logical_unit *lu)
 {
-       struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
+       struct fw_device *device = target_device(lu->tgt);
        __be32 d = 0;
 
        fw_run_transaction(device->card, TCODE_WRITE_QUADLET_REQUEST,
@@ -655,7 +666,7 @@ static void complete_agent_reset_write_no_wait(struct fw_card *card,
 
 static void sbp2_agent_reset_no_wait(struct sbp2_logical_unit *lu)
 {
-       struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
+       struct fw_device *device = target_device(lu->tgt);
        struct fw_transaction *t;
        static __be32 d;
 
@@ -694,7 +705,7 @@ static inline void sbp2_allow_block(struct sbp2_logical_unit *lu)
 static void sbp2_conditionally_block(struct sbp2_logical_unit *lu)
 {
        struct sbp2_target *tgt = lu->tgt;
-       struct fw_card *card = fw_device(tgt->unit->device.parent)->card;
+       struct fw_card *card = target_device(tgt)->card;
        struct Scsi_Host *shost =
                container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
        unsigned long flags;
@@ -718,7 +729,7 @@ static void sbp2_conditionally_block(struct sbp2_logical_unit *lu)
 static void sbp2_conditionally_unblock(struct sbp2_logical_unit *lu)
 {
        struct sbp2_target *tgt = lu->tgt;
-       struct fw_card *card = fw_device(tgt->unit->device.parent)->card;
+       struct fw_card *card = target_device(tgt)->card;
        struct Scsi_Host *shost =
                container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
        unsigned long flags;
@@ -743,7 +754,7 @@ static void sbp2_conditionally_unblock(struct sbp2_logical_unit *lu)
  */
 static void sbp2_unblock(struct sbp2_target *tgt)
 {
-       struct fw_card *card = fw_device(tgt->unit->device.parent)->card;
+       struct fw_card *card = target_device(tgt)->card;
        struct Scsi_Host *shost =
                container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
        unsigned long flags;
@@ -773,7 +784,7 @@ static void sbp2_release_target(struct kref *kref)
        struct Scsi_Host *shost =
                container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
        struct scsi_device *sdev;
-       struct fw_device *device = fw_device(tgt->unit->device.parent);
+       struct fw_device *device = target_device(tgt);
 
        /* prevent deadlocks */
        sbp2_unblock(tgt);
@@ -846,7 +857,7 @@ static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay)
  */
 static void sbp2_set_busy_timeout(struct sbp2_logical_unit *lu)
 {
-       struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
+       struct fw_device *device = target_device(lu->tgt);
        __be32 d = cpu_to_be32(SBP2_CYCLE_LIMIT | SBP2_RETRY_LIMIT);
 
        fw_run_transaction(device->card, TCODE_WRITE_QUADLET_REQUEST,
@@ -862,7 +873,7 @@ static void sbp2_login(struct work_struct *work)
        struct sbp2_logical_unit *lu =
                container_of(work, struct sbp2_logical_unit, work.work);
        struct sbp2_target *tgt = lu->tgt;
-       struct fw_device *device = fw_device(tgt->unit->device.parent);
+       struct fw_device *device = target_device(tgt);
        struct Scsi_Host *shost;
        struct scsi_device *sdev;
        struct sbp2_login_response response;
@@ -1110,7 +1121,7 @@ static struct scsi_host_template scsi_driver_template;
 static int sbp2_probe(struct device *dev)
 {
        struct fw_unit *unit = fw_unit(dev);
-       struct fw_device *device = fw_device(unit->device.parent);
+       struct fw_device *device = fw_parent_device(unit);
        struct sbp2_target *tgt;
        struct sbp2_logical_unit *lu;
        struct Scsi_Host *shost;
@@ -1125,7 +1136,7 @@ static int sbp2_probe(struct device *dev)
                return -ENOMEM;
 
        tgt = (struct sbp2_target *)shost->hostdata;
-       unit->device.driver_data = tgt;
+       dev_set_drvdata(&unit->device, tgt);
        tgt->unit = unit;
        kref_init(&tgt->kref);
        INIT_LIST_HEAD(&tgt->lu_list);
@@ -1180,7 +1191,7 @@ static int sbp2_probe(struct device *dev)
 static int sbp2_remove(struct device *dev)
 {
        struct fw_unit *unit = fw_unit(dev);
-       struct sbp2_target *tgt = unit->device.driver_data;
+       struct sbp2_target *tgt = dev_get_drvdata(&unit->device);
 
        sbp2_target_put(tgt);
        return 0;
@@ -1191,7 +1202,7 @@ static void sbp2_reconnect(struct work_struct *work)
        struct sbp2_logical_unit *lu =
                container_of(work, struct sbp2_logical_unit, work.work);
        struct sbp2_target *tgt = lu->tgt;
-       struct fw_device *device = fw_device(tgt->unit->device.parent);
+       struct fw_device *device = target_device(tgt);
        int generation, node_id, local_node_id;
 
        if (fw_device_is_shutdown(device))
@@ -1240,10 +1251,10 @@ static void sbp2_reconnect(struct work_struct *work)
 
 static void sbp2_update(struct fw_unit *unit)
 {
-       struct sbp2_target *tgt = unit->device.driver_data;
+       struct sbp2_target *tgt = dev_get_drvdata(&unit->device);
        struct sbp2_logical_unit *lu;
 
-       fw_device_enable_phys_dma(fw_device(unit->device.parent));
+       fw_device_enable_phys_dma(fw_parent_device(unit));
 
        /*
         * Fw-core serializes sbp2_update() against sbp2_remove().
@@ -1259,9 +1270,10 @@ static void sbp2_update(struct fw_unit *unit)
 #define SBP2_UNIT_SPEC_ID_ENTRY        0x0000609e
 #define SBP2_SW_VERSION_ENTRY  0x00010483
 
-static const struct fw_device_id sbp2_id_table[] = {
+static const struct ieee1394_device_id sbp2_id_table[] = {
        {
-               .match_flags  = FW_MATCH_SPECIFIER_ID | FW_MATCH_VERSION,
+               .match_flags  = IEEE1394_MATCH_SPECIFIER_ID |
+                               IEEE1394_MATCH_VERSION,
                .specifier_id = SBP2_UNIT_SPEC_ID_ENTRY,
                .version      = SBP2_SW_VERSION_ENTRY,
        },
@@ -1335,7 +1347,7 @@ static void complete_command_orb(struct sbp2_orb *base_orb,
 {
        struct sbp2_command_orb *orb =
                container_of(base_orb, struct sbp2_command_orb, base);
-       struct fw_device *device = fw_device(orb->lu->tgt->unit->device.parent);
+       struct fw_device *device = target_device(orb->lu->tgt);
        int result;
 
        if (status != NULL) {
@@ -1442,7 +1454,7 @@ static int sbp2_map_scatterlist(struct sbp2_command_orb *orb,
 static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
 {
        struct sbp2_logical_unit *lu = cmd->device->hostdata;
-       struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
+       struct fw_device *device = target_device(lu->tgt);
        struct sbp2_command_orb *orb;
        int generation, retval = SCSI_MLQUEUE_HOST_BUSY;
 
index 05aa2d406ac64769ecfbb3f6827d5e7fb53915e3..d5ea8a68d338ef80996d20dd0bbbf4e27d3fafc0 100644 (file)
  * information is necessary as for the resource tree.
  */
 struct firmware_map_entry {
-       resource_size_t         start;  /* start of the memory range */
-       resource_size_t         end;    /* end of the memory range (incl.) */
+       /*
+        * start and end must be u64 rather than resource_size_t, because e820
+        * resources can lie at addresses above 4G.
+        */
+       u64                     start;  /* start of the memory range */
+       u64                     end;    /* end of the memory range (incl.) */
        const char              *type;  /* type of the memory range */
        struct list_head        list;   /* entry for the linked list */
        struct kobject          kobj;   /* kobject for each entry */
@@ -101,7 +105,7 @@ static LIST_HEAD(map_entries);
  * Common implementation of firmware_map_add() and firmware_map_add_early()
  * which expects a pre-allocated struct firmware_map_entry.
  **/
-static int firmware_map_add_entry(resource_size_t start, resource_size_t end,
+static int firmware_map_add_entry(u64 start, u64 end,
                                  const char *type,
                                  struct firmware_map_entry *entry)
 {
@@ -132,8 +136,7 @@ static int firmware_map_add_entry(resource_size_t start, resource_size_t end,
  *
  * Returns 0 on success, or -ENOMEM if no memory could be allocated.
  **/
-int firmware_map_add(resource_size_t start, resource_size_t end,
-                    const char *type)
+int firmware_map_add(u64 start, u64 end, const char *type)
 {
        struct firmware_map_entry *entry;
 
@@ -157,8 +160,7 @@ int firmware_map_add(resource_size_t start, resource_size_t end,
  *
  * Returns 0 on success, or -ENOMEM if no memory could be allocated.
  **/
-int __init firmware_map_add_early(resource_size_t start, resource_size_t end,
-                                 const char *type)
+int __init firmware_map_add_early(u64 start, u64 end, const char *type)
 {
        struct firmware_map_entry *entry;
 
index f5d46e7199d48d03c12bfbc7b866540e607cddf1..c961fe415aef83bfecda56873b59431601674bce 100644 (file)
@@ -18,6 +18,14 @@ menuconfig DRM
          details.  You should also select and configure AGP
          (/dev/agpgart) support.
 
+config DRM_TTM
+       tristate
+       depends on DRM
+       help
+         GPU memory management subsystem for devices with multiple
+         GPU memory types. Will be enabled automatically if a device driver
+         uses it.
+
 config DRM_TDFX
        tristate "3dfx Banshee/Voodoo3+"
        depends on DRM && PCI
@@ -36,6 +44,11 @@ config DRM_R128
 config DRM_RADEON
        tristate "ATI Radeon"
        depends on DRM && PCI
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       select FB
+       select FRAMEBUFFER_CONSOLE if !EMBEDDED
        help
          Choose this option if you have an ATI Radeon graphics card.  There
          are both PCI and AGP versions.  You don't need to choose this to
index 4ec5061fa584aab4d070deabcf776de0994d3720..4e89ab08b7b8d9eecf6fccc6e16901f5e41f4ed9 100644 (file)
@@ -26,4 +26,4 @@ obj-$(CONFIG_DRM_I915)  += i915/
 obj-$(CONFIG_DRM_SIS)   += sis/
 obj-$(CONFIG_DRM_SAVAGE)+= savage/
 obj-$(CONFIG_DRM_VIA)  +=via/
-
+obj-$(CONFIG_DRM_TTM)  += ttm/
index c77c6c6d9d2c907eadf71c81f9a0aa3d5db4a37e..6ce0e2667a85f046987b9a7cd4f3a919b5630f5f 100644 (file)
@@ -105,7 +105,7 @@ int drm_debugfs_create_files(struct drm_info_list *files, int count,
                ent = debugfs_create_file(files[i].name, S_IFREG | S_IRUGO,
                                          root, tmp, &drm_debugfs_fops);
                if (!ent) {
-                       DRM_ERROR("Cannot create /debugfs/dri/%s/%s\n",
+                       DRM_ERROR("Cannot create /sys/kernel/debug/dri/%s/%s\n",
                                  name, files[i].name);
                        drm_free(tmp, sizeof(struct drm_info_node),
                                 _DRM_DRIVER);
@@ -133,9 +133,9 @@ EXPORT_SYMBOL(drm_debugfs_create_files);
  * \param minor device minor number
  * \param root DRI debugfs dir entry.
  *
- * Create the DRI debugfs root entry "/debugfs/dri", the device debugfs root entry
- * "/debugfs/dri/%minor%/", and each entry in debugfs_list as
- * "/debugfs/dri/%minor%/%name%".
+ * Create the DRI debugfs root entry "/sys/kernel/debug/dri", the device debugfs root entry
+ * "/sys/kernel/debug/dri/%minor%/", and each entry in debugfs_list as
+ * "/sys/kernel/debug/dri/%minor%/%name%".
  */
 int drm_debugfs_init(struct drm_minor *minor, int minor_id,
                     struct dentry *root)
@@ -148,7 +148,7 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id,
        sprintf(name, "%d", minor_id);
        minor->debugfs_root = debugfs_create_dir(name, root);
        if (!minor->debugfs_root) {
-               DRM_ERROR("Cannot create /debugfs/dri/%s\n", name);
+               DRM_ERROR("Cannot create /sys/kernel/debug/dri/%s\n", name);
                return -1;
        }
 
@@ -165,7 +165,7 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id,
                ret = dev->driver->debugfs_init(minor);
                if (ret) {
                        DRM_ERROR("DRM: Driver failed to initialize "
-                                 "/debugfs/dri.\n");
+                                 "/sys/kernel/debug/dri.\n");
                        return ret;
                }
        }
index 019b7c5782367390783dfa8fada2046872a6e0c8..1bf7efd8d334acf7908d5f5dd02bb4fd6db1abe5 100644 (file)
@@ -339,7 +339,7 @@ static int __init drm_core_init(void)
 
        drm_debugfs_root = debugfs_create_dir("dri", NULL);
        if (!drm_debugfs_root) {
-               DRM_ERROR("Cannot create /debugfs/dri\n");
+               DRM_ERROR("Cannot create /sys/kernel/debug/dri\n");
                ret = -1;
                goto err_p3;
        }
index 7819fd930a515ce8840c2b7f0b11c9e33cc08b0c..a912a0ff11ccbc595dd9f1f2308152c05ce9195d 100644 (file)
@@ -188,36 +188,34 @@ static struct drm_mm_node *drm_mm_split_at_start(struct drm_mm_node *parent,
 
 
 
-struct drm_mm_node *drm_mm_get_block(struct drm_mm_node * parent,
-                               unsigned long size, unsigned alignment)
+struct drm_mm_node *drm_mm_get_block(struct drm_mm_node *node,
+                                    unsigned long size, unsigned alignment)
 {
 
        struct drm_mm_node *align_splitoff = NULL;
-       struct drm_mm_node *child;
        unsigned tmp = 0;
 
        if (alignment)
-               tmp = parent->start % alignment;
+               tmp = node->start % alignment;
 
        if (tmp) {
                align_splitoff =
-                   drm_mm_split_at_start(parent, alignment - tmp, 0);
+                   drm_mm_split_at_start(node, alignment - tmp, 0);
                if (unlikely(align_splitoff == NULL))
                        return NULL;
        }
 
-       if (parent->size == size) {
-               list_del_init(&parent->fl_entry);
-               parent->free = 0;
-               return parent;
+       if (node->size == size) {
+               list_del_init(&node->fl_entry);
+               node->free = 0;
        } else {
-               child = drm_mm_split_at_start(parent, size, 0);
+               node = drm_mm_split_at_start(node, size, 0);
        }
 
        if (align_splitoff)
                drm_mm_put_block(align_splitoff);
 
-       return child;
+       return node;
 }
 
 EXPORT_SYMBOL(drm_mm_get_block);
index 89050684fe0d2c7b33a2fdf0a31287c5955e5778..387a8de1bc7e51f60af11c903d5852a93bc98e15 100644 (file)
@@ -343,7 +343,7 @@ static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor, int t
 #if defined(CONFIG_DEBUG_FS)
        ret = drm_debugfs_init(new_minor, minor_id, drm_debugfs_root);
        if (ret) {
-               DRM_ERROR("DRM: Failed to initialize /debugfs/dri.\n");
+               DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n");
                goto err_g2;
        }
 #endif
index 9987ab8808356d13b01c2540c085181e4f7db791..85ec31b3ff00a09f1d18b0a9b66cd31b68d8ba21 100644 (file)
@@ -70,6 +70,11 @@ static ssize_t version_show(struct class *dev, char *buf)
                       CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE);
 }
 
+static char *drm_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "dri/%s", dev_name(dev));
+}
+
 static CLASS_ATTR(version, S_IRUGO, version_show, NULL);
 
 /**
@@ -101,6 +106,8 @@ struct class *drm_sysfs_create(struct module *owner, char *name)
        if (err)
                goto err_out_class;
 
+       class->nodename = drm_nodename;
+
        return class;
 
 err_out_class:
index 0ecf6b76a401c043e00a12b3b027a07ef14cce01..8e28e5993df5b5607896db9c8c30a226faf1790d 100644 (file)
@@ -504,6 +504,14 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
        info->fbops = &intelfb_ops;
 
        info->fix.line_length = fb->pitch;
+
+       /* setup aperture base/size for vesafb takeover */
+       info->aperture_base = dev->mode_config.fb_base;
+       if (IS_I9XX(dev))
+               info->aperture_size = pci_resource_len(dev->pdev, 2);
+       else
+               info->aperture_size = pci_resource_len(dev->pdev, 0);
+
        info->fix.smem_start = dev->mode_config.fb_base + obj_priv->gtt_offset;
        info->fix.smem_len = size;
 
diff --git a/drivers/gpu/drm/radeon/Kconfig b/drivers/gpu/drm/radeon/Kconfig
new file mode 100644 (file)
index 0000000..2168d67
--- /dev/null
@@ -0,0 +1,34 @@
+config DRM_RADEON_KMS
+       bool "Enable modesetting on radeon by default"
+       depends on DRM_RADEON
+       select DRM_TTM
+       help
+         Choose this option if you want kernel modesetting enabled by default,
+         and you have a new enough userspace to support this. Running old
+         userspaces with this enabled will cause pain.
+
+         When kernel modesetting is enabled the IOCTL of radeon/drm
+         driver are considered as invalid and an error message is printed
+         in the log and they return failure.
+
+         KMS enabled userspace will use new API to talk with the radeon/drm
+         driver. The new API provide functions to create/destroy/share/mmap
+         buffer object which are then managed by the kernel memory manager
+         (here TTM). In order to submit command to the GPU the userspace
+         provide a buffer holding the command stream, along this buffer
+         userspace have to provide a list of buffer object used by the
+         command stream. The kernel radeon driver will then place buffer
+         in GPU accessible memory and will update command stream to reflect
+         the position of the different buffers.
+
+         The kernel will also perform security check on command stream
+         provided by the user, we want to catch and forbid any illegal use
+         of the GPU such as DMA into random system memory or into memory
+         not owned by the process supplying the command stream. This part
+         of the code is still incomplete and this why we propose that patch
+         as a staging driver addition, future security might forbid current
+         experimental userspace to run.
+
+         This code support the following hardware : R1XX,R2XX,R3XX,R4XX,R5XX
+         (radeon up to X1950). Works is underway to provide support for R6XX,
+         R7XX and newer hardware (radeon from HD2XXX to HD4XXX).
index 52ce439a0f2e77d5562056b6f58180cc90e7e5ca..5fae1e074b4b7fd8565f9c4e2f75202305f4ddb6 100644 (file)
@@ -3,7 +3,17 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 ccflags-y := -Iinclude/drm
-radeon-y := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o r600_cp.o
+radeon-y := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o \
+       radeon_irq.o r300_cmdbuf.o r600_cp.o
+
+radeon-$(CONFIG_DRM_RADEON_KMS) += radeon_device.o radeon_kms.o \
+       radeon_atombios.o radeon_agp.o atombios_crtc.o radeon_combios.o \
+       atom.o radeon_fence.o radeon_ttm.o radeon_object.o radeon_gart.o \
+       radeon_legacy_crtc.o radeon_legacy_encoders.o radeon_connectors.o \
+       radeon_encoders.o radeon_display.o radeon_cursor.o radeon_i2c.o \
+       radeon_clocks.o radeon_fb.o radeon_gem.o radeon_ring.o radeon_irq_kms.o \
+       radeon_cs.o radeon_bios.o radeon_benchmark.o r100.o r300.o r420.o \
+       rs400.o rs600.o rs690.o rv515.o r520.o r600.o rs780.o rv770.o
 
 radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
 
diff --git a/drivers/gpu/drm/radeon/ObjectID.h b/drivers/gpu/drm/radeon/ObjectID.h
new file mode 100644 (file)
index 0000000..6d0183c
--- /dev/null
@@ -0,0 +1,578 @@
+/*
+* Copyright 2006-2007 Advanced Micro Devices, Inc.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a
+* copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation
+* the rights to use, copy, modify, merge, publish, distribute, sublicense,
+* and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+* OTHER DEALINGS IN THE SOFTWARE.
+*/
+/* based on stg/asic_reg/drivers/inc/asic_reg/ObjectID.h ver 23 */
+
+#ifndef _OBJECTID_H
+#define _OBJECTID_H
+
+#if defined(_X86_)
+#pragma pack(1)
+#endif
+
+/****************************************************/
+/* Graphics Object Type Definition                  */
+/****************************************************/
+#define GRAPH_OBJECT_TYPE_NONE                    0x0
+#define GRAPH_OBJECT_TYPE_GPU                     0x1
+#define GRAPH_OBJECT_TYPE_ENCODER                 0x2
+#define GRAPH_OBJECT_TYPE_CONNECTOR               0x3
+#define GRAPH_OBJECT_TYPE_ROUTER                  0x4
+/* deleted */
+
+/****************************************************/
+/* Encoder Object ID Definition                     */
+/****************************************************/
+#define ENCODER_OBJECT_ID_NONE                    0x00
+
+/* Radeon Class Display Hardware */
+#define ENCODER_OBJECT_ID_INTERNAL_LVDS           0x01
+#define ENCODER_OBJECT_ID_INTERNAL_TMDS1          0x02
+#define ENCODER_OBJECT_ID_INTERNAL_TMDS2          0x03
+#define ENCODER_OBJECT_ID_INTERNAL_DAC1           0x04
+#define ENCODER_OBJECT_ID_INTERNAL_DAC2           0x05 /* TV/CV DAC */
+#define ENCODER_OBJECT_ID_INTERNAL_SDVOA          0x06
+#define ENCODER_OBJECT_ID_INTERNAL_SDVOB          0x07
+
+/* External Third Party Encoders */
+#define ENCODER_OBJECT_ID_SI170B                  0x08
+#define ENCODER_OBJECT_ID_CH7303                  0x09
+#define ENCODER_OBJECT_ID_CH7301                  0x0A
+#define ENCODER_OBJECT_ID_INTERNAL_DVO1           0x0B /* This belongs to Radeon Class Display Hardware */
+#define ENCODER_OBJECT_ID_EXTERNAL_SDVOA          0x0C
+#define ENCODER_OBJECT_ID_EXTERNAL_SDVOB          0x0D
+#define ENCODER_OBJECT_ID_TITFP513                0x0E
+#define ENCODER_OBJECT_ID_INTERNAL_LVTM1          0x0F /* not used for Radeon */
+#define ENCODER_OBJECT_ID_VT1623                  0x10
+#define ENCODER_OBJECT_ID_HDMI_SI1930             0x11
+#define ENCODER_OBJECT_ID_HDMI_INTERNAL           0x12
+/* Kaleidoscope (KLDSCP) Class Display Hardware (internal) */
+#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1   0x13
+#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1    0x14
+#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1    0x15
+#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2    0x16 /* Shared with CV/TV and CRT */
+#define ENCODER_OBJECT_ID_SI178                   0X17 /* External TMDS (dual link, no HDCP.) */
+#define ENCODER_OBJECT_ID_MVPU_FPGA               0x18 /* MVPU FPGA chip */
+#define ENCODER_OBJECT_ID_INTERNAL_DDI            0x19
+#define ENCODER_OBJECT_ID_VT1625                  0x1A
+#define ENCODER_OBJECT_ID_HDMI_SI1932             0x1B
+#define ENCODER_OBJECT_ID_DP_AN9801               0x1C
+#define ENCODER_OBJECT_ID_DP_DP501                0x1D
+#define ENCODER_OBJECT_ID_INTERNAL_UNIPHY         0x1E
+#define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA   0x1F
+#define ENCODER_OBJECT_ID_INTERNAL_UNIPHY1        0x20
+#define ENCODER_OBJECT_ID_INTERNAL_UNIPHY2        0x21
+
+#define ENCODER_OBJECT_ID_GENERAL_EXTERNAL_DVO    0xFF
+
+/****************************************************/
+/* Connector Object ID Definition                   */
+/****************************************************/
+#define CONNECTOR_OBJECT_ID_NONE                  0x00
+#define CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I     0x01
+#define CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I       0x02
+#define CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D     0x03
+#define CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D       0x04
+#define CONNECTOR_OBJECT_ID_VGA                   0x05
+#define CONNECTOR_OBJECT_ID_COMPOSITE             0x06
+#define CONNECTOR_OBJECT_ID_SVIDEO                0x07
+#define CONNECTOR_OBJECT_ID_YPbPr                 0x08
+#define CONNECTOR_OBJECT_ID_D_CONNECTOR           0x09
+#define CONNECTOR_OBJECT_ID_9PIN_DIN              0x0A /* Supports both CV & TV */
+#define CONNECTOR_OBJECT_ID_SCART                 0x0B
+#define CONNECTOR_OBJECT_ID_HDMI_TYPE_A           0x0C
+#define CONNECTOR_OBJECT_ID_HDMI_TYPE_B           0x0D
+#define CONNECTOR_OBJECT_ID_LVDS                  0x0E
+#define CONNECTOR_OBJECT_ID_7PIN_DIN              0x0F
+#define CONNECTOR_OBJECT_ID_PCIE_CONNECTOR        0x10
+#define CONNECTOR_OBJECT_ID_CROSSFIRE             0x11
+#define CONNECTOR_OBJECT_ID_HARDCODE_DVI          0x12
+#define CONNECTOR_OBJECT_ID_DISPLAYPORT           0x13
+
+/* deleted */
+
+/****************************************************/
+/* Router Object ID Definition                      */
+/****************************************************/
+#define ROUTER_OBJECT_ID_NONE                                                                                  0x00
+#define ROUTER_OBJECT_ID_I2C_EXTENDER_CNTL                             0x01
+
+/****************************************************/
+/* Graphics Object ENUM ID Definition               */
+/****************************************************/
+#define GRAPH_OBJECT_ENUM_ID1                     0x01
+#define GRAPH_OBJECT_ENUM_ID2                     0x02
+#define GRAPH_OBJECT_ENUM_ID3                     0x03
+#define GRAPH_OBJECT_ENUM_ID4                     0x04
+#define GRAPH_OBJECT_ENUM_ID5                     0x05
+#define GRAPH_OBJECT_ENUM_ID6                     0x06
+
+/****************************************************/
+/* Graphics Object ID Bit definition                */
+/****************************************************/
+#define OBJECT_ID_MASK                            0x00FF
+#define ENUM_ID_MASK                              0x0700
+#define RESERVED1_ID_MASK                         0x0800
+#define OBJECT_TYPE_MASK                          0x7000
+#define RESERVED2_ID_MASK                         0x8000
+
+#define OBJECT_ID_SHIFT                           0x00
+#define ENUM_ID_SHIFT                             0x08
+#define OBJECT_TYPE_SHIFT                         0x0C
+
+/****************************************************/
+/* Graphics Object family definition                */
+/****************************************************/
+#define CONSTRUCTOBJECTFAMILYID(GRAPHICS_OBJECT_TYPE, GRAPHICS_OBJECT_ID) \
+       (GRAPHICS_OBJECT_TYPE << OBJECT_TYPE_SHIFT | \
+        GRAPHICS_OBJECT_ID   << OBJECT_ID_SHIFT)
+/****************************************************/
+/* GPU Object ID definition - Shared with BIOS      */
+/****************************************************/
+#define GPU_ENUM_ID1   (GRAPH_OBJECT_TYPE_GPU << OBJECT_TYPE_SHIFT |\
+                        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT)
+
+/****************************************************/
+/* Encoder Object ID definition - Shared with BIOS  */
+/****************************************************/
+/*
+#define ENCODER_INTERNAL_LVDS_ENUM_ID1        0x2101
+#define ENCODER_INTERNAL_TMDS1_ENUM_ID1       0x2102
+#define ENCODER_INTERNAL_TMDS2_ENUM_ID1       0x2103
+#define ENCODER_INTERNAL_DAC1_ENUM_ID1        0x2104
+#define ENCODER_INTERNAL_DAC2_ENUM_ID1        0x2105
+#define ENCODER_INTERNAL_SDVOA_ENUM_ID1       0x2106
+#define ENCODER_INTERNAL_SDVOB_ENUM_ID1       0x2107
+#define ENCODER_SIL170B_ENUM_ID1              0x2108
+#define ENCODER_CH7303_ENUM_ID1               0x2109
+#define ENCODER_CH7301_ENUM_ID1               0x210A
+#define ENCODER_INTERNAL_DVO1_ENUM_ID1        0x210B
+#define ENCODER_EXTERNAL_SDVOA_ENUM_ID1       0x210C
+#define ENCODER_EXTERNAL_SDVOB_ENUM_ID1       0x210D
+#define ENCODER_TITFP513_ENUM_ID1             0x210E
+#define ENCODER_INTERNAL_LVTM1_ENUM_ID1       0x210F
+#define ENCODER_VT1623_ENUM_ID1               0x2110
+#define ENCODER_HDMI_SI1930_ENUM_ID1          0x2111
+#define ENCODER_HDMI_INTERNAL_ENUM_ID1        0x2112
+#define ENCODER_INTERNAL_KLDSCP_TMDS1_ENUM_ID1   0x2113
+#define ENCODER_INTERNAL_KLDSCP_DVO1_ENUM_ID1    0x2114
+#define ENCODER_INTERNAL_KLDSCP_DAC1_ENUM_ID1    0x2115
+#define ENCODER_INTERNAL_KLDSCP_DAC2_ENUM_ID1    0x2116
+#define ENCODER_SI178_ENUM_ID1                   0x2117
+#define ENCODER_MVPU_FPGA_ENUM_ID1               0x2118
+#define ENCODER_INTERNAL_DDI_ENUM_ID1            0x2119
+#define ENCODER_VT1625_ENUM_ID1                  0x211A
+#define ENCODER_HDMI_SI1932_ENUM_ID1             0x211B
+#define ENCODER_ENCODER_DP_AN9801_ENUM_ID1       0x211C
+#define ENCODER_DP_DP501_ENUM_ID1                0x211D
+#define ENCODER_INTERNAL_UNIPHY_ENUM_ID1         0x211E
+*/
+#define ENCODER_INTERNAL_LVDS_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_INTERNAL_LVDS << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_TMDS1_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_INTERNAL_TMDS1 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_TMDS2_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_INTERNAL_TMDS2 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_DAC1_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_INTERNAL_DAC1 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_DAC2_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_INTERNAL_DAC2 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_SDVOA_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_INTERNAL_SDVOA << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_SDVOA_ENUM_ID2 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_INTERNAL_SDVOA << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_SDVOB_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_INTERNAL_SDVOB << OBJECT_ID_SHIFT)
+
+#define ENCODER_SIL170B_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_SI170B << OBJECT_ID_SHIFT)
+
+#define ENCODER_CH7303_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_CH7303 << OBJECT_ID_SHIFT)
+
+#define ENCODER_CH7301_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_CH7301 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_DVO1_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_INTERNAL_DVO1 << OBJECT_ID_SHIFT)
+
+#define ENCODER_EXTERNAL_SDVOA_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_EXTERNAL_SDVOA << OBJECT_ID_SHIFT)
+
+#define ENCODER_EXTERNAL_SDVOA_ENUM_ID2 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_EXTERNAL_SDVOA << OBJECT_ID_SHIFT)
+
+#define ENCODER_EXTERNAL_SDVOB_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_EXTERNAL_SDVOB << OBJECT_ID_SHIFT)
+
+#define ENCODER_TITFP513_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_TITFP513 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_LVTM1_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_INTERNAL_LVTM1 << OBJECT_ID_SHIFT)
+
+#define ENCODER_VT1623_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_VT1623 << OBJECT_ID_SHIFT)
+
+#define ENCODER_HDMI_SI1930_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_HDMI_SI1930 << OBJECT_ID_SHIFT)
+
+#define ENCODER_HDMI_INTERNAL_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_HDMI_INTERNAL << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_KLDSCP_TMDS1_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_KLDSCP_TMDS1_ENUM_ID2 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_KLDSCP_DVO1_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_KLDSCP_DAC1_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_KLDSCP_DAC2_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2 << OBJECT_ID_SHIFT) /* Shared with CV/TV and CRT */
+
+#define ENCODER_SI178_ENUM_ID1  \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_SI178 << OBJECT_ID_SHIFT)
+
+#define ENCODER_MVPU_FPGA_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_MVPU_FPGA << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_DDI_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_INTERNAL_DDI << OBJECT_ID_SHIFT)
+
+#define ENCODER_VT1625_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_VT1625 << OBJECT_ID_SHIFT)
+
+#define ENCODER_HDMI_SI1932_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_HDMI_SI1932 << OBJECT_ID_SHIFT)
+
+#define ENCODER_DP_DP501_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_DP_DP501 << OBJECT_ID_SHIFT)
+
+#define ENCODER_DP_AN9801_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_DP_AN9801 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_UNIPHY_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_INTERNAL_UNIPHY << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_UNIPHY_ENUM_ID2 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_INTERNAL_UNIPHY << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_KLDSCP_LVTMA_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_UNIPHY1_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_INTERNAL_UNIPHY1 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_UNIPHY1_ENUM_ID2 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_INTERNAL_UNIPHY1 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_UNIPHY2_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_INTERNAL_UNIPHY2 << OBJECT_ID_SHIFT)
+
+#define ENCODER_INTERNAL_UNIPHY2_ENUM_ID2 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_INTERNAL_UNIPHY2 << OBJECT_ID_SHIFT)
+
+#define ENCODER_GENERAL_EXTERNAL_DVO_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ENCODER_OBJECT_ID_GENERAL_EXTERNAL_DVO << OBJECT_ID_SHIFT)
+
+/****************************************************/
+/* Connector Object ID definition - Shared with BIOS */
+/****************************************************/
+/*
+#define CONNECTOR_SINGLE_LINK_DVI_I_ENUM_ID1        0x3101
+#define CONNECTOR_DUAL_LINK_DVI_I_ENUM_ID1          0x3102
+#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID1        0x3103
+#define CONNECTOR_DUAL_LINK_DVI_D_ENUM_ID1          0x3104
+#define CONNECTOR_VGA_ENUM_ID1                      0x3105
+#define CONNECTOR_COMPOSITE_ENUM_ID1                0x3106
+#define CONNECTOR_SVIDEO_ENUM_ID1                   0x3107
+#define CONNECTOR_YPbPr_ENUM_ID1                    0x3108
+#define CONNECTOR_D_CONNECTORE_ENUM_ID1             0x3109
+#define CONNECTOR_9PIN_DIN_ENUM_ID1                 0x310A
+#define CONNECTOR_SCART_ENUM_ID1                    0x310B
+#define CONNECTOR_HDMI_TYPE_A_ENUM_ID1              0x310C
+#define CONNECTOR_HDMI_TYPE_B_ENUM_ID1              0x310D
+#define CONNECTOR_LVDS_ENUM_ID1                     0x310E
+#define CONNECTOR_7PIN_DIN_ENUM_ID1                 0x310F
+#define CONNECTOR_PCIE_CONNECTOR_ENUM_ID1           0x3110
+*/
+#define CONNECTOR_LVDS_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_LVDS << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_SINGLE_LINK_DVI_I_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_SINGLE_LINK_DVI_I_ENUM_ID2 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_DUAL_LINK_DVI_I_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_DUAL_LINK_DVI_I_ENUM_ID2 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID2 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_DUAL_LINK_DVI_D_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_VGA_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_VGA << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_VGA_ENUM_ID2 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_VGA << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_COMPOSITE_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_COMPOSITE << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_SVIDEO_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_SVIDEO << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_YPbPr_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_YPbPr << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_D_CONNECTOR_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_D_CONNECTOR << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_9PIN_DIN_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_9PIN_DIN << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_SCART_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_SCART << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_HDMI_TYPE_A_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_HDMI_TYPE_A << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_HDMI_TYPE_B_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_HDMI_TYPE_B << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_7PIN_DIN_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_7PIN_DIN << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_PCIE_CONNECTOR_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_PCIE_CONNECTOR << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_PCIE_CONNECTOR_ENUM_ID2 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_PCIE_CONNECTOR << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_CROSSFIRE_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_CROSSFIRE << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_CROSSFIRE_ENUM_ID2 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_CROSSFIRE << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_HARDCODE_DVI_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_HARDCODE_DVI << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_HARDCODE_DVI_ENUM_ID2 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_HARDCODE_DVI << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_DISPLAYPORT_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_DISPLAYPORT << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_DISPLAYPORT_ENUM_ID2 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_DISPLAYPORT << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_DISPLAYPORT_ENUM_ID3 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID3 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_DISPLAYPORT << OBJECT_ID_SHIFT)
+
+#define CONNECTOR_DISPLAYPORT_ENUM_ID4 \
+       (GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID4 << ENUM_ID_SHIFT |\
+        CONNECTOR_OBJECT_ID_DISPLAYPORT << OBJECT_ID_SHIFT)
+
+/****************************************************/
+/* Router Object ID definition - Shared with BIOS   */
+/****************************************************/
+#define ROUTER_I2C_EXTENDER_CNTL_ENUM_ID1 \
+       (GRAPH_OBJECT_TYPE_ROUTER << OBJECT_TYPE_SHIFT |\
+        GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\
+        ROUTER_OBJECT_ID_I2C_EXTENDER_CNTL << OBJECT_ID_SHIFT)
+
+/* deleted */
+
+/****************************************************/
+/* Object Cap definition - Shared with BIOS         */
+/****************************************************/
+#define GRAPHICS_OBJECT_CAP_I2C                 0x00000001L
+#define GRAPHICS_OBJECT_CAP_TABLE_ID            0x00000002L
+
+#define GRAPHICS_OBJECT_I2CCOMMAND_TABLE_ID                   0x01
+#define GRAPHICS_OBJECT_HOTPLUGDETECTIONINTERUPT_TABLE_ID     0x02
+#define GRAPHICS_OBJECT_ENCODER_OUTPUT_PROTECTION_TABLE_ID    0x03
+
+#if defined(_X86_)
+#pragma pack()
+#endif
+
+#endif /*GRAPHICTYPE */
diff --git a/drivers/gpu/drm/radeon/atom-bits.h b/drivers/gpu/drm/radeon/atom-bits.h
new file mode 100644 (file)
index 0000000..e8fae5c
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Stanislaw Skowronek
+ */
+
+#ifndef ATOM_BITS_H
+#define ATOM_BITS_H
+
+static inline uint8_t get_u8(void *bios, int ptr)
+{
+    return ((unsigned char *)bios)[ptr];
+}
+#define U8(ptr) get_u8(ctx->ctx->bios, (ptr))
+#define CU8(ptr) get_u8(ctx->bios, (ptr))
+static inline uint16_t get_u16(void *bios, int ptr)
+{
+    return get_u8(bios ,ptr)|(((uint16_t)get_u8(bios, ptr+1))<<8);
+}
+#define U16(ptr) get_u16(ctx->ctx->bios, (ptr))
+#define CU16(ptr) get_u16(ctx->bios, (ptr))
+static inline uint32_t get_u32(void *bios, int ptr)
+{
+    return get_u16(bios, ptr)|(((uint32_t)get_u16(bios, ptr+2))<<16);
+}
+#define U32(ptr) get_u32(ctx->ctx->bios, (ptr))
+#define CU32(ptr) get_u32(ctx->bios, (ptr))
+#define CSTR(ptr) (((char *)(ctx->bios))+(ptr))
+
+#endif
diff --git a/drivers/gpu/drm/radeon/atom-names.h b/drivers/gpu/drm/radeon/atom-names.h
new file mode 100644 (file)
index 0000000..6f907a5
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Stanislaw Skowronek
+ */
+
+#ifndef ATOM_NAMES_H
+#define ATOM_NAMES_H
+
+#include "atom.h"
+
+#ifdef ATOM_DEBUG
+
+#define ATOM_OP_NAMES_CNT 123
+static char *atom_op_names[ATOM_OP_NAMES_CNT] = {
+"RESERVED", "MOVE_REG", "MOVE_PS", "MOVE_WS", "MOVE_FB", "MOVE_PLL",
+"MOVE_MC", "AND_REG", "AND_PS", "AND_WS", "AND_FB", "AND_PLL", "AND_MC",
+"OR_REG", "OR_PS", "OR_WS", "OR_FB", "OR_PLL", "OR_MC", "SHIFT_LEFT_REG",
+"SHIFT_LEFT_PS", "SHIFT_LEFT_WS", "SHIFT_LEFT_FB", "SHIFT_LEFT_PLL",
+"SHIFT_LEFT_MC", "SHIFT_RIGHT_REG", "SHIFT_RIGHT_PS", "SHIFT_RIGHT_WS",
+"SHIFT_RIGHT_FB", "SHIFT_RIGHT_PLL", "SHIFT_RIGHT_MC", "MUL_REG",
+"MUL_PS", "MUL_WS", "MUL_FB", "MUL_PLL", "MUL_MC", "DIV_REG", "DIV_PS",
+"DIV_WS", "DIV_FB", "DIV_PLL", "DIV_MC", "ADD_REG", "ADD_PS", "ADD_WS",
+"ADD_FB", "ADD_PLL", "ADD_MC", "SUB_REG", "SUB_PS", "SUB_WS", "SUB_FB",
+"SUB_PLL", "SUB_MC", "SET_ATI_PORT", "SET_PCI_PORT", "SET_SYS_IO_PORT",
+"SET_REG_BLOCK", "SET_FB_BASE", "COMPARE_REG", "COMPARE_PS",
+"COMPARE_WS", "COMPARE_FB", "COMPARE_PLL", "COMPARE_MC", "SWITCH",
+"JUMP", "JUMP_EQUAL", "JUMP_BELOW", "JUMP_ABOVE", "JUMP_BELOW_OR_EQUAL",
+"JUMP_ABOVE_OR_EQUAL", "JUMP_NOT_EQUAL", "TEST_REG", "TEST_PS", "TEST_WS",
+"TEST_FB", "TEST_PLL", "TEST_MC", "DELAY_MILLISEC", "DELAY_MICROSEC",
+"CALL_TABLE", "REPEAT", "CLEAR_REG", "CLEAR_PS", "CLEAR_WS", "CLEAR_FB",
+"CLEAR_PLL", "CLEAR_MC", "NOP", "EOT", "MASK_REG", "MASK_PS", "MASK_WS",
+"MASK_FB", "MASK_PLL", "MASK_MC", "POST_CARD", "BEEP", "SAVE_REG",
+"RESTORE_REG", "SET_DATA_BLOCK", "XOR_REG", "XOR_PS", "XOR_WS", "XOR_FB",
+"XOR_PLL", "XOR_MC", "SHL_REG", "SHL_PS", "SHL_WS", "SHL_FB", "SHL_PLL",
+"SHL_MC", "SHR_REG", "SHR_PS", "SHR_WS", "SHR_FB", "SHR_PLL", "SHR_MC",
+"DEBUG", "CTB_DS",
+};
+
+#define ATOM_TABLE_NAMES_CNT 74
+static char *atom_table_names[ATOM_TABLE_NAMES_CNT] = {
+"ASIC_Init", "GetDisplaySurfaceSize", "ASIC_RegistersInit",
+"VRAM_BlockVenderDetection", "SetClocksRatio", "MemoryControllerInit",
+"GPIO_PinInit", "MemoryParamAdjust", "DVOEncoderControl",
+"GPIOPinControl", "SetEngineClock", "SetMemoryClock", "SetPixelClock",
+"DynamicClockGating", "ResetMemoryDLL", "ResetMemoryDevice",
+"MemoryPLLInit", "EnableMemorySelfRefresh", "AdjustMemoryController",
+"EnableASIC_StaticPwrMgt", "ASIC_StaticPwrMgtStatusChange",
+"DAC_LoadDetection", "TMDS2EncoderControl", "LCD1OutputControl",
+"DAC1EncoderControl", "DAC2EncoderControl", "DVOOutputControl",
+"CV1OutputControl", "SetCRTC_DPM_State", "TVEncoderControl",
+"TMDS1EncoderControl", "LVDSEncoderControl", "TV1OutputControl",
+"EnableScaler", "BlankCRTC", "EnableCRTC", "GetPixelClock",
+"EnableVGA_Render", "EnableVGA_Access", "SetCRTC_Timing",
+"SetCRTC_OverScan", "SetCRTC_Replication", "SelectCRTC_Source",
+"EnableGraphSurfaces", "UpdateCRTC_DoubleBufferRegisters",
+"LUT_AutoFill", "EnableHW_IconCursor", "GetMemoryClock",
+"GetEngineClock", "SetCRTC_UsingDTDTiming", "TVBootUpStdPinDetection",
+"DFP2OutputControl", "VRAM_BlockDetectionByStrap", "MemoryCleanUp",
+"ReadEDIDFromHWAssistedI2C", "WriteOneByteToHWAssistedI2C",
+"ReadHWAssistedI2CStatus", "SpeedFanControl", "PowerConnectorDetection",
+"MC_Synchronization", "ComputeMemoryEnginePLL", "MemoryRefreshConversion",
+"VRAM_GetCurrentInfoBlock", "DynamicMemorySettings", "MemoryTraining",
+"EnableLVDS_SS", "DFP1OutputControl", "SetVoltage", "CRT1OutputControl",
+"CRT2OutputControl", "SetupHWAssistedI2CStatus", "ClockSource",
+"MemoryDeviceInit", "EnableYUV",
+};
+
+#define ATOM_IO_NAMES_CNT 5
+static char *atom_io_names[ATOM_IO_NAMES_CNT] = {
+"MM", "PLL", "MC", "PCIE", "PCIE PORT",
+};
+
+#else
+
+#define ATOM_OP_NAMES_CNT 0
+#define ATOM_TABLE_NAMES_CNT 0
+#define ATOM_IO_NAMES_CNT 0
+
+#endif
+
+#endif
diff --git a/drivers/gpu/drm/radeon/atom-types.h b/drivers/gpu/drm/radeon/atom-types.h
new file mode 100644 (file)
index 0000000..1125b86
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2008 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Dave Airlie
+ */
+
+#ifndef ATOM_TYPES_H
+#define ATOM_TYPES_H
+
+/* sync atom types to kernel types */
+
+typedef uint16_t USHORT;
+typedef uint32_t ULONG;
+typedef uint8_t UCHAR;
+
+
+#ifndef ATOM_BIG_ENDIAN
+#if defined(__BIG_ENDIAN)
+#define ATOM_BIG_ENDIAN 1
+#else
+#define ATOM_BIG_ENDIAN 0
+#endif
+#endif
+#endif
diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c
new file mode 100644 (file)
index 0000000..901befe
--- /dev/null
@@ -0,0 +1,1215 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Stanislaw Skowronek
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+
+#define ATOM_DEBUG
+
+#include "atom.h"
+#include "atom-names.h"
+#include "atom-bits.h"
+
+#define ATOM_COND_ABOVE                0
+#define ATOM_COND_ABOVEOREQUAL 1
+#define ATOM_COND_ALWAYS       2
+#define ATOM_COND_BELOW                3
+#define ATOM_COND_BELOWOREQUAL 4
+#define ATOM_COND_EQUAL                5
+#define ATOM_COND_NOTEQUAL     6
+
+#define ATOM_PORT_ATI  0
+#define ATOM_PORT_PCI  1
+#define ATOM_PORT_SYSIO        2
+
+#define ATOM_UNIT_MICROSEC     0
+#define ATOM_UNIT_MILLISEC     1
+
+#define PLL_INDEX      2
+#define PLL_DATA       3
+
+typedef struct {
+       struct atom_context *ctx;
+
+       uint32_t *ps, *ws;
+       int ps_shift;
+       uint16_t start;
+} atom_exec_context;
+
+int atom_debug = 0;
+void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params);
+
+static uint32_t atom_arg_mask[8] =
+    { 0xFFFFFFFF, 0xFFFF, 0xFFFF00, 0xFFFF0000, 0xFF, 0xFF00, 0xFF0000,
+0xFF000000 };
+static int atom_arg_shift[8] = { 0, 0, 8, 16, 0, 8, 16, 24 };
+
+static int atom_dst_to_src[8][4] = {
+       /* translate destination alignment field to the source alignment encoding */
+       {0, 0, 0, 0},
+       {1, 2, 3, 0},
+       {1, 2, 3, 0},
+       {1, 2, 3, 0},
+       {4, 5, 6, 7},
+       {4, 5, 6, 7},
+       {4, 5, 6, 7},
+       {4, 5, 6, 7},
+};
+static int atom_def_dst[8] = { 0, 0, 1, 2, 0, 1, 2, 3 };
+
+static int debug_depth = 0;
+#ifdef ATOM_DEBUG
+static void debug_print_spaces(int n)
+{
+       while (n--)
+               printk("   ");
+}
+
+#define DEBUG(...) do if (atom_debug) { printk(KERN_DEBUG __VA_ARGS__); } while (0)
+#define SDEBUG(...) do if (atom_debug) { printk(KERN_DEBUG); debug_print_spaces(debug_depth); printk(__VA_ARGS__); } while (0)
+#else
+#define DEBUG(...) do { } while (0)
+#define SDEBUG(...) do { } while (0)
+#endif
+
+static uint32_t atom_iio_execute(struct atom_context *ctx, int base,
+                                uint32_t index, uint32_t data)
+{
+       uint32_t temp = 0xCDCDCDCD;
+       while (1)
+               switch (CU8(base)) {
+               case ATOM_IIO_NOP:
+                       base++;
+                       break;
+               case ATOM_IIO_READ:
+                       temp = ctx->card->reg_read(ctx->card, CU16(base + 1));
+                       base += 3;
+                       break;
+               case ATOM_IIO_WRITE:
+                       ctx->card->reg_write(ctx->card, CU16(base + 1), temp);
+                       base += 3;
+                       break;
+               case ATOM_IIO_CLEAR:
+                       temp &=
+                           ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
+                             CU8(base + 2));
+                       base += 3;
+                       break;
+               case ATOM_IIO_SET:
+                       temp |=
+                           (0xFFFFFFFF >> (32 - CU8(base + 1))) << CU8(base +
+                                                                       2);
+                       base += 3;
+                       break;
+               case ATOM_IIO_MOVE_INDEX:
+                       temp &=
+                           ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
+                             CU8(base + 2));
+                       temp |=
+                           ((index >> CU8(base + 2)) &
+                            (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
+                                                                         3);
+                       base += 4;
+                       break;
+               case ATOM_IIO_MOVE_DATA:
+                       temp &=
+                           ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
+                             CU8(base + 2));
+                       temp |=
+                           ((data >> CU8(base + 2)) &
+                            (0xFFFFFFFF >> (32 - CU8(base + 1)))) << CU8(base +
+                                                                         3);
+                       base += 4;
+                       break;
+               case ATOM_IIO_MOVE_ATTR:
+                       temp &=
+                           ~((0xFFFFFFFF >> (32 - CU8(base + 1))) <<
+                             CU8(base + 2));
+                       temp |=
+                           ((ctx->
+                             io_attr >> CU8(base + 2)) & (0xFFFFFFFF >> (32 -
+                                                                         CU8
+                                                                         (base
+                                                                          +
+                                                                          1))))
+                           << CU8(base + 3);
+                       base += 4;
+                       break;
+               case ATOM_IIO_END:
+                       return temp;
+               default:
+                       printk(KERN_INFO "Unknown IIO opcode.\n");
+                       return 0;
+               }
+}
+
+static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr,
+                                int *ptr, uint32_t *saved, int print)
+{
+       uint32_t idx, val = 0xCDCDCDCD, align, arg;
+       struct atom_context *gctx = ctx->ctx;
+       arg = attr & 7;
+       align = (attr >> 3) & 7;
+       switch (arg) {
+       case ATOM_ARG_REG:
+               idx = U16(*ptr);
+               (*ptr) += 2;
+               if (print)
+                       DEBUG("REG[0x%04X]", idx);
+               idx += gctx->reg_block;
+               switch (gctx->io_mode) {
+               case ATOM_IO_MM:
+                       val = gctx->card->reg_read(gctx->card, idx);
+                       break;
+               case ATOM_IO_PCI:
+                       printk(KERN_INFO
+                              "PCI registers are not implemented.\n");
+                       return 0;
+               case ATOM_IO_SYSIO:
+                       printk(KERN_INFO
+                              "SYSIO registers are not implemented.\n");
+                       return 0;
+               default:
+                       if (!(gctx->io_mode & 0x80)) {
+                               printk(KERN_INFO "Bad IO mode.\n");
+                               return 0;
+                       }
+                       if (!gctx->iio[gctx->io_mode & 0x7F]) {
+                               printk(KERN_INFO
+                                      "Undefined indirect IO read method %d.\n",
+                                      gctx->io_mode & 0x7F);
+                               return 0;
+                       }
+                       val =
+                           atom_iio_execute(gctx,
+                                            gctx->iio[gctx->io_mode & 0x7F],
+                                            idx, 0);
+               }
+               break;
+       case ATOM_ARG_PS:
+               idx = U8(*ptr);
+               (*ptr)++;
+               val = le32_to_cpu(ctx->ps[idx]);
+               if (print)
+                       DEBUG("PS[0x%02X,0x%04X]", idx, val);
+               break;
+       case ATOM_ARG_WS:
+               idx = U8(*ptr);
+               (*ptr)++;
+               if (print)
+                       DEBUG("WS[0x%02X]", idx);
+               switch (idx) {
+               case ATOM_WS_QUOTIENT:
+                       val = gctx->divmul[0];
+                       break;
+               case ATOM_WS_REMAINDER:
+                       val = gctx->divmul[1];
+                       break;
+               case ATOM_WS_DATAPTR:
+                       val = gctx->data_block;
+                       break;
+               case ATOM_WS_SHIFT:
+                       val = gctx->shift;
+                       break;
+               case ATOM_WS_OR_MASK:
+                       val = 1 << gctx->shift;
+                       break;
+               case ATOM_WS_AND_MASK:
+                       val = ~(1 << gctx->shift);
+                       break;
+               case ATOM_WS_FB_WINDOW:
+                       val = gctx->fb_base;
+                       break;
+               case ATOM_WS_ATTRIBUTES:
+                       val = gctx->io_attr;
+                       break;
+               default:
+                       val = ctx->ws[idx];
+               }
+               break;
+       case ATOM_ARG_ID:
+               idx = U16(*ptr);
+               (*ptr) += 2;
+               if (print) {
+                       if (gctx->data_block)
+                               DEBUG("ID[0x%04X+%04X]", idx, gctx->data_block);
+                       else
+                               DEBUG("ID[0x%04X]", idx);
+               }
+               val = U32(idx + gctx->data_block);
+               break;
+       case ATOM_ARG_FB:
+               idx = U8(*ptr);
+               (*ptr)++;
+               if (print)
+                       DEBUG("FB[0x%02X]", idx);
+               printk(KERN_INFO "FB access is not implemented.\n");
+               return 0;
+       case ATOM_ARG_IMM:
+               switch (align) {
+               case ATOM_SRC_DWORD:
+                       val = U32(*ptr);
+                       (*ptr) += 4;
+                       if (print)
+                               DEBUG("IMM 0x%08X\n", val);
+                       return val;
+               case ATOM_SRC_WORD0:
+               case ATOM_SRC_WORD8:
+               case ATOM_SRC_WORD16:
+                       val = U16(*ptr);
+                       (*ptr) += 2;
+                       if (print)
+                               DEBUG("IMM 0x%04X\n", val);
+                       return val;
+               case ATOM_SRC_BYTE0:
+               case ATOM_SRC_BYTE8:
+               case ATOM_SRC_BYTE16:
+               case ATOM_SRC_BYTE24:
+                       val = U8(*ptr);
+                       (*ptr)++;
+                       if (print)
+                               DEBUG("IMM 0x%02X\n", val);
+                       return val;
+               }
+               return 0;
+       case ATOM_ARG_PLL:
+               idx = U8(*ptr);
+               (*ptr)++;
+               if (print)
+                       DEBUG("PLL[0x%02X]", idx);
+               val = gctx->card->pll_read(gctx->card, idx);
+               break;
+       case ATOM_ARG_MC:
+               idx = U8(*ptr);
+               (*ptr)++;
+               if (print)
+                       DEBUG("MC[0x%02X]", idx);
+               val = gctx->card->mc_read(gctx->card, idx);
+               break;
+       }
+       if (saved)
+               *saved = val;
+       val &= atom_arg_mask[align];
+       val >>= atom_arg_shift[align];
+       if (print)
+               switch (align) {
+               case ATOM_SRC_DWORD:
+                       DEBUG(".[31:0] -> 0x%08X\n", val);
+                       break;
+               case ATOM_SRC_WORD0:
+                       DEBUG(".[15:0] -> 0x%04X\n", val);
+                       break;
+               case ATOM_SRC_WORD8:
+                       DEBUG(".[23:8] -> 0x%04X\n", val);
+                       break;
+               case ATOM_SRC_WORD16:
+                       DEBUG(".[31:16] -> 0x%04X\n", val);
+                       break;
+               case ATOM_SRC_BYTE0:
+                       DEBUG(".[7:0] -> 0x%02X\n", val);
+                       break;
+               case ATOM_SRC_BYTE8:
+                       DEBUG(".[15:8] -> 0x%02X\n", val);
+                       break;
+               case ATOM_SRC_BYTE16:
+                       DEBUG(".[23:16] -> 0x%02X\n", val);
+                       break;
+               case ATOM_SRC_BYTE24:
+                       DEBUG(".[31:24] -> 0x%02X\n", val);
+                       break;
+               }
+       return val;
+}
+
+static void atom_skip_src_int(atom_exec_context *ctx, uint8_t attr, int *ptr)
+{
+       uint32_t align = (attr >> 3) & 7, arg = attr & 7;
+       switch (arg) {
+       case ATOM_ARG_REG:
+       case ATOM_ARG_ID:
+               (*ptr) += 2;
+               break;
+       case ATOM_ARG_PLL:
+       case ATOM_ARG_MC:
+       case ATOM_ARG_PS:
+       case ATOM_ARG_WS:
+       case ATOM_ARG_FB:
+               (*ptr)++;
+               break;
+       case ATOM_ARG_IMM:
+               switch (align) {
+               case ATOM_SRC_DWORD:
+                       (*ptr) += 4;
+                       return;
+               case ATOM_SRC_WORD0:
+               case ATOM_SRC_WORD8:
+               case ATOM_SRC_WORD16:
+                       (*ptr) += 2;
+                       return;
+               case ATOM_SRC_BYTE0:
+               case ATOM_SRC_BYTE8:
+               case ATOM_SRC_BYTE16:
+               case ATOM_SRC_BYTE24:
+                       (*ptr)++;
+                       return;
+               }
+               return;
+       }
+}
+
+static uint32_t atom_get_src(atom_exec_context *ctx, uint8_t attr, int *ptr)
+{
+       return atom_get_src_int(ctx, attr, ptr, NULL, 1);
+}
+
+static uint32_t atom_get_dst(atom_exec_context *ctx, int arg, uint8_t attr,
+                            int *ptr, uint32_t *saved, int print)
+{
+       return atom_get_src_int(ctx,
+                               arg | atom_dst_to_src[(attr >> 3) &
+                                                     7][(attr >> 6) & 3] << 3,
+                               ptr, saved, print);
+}
+
+static void atom_skip_dst(atom_exec_context *ctx, int arg, uint8_t attr, int *ptr)
+{
+       atom_skip_src_int(ctx,
+                         arg | atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) &
+                                                                3] << 3, ptr);
+}
+
+static void atom_put_dst(atom_exec_context *ctx, int arg, uint8_t attr,
+                        int *ptr, uint32_t val, uint32_t saved)
+{
+       uint32_t align =
+           atom_dst_to_src[(attr >> 3) & 7][(attr >> 6) & 3], old_val =
+           val, idx;
+       struct atom_context *gctx = ctx->ctx;
+       old_val &= atom_arg_mask[align] >> atom_arg_shift[align];
+       val <<= atom_arg_shift[align];
+       val &= atom_arg_mask[align];
+       saved &= ~atom_arg_mask[align];
+       val |= saved;
+       switch (arg) {
+       case ATOM_ARG_REG:
+               idx = U16(*ptr);
+               (*ptr) += 2;
+               DEBUG("REG[0x%04X]", idx);
+               idx += gctx->reg_block;
+               switch (gctx->io_mode) {
+               case ATOM_IO_MM:
+                       if (idx == 0)
+                               gctx->card->reg_write(gctx->card, idx,
+                                                     val << 2);
+                       else
+                               gctx->card->reg_write(gctx->card, idx, val);
+                       break;
+               case ATOM_IO_PCI:
+                       printk(KERN_INFO
+                              "PCI registers are not implemented.\n");
+                       return;
+               case ATOM_IO_SYSIO:
+                       printk(KERN_INFO
+                              "SYSIO registers are not implemented.\n");
+                       return;
+               default:
+                       if (!(gctx->io_mode & 0x80)) {
+                               printk(KERN_INFO "Bad IO mode.\n");
+                               return;
+                       }
+                       if (!gctx->iio[gctx->io_mode & 0xFF]) {
+                               printk(KERN_INFO
+                                      "Undefined indirect IO write method %d.\n",
+                                      gctx->io_mode & 0x7F);
+                               return;
+                       }
+                       atom_iio_execute(gctx, gctx->iio[gctx->io_mode & 0xFF],
+                                        idx, val);
+               }
+               break;
+       case ATOM_ARG_PS:
+               idx = U8(*ptr);
+               (*ptr)++;
+               DEBUG("PS[0x%02X]", idx);
+               ctx->ps[idx] = cpu_to_le32(val);
+               break;
+       case ATOM_ARG_WS:
+               idx = U8(*ptr);
+               (*ptr)++;
+               DEBUG("WS[0x%02X]", idx);
+               switch (idx) {
+               case ATOM_WS_QUOTIENT:
+                       gctx->divmul[0] = val;
+                       break;
+               case ATOM_WS_REMAINDER:
+                       gctx->divmul[1] = val;
+                       break;
+               case ATOM_WS_DATAPTR:
+                       gctx->data_block = val;
+                       break;
+               case ATOM_WS_SHIFT:
+                       gctx->shift = val;
+                       break;
+               case ATOM_WS_OR_MASK:
+               case ATOM_WS_AND_MASK:
+                       break;
+               case ATOM_WS_FB_WINDOW:
+                       gctx->fb_base = val;
+                       break;
+               case ATOM_WS_ATTRIBUTES:
+                       gctx->io_attr = val;
+                       break;
+               default:
+                       ctx->ws[idx] = val;
+               }
+               break;
+       case ATOM_ARG_FB:
+               idx = U8(*ptr);
+               (*ptr)++;
+               DEBUG("FB[0x%02X]", idx);
+               printk(KERN_INFO "FB access is not implemented.\n");
+               return;
+       case ATOM_ARG_PLL:
+               idx = U8(*ptr);
+               (*ptr)++;
+               DEBUG("PLL[0x%02X]", idx);
+               gctx->card->pll_write(gctx->card, idx, val);
+               break;
+       case ATOM_ARG_MC:
+               idx = U8(*ptr);
+               (*ptr)++;
+               DEBUG("MC[0x%02X]", idx);
+               gctx->card->mc_write(gctx->card, idx, val);
+               return;
+       }
+       switch (align) {
+       case ATOM_SRC_DWORD:
+               DEBUG(".[31:0] <- 0x%08X\n", old_val);
+               break;
+       case ATOM_SRC_WORD0:
+               DEBUG(".[15:0] <- 0x%04X\n", old_val);
+               break;
+       case ATOM_SRC_WORD8:
+               DEBUG(".[23:8] <- 0x%04X\n", old_val);
+               break;
+       case ATOM_SRC_WORD16:
+               DEBUG(".[31:16] <- 0x%04X\n", old_val);
+               break;
+       case ATOM_SRC_BYTE0:
+               DEBUG(".[7:0] <- 0x%02X\n", old_val);
+               break;
+       case ATOM_SRC_BYTE8:
+               DEBUG(".[15:8] <- 0x%02X\n", old_val);
+               break;
+       case ATOM_SRC_BYTE16:
+               DEBUG(".[23:16] <- 0x%02X\n", old_val);
+               break;
+       case ATOM_SRC_BYTE24:
+               DEBUG(".[31:24] <- 0x%02X\n", old_val);
+               break;
+       }
+}
+
+static void atom_op_add(atom_exec_context *ctx, int *ptr, int arg)
+{
+       uint8_t attr = U8((*ptr)++);
+       uint32_t dst, src, saved;
+       int dptr = *ptr;
+       SDEBUG("   dst: ");
+       dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
+       SDEBUG("   src: ");
+       src = atom_get_src(ctx, attr, ptr);
+       dst += src;
+       SDEBUG("   dst: ");
+       atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
+}
+
+static void atom_op_and(atom_exec_context *ctx, int *ptr, int arg)
+{
+       uint8_t attr = U8((*ptr)++);
+       uint32_t dst, src, saved;
+       int dptr = *ptr;
+       SDEBUG("   dst: ");
+       dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
+       SDEBUG("   src: ");
+       src = atom_get_src(ctx, attr, ptr);
+       dst &= src;
+       SDEBUG("   dst: ");
+       atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
+}
+
+static void atom_op_beep(atom_exec_context *ctx, int *ptr, int arg)
+{
+       printk("ATOM BIOS beeped!\n");
+}
+
+static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg)
+{
+       int idx = U8((*ptr)++);
+       if (idx < ATOM_TABLE_NAMES_CNT)
+               SDEBUG("   table: %d (%s)\n", idx, atom_table_names[idx]);
+       else
+               SDEBUG("   table: %d\n", idx);
+       if (U16(ctx->ctx->cmd_table + 4 + 2 * idx))
+               atom_execute_table(ctx->ctx, idx, ctx->ps + ctx->ps_shift);
+}
+
+static void atom_op_clear(atom_exec_context *ctx, int *ptr, int arg)
+{
+       uint8_t attr = U8((*ptr)++);
+       uint32_t saved;
+       int dptr = *ptr;
+       attr &= 0x38;
+       attr |= atom_def_dst[attr >> 3] << 6;
+       atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
+       SDEBUG("   dst: ");
+       atom_put_dst(ctx, arg, attr, &dptr, 0, saved);
+}
+
+static void atom_op_compare(atom_exec_context *ctx, int *ptr, int arg)
+{
+       uint8_t attr = U8((*ptr)++);
+       uint32_t dst, src;
+       SDEBUG("   src1: ");
+       dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
+       SDEBUG("   src2: ");
+       src = atom_get_src(ctx, attr, ptr);
+       ctx->ctx->cs_equal = (dst == src);
+       ctx->ctx->cs_above = (dst > src);
+       SDEBUG("   result: %s %s\n", ctx->ctx->cs_equal ? "EQ" : "NE",
+              ctx->ctx->cs_above ? "GT" : "LE");
+}
+
+static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg)
+{
+       uint8_t count = U8((*ptr)++);
+       SDEBUG("   count: %d\n", count);
+       if (arg == ATOM_UNIT_MICROSEC)
+               schedule_timeout_uninterruptible(usecs_to_jiffies(count));
+       else
+               schedule_timeout_uninterruptible(msecs_to_jiffies(count));
+}
+
+static void atom_op_div(atom_exec_context *ctx, int *ptr, int arg)
+{
+       uint8_t attr = U8((*ptr)++);
+       uint32_t dst, src;
+       SDEBUG("   src1: ");
+       dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
+       SDEBUG("   src2: ");
+       src = atom_get_src(ctx, attr, ptr);
+       if (src != 0) {
+               ctx->ctx->divmul[0] = dst / src;
+               ctx->ctx->divmul[1] = dst % src;
+       } else {
+               ctx->ctx->divmul[0] = 0;
+               ctx->ctx->divmul[1] = 0;
+       }
+}
+
+static void atom_op_eot(atom_exec_context *ctx, int *ptr, int arg)
+{
+       /* functionally, a nop */
+}
+
+static void atom_op_jump(atom_exec_context *ctx, int *ptr, int arg)
+{
+       int execute = 0, target = U16(*ptr);
+       (*ptr) += 2;
+       switch (arg) {
+       case ATOM_COND_ABOVE:
+               execute = ctx->ctx->cs_above;
+               break;
+       case ATOM_COND_ABOVEOREQUAL:
+               execute = ctx->ctx->cs_above || ctx->ctx->cs_equal;
+               break;
+       case ATOM_COND_ALWAYS:
+               execute = 1;
+               break;
+       case ATOM_COND_BELOW:
+               execute = !(ctx->ctx->cs_above || ctx->ctx->cs_equal);
+               break;
+       case ATOM_COND_BELOWOREQUAL:
+               execute = !ctx->ctx->cs_above;
+               break;
+       case ATOM_COND_EQUAL:
+               execute = ctx->ctx->cs_equal;
+               break;
+       case ATOM_COND_NOTEQUAL:
+               execute = !ctx->ctx->cs_equal;
+               break;
+       }
+       if (arg != ATOM_COND_ALWAYS)
+               SDEBUG("   taken: %s\n", execute ? "yes" : "no");
+       SDEBUG("   target: 0x%04X\n", target);
+       if (execute)
+               *ptr = ctx->start + target;
+}
+
+static void atom_op_mask(atom_exec_context *ctx, int *ptr, int arg)
+{
+       uint8_t attr = U8((*ptr)++);
+       uint32_t dst, src1, src2, saved;
+       int dptr = *ptr;
+       SDEBUG("   dst: ");
+       dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
+       SDEBUG("   src1: ");
+       src1 = atom_get_src(ctx, attr, ptr);
+       SDEBUG("   src2: ");
+       src2 = atom_get_src(ctx, attr, ptr);
+       dst &= src1;
+       dst |= src2;
+       SDEBUG("   dst: ");
+       atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
+}
+
+static void atom_op_move(atom_exec_context *ctx, int *ptr, int arg)
+{
+       uint8_t attr = U8((*ptr)++);
+       uint32_t src, saved;
+       int dptr = *ptr;
+       if (((attr >> 3) & 7) != ATOM_SRC_DWORD)
+               atom_get_dst(ctx, arg, attr, ptr, &saved, 0);
+       else {
+               atom_skip_dst(ctx, arg, attr, ptr);
+               saved = 0xCDCDCDCD;
+       }
+       SDEBUG("   src: ");
+       src = atom_get_src(ctx, attr, ptr);
+       SDEBUG("   dst: ");
+       atom_put_dst(ctx, arg, attr, &dptr, src, saved);
+}
+
+static void atom_op_mul(atom_exec_context *ctx, int *ptr, int arg)
+{
+       uint8_t attr = U8((*ptr)++);
+       uint32_t dst, src;
+       SDEBUG("   src1: ");
+       dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
+       SDEBUG("   src2: ");
+       src = atom_get_src(ctx, attr, ptr);
+       ctx->ctx->divmul[0] = dst * src;
+}
+
+static void atom_op_nop(atom_exec_context *ctx, int *ptr, int arg)
+{
+       /* nothing */
+}
+
+static void atom_op_or(atom_exec_context *ctx, int *ptr, int arg)
+{
+       uint8_t attr = U8((*ptr)++);
+       uint32_t dst, src, saved;
+       int dptr = *ptr;
+       SDEBUG("   dst: ");
+       dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
+       SDEBUG("   src: ");
+       src = atom_get_src(ctx, attr, ptr);
+       dst |= src;
+       SDEBUG("   dst: ");
+       atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
+}
+
+static void atom_op_postcard(atom_exec_context *ctx, int *ptr, int arg)
+{
+       uint8_t val = U8((*ptr)++);
+       SDEBUG("POST card output: 0x%02X\n", val);
+}
+
+static void atom_op_repeat(atom_exec_context *ctx, int *ptr, int arg)
+{
+       printk(KERN_INFO "unimplemented!\n");
+}
+
+static void atom_op_restorereg(atom_exec_context *ctx, int *ptr, int arg)
+{
+       printk(KERN_INFO "unimplemented!\n");
+}
+
+static void atom_op_savereg(atom_exec_context *ctx, int *ptr, int arg)
+{
+       printk(KERN_INFO "unimplemented!\n");
+}
+
+static void atom_op_setdatablock(atom_exec_context *ctx, int *ptr, int arg)
+{
+       int idx = U8(*ptr);
+       (*ptr)++;
+       SDEBUG("   block: %d\n", idx);
+       if (!idx)
+               ctx->ctx->data_block = 0;
+       else if (idx == 255)
+               ctx->ctx->data_block = ctx->start;
+       else
+               ctx->ctx->data_block = U16(ctx->ctx->data_table + 4 + 2 * idx);
+       SDEBUG("   base: 0x%04X\n", ctx->ctx->data_block);
+}
+
+static void atom_op_setfbbase(atom_exec_context *ctx, int *ptr, int arg)
+{
+       uint8_t attr = U8((*ptr)++);
+       SDEBUG("   fb_base: ");
+       ctx->ctx->fb_base = atom_get_src(ctx, attr, ptr);
+}
+
+static void atom_op_setport(atom_exec_context *ctx, int *ptr, int arg)
+{
+       int port;
+       switch (arg) {
+       case ATOM_PORT_ATI:
+               port = U16(*ptr);
+               if (port < ATOM_IO_NAMES_CNT)
+                       SDEBUG("   port: %d (%s)\n", port, atom_io_names[port]);
+               else
+                       SDEBUG("   port: %d\n", port);
+               if (!port)
+                       ctx->ctx->io_mode = ATOM_IO_MM;
+               else
+                       ctx->ctx->io_mode = ATOM_IO_IIO | port;
+               (*ptr) += 2;
+               break;
+       case ATOM_PORT_PCI:
+               ctx->ctx->io_mode = ATOM_IO_PCI;
+               (*ptr)++;
+               break;
+       case ATOM_PORT_SYSIO:
+               ctx->ctx->io_mode = ATOM_IO_SYSIO;
+               (*ptr)++;
+               break;
+       }
+}
+
+static void atom_op_setregblock(atom_exec_context *ctx, int *ptr, int arg)
+{
+       ctx->ctx->reg_block = U16(*ptr);
+       (*ptr) += 2;
+       SDEBUG("   base: 0x%04X\n", ctx->ctx->reg_block);
+}
+
+static void atom_op_shl(atom_exec_context *ctx, int *ptr, int arg)
+{
+       uint8_t attr = U8((*ptr)++), shift;
+       uint32_t saved, dst;
+       int dptr = *ptr;
+       attr &= 0x38;
+       attr |= atom_def_dst[attr >> 3] << 6;
+       SDEBUG("   dst: ");
+       dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
+       shift = U8((*ptr)++);
+       SDEBUG("   shift: %d\n", shift);
+       dst <<= shift;
+       SDEBUG("   dst: ");
+       atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
+}
+
+static void atom_op_shr(atom_exec_context *ctx, int *ptr, int arg)
+{
+       uint8_t attr = U8((*ptr)++), shift;
+       uint32_t saved, dst;
+       int dptr = *ptr;
+       attr &= 0x38;
+       attr |= atom_def_dst[attr >> 3] << 6;
+       SDEBUG("   dst: ");
+       dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
+       shift = U8((*ptr)++);
+       SDEBUG("   shift: %d\n", shift);
+       dst >>= shift;
+       SDEBUG("   dst: ");
+       atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
+}
+
+static void atom_op_sub(atom_exec_context *ctx, int *ptr, int arg)
+{
+       uint8_t attr = U8((*ptr)++);
+       uint32_t dst, src, saved;
+       int dptr = *ptr;
+       SDEBUG("   dst: ");
+       dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
+       SDEBUG("   src: ");
+       src = atom_get_src(ctx, attr, ptr);
+       dst -= src;
+       SDEBUG("   dst: ");
+       atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
+}
+
+static void atom_op_switch(atom_exec_context *ctx, int *ptr, int arg)
+{
+       uint8_t attr = U8((*ptr)++);
+       uint32_t src, val, target;
+       SDEBUG("   switch: ");
+       src = atom_get_src(ctx, attr, ptr);
+       while (U16(*ptr) != ATOM_CASE_END)
+               if (U8(*ptr) == ATOM_CASE_MAGIC) {
+                       (*ptr)++;
+                       SDEBUG("   case: ");
+                       val =
+                           atom_get_src(ctx, (attr & 0x38) | ATOM_ARG_IMM,
+                                        ptr);
+                       target = U16(*ptr);
+                       if (val == src) {
+                               SDEBUG("   target: %04X\n", target);
+                               *ptr = ctx->start + target;
+                               return;
+                       }
+                       (*ptr) += 2;
+               } else {
+                       printk(KERN_INFO "Bad case.\n");
+                       return;
+               }
+       (*ptr) += 2;
+}
+
+static void atom_op_test(atom_exec_context *ctx, int *ptr, int arg)
+{
+       uint8_t attr = U8((*ptr)++);
+       uint32_t dst, src;
+       SDEBUG("   src1: ");
+       dst = atom_get_dst(ctx, arg, attr, ptr, NULL, 1);
+       SDEBUG("   src2: ");
+       src = atom_get_src(ctx, attr, ptr);
+       ctx->ctx->cs_equal = ((dst & src) == 0);
+       SDEBUG("   result: %s\n", ctx->ctx->cs_equal ? "EQ" : "NE");
+}
+
+static void atom_op_xor(atom_exec_context *ctx, int *ptr, int arg)
+{
+       uint8_t attr = U8((*ptr)++);
+       uint32_t dst, src, saved;
+       int dptr = *ptr;
+       SDEBUG("   dst: ");
+       dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
+       SDEBUG("   src: ");
+       src = atom_get_src(ctx, attr, ptr);
+       dst ^= src;
+       SDEBUG("   dst: ");
+       atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
+}
+
+static void atom_op_debug(atom_exec_context *ctx, int *ptr, int arg)
+{
+       printk(KERN_INFO "unimplemented!\n");
+}
+
+static struct {
+       void (*func) (atom_exec_context *, int *, int);
+       int arg;
+} opcode_table[ATOM_OP_CNT] = {
+       {
+       NULL, 0}, {
+       atom_op_move, ATOM_ARG_REG}, {
+       atom_op_move, ATOM_ARG_PS}, {
+       atom_op_move, ATOM_ARG_WS}, {
+       atom_op_move, ATOM_ARG_FB}, {
+       atom_op_move, ATOM_ARG_PLL}, {
+       atom_op_move, ATOM_ARG_MC}, {
+       atom_op_and, ATOM_ARG_REG}, {
+       atom_op_and, ATOM_ARG_PS}, {
+       atom_op_and, ATOM_ARG_WS}, {
+       atom_op_and, ATOM_ARG_FB}, {
+       atom_op_and, ATOM_ARG_PLL}, {
+       atom_op_and, ATOM_ARG_MC}, {
+       atom_op_or, ATOM_ARG_REG}, {
+       atom_op_or, ATOM_ARG_PS}, {
+       atom_op_or, ATOM_ARG_WS}, {
+       atom_op_or, ATOM_ARG_FB}, {
+       atom_op_or, ATOM_ARG_PLL}, {
+       atom_op_or, ATOM_ARG_MC}, {
+       atom_op_shl, ATOM_ARG_REG}, {
+       atom_op_shl, ATOM_ARG_PS}, {
+       atom_op_shl, ATOM_ARG_WS}, {
+       atom_op_shl, ATOM_ARG_FB}, {
+       atom_op_shl, ATOM_ARG_PLL}, {
+       atom_op_shl, ATOM_ARG_MC}, {
+       atom_op_shr, ATOM_ARG_REG}, {
+       atom_op_shr, ATOM_ARG_PS}, {
+       atom_op_shr, ATOM_ARG_WS}, {
+       atom_op_shr, ATOM_ARG_FB}, {
+       atom_op_shr, ATOM_ARG_PLL}, {
+       atom_op_shr, ATOM_ARG_MC}, {
+       atom_op_mul, ATOM_ARG_REG}, {
+       atom_op_mul, ATOM_ARG_PS}, {
+       atom_op_mul, ATOM_ARG_WS}, {
+       atom_op_mul, ATOM_ARG_FB}, {
+       atom_op_mul, ATOM_ARG_PLL}, {
+       atom_op_mul, ATOM_ARG_MC}, {
+       atom_op_div, ATOM_ARG_REG}, {
+       atom_op_div, ATOM_ARG_PS}, {
+       atom_op_div, ATOM_ARG_WS}, {
+       atom_op_div, ATOM_ARG_FB}, {
+       atom_op_div, ATOM_ARG_PLL}, {
+       atom_op_div, ATOM_ARG_MC}, {
+       atom_op_add, ATOM_ARG_REG}, {
+       atom_op_add, ATOM_ARG_PS}, {
+       atom_op_add, ATOM_ARG_WS}, {
+       atom_op_add, ATOM_ARG_FB}, {
+       atom_op_add, ATOM_ARG_PLL}, {
+       atom_op_add, ATOM_ARG_MC}, {
+       atom_op_sub, ATOM_ARG_REG}, {
+       atom_op_sub, ATOM_ARG_PS}, {
+       atom_op_sub, ATOM_ARG_WS}, {
+       atom_op_sub, ATOM_ARG_FB}, {
+       atom_op_sub, ATOM_ARG_PLL}, {
+       atom_op_sub, ATOM_ARG_MC}, {
+       atom_op_setport, ATOM_PORT_ATI}, {
+       atom_op_setport, ATOM_PORT_PCI}, {
+       atom_op_setport, ATOM_PORT_SYSIO}, {
+       atom_op_setregblock, 0}, {
+       atom_op_setfbbase, 0}, {
+       atom_op_compare, ATOM_ARG_REG}, {
+       atom_op_compare, ATOM_ARG_PS}, {
+       atom_op_compare, ATOM_ARG_WS}, {
+       atom_op_compare, ATOM_ARG_FB}, {
+       atom_op_compare, ATOM_ARG_PLL}, {
+       atom_op_compare, ATOM_ARG_MC}, {
+       atom_op_switch, 0}, {
+       atom_op_jump, ATOM_COND_ALWAYS}, {
+       atom_op_jump, ATOM_COND_EQUAL}, {
+       atom_op_jump, ATOM_COND_BELOW}, {
+       atom_op_jump, ATOM_COND_ABOVE}, {
+       atom_op_jump, ATOM_COND_BELOWOREQUAL}, {
+       atom_op_jump, ATOM_COND_ABOVEOREQUAL}, {
+       atom_op_jump, ATOM_COND_NOTEQUAL}, {
+       atom_op_test, ATOM_ARG_REG}, {
+       atom_op_test, ATOM_ARG_PS}, {
+       atom_op_test, ATOM_ARG_WS}, {
+       atom_op_test, ATOM_ARG_FB}, {
+       atom_op_test, ATOM_ARG_PLL}, {
+       atom_op_test, ATOM_ARG_MC}, {
+       atom_op_delay, ATOM_UNIT_MILLISEC}, {
+       atom_op_delay, ATOM_UNIT_MICROSEC}, {
+       atom_op_calltable, 0}, {
+       atom_op_repeat, 0}, {
+       atom_op_clear, ATOM_ARG_REG}, {
+       atom_op_clear, ATOM_ARG_PS}, {
+       atom_op_clear, ATOM_ARG_WS}, {
+       atom_op_clear, ATOM_ARG_FB}, {
+       atom_op_clear, ATOM_ARG_PLL}, {
+       atom_op_clear, ATOM_ARG_MC}, {
+       atom_op_nop, 0}, {
+       atom_op_eot, 0}, {
+       atom_op_mask, ATOM_ARG_REG}, {
+       atom_op_mask, ATOM_ARG_PS}, {
+       atom_op_mask, ATOM_ARG_WS}, {
+       atom_op_mask, ATOM_ARG_FB}, {
+       atom_op_mask, ATOM_ARG_PLL}, {
+       atom_op_mask, ATOM_ARG_MC}, {
+       atom_op_postcard, 0}, {
+       atom_op_beep, 0}, {
+       atom_op_savereg, 0}, {
+       atom_op_restorereg, 0}, {
+       atom_op_setdatablock, 0}, {
+       atom_op_xor, ATOM_ARG_REG}, {
+       atom_op_xor, ATOM_ARG_PS}, {
+       atom_op_xor, ATOM_ARG_WS}, {
+       atom_op_xor, ATOM_ARG_FB}, {
+       atom_op_xor, ATOM_ARG_PLL}, {
+       atom_op_xor, ATOM_ARG_MC}, {
+       atom_op_shl, ATOM_ARG_REG}, {
+       atom_op_shl, ATOM_ARG_PS}, {
+       atom_op_shl, ATOM_ARG_WS}, {
+       atom_op_shl, ATOM_ARG_FB}, {
+       atom_op_shl, ATOM_ARG_PLL}, {
+       atom_op_shl, ATOM_ARG_MC}, {
+       atom_op_shr, ATOM_ARG_REG}, {
+       atom_op_shr, ATOM_ARG_PS}, {
+       atom_op_shr, ATOM_ARG_WS}, {
+       atom_op_shr, ATOM_ARG_FB}, {
+       atom_op_shr, ATOM_ARG_PLL}, {
+       atom_op_shr, ATOM_ARG_MC}, {
+atom_op_debug, 0},};
+
+void atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
+{
+       int base = CU16(ctx->cmd_table + 4 + 2 * index);
+       int len, ws, ps, ptr;
+       unsigned char op;
+       atom_exec_context ectx;
+
+       if (!base)
+               return;
+
+       len = CU16(base + ATOM_CT_SIZE_PTR);
+       ws = CU8(base + ATOM_CT_WS_PTR);
+       ps = CU8(base + ATOM_CT_PS_PTR) & ATOM_CT_PS_MASK;
+       ptr = base + ATOM_CT_CODE_PTR;
+
+       SDEBUG(">> execute %04X (len %d, WS %d, PS %d)\n", base, len, ws, ps);
+
+       /* reset reg block */
+       ctx->reg_block = 0;
+       ectx.ctx = ctx;
+       ectx.ps_shift = ps / 4;
+       ectx.start = base;
+       ectx.ps = params;
+       if (ws)
+               ectx.ws = kzalloc(4 * ws, GFP_KERNEL);
+       else
+               ectx.ws = NULL;
+
+       debug_depth++;
+       while (1) {
+               op = CU8(ptr++);
+               if (op < ATOM_OP_NAMES_CNT)
+                       SDEBUG("%s @ 0x%04X\n", atom_op_names[op], ptr - 1);
+               else
+                       SDEBUG("[%d] @ 0x%04X\n", op, ptr - 1);
+
+               if (op < ATOM_OP_CNT && op > 0)
+                       opcode_table[op].func(&ectx, &ptr,
+                                             opcode_table[op].arg);
+               else
+                       break;
+
+               if (op == ATOM_OP_EOT)
+                       break;
+       }
+       debug_depth--;
+       SDEBUG("<<\n");
+
+       if (ws)
+               kfree(ectx.ws);
+}
+
+static int atom_iio_len[] = { 1, 2, 3, 3, 3, 3, 4, 4, 4, 3 };
+
+static void atom_index_iio(struct atom_context *ctx, int base)
+{
+       ctx->iio = kzalloc(2 * 256, GFP_KERNEL);
+       while (CU8(base) == ATOM_IIO_START) {
+               ctx->iio[CU8(base + 1)] = base + 2;
+               base += 2;
+               while (CU8(base) != ATOM_IIO_END)
+                       base += atom_iio_len[CU8(base)];
+               base += 3;
+       }
+}
+
+struct atom_context *atom_parse(struct card_info *card, void *bios)
+{
+       int base;
+       struct atom_context *ctx =
+           kzalloc(sizeof(struct atom_context), GFP_KERNEL);
+       char *str;
+       char name[512];
+       int i;
+
+       ctx->card = card;
+       ctx->bios = bios;
+
+       if (CU16(0) != ATOM_BIOS_MAGIC) {
+               printk(KERN_INFO "Invalid BIOS magic.\n");
+               kfree(ctx);
+               return NULL;
+       }
+       if (strncmp
+           (CSTR(ATOM_ATI_MAGIC_PTR), ATOM_ATI_MAGIC,
+            strlen(ATOM_ATI_MAGIC))) {
+               printk(KERN_INFO "Invalid ATI magic.\n");
+               kfree(ctx);
+               return NULL;
+       }
+
+       base = CU16(ATOM_ROM_TABLE_PTR);
+       if (strncmp
+           (CSTR(base + ATOM_ROM_MAGIC_PTR), ATOM_ROM_MAGIC,
+            strlen(ATOM_ROM_MAGIC))) {
+               printk(KERN_INFO "Invalid ATOM magic.\n");
+               kfree(ctx);
+               return NULL;
+       }
+
+       ctx->cmd_table = CU16(base + ATOM_ROM_CMD_PTR);
+       ctx->data_table = CU16(base + ATOM_ROM_DATA_PTR);
+       atom_index_iio(ctx, CU16(ctx->data_table + ATOM_DATA_IIO_PTR) + 4);
+
+       str = CSTR(CU16(base + ATOM_ROM_MSG_PTR));
+       while (*str && ((*str == '\n') || (*str == '\r')))
+               str++;
+       /* name string isn't always 0 terminated */
+       for (i = 0; i < 511; i++) {
+               name[i] = str[i];
+               if (name[i] < '.' || name[i] > 'z') {
+                       name[i] = 0;
+                       break;
+               }
+       }
+       printk(KERN_INFO "ATOM BIOS: %s\n", name);
+
+       return ctx;
+}
+
+int atom_asic_init(struct atom_context *ctx)
+{
+       int hwi = CU16(ctx->data_table + ATOM_DATA_FWI_PTR);
+       uint32_t ps[16];
+       memset(ps, 0, 64);
+
+       ps[0] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFSCLK_PTR));
+       ps[1] = cpu_to_le32(CU32(hwi + ATOM_FWI_DEFMCLK_PTR));
+       if (!ps[0] || !ps[1])
+               return 1;
+
+       if (!CU16(ctx->cmd_table + 4 + 2 * ATOM_CMD_INIT))
+               return 1;
+       atom_execute_table(ctx, ATOM_CMD_INIT, ps);
+
+       return 0;
+}
+
+void atom_destroy(struct atom_context *ctx)
+{
+       if (ctx->iio)
+               kfree(ctx->iio);
+       kfree(ctx);
+}
+
+void atom_parse_data_header(struct atom_context *ctx, int index,
+                           uint16_t * size, uint8_t * frev, uint8_t * crev,
+                           uint16_t * data_start)
+{
+       int offset = index * 2 + 4;
+       int idx = CU16(ctx->data_table + offset);
+
+       if (size)
+               *size = CU16(idx);
+       if (frev)
+               *frev = CU8(idx + 2);
+       if (crev)
+               *crev = CU8(idx + 3);
+       *data_start = idx;
+       return;
+}
+
+void atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t * frev,
+                          uint8_t * crev)
+{
+       int offset = index * 2 + 4;
+       int idx = CU16(ctx->cmd_table + offset);
+
+       if (frev)
+               *frev = CU8(idx + 2);
+       if (crev)
+               *crev = CU8(idx + 3);
+       return;
+}
diff --git a/drivers/gpu/drm/radeon/atom.h b/drivers/gpu/drm/radeon/atom.h
new file mode 100644 (file)
index 0000000..e6eb38f
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author: Stanislaw Skowronek
+ */
+
+#ifndef ATOM_H
+#define ATOM_H
+
+#include <linux/types.h>
+#include "drmP.h"
+
+#define ATOM_BIOS_MAGIC                0xAA55
+#define ATOM_ATI_MAGIC_PTR     0x30
+#define ATOM_ATI_MAGIC         " 761295520"
+#define ATOM_ROM_TABLE_PTR     0x48
+
+#define ATOM_ROM_MAGIC         "ATOM"
+#define ATOM_ROM_MAGIC_PTR     4
+
+#define ATOM_ROM_MSG_PTR       0x10
+#define ATOM_ROM_CMD_PTR       0x1E
+#define ATOM_ROM_DATA_PTR      0x20
+
+#define ATOM_CMD_INIT          0
+#define ATOM_CMD_SETSCLK       0x0A
+#define ATOM_CMD_SETMCLK       0x0B
+#define ATOM_CMD_SETPCLK       0x0C
+
+#define ATOM_DATA_FWI_PTR      0xC
+#define ATOM_DATA_IIO_PTR      0x32
+
+#define ATOM_FWI_DEFSCLK_PTR   8
+#define ATOM_FWI_DEFMCLK_PTR   0xC
+#define ATOM_FWI_MAXSCLK_PTR   0x24
+#define ATOM_FWI_MAXMCLK_PTR   0x28
+
+#define ATOM_CT_SIZE_PTR       0
+#define ATOM_CT_WS_PTR         4
+#define ATOM_CT_PS_PTR         5
+#define ATOM_CT_PS_MASK                0x7F
+#define ATOM_CT_CODE_PTR       6
+
+#define ATOM_OP_CNT            123
+#define ATOM_OP_EOT            91
+
+#define ATOM_CASE_MAGIC                0x63
+#define ATOM_CASE_END          0x5A5A
+
+#define ATOM_ARG_REG           0
+#define ATOM_ARG_PS            1
+#define ATOM_ARG_WS            2
+#define ATOM_ARG_FB            3
+#define ATOM_ARG_ID            4
+#define ATOM_ARG_IMM           5
+#define ATOM_ARG_PLL           6
+#define ATOM_ARG_MC            7
+
+#define ATOM_SRC_DWORD         0
+#define ATOM_SRC_WORD0         1
+#define ATOM_SRC_WORD8         2
+#define ATOM_SRC_WORD16                3
+#define ATOM_SRC_BYTE0         4
+#define ATOM_SRC_BYTE8         5
+#define ATOM_SRC_BYTE16                6
+#define ATOM_SRC_BYTE24                7
+
+#define ATOM_WS_QUOTIENT       0x40
+#define ATOM_WS_REMAINDER      0x41
+#define ATOM_WS_DATAPTR                0x42
+#define ATOM_WS_SHIFT          0x43
+#define ATOM_WS_OR_MASK                0x44
+#define ATOM_WS_AND_MASK       0x45
+#define ATOM_WS_FB_WINDOW      0x46
+#define ATOM_WS_ATTRIBUTES     0x47
+
+#define ATOM_IIO_NOP           0
+#define ATOM_IIO_START         1
+#define ATOM_IIO_READ          2
+#define ATOM_IIO_WRITE         3
+#define ATOM_IIO_CLEAR         4
+#define ATOM_IIO_SET           5
+#define ATOM_IIO_MOVE_INDEX    6
+#define ATOM_IIO_MOVE_ATTR     7
+#define ATOM_IIO_MOVE_DATA     8
+#define ATOM_IIO_END           9
+
+#define ATOM_IO_MM             0
+#define ATOM_IO_PCI            1
+#define ATOM_IO_SYSIO          2
+#define ATOM_IO_IIO            0x80
+
+struct card_info {
+       struct drm_device *dev;
+       void (* reg_write)(struct card_info *, uint32_t, uint32_t);   /*  filled by driver */
+        uint32_t (* reg_read)(struct card_info *, uint32_t);          /*  filled by driver */
+       void (* mc_write)(struct card_info *, uint32_t, uint32_t);   /*  filled by driver */
+        uint32_t (* mc_read)(struct card_info *, uint32_t);          /*  filled by driver */
+       void (* pll_write)(struct card_info *, uint32_t, uint32_t);   /*  filled by driver */
+        uint32_t (* pll_read)(struct card_info *, uint32_t);          /*  filled by driver */
+};
+
+struct atom_context {
+       struct card_info *card;
+       void *bios;
+       uint32_t cmd_table, data_table;
+       uint16_t *iio;
+
+       uint16_t data_block;
+       uint32_t fb_base;
+       uint32_t divmul[2];
+       uint16_t io_attr;
+       uint16_t reg_block;
+       uint8_t shift;
+       int cs_equal, cs_above;
+       int io_mode;
+};
+
+extern int atom_debug;
+
+struct atom_context *atom_parse(struct card_info *, void *);
+void atom_execute_table(struct atom_context *, int, uint32_t *);
+int atom_asic_init(struct atom_context *);
+void atom_destroy(struct atom_context *);
+void atom_parse_data_header(struct atom_context *ctx, int index, uint16_t *size, uint8_t *frev, uint8_t *crev, uint16_t *data_start);
+void atom_parse_cmd_header(struct atom_context *ctx, int index, uint8_t *frev, uint8_t *crev);
+#include "atom-types.h"
+#include "atombios.h"
+#include "ObjectID.h"
+
+#endif
diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h
new file mode 100644 (file)
index 0000000..cf67928
--- /dev/null
@@ -0,0 +1,4785 @@
+/*
+ * Copyright 2006-2007 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/****************************************************************************/
+/*Portion I: Definitions  shared between VBIOS and Driver                   */
+/****************************************************************************/
+
+#ifndef _ATOMBIOS_H
+#define _ATOMBIOS_H
+
+#define ATOM_VERSION_MAJOR                   0x00020000
+#define ATOM_VERSION_MINOR                   0x00000002
+
+#define ATOM_HEADER_VERSION (ATOM_VERSION_MAJOR | ATOM_VERSION_MINOR)
+
+/* Endianness should be specified before inclusion,
+ * default to little endian
+ */
+#ifndef ATOM_BIG_ENDIAN
+#error Endian not specified
+#endif
+
+#ifdef _H2INC
+#ifndef ULONG
+typedef unsigned long ULONG;
+#endif
+
+#ifndef UCHAR
+typedef unsigned char UCHAR;
+#endif
+
+#ifndef USHORT
+typedef unsigned short USHORT;
+#endif
+#endif
+
+#define ATOM_DAC_A            0
+#define ATOM_DAC_B            1
+#define ATOM_EXT_DAC          2
+
+#define ATOM_CRTC1            0
+#define ATOM_CRTC2            1
+
+#define ATOM_DIGA             0
+#define ATOM_DIGB             1
+
+#define ATOM_PPLL1            0
+#define ATOM_PPLL2            1
+
+#define ATOM_SCALER1          0
+#define ATOM_SCALER2          1
+
+#define ATOM_SCALER_DISABLE   0
+#define ATOM_SCALER_CENTER    1
+#define ATOM_SCALER_EXPANSION 2
+#define ATOM_SCALER_MULTI_EX  3
+
+#define ATOM_DISABLE          0
+#define ATOM_ENABLE           1
+#define ATOM_LCD_BLOFF                          (ATOM_DISABLE+2)
+#define ATOM_LCD_BLON                           (ATOM_ENABLE+2)
+#define ATOM_LCD_BL_BRIGHTNESS_CONTROL          (ATOM_ENABLE+3)
+#define ATOM_LCD_SELFTEST_START                                                                        (ATOM_DISABLE+5)
+#define ATOM_LCD_SELFTEST_STOP                                                                 (ATOM_ENABLE+5)
+#define ATOM_ENCODER_INIT                                        (ATOM_DISABLE+7)
+
+#define ATOM_BLANKING         1
+#define ATOM_BLANKING_OFF     0
+
+#define ATOM_CURSOR1          0
+#define ATOM_CURSOR2          1
+
+#define ATOM_ICON1            0
+#define ATOM_ICON2            1
+
+#define ATOM_CRT1             0
+#define ATOM_CRT2             1
+
+#define ATOM_TV_NTSC          1
+#define ATOM_TV_NTSCJ         2
+#define ATOM_TV_PAL           3
+#define ATOM_TV_PALM          4
+#define ATOM_TV_PALCN         5
+#define ATOM_TV_PALN          6
+#define ATOM_TV_PAL60         7
+#define ATOM_TV_SECAM         8
+#define ATOM_TV_CV            16
+
+#define ATOM_DAC1_PS2         1
+#define ATOM_DAC1_CV          2
+#define ATOM_DAC1_NTSC        3
+#define ATOM_DAC1_PAL         4
+
+#define ATOM_DAC2_PS2         ATOM_DAC1_PS2
+#define ATOM_DAC2_CV          ATOM_DAC1_CV
+#define ATOM_DAC2_NTSC        ATOM_DAC1_NTSC
+#define ATOM_DAC2_PAL         ATOM_DAC1_PAL
+
+#define ATOM_PM_ON            0
+#define ATOM_PM_STANDBY       1
+#define ATOM_PM_SUSPEND       2
+#define ATOM_PM_OFF           3
+
+/* Bit0:{=0:single, =1:dual},
+   Bit1 {=0:666RGB, =1:888RGB},
+   Bit2:3:{Grey level}
+   Bit4:{=0:LDI format for RGB888, =1 FPDI format for RGB888}*/
+
+#define ATOM_PANEL_MISC_DUAL               0x00000001
+#define ATOM_PANEL_MISC_888RGB             0x00000002
+#define ATOM_PANEL_MISC_GREY_LEVEL         0x0000000C
+#define ATOM_PANEL_MISC_FPDI               0x00000010
+#define ATOM_PANEL_MISC_GREY_LEVEL_SHIFT   2
+#define ATOM_PANEL_MISC_SPATIAL            0x00000020
+#define ATOM_PANEL_MISC_TEMPORAL           0x00000040
+#define ATOM_PANEL_MISC_API_ENABLED        0x00000080
+
+#define MEMTYPE_DDR1              "DDR1"
+#define MEMTYPE_DDR2              "DDR2"
+#define MEMTYPE_DDR3              "DDR3"
+#define MEMTYPE_DDR4              "DDR4"
+
+#define ASIC_BUS_TYPE_PCI         "PCI"
+#define ASIC_BUS_TYPE_AGP         "AGP"
+#define ASIC_BUS_TYPE_PCIE        "PCI_EXPRESS"
+
+/* Maximum size of that FireGL flag string */
+
+#define ATOM_FIREGL_FLAG_STRING     "FGL"      /* Flag used to enable FireGL Support */
+#define ATOM_MAX_SIZE_OF_FIREGL_FLAG_STRING  3 /* sizeof( ATOM_FIREGL_FLAG_STRING ) */
+
+#define ATOM_FAKE_DESKTOP_STRING    "DSK"      /* Flag used to enable mobile ASIC on Desktop */
+#define ATOM_MAX_SIZE_OF_FAKE_DESKTOP_STRING  ATOM_MAX_SIZE_OF_FIREGL_FLAG_STRING
+
+#define ATOM_M54T_FLAG_STRING       "M54T"     /* Flag used to enable M54T Support */
+#define ATOM_MAX_SIZE_OF_M54T_FLAG_STRING    4 /* sizeof( ATOM_M54T_FLAG_STRING ) */
+
+#define HW_ASSISTED_I2C_STATUS_FAILURE          2
+#define HW_ASSISTED_I2C_STATUS_SUCCESS          1
+
+#pragma pack(1)                        /* BIOS data must use byte aligment */
+
+/*  Define offset to location of ROM header. */
+
+#define OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER           0x00000048L
+#define OFFSET_TO_ATOM_ROM_IMAGE_SIZE                              0x00000002L
+
+#define OFFSET_TO_ATOMBIOS_ASIC_BUS_MEM_TYPE    0x94
+#define MAXSIZE_OF_ATOMBIOS_ASIC_BUS_MEM_TYPE   20     /* including the terminator 0x0! */
+#define        OFFSET_TO_GET_ATOMBIOS_STRINGS_NUMBER           0x002f
+#define        OFFSET_TO_GET_ATOMBIOS_STRINGS_START            0x006e
+
+/* Common header for all ROM Data tables.
+  Every table pointed  _ATOM_MASTER_DATA_TABLE has this common header.
+  And the pointer actually points to this header. */
+
+typedef struct _ATOM_COMMON_TABLE_HEADER {
+       USHORT usStructureSize;
+       UCHAR ucTableFormatRevision;    /*Change it when the Parser is not backward compatible */
+       UCHAR ucTableContentRevision;   /*Change it only when the table needs to change but the firmware */
+       /*Image can't be updated, while Driver needs to carry the new table! */
+} ATOM_COMMON_TABLE_HEADER;
+
+typedef struct _ATOM_ROM_HEADER {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       UCHAR uaFirmWareSignature[4];   /*Signature to distinguish between Atombios and non-atombios,
+                                          atombios should init it as "ATOM", don't change the position */
+       USHORT usBiosRuntimeSegmentAddress;
+       USHORT usProtectedModeInfoOffset;
+       USHORT usConfigFilenameOffset;
+       USHORT usCRC_BlockOffset;
+       USHORT usBIOS_BootupMessageOffset;
+       USHORT usInt10Offset;
+       USHORT usPciBusDevInitCode;
+       USHORT usIoBaseAddress;
+       USHORT usSubsystemVendorID;
+       USHORT usSubsystemID;
+       USHORT usPCI_InfoOffset;
+       USHORT usMasterCommandTableOffset;      /*Offset for SW to get all command table offsets, Don't change the position */
+       USHORT usMasterDataTableOffset; /*Offset for SW to get all data table offsets, Don't change the position */
+       UCHAR ucExtendedFunctionCode;
+       UCHAR ucReserved;
+} ATOM_ROM_HEADER;
+
+/*==============================Command Table Portion==================================== */
+
+#ifdef UEFI_BUILD
+#define        UTEMP   USHORT
+#define        USHORT  void*
+#endif
+
+typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES {
+       USHORT ASIC_Init;       /* Function Table, used by various SW components,latest version 1.1 */
+       USHORT GetDisplaySurfaceSize;   /* Atomic Table,  Used by Bios when enabling HW ICON */
+       USHORT ASIC_RegistersInit;      /* Atomic Table,  indirectly used by various SW components,called from ASIC_Init */
+       USHORT VRAM_BlockVenderDetection;       /* Atomic Table,  used only by Bios */
+       USHORT DIGxEncoderControl;      /* Only used by Bios */
+       USHORT MemoryControllerInit;    /* Atomic Table,  indirectly used by various SW components,called from ASIC_Init */
+       USHORT EnableCRTCMemReq;        /* Function Table,directly used by various SW components,latest version 2.1 */
+       USHORT MemoryParamAdjust;       /* Atomic Table,  indirectly used by various SW components,called from SetMemoryClock if needed */
+       USHORT DVOEncoderControl;       /* Function Table,directly used by various SW components,latest version 1.2 */
+       USHORT GPIOPinControl;  /* Atomic Table,  only used by Bios */
+       USHORT SetEngineClock;  /*Function Table,directly used by various SW components,latest version 1.1 */
+       USHORT SetMemoryClock;  /* Function Table,directly used by various SW components,latest version 1.1 */
+       USHORT SetPixelClock;   /*Function Table,directly used by various SW components,latest version 1.2 */
+       USHORT DynamicClockGating;      /* Atomic Table,  indirectly used by various SW components,called from ASIC_Init */
+       USHORT ResetMemoryDLL;  /* Atomic Table,  indirectly used by various SW components,called from SetMemoryClock */
+       USHORT ResetMemoryDevice;       /* Atomic Table,  indirectly used by various SW components,called from SetMemoryClock */
+       USHORT MemoryPLLInit;
+       USHORT AdjustDisplayPll;        /* only used by Bios */
+       USHORT AdjustMemoryController;  /* Atomic Table,  indirectly used by various SW components,called from SetMemoryClock */
+       USHORT EnableASIC_StaticPwrMgt; /* Atomic Table,  only used by Bios */
+       USHORT ASIC_StaticPwrMgtStatusChange;   /* Obsolete, only used by Bios */
+       USHORT DAC_LoadDetection;       /* Atomic Table,  directly used by various SW components,latest version 1.2 */
+       USHORT LVTMAEncoderControl;     /* Atomic Table,directly used by various SW components,latest version 1.3 */
+       USHORT LCD1OutputControl;       /* Atomic Table,  directly used by various SW components,latest version 1.1 */
+       USHORT DAC1EncoderControl;      /* Atomic Table,  directly used by various SW components,latest version 1.1 */
+       USHORT DAC2EncoderControl;      /* Atomic Table,  directly used by various SW components,latest version 1.1 */
+       USHORT DVOOutputControl;        /* Atomic Table,  directly used by various SW components,latest version 1.1 */
+       USHORT CV1OutputControl;        /* Atomic Table,  directly used by various SW components,latest version 1.1 */
+       USHORT GetConditionalGoldenSetting;     /* only used by Bios */
+       USHORT TVEncoderControl;        /* Function Table,directly used by various SW components,latest version 1.1 */
+       USHORT TMDSAEncoderControl;     /* Atomic Table,  directly used by various SW components,latest version 1.3 */
+       USHORT LVDSEncoderControl;      /* Atomic Table,  directly used by various SW components,latest version 1.3 */
+       USHORT TV1OutputControl;        /* Atomic Table,  directly used by various SW components,latest version 1.1 */
+       USHORT EnableScaler;    /* Atomic Table,  used only by Bios */
+       USHORT BlankCRTC;       /* Atomic Table,  directly used by various SW components,latest version 1.1 */
+       USHORT EnableCRTC;      /* Atomic Table,  directly used by various SW components,latest version 1.1 */
+       USHORT GetPixelClock;   /* Atomic Table,  directly used by various SW components,latest version 1.1 */
+       USHORT EnableVGA_Render;        /* Function Table,directly used by various SW components,latest version 1.1 */
+       USHORT EnableVGA_Access;        /* Obsolete ,     only used by Bios */
+       USHORT SetCRTC_Timing;  /* Atomic Table,  directly used by various SW components,latest version 1.1 */
+       USHORT SetCRTC_OverScan;        /* Atomic Table,  used by various SW components,latest version 1.1 */
+       USHORT SetCRTC_Replication;     /* Atomic Table,  used only by Bios */
+       USHORT SelectCRTC_Source;       /* Atomic Table,  directly used by various SW components,latest version 1.1 */
+       USHORT EnableGraphSurfaces;     /* Atomic Table,  used only by Bios */
+       USHORT UpdateCRTC_DoubleBufferRegisters;
+       USHORT LUT_AutoFill;    /* Atomic Table,  only used by Bios */
+       USHORT EnableHW_IconCursor;     /* Atomic Table,  only used by Bios */
+       USHORT GetMemoryClock;  /* Atomic Table,  directly used by various SW components,latest version 1.1 */
+       USHORT GetEngineClock;  /* Atomic Table,  directly used by various SW components,latest version 1.1 */
+       USHORT SetCRTC_UsingDTDTiming;  /* Atomic Table,  directly used by various SW components,latest version 1.1 */
+       USHORT ExternalEncoderControl;  /* Atomic Table,  directly used by various SW components,latest version 2.1 */
+       USHORT LVTMAOutputControl;      /* Atomic Table,  directly used by various SW components,latest version 1.1 */
+       USHORT VRAM_BlockDetectionByStrap;      /* Atomic Table,  used only by Bios */
+       USHORT MemoryCleanUp;   /* Atomic Table,  only used by Bios */
+       USHORT ProcessI2cChannelTransaction;    /* Function Table,only used by Bios */
+       USHORT WriteOneByteToHWAssistedI2C;     /* Function Table,indirectly used by various SW components */
+       USHORT ReadHWAssistedI2CStatus; /* Atomic Table,  indirectly used by various SW components */
+       USHORT SpeedFanControl; /* Function Table,indirectly used by various SW components,called from ASIC_Init */
+       USHORT PowerConnectorDetection; /* Atomic Table,  directly used by various SW components,latest version 1.1 */
+       USHORT MC_Synchronization;      /* Atomic Table,  indirectly used by various SW components,called from SetMemoryClock */
+       USHORT ComputeMemoryEnginePLL;  /* Atomic Table,  indirectly used by various SW components,called from SetMemory/EngineClock */
+       USHORT MemoryRefreshConversion; /* Atomic Table,  indirectly used by various SW components,called from SetMemory or SetEngineClock */
+       USHORT VRAM_GetCurrentInfoBlock;        /* Atomic Table,  used only by Bios */
+       USHORT DynamicMemorySettings;   /* Atomic Table,  indirectly used by various SW components,called from SetMemoryClock */
+       USHORT MemoryTraining;  /* Atomic Table,  used only by Bios */
+       USHORT EnableSpreadSpectrumOnPPLL;      /* Atomic Table,  directly used by various SW components,latest version 1.2 */
+       USHORT TMDSAOutputControl;      /* Atomic Table,  directly used by various SW components,latest version 1.1 */
+       USHORT SetVoltage;      /* Function Table,directly and/or indirectly used by various SW components,latest version 1.1 */
+       USHORT DAC1OutputControl;       /* Atomic Table,  directly used by various SW components,latest version 1.1 */
+       USHORT DAC2OutputControl;       /* Atomic Table,  directly used by various SW components,latest version 1.1 */
+       USHORT SetupHWAssistedI2CStatus;        /* Function Table,only used by Bios, obsolete soon.Switch to use "ReadEDIDFromHWAssistedI2C" */
+       USHORT ClockSource;     /* Atomic Table,  indirectly used by various SW components,called from ASIC_Init */
+       USHORT MemoryDeviceInit;        /* Atomic Table,  indirectly used by various SW components,called from SetMemoryClock */
+       USHORT EnableYUV;       /* Atomic Table,  indirectly used by various SW components,called from EnableVGARender */
+       USHORT DIG1EncoderControl;      /* Atomic Table,directly used by various SW components,latest version 1.1 */
+       USHORT DIG2EncoderControl;      /* Atomic Table,directly used by various SW components,latest version 1.1 */
+       USHORT DIG1TransmitterControl;  /* Atomic Table,directly used by various SW components,latest version 1.1 */
+       USHORT DIG2TransmitterControl;  /* Atomic Table,directly used by various SW components,latest version 1.1 */
+       USHORT ProcessAuxChannelTransaction;    /* Function Table,only used by Bios */
+       USHORT DPEncoderService;        /* Function Table,only used by Bios */
+} ATOM_MASTER_LIST_OF_COMMAND_TABLES;
+
+/*  For backward compatible */
+#define ReadEDIDFromHWAssistedI2C                ProcessI2cChannelTransaction
+#define UNIPHYTransmitterControl                                                    DIG1TransmitterControl
+#define LVTMATransmitterControl                                                             DIG2TransmitterControl
+#define SetCRTC_DPM_State                        GetConditionalGoldenSetting
+#define SetUniphyInstance                        ASIC_StaticPwrMgtStatusChange
+
+typedef struct _ATOM_MASTER_COMMAND_TABLE {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       ATOM_MASTER_LIST_OF_COMMAND_TABLES ListOfCommandTables;
+} ATOM_MASTER_COMMAND_TABLE;
+
+/****************************************************************************/
+/*  Structures used in every command table */
+/****************************************************************************/
+typedef struct _ATOM_TABLE_ATTRIBUTE {
+#if ATOM_BIG_ENDIAN
+       USHORT UpdatedByUtility:1;      /* [15]=Table updated by utility flag */
+       USHORT PS_SizeInBytes:7;        /* [14:8]=Size of parameter space in Bytes (multiple of a dword), */
+       USHORT WS_SizeInBytes:8;        /* [7:0]=Size of workspace in Bytes (in multiple of a dword), */
+#else
+       USHORT WS_SizeInBytes:8;        /* [7:0]=Size of workspace in Bytes (in multiple of a dword), */
+       USHORT PS_SizeInBytes:7;        /* [14:8]=Size of parameter space in Bytes (multiple of a dword), */
+       USHORT UpdatedByUtility:1;      /* [15]=Table updated by utility flag */
+#endif
+} ATOM_TABLE_ATTRIBUTE;
+
+typedef union _ATOM_TABLE_ATTRIBUTE_ACCESS {
+       ATOM_TABLE_ATTRIBUTE sbfAccess;
+       USHORT susAccess;
+} ATOM_TABLE_ATTRIBUTE_ACCESS;
+
+/****************************************************************************/
+/*  Common header for all command tables. */
+/*  Every table pointed by _ATOM_MASTER_COMMAND_TABLE has this common header. */
+/*  And the pointer actually points to this header. */
+/****************************************************************************/
+typedef struct _ATOM_COMMON_ROM_COMMAND_TABLE_HEADER {
+       ATOM_COMMON_TABLE_HEADER CommonHeader;
+       ATOM_TABLE_ATTRIBUTE TableAttribute;
+} ATOM_COMMON_ROM_COMMAND_TABLE_HEADER;
+
+/****************************************************************************/
+/*  Structures used by ComputeMemoryEnginePLLTable */
+/****************************************************************************/
+#define COMPUTE_MEMORY_PLL_PARAM        1
+#define COMPUTE_ENGINE_PLL_PARAM        2
+
+typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS {
+       ULONG ulClock;          /* When returen, it's the re-calculated clock based on given Fb_div Post_Div and ref_div */
+       UCHAR ucAction;         /* 0:reserved //1:Memory //2:Engine */
+       UCHAR ucReserved;       /* may expand to return larger Fbdiv later */
+       UCHAR ucFbDiv;          /* return value */
+       UCHAR ucPostDiv;        /* return value */
+} COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS;
+
+typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2 {
+       ULONG ulClock;          /* When return, [23:0] return real clock */
+       UCHAR ucAction;         /* 0:reserved;COMPUTE_MEMORY_PLL_PARAM:Memory;COMPUTE_ENGINE_PLL_PARAM:Engine. it return ref_div to be written to register */
+       USHORT usFbDiv;         /* return Feedback value to be written to register */
+       UCHAR ucPostDiv;        /* return post div to be written to register */
+} COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V2;
+#define COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_PS_ALLOCATION   COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS
+
+#define SET_CLOCK_FREQ_MASK                     0x00FFFFFF     /* Clock change tables only take bit [23:0] as the requested clock value */
+#define USE_NON_BUS_CLOCK_MASK                  0x01000000     /* Applicable to both memory and engine clock change, when set, it uses another clock as the temporary clock (engine uses memory and vice versa) */
+#define USE_MEMORY_SELF_REFRESH_MASK            0x02000000     /* Only applicable to memory clock change, when set, using memory self refresh during clock transition */
+#define SKIP_INTERNAL_MEMORY_PARAMETER_CHANGE   0x04000000     /* Only applicable to memory clock change, when set, the table will skip predefined internal memory parameter change */
+#define FIRST_TIME_CHANGE_CLOCK                                                                        0x08000000      /* Applicable to both memory and engine clock change,when set, it means this is 1st time to change clock after ASIC bootup */
+#define SKIP_SW_PROGRAM_PLL                                                                                    0x10000000      /* Applicable to both memory and engine clock change, when set, it means the table will not program SPLL/MPLL */
+#define USE_SS_ENABLED_PIXEL_CLOCK  USE_NON_BUS_CLOCK_MASK
+
+#define b3USE_NON_BUS_CLOCK_MASK                  0x01 /* Applicable to both memory and engine clock change, when set, it uses another clock as the temporary clock (engine uses memory and vice versa) */
+#define b3USE_MEMORY_SELF_REFRESH                 0x02 /* Only applicable to memory clock change, when set, using memory self refresh during clock transition */
+#define b3SKIP_INTERNAL_MEMORY_PARAMETER_CHANGE   0x04 /* Only applicable to memory clock change, when set, the table will skip predefined internal memory parameter change */
+#define b3FIRST_TIME_CHANGE_CLOCK                                                                      0x08    /* Applicable to both memory and engine clock change,when set, it means this is 1st time to change clock after ASIC bootup */
+#define b3SKIP_SW_PROGRAM_PLL                                                                                  0x10    /* Applicable to both memory and engine clock change, when set, it means the table will not program SPLL/MPLL */
+
+typedef struct _ATOM_COMPUTE_CLOCK_FREQ {
+#if ATOM_BIG_ENDIAN
+       ULONG ulComputeClockFlag:8;     /*  =1: COMPUTE_MEMORY_PLL_PARAM, =2: COMPUTE_ENGINE_PLL_PARAM */
+       ULONG ulClockFreq:24;   /*  in unit of 10kHz */
+#else
+       ULONG ulClockFreq:24;   /*  in unit of 10kHz */
+       ULONG ulComputeClockFlag:8;     /*  =1: COMPUTE_MEMORY_PLL_PARAM, =2: COMPUTE_ENGINE_PLL_PARAM */
+#endif
+} ATOM_COMPUTE_CLOCK_FREQ;
+
+typedef struct _ATOM_S_MPLL_FB_DIVIDER {
+       USHORT usFbDivFrac;
+       USHORT usFbDiv;
+} ATOM_S_MPLL_FB_DIVIDER;
+
+typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3 {
+       union {
+               ATOM_COMPUTE_CLOCK_FREQ ulClock;        /* Input Parameter */
+               ATOM_S_MPLL_FB_DIVIDER ulFbDiv; /* Output Parameter */
+       };
+       UCHAR ucRefDiv;         /* Output Parameter */
+       UCHAR ucPostDiv;        /* Output Parameter */
+       UCHAR ucCntlFlag;       /* Output Parameter */
+       UCHAR ucReserved;
+} COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V3;
+
+/*  ucCntlFlag */
+#define ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN          1
+#define ATOM_PLL_CNTL_FLAG_MPLL_VCO_MODE            2
+#define ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE         4
+
+typedef struct _DYNAMICE_MEMORY_SETTINGS_PARAMETER {
+       ATOM_COMPUTE_CLOCK_FREQ ulClock;
+       ULONG ulReserved[2];
+} DYNAMICE_MEMORY_SETTINGS_PARAMETER;
+
+typedef struct _DYNAMICE_ENGINE_SETTINGS_PARAMETER {
+       ATOM_COMPUTE_CLOCK_FREQ ulClock;
+       ULONG ulMemoryClock;
+       ULONG ulReserved;
+} DYNAMICE_ENGINE_SETTINGS_PARAMETER;
+
+/****************************************************************************/
+/*  Structures used by SetEngineClockTable */
+/****************************************************************************/
+typedef struct _SET_ENGINE_CLOCK_PARAMETERS {
+       ULONG ulTargetEngineClock;      /* In 10Khz unit */
+} SET_ENGINE_CLOCK_PARAMETERS;
+
+typedef struct _SET_ENGINE_CLOCK_PS_ALLOCATION {
+       ULONG ulTargetEngineClock;      /* In 10Khz unit */
+       COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_PS_ALLOCATION sReserved;
+} SET_ENGINE_CLOCK_PS_ALLOCATION;
+
+/****************************************************************************/
+/*  Structures used by SetMemoryClockTable */
+/****************************************************************************/
+typedef struct _SET_MEMORY_CLOCK_PARAMETERS {
+       ULONG ulTargetMemoryClock;      /* In 10Khz unit */
+} SET_MEMORY_CLOCK_PARAMETERS;
+
+typedef struct _SET_MEMORY_CLOCK_PS_ALLOCATION {
+       ULONG ulTargetMemoryClock;      /* In 10Khz unit */
+       COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_PS_ALLOCATION sReserved;
+} SET_MEMORY_CLOCK_PS_ALLOCATION;
+
+/****************************************************************************/
+/*  Structures used by ASIC_Init.ctb */
+/****************************************************************************/
+typedef struct _ASIC_INIT_PARAMETERS {
+       ULONG ulDefaultEngineClock;     /* In 10Khz unit */
+       ULONG ulDefaultMemoryClock;     /* In 10Khz unit */
+} ASIC_INIT_PARAMETERS;
+
+typedef struct _ASIC_INIT_PS_ALLOCATION {
+       ASIC_INIT_PARAMETERS sASICInitClocks;
+       SET_ENGINE_CLOCK_PS_ALLOCATION sReserved;       /* Caller doesn't need to init this structure */
+} ASIC_INIT_PS_ALLOCATION;
+
+/****************************************************************************/
+/*  Structure used by DynamicClockGatingTable.ctb */
+/****************************************************************************/
+typedef struct _DYNAMIC_CLOCK_GATING_PARAMETERS {
+       UCHAR ucEnable;         /*  ATOM_ENABLE or ATOM_DISABLE */
+       UCHAR ucPadding[3];
+} DYNAMIC_CLOCK_GATING_PARAMETERS;
+#define  DYNAMIC_CLOCK_GATING_PS_ALLOCATION  DYNAMIC_CLOCK_GATING_PARAMETERS
+
+/****************************************************************************/
+/*  Structure used by EnableASIC_StaticPwrMgtTable.ctb */
+/****************************************************************************/
+typedef struct _ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS {
+       UCHAR ucEnable;         /*  ATOM_ENABLE or ATOM_DISABLE */
+       UCHAR ucPadding[3];
+} ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS;
+#define ENABLE_ASIC_STATIC_PWR_MGT_PS_ALLOCATION  ENABLE_ASIC_STATIC_PWR_MGT_PARAMETERS
+
+/****************************************************************************/
+/*  Structures used by DAC_LoadDetectionTable.ctb */
+/****************************************************************************/
+typedef struct _DAC_LOAD_DETECTION_PARAMETERS {
+       USHORT usDeviceID;      /* {ATOM_DEVICE_CRTx_SUPPORT,ATOM_DEVICE_TVx_SUPPORT,ATOM_DEVICE_CVx_SUPPORT} */
+       UCHAR ucDacType;        /* {ATOM_DAC_A,ATOM_DAC_B, ATOM_EXT_DAC} */
+       UCHAR ucMisc;           /* Valid only when table revision =1.3 and above */
+} DAC_LOAD_DETECTION_PARAMETERS;
+
+/*  DAC_LOAD_DETECTION_PARAMETERS.ucMisc */
+#define DAC_LOAD_MISC_YPrPb                                            0x01
+
+typedef struct _DAC_LOAD_DETECTION_PS_ALLOCATION {
+       DAC_LOAD_DETECTION_PARAMETERS sDacload;
+       ULONG Reserved[2];      /*  Don't set this one, allocation for EXT DAC */
+} DAC_LOAD_DETECTION_PS_ALLOCATION;
+
+/****************************************************************************/
+/*  Structures used by DAC1EncoderControlTable.ctb and DAC2EncoderControlTable.ctb */
+/****************************************************************************/
+typedef struct _DAC_ENCODER_CONTROL_PARAMETERS {
+       USHORT usPixelClock;    /*  in 10KHz; for bios convenient */
+       UCHAR ucDacStandard;    /*  See definition of ATOM_DACx_xxx, For DEC3.0, bit 7 used as internal flag to indicate DAC2 (==1) or DAC1 (==0) */
+       UCHAR ucAction;         /*  0: turn off encoder */
+       /*  1: setup and turn on encoder */
+       /*  7: ATOM_ENCODER_INIT Initialize DAC */
+} DAC_ENCODER_CONTROL_PARAMETERS;
+
+#define DAC_ENCODER_CONTROL_PS_ALLOCATION  DAC_ENCODER_CONTROL_PARAMETERS
+
+/****************************************************************************/
+/*  Structures used by DIG1EncoderControlTable */
+/*                     DIG2EncoderControlTable */
+/*                     ExternalEncoderControlTable */
+/****************************************************************************/
+typedef struct _DIG_ENCODER_CONTROL_PARAMETERS {
+       USHORT usPixelClock;    /*  in 10KHz; for bios convenient */
+       UCHAR ucConfig;
+       /*  [2] Link Select: */
+       /*  =0: PHY linkA if bfLane<3 */
+       /*  =1: PHY linkB if bfLanes<3 */
+       /*  =0: PHY linkA+B if bfLanes=3 */
+       /*  [3] Transmitter Sel */
+       /*  =0: UNIPHY or PCIEPHY */
+       /*  =1: LVTMA */
+       UCHAR ucAction;         /*  =0: turn off encoder */
+       /*  =1: turn on encoder */
+       UCHAR ucEncoderMode;
+       /*  =0: DP   encoder */
+       /*  =1: LVDS encoder */
+       /*  =2: DVI  encoder */
+       /*  =3: HDMI encoder */
+       /*  =4: SDVO encoder */
+       UCHAR ucLaneNum;        /*  how many lanes to enable */
+       UCHAR ucReserved[2];
+} DIG_ENCODER_CONTROL_PARAMETERS;
+#define DIG_ENCODER_CONTROL_PS_ALLOCATION                        DIG_ENCODER_CONTROL_PARAMETERS
+#define EXTERNAL_ENCODER_CONTROL_PARAMETER                     DIG_ENCODER_CONTROL_PARAMETERS
+
+/* ucConfig */
+#define ATOM_ENCODER_CONFIG_DPLINKRATE_MASK                            0x01
+#define ATOM_ENCODER_CONFIG_DPLINKRATE_1_62GHZ         0x00
+#define ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ         0x01
+#define ATOM_ENCODER_CONFIG_LINK_SEL_MASK                                0x04
+#define ATOM_ENCODER_CONFIG_LINKA                                                                0x00
+#define ATOM_ENCODER_CONFIG_LINKB                                                                0x04
+#define ATOM_ENCODER_CONFIG_LINKA_B                                                      ATOM_TRANSMITTER_CONFIG_LINKA
+#define ATOM_ENCODER_CONFIG_LINKB_A                                                      ATOM_ENCODER_CONFIG_LINKB
+#define ATOM_ENCODER_CONFIG_TRANSMITTER_SEL_MASK       0x08
+#define ATOM_ENCODER_CONFIG_UNIPHY                                                       0x00
+#define ATOM_ENCODER_CONFIG_LVTMA                                                                0x08
+#define ATOM_ENCODER_CONFIG_TRANSMITTER1                                 0x00
+#define ATOM_ENCODER_CONFIG_TRANSMITTER2                                 0x08
+#define ATOM_ENCODER_CONFIG_DIGB                                                                 0x80  /*  VBIOS Internal use, outside SW should set this bit=0 */
+/*  ucAction */
+/*  ATOM_ENABLE:  Enable Encoder */
+/*  ATOM_DISABLE: Disable Encoder */
+
+/* ucEncoderMode */
+#define ATOM_ENCODER_MODE_DP                                                                                   0
+#define ATOM_ENCODER_MODE_LVDS                                                                         1
+#define ATOM_ENCODER_MODE_DVI                                                                                  2
+#define ATOM_ENCODER_MODE_HDMI                                                                         3
+#define ATOM_ENCODER_MODE_SDVO                                                                         4
+#define ATOM_ENCODER_MODE_TV                                                                                   13
+#define ATOM_ENCODER_MODE_CV                                                                                   14
+#define ATOM_ENCODER_MODE_CRT                                                                                  15
+
+typedef struct _ATOM_DIG_ENCODER_CONFIG_V2 {
+#if ATOM_BIG_ENDIAN
+       UCHAR ucReserved1:2;
+       UCHAR ucTransmitterSel:2;       /*  =0: UniphyAB, =1: UniphyCD  =2: UniphyEF */
+       UCHAR ucLinkSel:1;      /*  =0: linkA/C/E =1: linkB/D/F */
+       UCHAR ucReserved:1;
+       UCHAR ucDPLinkRate:1;   /*  =0: 1.62Ghz, =1: 2.7Ghz */
+#else
+       UCHAR ucDPLinkRate:1;   /*  =0: 1.62Ghz, =1: 2.7Ghz */
+       UCHAR ucReserved:1;
+       UCHAR ucLinkSel:1;      /*  =0: linkA/C/E =1: linkB/D/F */
+       UCHAR ucTransmitterSel:2;       /*  =0: UniphyAB, =1: UniphyCD  =2: UniphyEF */
+       UCHAR ucReserved1:2;
+#endif
+} ATOM_DIG_ENCODER_CONFIG_V2;
+
+typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V2 {
+       USHORT usPixelClock;    /*  in 10KHz; for bios convenient */
+       ATOM_DIG_ENCODER_CONFIG_V2 acConfig;
+       UCHAR ucAction;
+       UCHAR ucEncoderMode;
+       /*  =0: DP   encoder */
+       /*  =1: LVDS encoder */
+       /*  =2: DVI  encoder */
+       /*  =3: HDMI encoder */
+       /*  =4: SDVO encoder */
+       UCHAR ucLaneNum;        /*  how many lanes to enable */
+       UCHAR ucReserved[2];
+} DIG_ENCODER_CONTROL_PARAMETERS_V2;
+
+/* ucConfig */
+#define ATOM_ENCODER_CONFIG_V2_DPLINKRATE_MASK                         0x01
+#define ATOM_ENCODER_CONFIG_V2_DPLINKRATE_1_62GHZ                0x00
+#define ATOM_ENCODER_CONFIG_V2_DPLINKRATE_2_70GHZ                0x01
+#define ATOM_ENCODER_CONFIG_V2_LINK_SEL_MASK                             0x04
+#define ATOM_ENCODER_CONFIG_V2_LINKA                                                             0x00
+#define ATOM_ENCODER_CONFIG_V2_LINKB                                                             0x04
+#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER_SEL_MASK      0x18
+#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER1                                0x00
+#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER2                                0x08
+#define ATOM_ENCODER_CONFIG_V2_TRANSMITTER3                                0x10
+
+/****************************************************************************/
+/*  Structures used by UNIPHYTransmitterControlTable */
+/*                     LVTMATransmitterControlTable */
+/*                     DVOOutputControlTable */
+/****************************************************************************/
+typedef struct _ATOM_DP_VS_MODE {
+       UCHAR ucLaneSel;
+       UCHAR ucLaneSet;
+} ATOM_DP_VS_MODE;
+
+typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS {
+       union {
+               USHORT usPixelClock;    /*  in 10KHz; for bios convenient */
+               USHORT usInitInfo;      /*  when init uniphy,lower 8bit is used for connector type defined in objectid.h */
+               ATOM_DP_VS_MODE asMode; /*  DP Voltage swing mode */
+       };
+       UCHAR ucConfig;
+       /*  [0]=0: 4 lane Link, */
+       /*     =1: 8 lane Link ( Dual Links TMDS ) */
+       /*  [1]=0: InCoherent mode */
+       /*     =1: Coherent Mode */
+       /*  [2] Link Select: */
+       /*  =0: PHY linkA   if bfLane<3 */
+       /*  =1: PHY linkB   if bfLanes<3 */
+       /*  =0: PHY linkA+B if bfLanes=3 */
+       /*  [5:4]PCIE lane Sel */
+       /*  =0: lane 0~3 or 0~7 */
+       /*  =1: lane 4~7 */
+       /*  =2: lane 8~11 or 8~15 */
+       /*  =3: lane 12~15 */
+       UCHAR ucAction;         /*  =0: turn off encoder */
+       /*  =1: turn on encoder */
+       UCHAR ucReserved[4];
+} DIG_TRANSMITTER_CONTROL_PARAMETERS;
+
+#define DIG_TRANSMITTER_CONTROL_PS_ALLOCATION          DIG_TRANSMITTER_CONTROL_PARAMETERS
+
+/* ucInitInfo */
+#define ATOM_TRAMITTER_INITINFO_CONNECTOR_MASK 0x00ff
+
+/* ucConfig */
+#define ATOM_TRANSMITTER_CONFIG_8LANE_LINK                     0x01
+#define ATOM_TRANSMITTER_CONFIG_COHERENT                               0x02
+#define ATOM_TRANSMITTER_CONFIG_LINK_SEL_MASK          0x04
+#define ATOM_TRANSMITTER_CONFIG_LINKA                                          0x00
+#define ATOM_TRANSMITTER_CONFIG_LINKB                                          0x04
+#define ATOM_TRANSMITTER_CONFIG_LINKA_B                                        0x00
+#define ATOM_TRANSMITTER_CONFIG_LINKB_A                                        0x04
+
+#define ATOM_TRANSMITTER_CONFIG_ENCODER_SEL_MASK       0x08    /*  only used when ATOM_TRANSMITTER_ACTION_ENABLE */
+#define ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER           0x00    /*  only used when ATOM_TRANSMITTER_ACTION_ENABLE */
+#define ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER           0x08    /*  only used when ATOM_TRANSMITTER_ACTION_ENABLE */
+
+#define ATOM_TRANSMITTER_CONFIG_CLKSRC_MASK                    0x30
+#define ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL                    0x00
+#define ATOM_TRANSMITTER_CONFIG_CLKSRC_PCIE                    0x20
+#define ATOM_TRANSMITTER_CONFIG_CLKSRC_XTALIN          0x30
+#define ATOM_TRANSMITTER_CONFIG_LANE_SEL_MASK          0xc0
+#define ATOM_TRANSMITTER_CONFIG_LANE_0_3                               0x00
+#define ATOM_TRANSMITTER_CONFIG_LANE_0_7                               0x00
+#define ATOM_TRANSMITTER_CONFIG_LANE_4_7                               0x40
+#define ATOM_TRANSMITTER_CONFIG_LANE_8_11                              0x80
+#define ATOM_TRANSMITTER_CONFIG_LANE_8_15                              0x80
+#define ATOM_TRANSMITTER_CONFIG_LANE_12_15                     0xc0
+
+/* ucAction */
+#define ATOM_TRANSMITTER_ACTION_DISABLE                                               0
+#define ATOM_TRANSMITTER_ACTION_ENABLE                                        1
+#define ATOM_TRANSMITTER_ACTION_LCD_BLOFF                                     2
+#define ATOM_TRANSMITTER_ACTION_LCD_BLON                                      3
+#define ATOM_TRANSMITTER_ACTION_BL_BRIGHTNESS_CONTROL  4
+#define ATOM_TRANSMITTER_ACTION_LCD_SELFTEST_START              5
+#define ATOM_TRANSMITTER_ACTION_LCD_SELFTEST_STOP                       6
+#define ATOM_TRANSMITTER_ACTION_INIT                                                  7
+#define ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT        8
+#define ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT                 9
+#define ATOM_TRANSMITTER_ACTION_SETUP                                                 10
+#define ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH           11
+
+/*  Following are used for DigTransmitterControlTable ver1.2 */
+typedef struct _ATOM_DIG_TRANSMITTER_CONFIG_V2 {
+#if ATOM_BIG_ENDIAN
+       UCHAR ucTransmitterSel:2;       /* bit7:6: =0 Dig Transmitter 1 ( Uniphy AB ) */
+       /*         =1 Dig Transmitter 2 ( Uniphy CD ) */
+       /*         =2 Dig Transmitter 3 ( Uniphy EF ) */
+       UCHAR ucReserved:1;
+       UCHAR fDPConnector:1;   /* bit4=0: DP connector  =1: None DP connector */
+       UCHAR ucEncoderSel:1;   /* bit3=0: Data/Clk path source from DIGA( DIG inst0 ). =1: Data/clk path source from DIGB ( DIG inst1 ) */
+       UCHAR ucLinkSel:1;      /* bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E */
+       /*     =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F */
+
+       UCHAR fCoherentMode:1;  /* bit1=1: Coherent Mode ( for DVI/HDMI mode ) */
+       UCHAR fDualLinkConnector:1;     /* bit0=1: Dual Link DVI connector */
+#else
+       UCHAR fDualLinkConnector:1;     /* bit0=1: Dual Link DVI connector */
+       UCHAR fCoherentMode:1;  /* bit1=1: Coherent Mode ( for DVI/HDMI mode ) */
+       UCHAR ucLinkSel:1;      /* bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E */
+       /*     =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F */
+       UCHAR ucEncoderSel:1;   /* bit3=0: Data/Clk path source from DIGA( DIG inst0 ). =1: Data/clk path source from DIGB ( DIG inst1 ) */
+       UCHAR fDPConnector:1;   /* bit4=0: DP connector  =1: None DP connector */
+       UCHAR ucReserved:1;
+       UCHAR ucTransmitterSel:2;       /* bit7:6: =0 Dig Transmitter 1 ( Uniphy AB ) */
+       /*         =1 Dig Transmitter 2 ( Uniphy CD ) */
+       /*         =2 Dig Transmitter 3 ( Uniphy EF ) */
+#endif
+} ATOM_DIG_TRANSMITTER_CONFIG_V2;
+
+/* ucConfig */
+/* Bit0 */
+#define ATOM_TRANSMITTER_CONFIG_V2_DUAL_LINK_CONNECTOR                 0x01
+
+/* Bit1 */
+#define ATOM_TRANSMITTER_CONFIG_V2_COHERENT                                      0x02
+
+/* Bit2 */
+#define ATOM_TRANSMITTER_CONFIG_V2_LINK_SEL_MASK                       0x04
+#define ATOM_TRANSMITTER_CONFIG_V2_LINKA                                   0x00
+#define ATOM_TRANSMITTER_CONFIG_V2_LINKB                                           0x04
+
+/*  Bit3 */
+#define ATOM_TRANSMITTER_CONFIG_V2_ENCODER_SEL_MASK            0x08
+#define ATOM_TRANSMITTER_CONFIG_V2_DIG1_ENCODER                          0x00  /*  only used when ucAction == ATOM_TRANSMITTER_ACTION_ENABLE or ATOM_TRANSMITTER_ACTION_SETUP */
+#define ATOM_TRANSMITTER_CONFIG_V2_DIG2_ENCODER                          0x08  /*  only used when ucAction == ATOM_TRANSMITTER_ACTION_ENABLE or ATOM_TRANSMITTER_ACTION_SETUP */
+
+/*  Bit4 */
+#define ATOM_TRASMITTER_CONFIG_V2_DP_CONNECTOR                         0x10
+
+/*  Bit7:6 */
+#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER_SEL_MASK     0xC0
+#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER1                        0x00    /* AB */
+#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER2                        0x40    /* CD */
+#define ATOM_TRANSMITTER_CONFIG_V2_TRANSMITTER3                        0x80    /* EF */
+
+typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 {
+       union {
+               USHORT usPixelClock;    /*  in 10KHz; for bios convenient */
+               USHORT usInitInfo;      /*  when init uniphy,lower 8bit is used for connector type defined in objectid.h */
+               ATOM_DP_VS_MODE asMode; /*  DP Voltage swing mode */
+       };
+       ATOM_DIG_TRANSMITTER_CONFIG_V2 acConfig;
+       UCHAR ucAction;         /*  define as ATOM_TRANSMITER_ACTION_XXX */
+       UCHAR ucReserved[4];
+} DIG_TRANSMITTER_CONTROL_PARAMETERS_V2;
+
+/****************************************************************************/
+/*  Structures used by DAC1OuputControlTable */
+/*                     DAC2OuputControlTable */
+/*                     LVTMAOutputControlTable  (Before DEC30) */
+/*                     TMDSAOutputControlTable  (Before DEC30) */
+/****************************************************************************/
+typedef struct _DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS {
+       UCHAR ucAction;         /*  Possible input:ATOM_ENABLE||ATOMDISABLE */
+       /*  When the display is LCD, in addition to above: */
+       /*  ATOM_LCD_BLOFF|| ATOM_LCD_BLON ||ATOM_LCD_BL_BRIGHTNESS_CONTROL||ATOM_LCD_SELFTEST_START|| */
+       /*  ATOM_LCD_SELFTEST_STOP */
+
+       UCHAR aucPadding[3];    /*  padding to DWORD aligned */
+} DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS;
+
+#define DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
+
+#define CRT1_OUTPUT_CONTROL_PARAMETERS     DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
+#define CRT1_OUTPUT_CONTROL_PS_ALLOCATION  DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION
+
+#define CRT2_OUTPUT_CONTROL_PARAMETERS     DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
+#define CRT2_OUTPUT_CONTROL_PS_ALLOCATION  DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION
+
+#define CV1_OUTPUT_CONTROL_PARAMETERS      DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
+#define CV1_OUTPUT_CONTROL_PS_ALLOCATION   DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION
+
+#define TV1_OUTPUT_CONTROL_PARAMETERS      DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
+#define TV1_OUTPUT_CONTROL_PS_ALLOCATION   DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION
+
+#define DFP1_OUTPUT_CONTROL_PARAMETERS     DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
+#define DFP1_OUTPUT_CONTROL_PS_ALLOCATION  DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION
+
+#define DFP2_OUTPUT_CONTROL_PARAMETERS     DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
+#define DFP2_OUTPUT_CONTROL_PS_ALLOCATION  DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION
+
+#define LCD1_OUTPUT_CONTROL_PARAMETERS     DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
+#define LCD1_OUTPUT_CONTROL_PS_ALLOCATION  DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION
+
+#define DVO_OUTPUT_CONTROL_PARAMETERS      DISPLAY_DEVICE_OUTPUT_CONTROL_PARAMETERS
+#define DVO_OUTPUT_CONTROL_PS_ALLOCATION   DIG_TRANSMITTER_CONTROL_PS_ALLOCATION
+#define DVO_OUTPUT_CONTROL_PARAMETERS_V3        DIG_TRANSMITTER_CONTROL_PARAMETERS
+
+/****************************************************************************/
+/*  Structures used by BlankCRTCTable */
+/****************************************************************************/
+typedef struct _BLANK_CRTC_PARAMETERS {
+       UCHAR ucCRTC;           /*  ATOM_CRTC1 or ATOM_CRTC2 */
+       UCHAR ucBlanking;       /*  ATOM_BLANKING or ATOM_BLANKINGOFF */
+       USHORT usBlackColorRCr;
+       USHORT usBlackColorGY;
+       USHORT usBlackColorBCb;
+} BLANK_CRTC_PARAMETERS;
+#define BLANK_CRTC_PS_ALLOCATION    BLANK_CRTC_PARAMETERS
+
+/****************************************************************************/
+/*  Structures used by EnableCRTCTable */
+/*                     EnableCRTCMemReqTable */
+/*                     UpdateCRTC_DoubleBufferRegistersTable */
+/****************************************************************************/
+typedef struct _ENABLE_CRTC_PARAMETERS {
+       UCHAR ucCRTC;           /*  ATOM_CRTC1 or ATOM_CRTC2 */
+       UCHAR ucEnable;         /*  ATOM_ENABLE or ATOM_DISABLE */
+       UCHAR ucPadding[2];
+} ENABLE_CRTC_PARAMETERS;
+#define ENABLE_CRTC_PS_ALLOCATION   ENABLE_CRTC_PARAMETERS
+
+/****************************************************************************/
+/*  Structures used by SetCRTC_OverScanTable */
+/****************************************************************************/
+typedef struct _SET_CRTC_OVERSCAN_PARAMETERS {
+       USHORT usOverscanRight; /*  right */
+       USHORT usOverscanLeft;  /*  left */
+       USHORT usOverscanBottom;        /*  bottom */
+       USHORT usOverscanTop;   /*  top */
+       UCHAR ucCRTC;           /*  ATOM_CRTC1 or ATOM_CRTC2 */
+       UCHAR ucPadding[3];
+} SET_CRTC_OVERSCAN_PARAMETERS;
+#define SET_CRTC_OVERSCAN_PS_ALLOCATION  SET_CRTC_OVERSCAN_PARAMETERS
+
+/****************************************************************************/
+/*  Structures used by SetCRTC_ReplicationTable */
+/****************************************************************************/
+typedef struct _SET_CRTC_REPLICATION_PARAMETERS {
+       UCHAR ucH_Replication;  /*  horizontal replication */
+       UCHAR ucV_Replication;  /*  vertical replication */
+       UCHAR usCRTC;           /*  ATOM_CRTC1 or ATOM_CRTC2 */
+       UCHAR ucPadding;
+} SET_CRTC_REPLICATION_PARAMETERS;
+#define SET_CRTC_REPLICATION_PS_ALLOCATION  SET_CRTC_REPLICATION_PARAMETERS
+
+/****************************************************************************/
+/*  Structures used by SelectCRTC_SourceTable */
+/****************************************************************************/
+typedef struct _SELECT_CRTC_SOURCE_PARAMETERS {
+       UCHAR ucCRTC;           /*  ATOM_CRTC1 or ATOM_CRTC2 */
+       UCHAR ucDevice;         /*  ATOM_DEVICE_CRT1|ATOM_DEVICE_CRT2|.... */
+       UCHAR ucPadding[2];
+} SELECT_CRTC_SOURCE_PARAMETERS;
+#define SELECT_CRTC_SOURCE_PS_ALLOCATION  SELECT_CRTC_SOURCE_PARAMETERS
+
+typedef struct _SELECT_CRTC_SOURCE_PARAMETERS_V2 {
+       UCHAR ucCRTC;           /*  ATOM_CRTC1 or ATOM_CRTC2 */
+       UCHAR ucEncoderID;      /*  DAC1/DAC2/TVOUT/DIG1/DIG2/DVO */
+       UCHAR ucEncodeMode;     /*  Encoding mode, only valid when using DIG1/DIG2/DVO */
+       UCHAR ucPadding;
+} SELECT_CRTC_SOURCE_PARAMETERS_V2;
+
+/* ucEncoderID */
+/* #define ASIC_INT_DAC1_ENCODER_ID                                              0x00 */
+/* #define ASIC_INT_TV_ENCODER_ID                                                                        0x02 */
+/* #define ASIC_INT_DIG1_ENCODER_ID                                                              0x03 */
+/* #define ASIC_INT_DAC2_ENCODER_ID                                                              0x04 */
+/* #define ASIC_EXT_TV_ENCODER_ID                                                                        0x06 */
+/* #define ASIC_INT_DVO_ENCODER_ID                                                                       0x07 */
+/* #define ASIC_INT_DIG2_ENCODER_ID                                                              0x09 */
+/* #define ASIC_EXT_DIG_ENCODER_ID                                                                       0x05 */
+
+/* ucEncodeMode */
+/* #define ATOM_ENCODER_MODE_DP                                                                          0 */
+/* #define ATOM_ENCODER_MODE_LVDS                                                                        1 */
+/* #define ATOM_ENCODER_MODE_DVI                                                                         2 */
+/* #define ATOM_ENCODER_MODE_HDMI                                                                        3 */
+/* #define ATOM_ENCODER_MODE_SDVO                                                                        4 */
+/* #define ATOM_ENCODER_MODE_TV                                                                          13 */
+/* #define ATOM_ENCODER_MODE_CV                                                                          14 */
+/* #define ATOM_ENCODER_MODE_CRT                                                                         15 */
+
+/****************************************************************************/
+/*  Structures used by SetPixelClockTable */
+/*                     GetPixelClockTable */
+/****************************************************************************/
+/* Major revision=1., Minor revision=1 */
+typedef struct _PIXEL_CLOCK_PARAMETERS {
+       USHORT usPixelClock;    /*  in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div) */
+       /*  0 means disable PPLL */
+       USHORT usRefDiv;        /*  Reference divider */
+       USHORT usFbDiv;         /*  feedback divider */
+       UCHAR ucPostDiv;        /*  post divider */
+       UCHAR ucFracFbDiv;      /*  fractional feedback divider */
+       UCHAR ucPpll;           /*  ATOM_PPLL1 or ATOM_PPL2 */
+       UCHAR ucRefDivSrc;      /*  ATOM_PJITTER or ATO_NONPJITTER */
+       UCHAR ucCRTC;           /*  Which CRTC uses this Ppll */
+       UCHAR ucPadding;
+} PIXEL_CLOCK_PARAMETERS;
+
+/* Major revision=1., Minor revision=2, add ucMiscIfno */
+/* ucMiscInfo: */
+#define MISC_FORCE_REPROG_PIXEL_CLOCK 0x1
+#define MISC_DEVICE_INDEX_MASK        0xF0
+#define MISC_DEVICE_INDEX_SHIFT       4
+
+typedef struct _PIXEL_CLOCK_PARAMETERS_V2 {
+       USHORT usPixelClock;    /*  in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div) */
+       /*  0 means disable PPLL */
+       USHORT usRefDiv;        /*  Reference divider */
+       USHORT usFbDiv;         /*  feedback divider */
+       UCHAR ucPostDiv;        /*  post divider */
+       UCHAR ucFracFbDiv;      /*  fractional feedback divider */
+       UCHAR ucPpll;           /*  ATOM_PPLL1 or ATOM_PPL2 */
+       UCHAR ucRefDivSrc;      /*  ATOM_PJITTER or ATO_NONPJITTER */
+       UCHAR ucCRTC;           /*  Which CRTC uses this Ppll */
+       UCHAR ucMiscInfo;       /*  Different bits for different purpose, bit [7:4] as device index, bit[0]=Force prog */
+} PIXEL_CLOCK_PARAMETERS_V2;
+
+/* Major revision=1., Minor revision=3, structure/definition change */
+/* ucEncoderMode: */
+/* ATOM_ENCODER_MODE_DP */
+/* ATOM_ENOCDER_MODE_LVDS */
+/* ATOM_ENOCDER_MODE_DVI */
+/* ATOM_ENOCDER_MODE_HDMI */
+/* ATOM_ENOCDER_MODE_SDVO */
+/* ATOM_ENCODER_MODE_TV                                                                          13 */
+/* ATOM_ENCODER_MODE_CV                                                                          14 */
+/* ATOM_ENCODER_MODE_CRT                                                                         15 */
+
+/* ucDVOConfig */
+/* #define DVO_ENCODER_CONFIG_RATE_SEL                                                   0x01 */
+/* #define DVO_ENCODER_CONFIG_DDR_SPEED                                          0x00 */
+/* #define DVO_ENCODER_CONFIG_SDR_SPEED                                          0x01 */
+/* #define DVO_ENCODER_CONFIG_OUTPUT_SEL                                         0x0c */
+/* #define DVO_ENCODER_CONFIG_LOW12BIT                                                   0x00 */
+/* #define DVO_ENCODER_CONFIG_UPPER12BIT                                         0x04 */
+/* #define DVO_ENCODER_CONFIG_24BIT                                                              0x08 */
+
+/* ucMiscInfo: also changed, see below */
+#define PIXEL_CLOCK_MISC_FORCE_PROG_PPLL                                               0x01
+#define PIXEL_CLOCK_MISC_VGA_MODE                                                                              0x02
+#define PIXEL_CLOCK_MISC_CRTC_SEL_MASK                                                 0x04
+#define PIXEL_CLOCK_MISC_CRTC_SEL_CRTC1                                                        0x00
+#define PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2                                                        0x04
+#define PIXEL_CLOCK_MISC_USE_ENGINE_FOR_DISPCLK                        0x08
+
+typedef struct _PIXEL_CLOCK_PARAMETERS_V3 {
+       USHORT usPixelClock;    /*  in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div) */
+       /*  0 means disable PPLL. For VGA PPLL,make sure this value is not 0. */
+       USHORT usRefDiv;        /*  Reference divider */
+       USHORT usFbDiv;         /*  feedback divider */
+       UCHAR ucPostDiv;        /*  post divider */
+       UCHAR ucFracFbDiv;      /*  fractional feedback divider */
+       UCHAR ucPpll;           /*  ATOM_PPLL1 or ATOM_PPL2 */
+       UCHAR ucTransmitterId;  /*  graphic encoder id defined in objectId.h */
+       union {
+               UCHAR ucEncoderMode;    /*  encoder type defined as ATOM_ENCODER_MODE_DP/DVI/HDMI/ */
+               UCHAR ucDVOConfig;      /*  when use DVO, need to know SDR/DDR, 12bit or 24bit */
+       };
+       UCHAR ucMiscInfo;       /*  bit[0]=Force program, bit[1]= set pclk for VGA, b[2]= CRTC sel */
+       /*  bit[3]=0:use PPLL for dispclk source, =1: use engine clock for dispclock source */
+} PIXEL_CLOCK_PARAMETERS_V3;
+
+#define PIXEL_CLOCK_PARAMETERS_LAST                    PIXEL_CLOCK_PARAMETERS_V2
+#define GET_PIXEL_CLOCK_PS_ALLOCATION          PIXEL_CLOCK_PARAMETERS_LAST
+
+/****************************************************************************/
+/*  Structures used by AdjustDisplayPllTable */
+/****************************************************************************/
+typedef struct _ADJUST_DISPLAY_PLL_PARAMETERS {
+       USHORT usPixelClock;
+       UCHAR ucTransmitterID;
+       UCHAR ucEncodeMode;
+       union {
+               UCHAR ucDVOConfig;      /* if DVO, need passing link rate and output 12bitlow or 24bit */
+               UCHAR ucConfig; /* if none DVO, not defined yet */
+       };
+       UCHAR ucReserved[3];
+} ADJUST_DISPLAY_PLL_PARAMETERS;
+
+#define ADJUST_DISPLAY_CONFIG_SS_ENABLE       0x10
+
+#define ADJUST_DISPLAY_PLL_PS_ALLOCATION                       ADJUST_DISPLAY_PLL_PARAMETERS
+
+/****************************************************************************/
+/*  Structures used by EnableYUVTable */
+/****************************************************************************/
+typedef struct _ENABLE_YUV_PARAMETERS {
+       UCHAR ucEnable;         /*  ATOM_ENABLE:Enable YUV or ATOM_DISABLE:Disable YUV (RGB) */
+       UCHAR ucCRTC;           /*  Which CRTC needs this YUV or RGB format */
+       UCHAR ucPadding[2];
+} ENABLE_YUV_PARAMETERS;
+#define ENABLE_YUV_PS_ALLOCATION ENABLE_YUV_PARAMETERS
+
+/****************************************************************************/
+/*  Structures used by GetMemoryClockTable */
+/****************************************************************************/
+typedef struct _GET_MEMORY_CLOCK_PARAMETERS {
+       ULONG ulReturnMemoryClock;      /*  current memory speed in 10KHz unit */
+} GET_MEMORY_CLOCK_PARAMETERS;
+#define GET_MEMORY_CLOCK_PS_ALLOCATION  GET_MEMORY_CLOCK_PARAMETERS
+
+/****************************************************************************/
+/*  Structures used by GetEngineClockTable */
+/****************************************************************************/
+typedef struct _GET_ENGINE_CLOCK_PARAMETERS {
+       ULONG ulReturnEngineClock;      /*  current engine speed in 10KHz unit */
+} GET_ENGINE_CLOCK_PARAMETERS;
+#define GET_ENGINE_CLOCK_PS_ALLOCATION  GET_ENGINE_CLOCK_PARAMETERS
+
+/****************************************************************************/
+/*  Following Structures and constant may be obsolete */
+/****************************************************************************/
+/* Maxium 8 bytes,the data read in will be placed in the parameter space. */
+/* Read operaion successeful when the paramter space is non-zero, otherwise read operation failed */
+typedef struct _READ_EDID_FROM_HW_I2C_DATA_PARAMETERS {
+       USHORT usPrescale;      /* Ratio between Engine clock and I2C clock */
+       USHORT usVRAMAddress;   /* Adress in Frame Buffer where to pace raw EDID */
+       USHORT usStatus;        /* When use output: lower byte EDID checksum, high byte hardware status */
+       /* WHen use input:  lower byte as 'byte to read':currently limited to 128byte or 1byte */
+       UCHAR ucSlaveAddr;      /* Read from which slave */
+       UCHAR ucLineNumber;     /* Read from which HW assisted line */
+} READ_EDID_FROM_HW_I2C_DATA_PARAMETERS;
+#define READ_EDID_FROM_HW_I2C_DATA_PS_ALLOCATION  READ_EDID_FROM_HW_I2C_DATA_PARAMETERS
+
+#define  ATOM_WRITE_I2C_FORMAT_PSOFFSET_PSDATABYTE                  0
+#define  ATOM_WRITE_I2C_FORMAT_PSOFFSET_PSTWODATABYTES              1
+#define  ATOM_WRITE_I2C_FORMAT_PSCOUNTER_PSOFFSET_IDDATABLOCK       2
+#define  ATOM_WRITE_I2C_FORMAT_PSCOUNTER_IDOFFSET_PLUS_IDDATABLOCK  3
+#define  ATOM_WRITE_I2C_FORMAT_IDCOUNTER_IDOFFSET_IDDATABLOCK       4
+
+typedef struct _WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS {
+       USHORT usPrescale;      /* Ratio between Engine clock and I2C clock */
+       USHORT usByteOffset;    /* Write to which byte */
+       /* Upper portion of usByteOffset is Format of data */
+       /* 1bytePS+offsetPS */
+       /* 2bytesPS+offsetPS */
+       /* blockID+offsetPS */
+       /* blockID+offsetID */
+       /* blockID+counterID+offsetID */
+       UCHAR ucData;           /* PS data1 */
+       UCHAR ucStatus;         /* Status byte 1=success, 2=failure, Also is used as PS data2 */
+       UCHAR ucSlaveAddr;      /* Write to which slave */
+       UCHAR ucLineNumber;     /* Write from which HW assisted line */
+} WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS;
+
+#define WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION  WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS
+
+typedef struct _SET_UP_HW_I2C_DATA_PARAMETERS {
+       USHORT usPrescale;      /* Ratio between Engine clock and I2C clock */
+       UCHAR ucSlaveAddr;      /* Write to which slave */
+       UCHAR ucLineNumber;     /* Write from which HW assisted line */
+} SET_UP_HW_I2C_DATA_PARAMETERS;
+
+/**************************************************************************/
+#define SPEED_FAN_CONTROL_PS_ALLOCATION   WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS
+
+/****************************************************************************/
+/*  Structures used by PowerConnectorDetectionTable */
+/****************************************************************************/
+typedef struct _POWER_CONNECTOR_DETECTION_PARAMETERS {
+       UCHAR ucPowerConnectorStatus;   /* Used for return value 0: detected, 1:not detected */
+       UCHAR ucPwrBehaviorId;
+       USHORT usPwrBudget;     /* how much power currently boot to in unit of watt */
+} POWER_CONNECTOR_DETECTION_PARAMETERS;
+
+typedef struct POWER_CONNECTOR_DETECTION_PS_ALLOCATION {
+       UCHAR ucPowerConnectorStatus;   /* Used for return value 0: detected, 1:not detected */
+       UCHAR ucReserved;
+       USHORT usPwrBudget;     /* how much power currently boot to in unit of watt */
+       WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved;
+} POWER_CONNECTOR_DETECTION_PS_ALLOCATION;
+
+/****************************LVDS SS Command Table Definitions**********************/
+
+/****************************************************************************/
+/*  Structures used by EnableSpreadSpectrumOnPPLLTable */
+/****************************************************************************/
+typedef struct _ENABLE_LVDS_SS_PARAMETERS {
+       USHORT usSpreadSpectrumPercentage;
+       UCHAR ucSpreadSpectrumType;     /* Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD */
+       UCHAR ucSpreadSpectrumStepSize_Delay;   /* bits3:2 SS_STEP_SIZE; bit 6:4 SS_DELAY */
+       UCHAR ucEnable;         /* ATOM_ENABLE or ATOM_DISABLE */
+       UCHAR ucPadding[3];
+} ENABLE_LVDS_SS_PARAMETERS;
+
+/* ucTableFormatRevision=1,ucTableContentRevision=2 */
+typedef struct _ENABLE_LVDS_SS_PARAMETERS_V2 {
+       USHORT usSpreadSpectrumPercentage;
+       UCHAR ucSpreadSpectrumType;     /* Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD */
+       UCHAR ucSpreadSpectrumStep;     /*  */
+       UCHAR ucEnable;         /* ATOM_ENABLE or ATOM_DISABLE */
+       UCHAR ucSpreadSpectrumDelay;
+       UCHAR ucSpreadSpectrumRange;
+       UCHAR ucPadding;
+} ENABLE_LVDS_SS_PARAMETERS_V2;
+
+/* This new structure is based on ENABLE_LVDS_SS_PARAMETERS but expands to SS on PPLL, so other devices can use SS. */
+typedef struct _ENABLE_SPREAD_SPECTRUM_ON_PPLL {
+       USHORT usSpreadSpectrumPercentage;
+       UCHAR ucSpreadSpectrumType;     /*  Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD */
+       UCHAR ucSpreadSpectrumStep;     /*  */
+       UCHAR ucEnable;         /*  ATOM_ENABLE or ATOM_DISABLE */
+       UCHAR ucSpreadSpectrumDelay;
+       UCHAR ucSpreadSpectrumRange;
+       UCHAR ucPpll;           /*  ATOM_PPLL1/ATOM_PPLL2 */
+} ENABLE_SPREAD_SPECTRUM_ON_PPLL;
+
+#define ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION  ENABLE_SPREAD_SPECTRUM_ON_PPLL
+
+/**************************************************************************/
+
+typedef struct _SET_PIXEL_CLOCK_PS_ALLOCATION {
+       PIXEL_CLOCK_PARAMETERS sPCLKInput;
+       ENABLE_SPREAD_SPECTRUM_ON_PPLL sReserved;       /* Caller doesn't need to init this portion */
+} SET_PIXEL_CLOCK_PS_ALLOCATION;
+
+#define ENABLE_VGA_RENDER_PS_ALLOCATION   SET_PIXEL_CLOCK_PS_ALLOCATION
+
+/****************************************************************************/
+/*  Structures used by ### */
+/****************************************************************************/
+typedef struct _MEMORY_TRAINING_PARAMETERS {
+       ULONG ulTargetMemoryClock;      /* In 10Khz unit */
+} MEMORY_TRAINING_PARAMETERS;
+#define MEMORY_TRAINING_PS_ALLOCATION MEMORY_TRAINING_PARAMETERS
+
+/****************************LVDS and other encoder command table definitions **********************/
+
+/****************************************************************************/
+/*  Structures used by LVDSEncoderControlTable   (Before DCE30) */
+/*                     LVTMAEncoderControlTable  (Before DCE30) */
+/*                     TMDSAEncoderControlTable  (Before DCE30) */
+/****************************************************************************/
+typedef struct _LVDS_ENCODER_CONTROL_PARAMETERS {
+       USHORT usPixelClock;    /*  in 10KHz; for bios convenient */
+       UCHAR ucMisc;           /*  bit0=0: Enable single link */
+       /*      =1: Enable dual link */
+       /*  Bit1=0: 666RGB */
+       /*      =1: 888RGB */
+       UCHAR ucAction;         /*  0: turn off encoder */
+       /*  1: setup and turn on encoder */
+} LVDS_ENCODER_CONTROL_PARAMETERS;
+
+#define LVDS_ENCODER_CONTROL_PS_ALLOCATION  LVDS_ENCODER_CONTROL_PARAMETERS
+
+#define TMDS1_ENCODER_CONTROL_PARAMETERS    LVDS_ENCODER_CONTROL_PARAMETERS
+#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION TMDS1_ENCODER_CONTROL_PARAMETERS
+
+#define TMDS2_ENCODER_CONTROL_PARAMETERS    TMDS1_ENCODER_CONTROL_PARAMETERS
+#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION TMDS2_ENCODER_CONTROL_PARAMETERS
+
+/* ucTableFormatRevision=1,ucTableContentRevision=2 */
+typedef struct _LVDS_ENCODER_CONTROL_PARAMETERS_V2 {
+       USHORT usPixelClock;    /*  in 10KHz; for bios convenient */
+       UCHAR ucMisc;           /*  see PANEL_ENCODER_MISC_xx defintions below */
+       UCHAR ucAction;         /*  0: turn off encoder */
+       /*  1: setup and turn on encoder */
+       UCHAR ucTruncate;       /*  bit0=0: Disable truncate */
+       /*      =1: Enable truncate */
+       /*  bit4=0: 666RGB */
+       /*      =1: 888RGB */
+       UCHAR ucSpatial;        /*  bit0=0: Disable spatial dithering */
+       /*      =1: Enable spatial dithering */
+       /*  bit4=0: 666RGB */
+       /*      =1: 888RGB */
+       UCHAR ucTemporal;       /*  bit0=0: Disable temporal dithering */
+       /*      =1: Enable temporal dithering */
+       /*  bit4=0: 666RGB */
+       /*      =1: 888RGB */
+       /*  bit5=0: Gray level 2 */
+       /*      =1: Gray level 4 */
+       UCHAR ucFRC;            /*  bit4=0: 25FRC_SEL pattern E */
+       /*      =1: 25FRC_SEL pattern F */
+       /*  bit6:5=0: 50FRC_SEL pattern A */
+       /*        =1: 50FRC_SEL pattern B */
+       /*        =2: 50FRC_SEL pattern C */
+       /*        =3: 50FRC_SEL pattern D */
+       /*  bit7=0: 75FRC_SEL pattern E */
+       /*      =1: 75FRC_SEL pattern F */
+} LVDS_ENCODER_CONTROL_PARAMETERS_V2;
+
+#define LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2  LVDS_ENCODER_CONTROL_PARAMETERS_V2
+
+#define TMDS1_ENCODER_CONTROL_PARAMETERS_V2    LVDS_ENCODER_CONTROL_PARAMETERS_V2
+#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION_V2 TMDS1_ENCODER_CONTROL_PARAMETERS_V2
+
+#define TMDS2_ENCODER_CONTROL_PARAMETERS_V2    TMDS1_ENCODER_CONTROL_PARAMETERS_V2
+#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION_V2 TMDS2_ENCODER_CONTROL_PARAMETERS_V2
+
+#define LVDS_ENCODER_CONTROL_PARAMETERS_V3     LVDS_ENCODER_CONTROL_PARAMETERS_V2
+#define LVDS_ENCODER_CONTROL_PS_ALLOCATION_V3  LVDS_ENCODER_CONTROL_PARAMETERS_V3
+
+#define TMDS1_ENCODER_CONTROL_PARAMETERS_V3    LVDS_ENCODER_CONTROL_PARAMETERS_V3
+#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION_V3 TMDS1_ENCODER_CONTROL_PARAMETERS_V3
+
+#define TMDS2_ENCODER_CONTROL_PARAMETERS_V3    LVDS_ENCODER_CONTROL_PARAMETERS_V3
+#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION_V3 TMDS2_ENCODER_CONTROL_PARAMETERS_V3
+
+/****************************************************************************/
+/*  Structures used by ### */
+/****************************************************************************/
+typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS {
+       UCHAR ucEnable;         /*  Enable or Disable External TMDS encoder */
+       UCHAR ucMisc;           /*  Bit0=0:Enable Single link;=1:Enable Dual link;Bit1 {=0:666RGB, =1:888RGB} */
+       UCHAR ucPadding[2];
+} ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS;
+
+typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION {
+       ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS sXTmdsEncoder;
+       WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved;     /* Caller doesn't need to init this portion */
+} ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION;
+
+#define ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS_V2  LVDS_ENCODER_CONTROL_PARAMETERS_V2
+
+typedef struct _ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION_V2 {
+       ENABLE_EXTERNAL_TMDS_ENCODER_PARAMETERS_V2 sXTmdsEncoder;
+       WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved;     /* Caller doesn't need to init this portion */
+} ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION_V2;
+
+typedef struct _EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION {
+       DIG_ENCODER_CONTROL_PARAMETERS sDigEncoder;
+       WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved;
+} EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION;
+
+/****************************************************************************/
+/*  Structures used by DVOEncoderControlTable */
+/****************************************************************************/
+/* ucTableFormatRevision=1,ucTableContentRevision=3 */
+
+/* ucDVOConfig: */
+#define DVO_ENCODER_CONFIG_RATE_SEL                                                    0x01
+#define DVO_ENCODER_CONFIG_DDR_SPEED                                           0x00
+#define DVO_ENCODER_CONFIG_SDR_SPEED                                           0x01
+#define DVO_ENCODER_CONFIG_OUTPUT_SEL                                          0x0c
+#define DVO_ENCODER_CONFIG_LOW12BIT                                                    0x00
+#define DVO_ENCODER_CONFIG_UPPER12BIT                                          0x04
+#define DVO_ENCODER_CONFIG_24BIT                                                               0x08
+
+typedef struct _DVO_ENCODER_CONTROL_PARAMETERS_V3 {
+       USHORT usPixelClock;
+       UCHAR ucDVOConfig;
+       UCHAR ucAction;         /* ATOM_ENABLE/ATOM_DISABLE/ATOM_HPD_INIT */
+       UCHAR ucReseved[4];
+} DVO_ENCODER_CONTROL_PARAMETERS_V3;
+#define DVO_ENCODER_CONTROL_PS_ALLOCATION_V3   DVO_ENCODER_CONTROL_PARAMETERS_V3
+
+/* ucTableFormatRevision=1 */
+/* ucTableContentRevision=3 structure is not changed but usMisc add bit 1 as another input for */
+/*  bit1=0: non-coherent mode */
+/*      =1: coherent mode */
+
+/* ========================================================================================== */
+/* Only change is here next time when changing encoder parameter definitions again! */
+#define LVDS_ENCODER_CONTROL_PARAMETERS_LAST     LVDS_ENCODER_CONTROL_PARAMETERS_V3
+#define LVDS_ENCODER_CONTROL_PS_ALLOCATION_LAST  LVDS_ENCODER_CONTROL_PARAMETERS_LAST
+
+#define TMDS1_ENCODER_CONTROL_PARAMETERS_LAST    LVDS_ENCODER_CONTROL_PARAMETERS_V3
+#define TMDS1_ENCODER_CONTROL_PS_ALLOCATION_LAST TMDS1_ENCODER_CONTROL_PARAMETERS_LAST
+
+#define TMDS2_ENCODER_CONTROL_PARAMETERS_LAST    LVDS_ENCODER_CONTROL_PARAMETERS_V3
+#define TMDS2_ENCODER_CONTROL_PS_ALLOCATION_LAST TMDS2_ENCODER_CONTROL_PARAMETERS_LAST
+
+#define DVO_ENCODER_CONTROL_PARAMETERS_LAST      DVO_ENCODER_CONTROL_PARAMETERS
+#define DVO_ENCODER_CONTROL_PS_ALLOCATION_LAST   DVO_ENCODER_CONTROL_PS_ALLOCATION
+
+/* ========================================================================================== */
+#define PANEL_ENCODER_MISC_DUAL                0x01
+#define PANEL_ENCODER_MISC_COHERENT            0x02
+#define        PANEL_ENCODER_MISC_TMDS_LINKB                                    0x04
+#define        PANEL_ENCODER_MISC_HDMI_TYPE                                     0x08
+
+#define PANEL_ENCODER_ACTION_DISABLE           ATOM_DISABLE
+#define PANEL_ENCODER_ACTION_ENABLE            ATOM_ENABLE
+#define PANEL_ENCODER_ACTION_COHERENTSEQ       (ATOM_ENABLE+1)
+
+#define PANEL_ENCODER_TRUNCATE_EN              0x01
+#define PANEL_ENCODER_TRUNCATE_DEPTH           0x10
+#define PANEL_ENCODER_SPATIAL_DITHER_EN        0x01
+#define PANEL_ENCODER_SPATIAL_DITHER_DEPTH     0x10
+#define PANEL_ENCODER_TEMPORAL_DITHER_EN       0x01
+#define PANEL_ENCODER_TEMPORAL_DITHER_DEPTH    0x10
+#define PANEL_ENCODER_TEMPORAL_LEVEL_4         0x20
+#define PANEL_ENCODER_25FRC_MASK               0x10
+#define PANEL_ENCODER_25FRC_E                  0x00
+#define PANEL_ENCODER_25FRC_F                  0x10
+#define PANEL_ENCODER_50FRC_MASK               0x60
+#define PANEL_ENCODER_50FRC_A                  0x00
+#define PANEL_ENCODER_50FRC_B                  0x20
+#define PANEL_ENCODER_50FRC_C                  0x40
+#define PANEL_ENCODER_50FRC_D                  0x60
+#define PANEL_ENCODER_75FRC_MASK               0x80
+#define PANEL_ENCODER_75FRC_E                  0x00
+#define PANEL_ENCODER_75FRC_F                  0x80
+
+/****************************************************************************/
+/*  Structures used by SetVoltageTable */
+/****************************************************************************/
+#define SET_VOLTAGE_TYPE_ASIC_VDDC             1
+#define SET_VOLTAGE_TYPE_ASIC_MVDDC            2
+#define SET_VOLTAGE_TYPE_ASIC_MVDDQ            3
+#define SET_VOLTAGE_TYPE_ASIC_VDDCI            4
+#define SET_VOLTAGE_INIT_MODE                  5
+#define SET_VOLTAGE_GET_MAX_VOLTAGE            6       /* Gets the Max. voltage for the soldered Asic */
+
+#define SET_ASIC_VOLTAGE_MODE_ALL_SOURCE       0x1
+#define SET_ASIC_VOLTAGE_MODE_SOURCE_A         0x2
+#define SET_ASIC_VOLTAGE_MODE_SOURCE_B         0x4
+
+#define        SET_ASIC_VOLTAGE_MODE_SET_VOLTAGE      0x0
+#define        SET_ASIC_VOLTAGE_MODE_GET_GPIOVAL      0x1
+#define        SET_ASIC_VOLTAGE_MODE_GET_GPIOMASK     0x2
+
+typedef struct _SET_VOLTAGE_PARAMETERS {
+       UCHAR ucVoltageType;    /*  To tell which voltage to set up, VDDC/MVDDC/MVDDQ */
+       UCHAR ucVoltageMode;    /*  To set all, to set source A or source B or ... */
+       UCHAR ucVoltageIndex;   /*  An index to tell which voltage level */
+       UCHAR ucReserved;
+} SET_VOLTAGE_PARAMETERS;
+
+typedef struct _SET_VOLTAGE_PARAMETERS_V2 {
+       UCHAR ucVoltageType;    /*  To tell which voltage to set up, VDDC/MVDDC/MVDDQ */
+       UCHAR ucVoltageMode;    /*  Not used, maybe use for state machine for differen power mode */
+       USHORT usVoltageLevel;  /*  real voltage level */
+} SET_VOLTAGE_PARAMETERS_V2;
+
+typedef struct _SET_VOLTAGE_PS_ALLOCATION {
+       SET_VOLTAGE_PARAMETERS sASICSetVoltage;
+       WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved;
+} SET_VOLTAGE_PS_ALLOCATION;
+
+/****************************************************************************/
+/*  Structures used by TVEncoderControlTable */
+/****************************************************************************/
+typedef struct _TV_ENCODER_CONTROL_PARAMETERS {
+       USHORT usPixelClock;    /*  in 10KHz; for bios convenient */
+       UCHAR ucTvStandard;     /*  See definition "ATOM_TV_NTSC ..." */
+       UCHAR ucAction;         /*  0: turn off encoder */
+       /*  1: setup and turn on encoder */
+} TV_ENCODER_CONTROL_PARAMETERS;
+
+typedef struct _TV_ENCODER_CONTROL_PS_ALLOCATION {
+       TV_ENCODER_CONTROL_PARAMETERS sTVEncoder;
+       WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved;     /*  Don't set this one */
+} TV_ENCODER_CONTROL_PS_ALLOCATION;
+
+/* ==============================Data Table Portion==================================== */
+
+#ifdef UEFI_BUILD
+#define        UTEMP   USHORT
+#define        USHORT  void*
+#endif
+
+/****************************************************************************/
+/*  Structure used in Data.mtb */
+/****************************************************************************/
+typedef struct _ATOM_MASTER_LIST_OF_DATA_TABLES {
+       USHORT UtilityPipeLine; /*  Offest for the utility to get parser info,Don't change this position! */
+       USHORT MultimediaCapabilityInfo;        /*  Only used by MM Lib,latest version 1.1, not configuable from Bios, need to include the table to build Bios */
+       USHORT MultimediaConfigInfo;    /*  Only used by MM Lib,latest version 2.1, not configuable from Bios, need to include the table to build Bios */
+       USHORT StandardVESA_Timing;     /*  Only used by Bios */
+       USHORT FirmwareInfo;    /*  Shared by various SW components,latest version 1.4 */
+       USHORT DAC_Info;        /*  Will be obsolete from R600 */
+       USHORT LVDS_Info;       /*  Shared by various SW components,latest version 1.1 */
+       USHORT TMDS_Info;       /*  Will be obsolete from R600 */
+       USHORT AnalogTV_Info;   /*  Shared by various SW components,latest version 1.1 */
+       USHORT SupportedDevicesInfo;    /*  Will be obsolete from R600 */
+       USHORT GPIO_I2C_Info;   /*  Shared by various SW components,latest version 1.2 will be used from R600 */
+       USHORT VRAM_UsageByFirmware;    /*  Shared by various SW components,latest version 1.3 will be used from R600 */
+       USHORT GPIO_Pin_LUT;    /*  Shared by various SW components,latest version 1.1 */
+       USHORT VESA_ToInternalModeLUT;  /*  Only used by Bios */
+       USHORT ComponentVideoInfo;      /*  Shared by various SW components,latest version 2.1 will be used from R600 */
+       USHORT PowerPlayInfo;   /*  Shared by various SW components,latest version 2.1,new design from R600 */
+       USHORT CompassionateData;       /*  Will be obsolete from R600 */
+       USHORT SaveRestoreInfo; /*  Only used by Bios */
+       USHORT PPLL_SS_Info;    /*  Shared by various SW components,latest version 1.2, used to call SS_Info, change to new name because of int ASIC SS info */
+       USHORT OemInfo;         /*  Defined and used by external SW, should be obsolete soon */
+       USHORT XTMDS_Info;      /*  Will be obsolete from R600 */
+       USHORT MclkSS_Info;     /*  Shared by various SW components,latest version 1.1, only enabled when ext SS chip is used */
+       USHORT Object_Header;   /*  Shared by various SW components,latest version 1.1 */
+       USHORT IndirectIOAccess;        /*  Only used by Bios,this table position can't change at all!! */
+       USHORT MC_InitParameter;        /*  Only used by command table */
+       USHORT ASIC_VDDC_Info;  /*  Will be obsolete from R600 */
+       USHORT ASIC_InternalSS_Info;    /*  New tabel name from R600, used to be called "ASIC_MVDDC_Info" */
+       USHORT TV_VideoMode;    /*  Only used by command table */
+       USHORT VRAM_Info;       /*  Only used by command table, latest version 1.3 */
+       USHORT MemoryTrainingInfo;      /*  Used for VBIOS and Diag utility for memory training purpose since R600. the new table rev start from 2.1 */
+       USHORT IntegratedSystemInfo;    /*  Shared by various SW components */
+       USHORT ASIC_ProfilingInfo;      /*  New table name from R600, used to be called "ASIC_VDDCI_Info" for pre-R600 */
+       USHORT VoltageObjectInfo;       /*  Shared by various SW components, latest version 1.1 */
+       USHORT PowerSourceInfo; /*  Shared by various SW components, latest versoin 1.1 */
+} ATOM_MASTER_LIST_OF_DATA_TABLES;
+
+#ifdef UEFI_BUILD
+#define        USHORT  UTEMP
+#endif
+
+typedef struct _ATOM_MASTER_DATA_TABLE {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       ATOM_MASTER_LIST_OF_DATA_TABLES ListOfDataTables;
+} ATOM_MASTER_DATA_TABLE;
+
+/****************************************************************************/
+/*  Structure used in MultimediaCapabilityInfoTable */
+/****************************************************************************/
+typedef struct _ATOM_MULTIMEDIA_CAPABILITY_INFO {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       ULONG ulSignature;      /*  HW info table signature string "$ATI" */
+       UCHAR ucI2C_Type;       /*  I2C type (normal GP_IO, ImpactTV GP_IO, Dedicated I2C pin, etc) */
+       UCHAR ucTV_OutInfo;     /*  Type of TV out supported (3:0) and video out crystal frequency (6:4) and TV data port (7) */
+       UCHAR ucVideoPortInfo;  /*  Provides the video port capabilities */
+       UCHAR ucHostPortInfo;   /*  Provides host port configuration information */
+} ATOM_MULTIMEDIA_CAPABILITY_INFO;
+
+/****************************************************************************/
+/*  Structure used in MultimediaConfigInfoTable */
+/****************************************************************************/
+typedef struct _ATOM_MULTIMEDIA_CONFIG_INFO {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       ULONG ulSignature;      /*  MM info table signature sting "$MMT" */
+       UCHAR ucTunerInfo;      /*  Type of tuner installed on the adapter (4:0) and video input for tuner (7:5) */
+       UCHAR ucAudioChipInfo;  /*  List the audio chip type (3:0) product type (4) and OEM revision (7:5) */
+       UCHAR ucProductID;      /*  Defines as OEM ID or ATI board ID dependent on product type setting */
+       UCHAR ucMiscInfo1;      /*  Tuner voltage (1:0) HW teletext support (3:2) FM audio decoder (5:4) reserved (6) audio scrambling (7) */
+       UCHAR ucMiscInfo2;      /*  I2S input config (0) I2S output config (1) I2S Audio Chip (4:2) SPDIF Output Config (5) reserved (7:6) */
+       UCHAR ucMiscInfo3;      /*  Video Decoder Type (3:0) Video In Standard/Crystal (7:4) */
+       UCHAR ucMiscInfo4;      /*  Video Decoder Host Config (2:0) reserved (7:3) */
+       UCHAR ucVideoInput0Info;        /*  Video Input 0 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) */
+       UCHAR ucVideoInput1Info;        /*  Video Input 1 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) */
+       UCHAR ucVideoInput2Info;        /*  Video Input 2 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) */
+       UCHAR ucVideoInput3Info;        /*  Video Input 3 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) */
+       UCHAR ucVideoInput4Info;        /*  Video Input 4 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) */
+} ATOM_MULTIMEDIA_CONFIG_INFO;
+
+/****************************************************************************/
+/*  Structures used in FirmwareInfoTable */
+/****************************************************************************/
+
+/*  usBIOSCapability Defintion: */
+/*  Bit 0 = 0: Bios image is not Posted, =1:Bios image is Posted; */
+/*  Bit 1 = 0: Dual CRTC is not supported, =1: Dual CRTC is supported; */
+/*  Bit 2 = 0: Extended Desktop is not supported, =1: Extended Desktop is supported; */
+/*  Others: Reserved */
+#define ATOM_BIOS_INFO_ATOM_FIRMWARE_POSTED         0x0001
+#define ATOM_BIOS_INFO_DUAL_CRTC_SUPPORT            0x0002
+#define ATOM_BIOS_INFO_EXTENDED_DESKTOP_SUPPORT     0x0004
+#define ATOM_BIOS_INFO_MEMORY_CLOCK_SS_SUPPORT      0x0008
+#define ATOM_BIOS_INFO_ENGINE_CLOCK_SS_SUPPORT      0x0010
+#define ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU         0x0020
+#define ATOM_BIOS_INFO_WMI_SUPPORT                  0x0040
+#define ATOM_BIOS_INFO_PPMODE_ASSIGNGED_BY_SYSTEM   0x0080
+#define ATOM_BIOS_INFO_HYPERMEMORY_SUPPORT          0x0100
+#define ATOM_BIOS_INFO_HYPERMEMORY_SIZE_MASK        0x1E00
+#define ATOM_BIOS_INFO_VPOST_WITHOUT_FIRST_MODE_SET 0x2000
+#define ATOM_BIOS_INFO_BIOS_SCRATCH6_SCL2_REDEFINE  0x4000
+
+#ifndef _H2INC
+
+/* Please don't add or expand this bitfield structure below, this one will retire soon.! */
+typedef struct _ATOM_FIRMWARE_CAPABILITY {
+#if ATOM_BIG_ENDIAN
+       USHORT Reserved:3;
+       USHORT HyperMemory_Size:4;
+       USHORT HyperMemory_Support:1;
+       USHORT PPMode_Assigned:1;
+       USHORT WMI_SUPPORT:1;
+       USHORT GPUControlsBL:1;
+       USHORT EngineClockSS_Support:1;
+       USHORT MemoryClockSS_Support:1;
+       USHORT ExtendedDesktopSupport:1;
+       USHORT DualCRTC_Support:1;
+       USHORT FirmwarePosted:1;
+#else
+       USHORT FirmwarePosted:1;
+       USHORT DualCRTC_Support:1;
+       USHORT ExtendedDesktopSupport:1;
+       USHORT MemoryClockSS_Support:1;
+       USHORT EngineClockSS_Support:1;
+       USHORT GPUControlsBL:1;
+       USHORT WMI_SUPPORT:1;
+       USHORT PPMode_Assigned:1;
+       USHORT HyperMemory_Support:1;
+       USHORT HyperMemory_Size:4;
+       USHORT Reserved:3;
+#endif
+} ATOM_FIRMWARE_CAPABILITY;
+
+typedef union _ATOM_FIRMWARE_CAPABILITY_ACCESS {
+       ATOM_FIRMWARE_CAPABILITY sbfAccess;
+       USHORT susAccess;
+} ATOM_FIRMWARE_CAPABILITY_ACCESS;
+
+#else
+
+typedef union _ATOM_FIRMWARE_CAPABILITY_ACCESS {
+       USHORT susAccess;
+} ATOM_FIRMWARE_CAPABILITY_ACCESS;
+
+#endif
+
+typedef struct _ATOM_FIRMWARE_INFO {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       ULONG ulFirmwareRevision;
+       ULONG ulDefaultEngineClock;     /* In 10Khz unit */
+       ULONG ulDefaultMemoryClock;     /* In 10Khz unit */
+       ULONG ulDriverTargetEngineClock;        /* In 10Khz unit */
+       ULONG ulDriverTargetMemoryClock;        /* In 10Khz unit */
+       ULONG ulMaxEngineClockPLL_Output;       /* In 10Khz unit */
+       ULONG ulMaxMemoryClockPLL_Output;       /* In 10Khz unit */
+       ULONG ulMaxPixelClockPLL_Output;        /* In 10Khz unit */
+       ULONG ulASICMaxEngineClock;     /* In 10Khz unit */
+       ULONG ulASICMaxMemoryClock;     /* In 10Khz unit */
+       UCHAR ucASICMaxTemperature;
+       UCHAR ucPadding[3];     /* Don't use them */
+       ULONG aulReservedForBIOS[3];    /* Don't use them */
+       USHORT usMinEngineClockPLL_Input;       /* In 10Khz unit */
+       USHORT usMaxEngineClockPLL_Input;       /* In 10Khz unit */
+       USHORT usMinEngineClockPLL_Output;      /* In 10Khz unit */
+       USHORT usMinMemoryClockPLL_Input;       /* In 10Khz unit */
+       USHORT usMaxMemoryClockPLL_Input;       /* In 10Khz unit */
+       USHORT usMinMemoryClockPLL_Output;      /* In 10Khz unit */
+       USHORT usMaxPixelClock; /* In 10Khz unit, Max.  Pclk */
+       USHORT usMinPixelClockPLL_Input;        /* In 10Khz unit */
+       USHORT usMaxPixelClockPLL_Input;        /* In 10Khz unit */
+       USHORT usMinPixelClockPLL_Output;       /* In 10Khz unit, the definitions above can't change!!! */
+       ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability;
+       USHORT usReferenceClock;        /* In 10Khz unit */
+       USHORT usPM_RTS_Location;       /* RTS PM4 starting location in ROM in 1Kb unit */
+       UCHAR ucPM_RTS_StreamSize;      /* RTS PM4 packets in Kb unit */
+       UCHAR ucDesign_ID;      /* Indicate what is the board design */
+       UCHAR ucMemoryModule_ID;        /* Indicate what is the board design */
+} ATOM_FIRMWARE_INFO;
+
+typedef struct _ATOM_FIRMWARE_INFO_V1_2 {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       ULONG ulFirmwareRevision;
+       ULONG ulDefaultEngineClock;     /* In 10Khz unit */
+       ULONG ulDefaultMemoryClock;     /* In 10Khz unit */
+       ULONG ulDriverTargetEngineClock;        /* In 10Khz unit */
+       ULONG ulDriverTargetMemoryClock;        /* In 10Khz unit */
+       ULONG ulMaxEngineClockPLL_Output;       /* In 10Khz unit */
+       ULONG ulMaxMemoryClockPLL_Output;       /* In 10Khz unit */
+       ULONG ulMaxPixelClockPLL_Output;        /* In 10Khz unit */
+       ULONG ulASICMaxEngineClock;     /* In 10Khz unit */
+       ULONG ulASICMaxMemoryClock;     /* In 10Khz unit */
+       UCHAR ucASICMaxTemperature;
+       UCHAR ucMinAllowedBL_Level;
+       UCHAR ucPadding[2];     /* Don't use them */
+       ULONG aulReservedForBIOS[2];    /* Don't use them */
+       ULONG ulMinPixelClockPLL_Output;        /* In 10Khz unit */
+       USHORT usMinEngineClockPLL_Input;       /* In 10Khz unit */
+       USHORT usMaxEngineClockPLL_Input;       /* In 10Khz unit */
+       USHORT usMinEngineClockPLL_Output;      /* In 10Khz unit */
+       USHORT usMinMemoryClockPLL_Input;       /* In 10Khz unit */
+       USHORT usMaxMemoryClockPLL_Input;       /* In 10Khz unit */
+       USHORT usMinMemoryClockPLL_Output;      /* In 10Khz unit */
+       USHORT usMaxPixelClock; /* In 10Khz unit, Max.  Pclk */
+       USHORT usMinPixelClockPLL_Input;        /* In 10Khz unit */
+       USHORT usMaxPixelClockPLL_Input;        /* In 10Khz unit */
+       USHORT usMinPixelClockPLL_Output;       /* In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output */
+       ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability;
+       USHORT usReferenceClock;        /* In 10Khz unit */
+       USHORT usPM_RTS_Location;       /* RTS PM4 starting location in ROM in 1Kb unit */
+       UCHAR ucPM_RTS_StreamSize;      /* RTS PM4 packets in Kb unit */
+       UCHAR ucDesign_ID;      /* Indicate what is the board design */
+       UCHAR ucMemoryModule_ID;        /* Indicate what is the board design */
+} ATOM_FIRMWARE_INFO_V1_2;
+
+typedef struct _ATOM_FIRMWARE_INFO_V1_3 {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       ULONG ulFirmwareRevision;
+       ULONG ulDefaultEngineClock;     /* In 10Khz unit */
+       ULONG ulDefaultMemoryClock;     /* In 10Khz unit */
+       ULONG ulDriverTargetEngineClock;        /* In 10Khz unit */
+       ULONG ulDriverTargetMemoryClock;        /* In 10Khz unit */
+       ULONG ulMaxEngineClockPLL_Output;       /* In 10Khz unit */
+       ULONG ulMaxMemoryClockPLL_Output;       /* In 10Khz unit */
+       ULONG ulMaxPixelClockPLL_Output;        /* In 10Khz unit */
+       ULONG ulASICMaxEngineClock;     /* In 10Khz unit */
+       ULONG ulASICMaxMemoryClock;     /* In 10Khz unit */
+       UCHAR ucASICMaxTemperature;
+       UCHAR ucMinAllowedBL_Level;
+       UCHAR ucPadding[2];     /* Don't use them */
+       ULONG aulReservedForBIOS;       /* Don't use them */
+       ULONG ul3DAccelerationEngineClock;      /* In 10Khz unit */
+       ULONG ulMinPixelClockPLL_Output;        /* In 10Khz unit */
+       USHORT usMinEngineClockPLL_Input;       /* In 10Khz unit */
+       USHORT usMaxEngineClockPLL_Input;       /* In 10Khz unit */
+       USHORT usMinEngineClockPLL_Output;      /* In 10Khz unit */
+       USHORT usMinMemoryClockPLL_Input;       /* In 10Khz unit */
+       USHORT usMaxMemoryClockPLL_Input;       /* In 10Khz unit */
+       USHORT usMinMemoryClockPLL_Output;      /* In 10Khz unit */
+       USHORT usMaxPixelClock; /* In 10Khz unit, Max.  Pclk */
+       USHORT usMinPixelClockPLL_Input;        /* In 10Khz unit */
+       USHORT usMaxPixelClockPLL_Input;        /* In 10Khz unit */
+       USHORT usMinPixelClockPLL_Output;       /* In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output */
+       ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability;
+       USHORT usReferenceClock;        /* In 10Khz unit */
+       USHORT usPM_RTS_Location;       /* RTS PM4 starting location in ROM in 1Kb unit */
+       UCHAR ucPM_RTS_StreamSize;      /* RTS PM4 packets in Kb unit */
+       UCHAR ucDesign_ID;      /* Indicate what is the board design */
+       UCHAR ucMemoryModule_ID;        /* Indicate what is the board design */
+} ATOM_FIRMWARE_INFO_V1_3;
+
+typedef struct _ATOM_FIRMWARE_INFO_V1_4 {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       ULONG ulFirmwareRevision;
+       ULONG ulDefaultEngineClock;     /* In 10Khz unit */
+       ULONG ulDefaultMemoryClock;     /* In 10Khz unit */
+       ULONG ulDriverTargetEngineClock;        /* In 10Khz unit */
+       ULONG ulDriverTargetMemoryClock;        /* In 10Khz unit */
+       ULONG ulMaxEngineClockPLL_Output;       /* In 10Khz unit */
+       ULONG ulMaxMemoryClockPLL_Output;       /* In 10Khz unit */
+       ULONG ulMaxPixelClockPLL_Output;        /* In 10Khz unit */
+       ULONG ulASICMaxEngineClock;     /* In 10Khz unit */
+       ULONG ulASICMaxMemoryClock;     /* In 10Khz unit */
+       UCHAR ucASICMaxTemperature;
+       UCHAR ucMinAllowedBL_Level;
+       USHORT usBootUpVDDCVoltage;     /* In MV unit */
+       USHORT usLcdMinPixelClockPLL_Output;    /*  In MHz unit */
+       USHORT usLcdMaxPixelClockPLL_Output;    /*  In MHz unit */
+       ULONG ul3DAccelerationEngineClock;      /* In 10Khz unit */
+       ULONG ulMinPixelClockPLL_Output;        /* In 10Khz unit */
+       USHORT usMinEngineClockPLL_Input;       /* In 10Khz unit */
+       USHORT usMaxEngineClockPLL_Input;       /* In 10Khz unit */
+       USHORT usMinEngineClockPLL_Output;      /* In 10Khz unit */
+       USHORT usMinMemoryClockPLL_Input;       /* In 10Khz unit */
+       USHORT usMaxMemoryClockPLL_Input;       /* In 10Khz unit */
+       USHORT usMinMemoryClockPLL_Output;      /* In 10Khz unit */
+       USHORT usMaxPixelClock; /* In 10Khz unit, Max.  Pclk */
+       USHORT usMinPixelClockPLL_Input;        /* In 10Khz unit */
+       USHORT usMaxPixelClockPLL_Input;        /* In 10Khz unit */
+       USHORT usMinPixelClockPLL_Output;       /* In 10Khz unit - lower 16bit of ulMinPixelClockPLL_Output */
+       ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability;
+       USHORT usReferenceClock;        /* In 10Khz unit */
+       USHORT usPM_RTS_Location;       /* RTS PM4 starting location in ROM in 1Kb unit */
+       UCHAR ucPM_RTS_StreamSize;      /* RTS PM4 packets in Kb unit */
+       UCHAR ucDesign_ID;      /* Indicate what is the board design */
+       UCHAR ucMemoryModule_ID;        /* Indicate what is the board design */
+} ATOM_FIRMWARE_INFO_V1_4;
+
+#define ATOM_FIRMWARE_INFO_LAST  ATOM_FIRMWARE_INFO_V1_4
+
+/****************************************************************************/
+/*  Structures used in IntegratedSystemInfoTable */
+/****************************************************************************/
+#define IGP_CAP_FLAG_DYNAMIC_CLOCK_EN      0x2
+#define IGP_CAP_FLAG_AC_CARD               0x4
+#define IGP_CAP_FLAG_SDVO_CARD             0x8
+#define IGP_CAP_FLAG_POSTDIV_BY_2_MODE     0x10
+
+typedef struct _ATOM_INTEGRATED_SYSTEM_INFO {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       ULONG ulBootUpEngineClock;      /* in 10kHz unit */
+       ULONG ulBootUpMemoryClock;      /* in 10kHz unit */
+       ULONG ulMaxSystemMemoryClock;   /* in 10kHz unit */
+       ULONG ulMinSystemMemoryClock;   /* in 10kHz unit */
+       UCHAR ucNumberOfCyclesInPeriodHi;
+       UCHAR ucLCDTimingSel;   /* =0:not valid.!=0 sel this timing descriptor from LCD EDID. */
+       USHORT usReserved1;
+       USHORT usInterNBVoltageLow;     /* An intermidiate PMW value to set the voltage */
+       USHORT usInterNBVoltageHigh;    /* Another intermidiate PMW value to set the voltage */
+       ULONG ulReserved[2];
+
+       USHORT usFSBClock;      /* In MHz unit */
+       USHORT usCapabilityFlag;        /* Bit0=1 indicates the fake HDMI support,Bit1=0/1 for Dynamic clocking dis/enable */
+       /* Bit[3:2]== 0:No PCIE card, 1:AC card, 2:SDVO card */
+       /* Bit[4]==1: P/2 mode, ==0: P/1 mode */
+       USHORT usPCIENBCfgReg7; /* bit[7:0]=MUX_Sel, bit[9:8]=MUX_SEL_LEVEL2, bit[10]=Lane_Reversal */
+       USHORT usK8MemoryClock; /* in MHz unit */
+       USHORT usK8SyncStartDelay;      /* in 0.01 us unit */
+       USHORT usK8DataReturnTime;      /* in 0.01 us unit */
+       UCHAR ucMaxNBVoltage;
+       UCHAR ucMinNBVoltage;
+       UCHAR ucMemoryType;     /* [7:4]=1:DDR1;=2:DDR2;=3:DDR3.[3:0] is reserved */
+       UCHAR ucNumberOfCyclesInPeriod; /* CG.FVTHROT_PWM_CTRL_REG0.NumberOfCyclesInPeriod */
+       UCHAR ucStartingPWM_HighTime;   /* CG.FVTHROT_PWM_CTRL_REG0.StartingPWM_HighTime */
+       UCHAR ucHTLinkWidth;    /* 16 bit vs. 8 bit */
+       UCHAR ucMaxNBVoltageHigh;
+       UCHAR ucMinNBVoltageHigh;
+} ATOM_INTEGRATED_SYSTEM_INFO;
+
+/* Explanation on entries in ATOM_INTEGRATED_SYSTEM_INFO
+ulBootUpMemoryClock:    For Intel IGP,it's the UMA system memory clock
+                        For AMD IGP,it's 0 if no SidePort memory installed or it's the boot-up SidePort memory clock
+ulMaxSystemMemoryClock: For Intel IGP,it's the Max freq from memory SPD if memory runs in ASYNC mode or otherwise (SYNC mode) it's 0
+                        For AMD IGP,for now this can be 0
+ulMinSystemMemoryClock: For Intel IGP,it's 133MHz if memory runs in ASYNC mode or otherwise (SYNC mode) it's 0
+                        For AMD IGP,for now this can be 0
+
+usFSBClock:             For Intel IGP,it's FSB Freq
+                        For AMD IGP,it's HT Link Speed
+
+usK8MemoryClock:        For AMD IGP only. For RevF CPU, set it to 200
+usK8SyncStartDelay:     For AMD IGP only. Memory access latency in K8, required for watermark calculation
+usK8DataReturnTime:     For AMD IGP only. Memory access latency in K8, required for watermark calculation
+
+VC:Voltage Control
+ucMaxNBVoltage:         Voltage regulator dependent PWM value. Low 8 bits of the value for the max voltage.Set this one to 0xFF if VC without PWM. Set this to 0x0 if no VC at all.
+ucMinNBVoltage:         Voltage regulator dependent PWM value. Low 8 bits of the value for the min voltage.Set this one to 0x00 if VC without PWM or no VC at all.
+
+ucNumberOfCyclesInPeriod:   Indicate how many cycles when PWM duty is 100%. low 8 bits of the value.
+ucNumberOfCyclesInPeriodHi: Indicate how many cycles when PWM duty is 100%. high 8 bits of the value.If the PWM has an inverter,set bit [7]==1,otherwise set it 0
+
+ucMaxNBVoltageHigh:     Voltage regulator dependent PWM value. High 8 bits of  the value for the max voltage.Set this one to 0xFF if VC without PWM. Set this to 0x0 if no VC at all.
+ucMinNBVoltageHigh:     Voltage regulator dependent PWM value. High 8 bits of the value for the min voltage.Set this one to 0x00 if VC without PWM or no VC at all.
+
+usInterNBVoltageLow:    Voltage regulator dependent PWM value. The value makes the the voltage >=Min NB voltage but <=InterNBVoltageHigh. Set this to 0x0000 if VC without PWM or no VC at all.
+usInterNBVoltageHigh:   Voltage regulator dependent PWM value. The value makes the the voltage >=InterNBVoltageLow but <=Max NB voltage.Set this to 0x0000 if VC without PWM or no VC at all.
+*/
+
+/*
+The following IGP table is introduced from RS780, which is supposed to be put by SBIOS in FB before IGP VBIOS starts VPOST;
+Then VBIOS will copy the whole structure to its image so all GPU SW components can access this data structure to get whatever they need.
+The enough reservation should allow us to never change table revisions. Whenever needed, a GPU SW component can use reserved portion for new data entries.
+
+SW components can access the IGP system infor structure in the same way as before
+*/
+
+typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       ULONG ulBootUpEngineClock;      /* in 10kHz unit */
+       ULONG ulReserved1[2];   /* must be 0x0 for the reserved */
+       ULONG ulBootUpUMAClock; /* in 10kHz unit */
+       ULONG ulBootUpSidePortClock;    /* in 10kHz unit */
+       ULONG ulMinSidePortClock;       /* in 10kHz unit */
+       ULONG ulReserved2[6];   /* must be 0x0 for the reserved */
+       ULONG ulSystemConfig;   /* see explanation below */
+       ULONG ulBootUpReqDisplayVector;
+       ULONG ulOtherDisplayMisc;
+       ULONG ulDDISlot1Config;
+       ULONG ulDDISlot2Config;
+       UCHAR ucMemoryType;     /* [3:0]=1:DDR1;=2:DDR2;=3:DDR3.[7:4] is reserved */
+       UCHAR ucUMAChannelNumber;
+       UCHAR ucDockingPinBit;
+       UCHAR ucDockingPinPolarity;
+       ULONG ulDockingPinCFGInfo;
+       ULONG ulCPUCapInfo;
+       USHORT usNumberOfCyclesInPeriod;
+       USHORT usMaxNBVoltage;
+       USHORT usMinNBVoltage;
+       USHORT usBootUpNBVoltage;
+       ULONG ulHTLinkFreq;     /* in 10Khz */
+       USHORT usMinHTLinkWidth;
+       USHORT usMaxHTLinkWidth;
+       USHORT usUMASyncStartDelay;
+       USHORT usUMADataReturnTime;
+       USHORT usLinkStatusZeroTime;
+       USHORT usReserved;
+       ULONG ulHighVoltageHTLinkFreq;  /*  in 10Khz */
+       ULONG ulLowVoltageHTLinkFreq;   /*  in 10Khz */
+       USHORT usMaxUpStreamHTLinkWidth;
+       USHORT usMaxDownStreamHTLinkWidth;
+       USHORT usMinUpStreamHTLinkWidth;
+       USHORT usMinDownStreamHTLinkWidth;
+       ULONG ulReserved3[97];  /* must be 0x0 */
+} ATOM_INTEGRATED_SYSTEM_INFO_V2;
+
+/*
+ulBootUpEngineClock:   Boot-up Engine Clock in 10Khz;
+ulBootUpUMAClock:      Boot-up UMA Clock in 10Khz; it must be 0x0 when UMA is not present
+ulBootUpSidePortClock: Boot-up SidePort Clock in 10Khz; it must be 0x0 when SidePort Memory is not present,this could be equal to or less than maximum supported Sideport memory clock
+
+ulSystemConfig:
+Bit[0]=1: PowerExpress mode =0 Non-PowerExpress mode;
+Bit[1]=1: system boots up at AMD overdrived state or user customized  mode. In this case, driver will just stick to this boot-up mode. No other PowerPlay state
+      =0: system boots up at driver control state. Power state depends on PowerPlay table.
+Bit[2]=1: PWM method is used on NB voltage control. =0: GPIO method is used.
+Bit[3]=1: Only one power state(Performance) will be supported.
+      =0: Multiple power states supported from PowerPlay table.
+Bit[4]=1: CLMC is supported and enabled on current system.
+      =0: CLMC is not supported or enabled on current system. SBIOS need to support HT link/freq change through ATIF interface.
+Bit[5]=1: Enable CDLW for all driver control power states. Max HT width is from SBIOS, while Min HT width is determined by display requirement.
+      =0: CDLW is disabled. If CLMC is enabled case, Min HT width will be set equal to Max HT width. If CLMC disabled case, Max HT width will be applied.
+Bit[6]=1: High Voltage requested for all power states. In this case, voltage will be forced at 1.1v and powerplay table voltage drop/throttling request will be ignored.
+      =0: Voltage settings is determined by powerplay table.
+Bit[7]=1: Enable CLMC as hybrid Mode. CDLD and CILR will be disabled in this case and we're using legacy C1E. This is workaround for CPU(Griffin) performance issue.
+      =0: Enable CLMC as regular mode, CDLD and CILR will be enabled.
+
+ulBootUpReqDisplayVector: This dword is a bit vector indicates what display devices are requested during boot-up. Refer to ATOM_DEVICE_xxx_SUPPORT for the bit vector definitions.
+
+ulOtherDisplayMisc: [15:8]- Bootup LCD Expansion selection; 0-center, 1-full panel size expansion;
+                                     [7:0] - BootupTV standard selection; This is a bit vector to indicate what TV standards are supported by the system. Refer to ucTVSuppportedStd definition;
+
+ulDDISlot1Config: Describes the PCIE lane configuration on this DDI PCIE slot (ADD2 card) or connector (Mobile design).
+      [3:0]  - Bit vector to indicate PCIE lane config of the DDI slot/connector on chassis (bit 0=1 lane 3:0; bit 1=1 lane 7:4; bit 2=1 lane 11:8; bit 3=1 lane 15:12)
+                       [7:4]  - Bit vector to indicate PCIE lane config of the same DDI slot/connector on docking station (bit 0=1 lane 3:0; bit 1=1 lane 7:4; bit 2=1 lane 11:8; bit 3=1 lane 15:12)
+                       [15:8] - Lane configuration attribute;
+      [23:16]- Connector type, possible value:
+               CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D
+               CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D
+               CONNECTOR_OBJECT_ID_HDMI_TYPE_A
+               CONNECTOR_OBJECT_ID_DISPLAYPORT
+                       [31:24]- Reserved
+
+ulDDISlot2Config: Same as Slot1.
+ucMemoryType: SidePort memory type, set it to 0x0 when Sideport memory is not installed. Driver needs this info to change sideport memory clock. Not for display in CCC.
+For IGP, Hypermemory is the only memory type showed in CCC.
+
+ucUMAChannelNumber:  how many channels for the UMA;
+
+ulDockingPinCFGInfo: [15:0]-Bus/Device/Function # to CFG to read this Docking Pin; [31:16]-reg offset in CFG to read this pin
+ucDockingPinBit:     which bit in this register to read the pin status;
+ucDockingPinPolarity:Polarity of the pin when docked;
+
+ulCPUCapInfo:        [7:0]=1:Griffin;[7:0]=2:Greyhound;[7:0]=3:K8, other bits reserved for now and must be 0x0
+
+usNumberOfCyclesInPeriod:Indicate how many cycles when PWM duty is 100%.
+usMaxNBVoltage:Max. voltage control value in either PWM or GPIO mode.
+usMinNBVoltage:Min. voltage control value in either PWM or GPIO mode.
+                    GPIO mode: both usMaxNBVoltage & usMinNBVoltage have a valid value ulSystemConfig.SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE=0
+                    PWM mode: both usMaxNBVoltage & usMinNBVoltage have a valid value ulSystemConfig.SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE=1
+                    GPU SW don't control mode: usMaxNBVoltage & usMinNBVoltage=0 and no care about ulSystemConfig.SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE
+usBootUpNBVoltage:Boot-up voltage regulator dependent PWM value.
+
+ulHTLinkFreq:       Bootup HT link Frequency in 10Khz.
+usMinHTLinkWidth:   Bootup minimum HT link width. If CDLW disabled, this is equal to usMaxHTLinkWidth.
+                    If CDLW enabled, both upstream and downstream width should be the same during bootup.
+usMaxHTLinkWidth:   Bootup maximum HT link width. If CDLW disabled, this is equal to usMinHTLinkWidth.
+                    If CDLW enabled, both upstream and downstream width should be the same during bootup.
+
+usUMASyncStartDelay: Memory access latency, required for watermark calculation
+usUMADataReturnTime: Memory access latency, required for watermark calculation
+usLinkStatusZeroTime:Memory access latency required for watermark calculation, set this to 0x0 for K8 CPU, set a proper value in 0.01 the unit of us
+for Griffin or Greyhound. SBIOS needs to convert to actual time by:
+                     if T0Ttime [5:4]=00b, then usLinkStatusZeroTime=T0Ttime [3:0]*0.1us (0.0 to 1.5us)
+                     if T0Ttime [5:4]=01b, then usLinkStatusZeroTime=T0Ttime [3:0]*0.5us (0.0 to 7.5us)
+                     if T0Ttime [5:4]=10b, then usLinkStatusZeroTime=T0Ttime [3:0]*2.0us (0.0 to 30us)
+                     if T0Ttime [5:4]=11b, and T0Ttime [3:0]=0x0 to 0xa, then usLinkStatusZeroTime=T0Ttime [3:0]*20us (0.0 to 200us)
+
+ulHighVoltageHTLinkFreq:     HT link frequency for power state with low voltage. If boot up runs in HT1, this must be 0.
+                             This must be less than or equal to ulHTLinkFreq(bootup frequency).
+ulLowVoltageHTLinkFreq:      HT link frequency for power state with low voltage or voltage scaling 1.0v~1.1v. If boot up runs in HT1, this must be 0.
+                             This must be less than or equal to ulHighVoltageHTLinkFreq.
+
+usMaxUpStreamHTLinkWidth:    Asymmetric link width support in the future, to replace usMaxHTLinkWidth. Not used for now.
+usMaxDownStreamHTLinkWidth:  same as above.
+usMinUpStreamHTLinkWidth:    Asymmetric link width support in the future, to replace usMinHTLinkWidth. Not used for now.
+usMinDownStreamHTLinkWidth:  same as above.
+*/
+
+#define SYSTEM_CONFIG_POWEREXPRESS_ENABLE                 0x00000001
+#define SYSTEM_CONFIG_RUN_AT_OVERDRIVE_ENGINE             0x00000002
+#define SYSTEM_CONFIG_USE_PWM_ON_VOLTAGE                  0x00000004
+#define SYSTEM_CONFIG_PERFORMANCE_POWERSTATE_ONLY         0x00000008
+#define SYSTEM_CONFIG_CLMC_ENABLED                        0x00000010
+#define SYSTEM_CONFIG_CDLW_ENABLED                        0x00000020
+#define SYSTEM_CONFIG_HIGH_VOLTAGE_REQUESTED              0x00000040
+#define SYSTEM_CONFIG_CLMC_HYBRID_MODE_ENABLED            0x00000080
+
+#define IGP_DDI_SLOT_LANE_CONFIG_MASK                     0x000000FF
+
+#define b0IGP_DDI_SLOT_LANE_MAP_MASK                      0x0F
+#define b0IGP_DDI_SLOT_DOCKING_LANE_MAP_MASK              0xF0
+#define b0IGP_DDI_SLOT_CONFIG_LANE_0_3                    0x01
+#define b0IGP_DDI_SLOT_CONFIG_LANE_4_7                    0x02
+#define b0IGP_DDI_SLOT_CONFIG_LANE_8_11                   0x04
+#define b0IGP_DDI_SLOT_CONFIG_LANE_12_15                  0x08
+
+#define IGP_DDI_SLOT_ATTRIBUTE_MASK                       0x0000FF00
+#define IGP_DDI_SLOT_CONFIG_REVERSED                      0x00000100
+#define b1IGP_DDI_SLOT_CONFIG_REVERSED                    0x01
+
+#define IGP_DDI_SLOT_CONNECTOR_TYPE_MASK                  0x00FF0000
+
+#define ATOM_CRT_INT_ENCODER1_INDEX                       0x00000000
+#define ATOM_LCD_INT_ENCODER1_INDEX                       0x00000001
+#define ATOM_TV_INT_ENCODER1_INDEX                        0x00000002
+#define ATOM_DFP_INT_ENCODER1_INDEX                       0x00000003
+#define ATOM_CRT_INT_ENCODER2_INDEX                       0x00000004
+#define ATOM_LCD_EXT_ENCODER1_INDEX                       0x00000005
+#define ATOM_TV_EXT_ENCODER1_INDEX                        0x00000006
+#define ATOM_DFP_EXT_ENCODER1_INDEX                       0x00000007
+#define ATOM_CV_INT_ENCODER1_INDEX                        0x00000008
+#define ATOM_DFP_INT_ENCODER2_INDEX                       0x00000009
+#define ATOM_CRT_EXT_ENCODER1_INDEX                       0x0000000A
+#define ATOM_CV_EXT_ENCODER1_INDEX                        0x0000000B
+#define ATOM_DFP_INT_ENCODER3_INDEX                       0x0000000C
+#define ATOM_DFP_INT_ENCODER4_INDEX                       0x0000000D
+
+/*  define ASIC internal encoder id ( bit vector ) */
+#define ASIC_INT_DAC1_ENCODER_ID                                                                                       0x00
+#define ASIC_INT_TV_ENCODER_ID                                                                                                         0x02
+#define ASIC_INT_DIG1_ENCODER_ID                                                                                                       0x03
+#define ASIC_INT_DAC2_ENCODER_ID                                                                                                       0x04
+#define ASIC_EXT_TV_ENCODER_ID                                                                                                         0x06
+#define ASIC_INT_DVO_ENCODER_ID                                                                                                                0x07
+#define ASIC_INT_DIG2_ENCODER_ID                                                                                                       0x09
+#define ASIC_EXT_DIG_ENCODER_ID                                                                                                                0x05
+
+/* define Encoder attribute */
+#define ATOM_ANALOG_ENCODER                                                                                                                            0
+#define ATOM_DIGITAL_ENCODER                                                                                                                   1
+
+#define ATOM_DEVICE_CRT1_INDEX                            0x00000000
+#define ATOM_DEVICE_LCD1_INDEX                            0x00000001
+#define ATOM_DEVICE_TV1_INDEX                             0x00000002
+#define ATOM_DEVICE_DFP1_INDEX                            0x00000003
+#define ATOM_DEVICE_CRT2_INDEX                            0x00000004
+#define ATOM_DEVICE_LCD2_INDEX                            0x00000005
+#define ATOM_DEVICE_TV2_INDEX                             0x00000006
+#define ATOM_DEVICE_DFP2_INDEX                            0x00000007
+#define ATOM_DEVICE_CV_INDEX                              0x00000008
+#define ATOM_DEVICE_DFP3_INDEX                                                                                                         0x00000009
+#define ATOM_DEVICE_DFP4_INDEX                                                                                                         0x0000000A
+#define ATOM_DEVICE_DFP5_INDEX                                                                                                         0x0000000B
+#define ATOM_DEVICE_RESERVEDC_INDEX                       0x0000000C
+#define ATOM_DEVICE_RESERVEDD_INDEX                       0x0000000D
+#define ATOM_DEVICE_RESERVEDE_INDEX                       0x0000000E
+#define ATOM_DEVICE_RESERVEDF_INDEX                       0x0000000F
+#define ATOM_MAX_SUPPORTED_DEVICE_INFO                    (ATOM_DEVICE_DFP3_INDEX+1)
+#define ATOM_MAX_SUPPORTED_DEVICE_INFO_2                  ATOM_MAX_SUPPORTED_DEVICE_INFO
+#define ATOM_MAX_SUPPORTED_DEVICE_INFO_3                  (ATOM_DEVICE_DFP5_INDEX + 1)
+
+#define ATOM_MAX_SUPPORTED_DEVICE                         (ATOM_DEVICE_RESERVEDF_INDEX+1)
+
+#define ATOM_DEVICE_CRT1_SUPPORT                          (0x1L << ATOM_DEVICE_CRT1_INDEX)
+#define ATOM_DEVICE_LCD1_SUPPORT                          (0x1L << ATOM_DEVICE_LCD1_INDEX)
+#define ATOM_DEVICE_TV1_SUPPORT                           (0x1L << ATOM_DEVICE_TV1_INDEX)
+#define ATOM_DEVICE_DFP1_SUPPORT                          (0x1L << ATOM_DEVICE_DFP1_INDEX)
+#define ATOM_DEVICE_CRT2_SUPPORT                          (0x1L << ATOM_DEVICE_CRT2_INDEX)
+#define ATOM_DEVICE_LCD2_SUPPORT                          (0x1L << ATOM_DEVICE_LCD2_INDEX)
+#define ATOM_DEVICE_TV2_SUPPORT                           (0x1L << ATOM_DEVICE_TV2_INDEX)
+#define ATOM_DEVICE_DFP2_SUPPORT                          (0x1L << ATOM_DEVICE_DFP2_INDEX)
+#define ATOM_DEVICE_CV_SUPPORT                            (0x1L << ATOM_DEVICE_CV_INDEX)
+#define ATOM_DEVICE_DFP3_SUPPORT                                                                                                       (0x1L << ATOM_DEVICE_DFP3_INDEX)
+#define ATOM_DEVICE_DFP4_SUPPORT                                                                                                       (0x1L << ATOM_DEVICE_DFP4_INDEX )
+#define ATOM_DEVICE_DFP5_SUPPORT                                                                                                       (0x1L << ATOM_DEVICE_DFP5_INDEX)
+
+#define ATOM_DEVICE_CRT_SUPPORT \
+       (ATOM_DEVICE_CRT1_SUPPORT | ATOM_DEVICE_CRT2_SUPPORT)
+#define ATOM_DEVICE_DFP_SUPPORT \
+       (ATOM_DEVICE_DFP1_SUPPORT | ATOM_DEVICE_DFP2_SUPPORT | \
+        ATOM_DEVICE_DFP3_SUPPORT | ATOM_DEVICE_DFP4_SUPPORT | \
+        ATOM_DEVICE_DFP5_SUPPORT)
+#define ATOM_DEVICE_TV_SUPPORT \
+       (ATOM_DEVICE_TV1_SUPPORT  | ATOM_DEVICE_TV2_SUPPORT)
+#define ATOM_DEVICE_LCD_SUPPORT \
+       (ATOM_DEVICE_LCD1_SUPPORT | ATOM_DEVICE_LCD2_SUPPORT)
+
+#define ATOM_DEVICE_CONNECTOR_TYPE_MASK                   0x000000F0
+#define ATOM_DEVICE_CONNECTOR_TYPE_SHIFT                  0x00000004
+#define ATOM_DEVICE_CONNECTOR_VGA                         0x00000001
+#define ATOM_DEVICE_CONNECTOR_DVI_I                       0x00000002
+#define ATOM_DEVICE_CONNECTOR_DVI_D                       0x00000003
+#define ATOM_DEVICE_CONNECTOR_DVI_A                       0x00000004
+#define ATOM_DEVICE_CONNECTOR_SVIDEO                      0x00000005
+#define ATOM_DEVICE_CONNECTOR_COMPOSITE                   0x00000006
+#define ATOM_DEVICE_CONNECTOR_LVDS                        0x00000007
+#define ATOM_DEVICE_CONNECTOR_DIGI_LINK                   0x00000008
+#define ATOM_DEVICE_CONNECTOR_SCART                       0x00000009
+#define ATOM_DEVICE_CONNECTOR_HDMI_TYPE_A                 0x0000000A
+#define ATOM_DEVICE_CONNECTOR_HDMI_TYPE_B                 0x0000000B
+#define ATOM_DEVICE_CONNECTOR_CASE_1                      0x0000000E
+#define ATOM_DEVICE_CONNECTOR_DISPLAYPORT                 0x0000000F
+
+#define ATOM_DEVICE_DAC_INFO_MASK                         0x0000000F
+#define ATOM_DEVICE_DAC_INFO_SHIFT                        0x00000000
+#define ATOM_DEVICE_DAC_INFO_NODAC                        0x00000000
+#define ATOM_DEVICE_DAC_INFO_DACA                         0x00000001
+#define ATOM_DEVICE_DAC_INFO_DACB                         0x00000002
+#define ATOM_DEVICE_DAC_INFO_EXDAC                        0x00000003
+
+#define ATOM_DEVICE_I2C_ID_NOI2C                          0x00000000
+
+#define ATOM_DEVICE_I2C_LINEMUX_MASK                      0x0000000F
+#define ATOM_DEVICE_I2C_LINEMUX_SHIFT                     0x00000000
+
+#define ATOM_DEVICE_I2C_ID_MASK                           0x00000070
+#define ATOM_DEVICE_I2C_ID_SHIFT                          0x00000004
+#define ATOM_DEVICE_I2C_ID_IS_FOR_NON_MM_USE              0x00000001
+#define ATOM_DEVICE_I2C_ID_IS_FOR_MM_USE                  0x00000002
+#define ATOM_DEVICE_I2C_ID_IS_FOR_SDVO_USE                0x00000003   /* For IGP RS600 */
+#define ATOM_DEVICE_I2C_ID_IS_FOR_DAC_SCL                 0x00000004   /* For IGP RS690 */
+
+#define ATOM_DEVICE_I2C_HARDWARE_CAP_MASK                 0x00000080
+#define ATOM_DEVICE_I2C_HARDWARE_CAP_SHIFT                0x00000007
+#define        ATOM_DEVICE_USES_SOFTWARE_ASSISTED_I2C            0x00000000
+#define        ATOM_DEVICE_USES_HARDWARE_ASSISTED_I2C            0x00000001
+
+/*   usDeviceSupport: */
+/*   Bits0       = 0 - no CRT1 support= 1- CRT1 is supported */
+/*   Bit 1       = 0 - no LCD1 support= 1- LCD1 is supported */
+/*   Bit 2       = 0 - no TV1  support= 1- TV1  is supported */
+/*   Bit 3       = 0 - no DFP1 support= 1- DFP1 is supported */
+/*   Bit 4       = 0 - no CRT2 support= 1- CRT2 is supported */
+/*   Bit 5       = 0 - no LCD2 support= 1- LCD2 is supported */
+/*   Bit 6       = 0 - no TV2  support= 1- TV2  is supported */
+/*   Bit 7       = 0 - no DFP2 support= 1- DFP2 is supported */
+/*   Bit 8       = 0 - no CV   support= 1- CV   is supported */
+/*   Bit 9       = 0 - no DFP3 support= 1- DFP3 is supported */
+/*   Byte1 (Supported Device Info) */
+/*   Bit 0       = = 0 - no CV support= 1- CV is supported */
+/*  */
+/*  */
+
+/*               ucI2C_ConfigID */
+/*     [7:0] - I2C LINE Associate ID */
+/*           = 0   - no I2C */
+/*     [7]               -       HW_Cap        = 1,  [6:0]=HW assisted I2C ID(HW line selection) */
+/*                           =   0,  [6:0]=SW assisted I2C ID */
+/*     [6-4]     - HW_ENGINE_ID  =       1,  HW engine for NON multimedia use */
+/*                           =   2,      HW engine for Multimedia use */
+/*                           =   3-7     Reserved for future I2C engines */
+/*               [3-0] - I2C_LINE_MUX  = A Mux number when it's HW assisted I2C or GPIO ID when it's SW I2C */
+
+typedef struct _ATOM_I2C_ID_CONFIG {
+#if ATOM_BIG_ENDIAN
+       UCHAR bfHW_Capable:1;
+       UCHAR bfHW_EngineID:3;
+       UCHAR bfI2C_LineMux:4;
+#else
+       UCHAR bfI2C_LineMux:4;
+       UCHAR bfHW_EngineID:3;
+       UCHAR bfHW_Capable:1;
+#endif
+} ATOM_I2C_ID_CONFIG;
+
+typedef union _ATOM_I2C_ID_CONFIG_ACCESS {
+       ATOM_I2C_ID_CONFIG sbfAccess;
+       UCHAR ucAccess;
+} ATOM_I2C_ID_CONFIG_ACCESS;
+
+/****************************************************************************/
+/*  Structure used in GPIO_I2C_InfoTable */
+/****************************************************************************/
+typedef struct _ATOM_GPIO_I2C_ASSIGMENT {
+       USHORT usClkMaskRegisterIndex;
+       USHORT usClkEnRegisterIndex;
+       USHORT usClkY_RegisterIndex;
+       USHORT usClkA_RegisterIndex;
+       USHORT usDataMaskRegisterIndex;
+       USHORT usDataEnRegisterIndex;
+       USHORT usDataY_RegisterIndex;
+       USHORT usDataA_RegisterIndex;
+       ATOM_I2C_ID_CONFIG_ACCESS sucI2cId;
+       UCHAR ucClkMaskShift;
+       UCHAR ucClkEnShift;
+       UCHAR ucClkY_Shift;
+       UCHAR ucClkA_Shift;
+       UCHAR ucDataMaskShift;
+       UCHAR ucDataEnShift;
+       UCHAR ucDataY_Shift;
+       UCHAR ucDataA_Shift;
+       UCHAR ucReserved1;
+       UCHAR ucReserved2;
+} ATOM_GPIO_I2C_ASSIGMENT;
+
+typedef struct _ATOM_GPIO_I2C_INFO {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       ATOM_GPIO_I2C_ASSIGMENT asGPIO_Info[ATOM_MAX_SUPPORTED_DEVICE];
+} ATOM_GPIO_I2C_INFO;
+
+/****************************************************************************/
+/*  Common Structure used in other structures */
+/****************************************************************************/
+
+#ifndef _H2INC
+
+/* Please don't add or expand this bitfield structure below, this one will retire soon.! */
+typedef struct _ATOM_MODE_MISC_INFO {
+#if ATOM_BIG_ENDIAN
+       USHORT Reserved:6;
+       USHORT RGB888:1;
+       USHORT DoubleClock:1;
+       USHORT Interlace:1;
+       USHORT CompositeSync:1;
+       USHORT V_ReplicationBy2:1;
+       USHORT H_ReplicationBy2:1;
+       USHORT VerticalCutOff:1;
+       USHORT VSyncPolarity:1; /* 0=Active High, 1=Active Low */
+       USHORT HSyncPolarity:1; /* 0=Active High, 1=Active Low */
+       USHORT HorizontalCutOff:1;
+#else
+       USHORT HorizontalCutOff:1;
+       USHORT HSyncPolarity:1; /* 0=Active High, 1=Active Low */
+       USHORT VSyncPolarity:1; /* 0=Active High, 1=Active Low */
+       USHORT VerticalCutOff:1;
+       USHORT H_ReplicationBy2:1;
+       USHORT V_ReplicationBy2:1;
+       USHORT CompositeSync:1;
+       USHORT Interlace:1;
+       USHORT DoubleClock:1;
+       USHORT RGB888:1;
+       USHORT Reserved:6;
+#endif
+} ATOM_MODE_MISC_INFO;
+
+typedef union _ATOM_MODE_MISC_INFO_ACCESS {
+       ATOM_MODE_MISC_INFO sbfAccess;
+       USHORT usAccess;
+} ATOM_MODE_MISC_INFO_ACCESS;
+
+#else
+
+typedef union _ATOM_MODE_MISC_INFO_ACCESS {
+       USHORT usAccess;
+} ATOM_MODE_MISC_INFO_ACCESS;
+
+#endif
+
+/*  usModeMiscInfo- */
+#define ATOM_H_CUTOFF           0x01
+#define ATOM_HSYNC_POLARITY     0x02   /* 0=Active High, 1=Active Low */
+#define ATOM_VSYNC_POLARITY     0x04   /* 0=Active High, 1=Active Low */
+#define ATOM_V_CUTOFF           0x08
+#define ATOM_H_REPLICATIONBY2   0x10
+#define ATOM_V_REPLICATIONBY2   0x20
+#define ATOM_COMPOSITESYNC      0x40
+#define ATOM_INTERLACE          0x80
+#define ATOM_DOUBLE_CLOCK_MODE  0x100
+#define ATOM_RGB888_MODE        0x200
+
+/* usRefreshRate- */
+#define ATOM_REFRESH_43         43
+#define ATOM_REFRESH_47         47
+#define ATOM_REFRESH_56         56
+#define ATOM_REFRESH_60         60
+#define ATOM_REFRESH_65         65
+#define ATOM_REFRESH_70         70
+#define ATOM_REFRESH_72         72
+#define ATOM_REFRESH_75         75
+#define ATOM_REFRESH_85         85
+
+/*  ATOM_MODE_TIMING data are exactly the same as VESA timing data. */
+/*  Translation from EDID to ATOM_MODE_TIMING, use the following formula. */
+/*  */
+/*       VESA_HTOTAL                     =       VESA_ACTIVE + 2* VESA_BORDER + VESA_BLANK */
+/*                                               =       EDID_HA + EDID_HBL */
+/*       VESA_HDISP                      =       VESA_ACTIVE     =       EDID_HA */
+/*       VESA_HSYNC_START        =       VESA_ACTIVE + VESA_BORDER + VESA_FRONT_PORCH */
+/*                                               =       EDID_HA + EDID_HSO */
+/*       VESA_HSYNC_WIDTH        =       VESA_HSYNC_TIME =       EDID_HSPW */
+/*       VESA_BORDER                     =       EDID_BORDER */
+
+/****************************************************************************/
+/*  Structure used in SetCRTC_UsingDTDTimingTable */
+/****************************************************************************/
+typedef struct _SET_CRTC_USING_DTD_TIMING_PARAMETERS {
+       USHORT usH_Size;
+       USHORT usH_Blanking_Time;
+       USHORT usV_Size;
+       USHORT usV_Blanking_Time;
+       USHORT usH_SyncOffset;
+       USHORT usH_SyncWidth;
+       USHORT usV_SyncOffset;
+       USHORT usV_SyncWidth;
+       ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo;
+       UCHAR ucH_Border;       /*  From DFP EDID */
+       UCHAR ucV_Border;
+       UCHAR ucCRTC;           /*  ATOM_CRTC1 or ATOM_CRTC2 */
+       UCHAR ucPadding[3];
+} SET_CRTC_USING_DTD_TIMING_PARAMETERS;
+
+/****************************************************************************/
+/*  Structure used in SetCRTC_TimingTable */
+/****************************************************************************/
+typedef struct _SET_CRTC_TIMING_PARAMETERS {
+       USHORT usH_Total;       /*  horizontal total */
+       USHORT usH_Disp;        /*  horizontal display */
+       USHORT usH_SyncStart;   /*  horozontal Sync start */
+       USHORT usH_SyncWidth;   /*  horizontal Sync width */
+       USHORT usV_Total;       /*  vertical total */
+       USHORT usV_Disp;        /*  vertical display */
+       USHORT usV_SyncStart;   /*  vertical Sync start */
+       USHORT usV_SyncWidth;   /*  vertical Sync width */
+       ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo;
+       UCHAR ucCRTC;           /*  ATOM_CRTC1 or ATOM_CRTC2 */
+       UCHAR ucOverscanRight;  /*  right */
+       UCHAR ucOverscanLeft;   /*  left */
+       UCHAR ucOverscanBottom; /*  bottom */
+       UCHAR ucOverscanTop;    /*  top */
+       UCHAR ucReserved;
+} SET_CRTC_TIMING_PARAMETERS;
+#define SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION SET_CRTC_TIMING_PARAMETERS
+
+/****************************************************************************/
+/*  Structure used in StandardVESA_TimingTable */
+/*                    AnalogTV_InfoTable */
+/*                    ComponentVideoInfoTable */
+/****************************************************************************/
+typedef struct _ATOM_MODE_TIMING {
+       USHORT usCRTC_H_Total;
+       USHORT usCRTC_H_Disp;
+       USHORT usCRTC_H_SyncStart;
+       USHORT usCRTC_H_SyncWidth;
+       USHORT usCRTC_V_Total;
+       USHORT usCRTC_V_Disp;
+       USHORT usCRTC_V_SyncStart;
+       USHORT usCRTC_V_SyncWidth;
+       USHORT usPixelClock;    /* in 10Khz unit */
+       ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo;
+       USHORT usCRTC_OverscanRight;
+       USHORT usCRTC_OverscanLeft;
+       USHORT usCRTC_OverscanBottom;
+       USHORT usCRTC_OverscanTop;
+       USHORT usReserve;
+       UCHAR ucInternalModeNumber;
+       UCHAR ucRefreshRate;
+} ATOM_MODE_TIMING;
+
+typedef struct _ATOM_DTD_FORMAT {
+       USHORT usPixClk;
+       USHORT usHActive;
+       USHORT usHBlanking_Time;
+       USHORT usVActive;
+       USHORT usVBlanking_Time;
+       USHORT usHSyncOffset;
+       USHORT usHSyncWidth;
+       USHORT usVSyncOffset;
+       USHORT usVSyncWidth;
+       USHORT usImageHSize;
+       USHORT usImageVSize;
+       UCHAR ucHBorder;
+       UCHAR ucVBorder;
+       ATOM_MODE_MISC_INFO_ACCESS susModeMiscInfo;
+       UCHAR ucInternalModeNumber;
+       UCHAR ucRefreshRate;
+} ATOM_DTD_FORMAT;
+
+/****************************************************************************/
+/*  Structure used in LVDS_InfoTable */
+/*   * Need a document to describe this table */
+/****************************************************************************/
+#define SUPPORTED_LCD_REFRESHRATE_30Hz          0x0004
+#define SUPPORTED_LCD_REFRESHRATE_40Hz          0x0008
+#define SUPPORTED_LCD_REFRESHRATE_50Hz          0x0010
+#define SUPPORTED_LCD_REFRESHRATE_60Hz          0x0020
+
+/* Once DAL sees this CAP is set, it will read EDID from LCD on its own instead of using sLCDTiming in ATOM_LVDS_INFO_V12. */
+/* Other entries in ATOM_LVDS_INFO_V12 are still valid/useful to DAL */
+#define        LCDPANEL_CAP_READ_EDID                                                                  0x1
+
+/* ucTableFormatRevision=1 */
+/* ucTableContentRevision=1 */
+typedef struct _ATOM_LVDS_INFO {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       ATOM_DTD_FORMAT sLCDTiming;
+       USHORT usModePatchTableOffset;
+       USHORT usSupportedRefreshRate;  /* Refer to panel info table in ATOMBIOS extension Spec. */
+       USHORT usOffDelayInMs;
+       UCHAR ucPowerSequenceDigOntoDEin10Ms;
+       UCHAR ucPowerSequenceDEtoBLOnin10Ms;
+       UCHAR ucLVDS_Misc;      /*  Bit0:{=0:single, =1:dual},Bit1 {=0:666RGB, =1:888RGB},Bit2:3:{Grey level} */
+       /*  Bit4:{=0:LDI format for RGB888, =1 FPDI format for RGB888} */
+       /*  Bit5:{=0:Spatial Dithering disabled;1 Spatial Dithering enabled} */
+       /*  Bit6:{=0:Temporal Dithering disabled;1 Temporal Dithering enabled} */
+       UCHAR ucPanelDefaultRefreshRate;
+       UCHAR ucPanelIdentification;
+       UCHAR ucSS_Id;
+} ATOM_LVDS_INFO;
+
+/* ucTableFormatRevision=1 */
+/* ucTableContentRevision=2 */
+typedef struct _ATOM_LVDS_INFO_V12 {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       ATOM_DTD_FORMAT sLCDTiming;
+       USHORT usExtInfoTableOffset;
+       USHORT usSupportedRefreshRate;  /* Refer to panel info table in ATOMBIOS extension Spec. */
+       USHORT usOffDelayInMs;
+       UCHAR ucPowerSequenceDigOntoDEin10Ms;
+       UCHAR ucPowerSequenceDEtoBLOnin10Ms;
+       UCHAR ucLVDS_Misc;      /*  Bit0:{=0:single, =1:dual},Bit1 {=0:666RGB, =1:888RGB},Bit2:3:{Grey level} */
+       /*  Bit4:{=0:LDI format for RGB888, =1 FPDI format for RGB888} */
+       /*  Bit5:{=0:Spatial Dithering disabled;1 Spatial Dithering enabled} */
+       /*  Bit6:{=0:Temporal Dithering disabled;1 Temporal Dithering enabled} */
+       UCHAR ucPanelDefaultRefreshRate;
+       UCHAR ucPanelIdentification;
+       UCHAR ucSS_Id;
+       USHORT usLCDVenderID;
+       USHORT usLCDProductID;
+       UCHAR ucLCDPanel_SpecialHandlingCap;
+       UCHAR ucPanelInfoSize;  /*   start from ATOM_DTD_FORMAT to end of panel info, include ExtInfoTable */
+       UCHAR ucReserved[2];
+} ATOM_LVDS_INFO_V12;
+
+#define ATOM_LVDS_INFO_LAST  ATOM_LVDS_INFO_V12
+
+typedef struct _ATOM_PATCH_RECORD_MODE {
+       UCHAR ucRecordType;
+       USHORT usHDisp;
+       USHORT usVDisp;
+} ATOM_PATCH_RECORD_MODE;
+
+typedef struct _ATOM_LCD_RTS_RECORD {
+       UCHAR ucRecordType;
+       UCHAR ucRTSValue;
+} ATOM_LCD_RTS_RECORD;
+
+/* !! If the record below exits, it shoud always be the first record for easy use in command table!!! */
+typedef struct _ATOM_LCD_MODE_CONTROL_CAP {
+       UCHAR ucRecordType;
+       USHORT usLCDCap;
+} ATOM_LCD_MODE_CONTROL_CAP;
+
+#define LCD_MODE_CAP_BL_OFF                   1
+#define LCD_MODE_CAP_CRTC_OFF                 2
+#define LCD_MODE_CAP_PANEL_OFF                4
+
+typedef struct _ATOM_FAKE_EDID_PATCH_RECORD {
+       UCHAR ucRecordType;
+       UCHAR ucFakeEDIDLength;
+       UCHAR ucFakeEDIDString[1];      /*  This actually has ucFakeEdidLength elements. */
+} ATOM_FAKE_EDID_PATCH_RECORD;
+
+typedef struct _ATOM_PANEL_RESOLUTION_PATCH_RECORD {
+       UCHAR ucRecordType;
+       USHORT usHSize;
+       USHORT usVSize;
+} ATOM_PANEL_RESOLUTION_PATCH_RECORD;
+
+#define LCD_MODE_PATCH_RECORD_MODE_TYPE       1
+#define LCD_RTS_RECORD_TYPE                   2
+#define LCD_CAP_RECORD_TYPE                   3
+#define LCD_FAKE_EDID_PATCH_RECORD_TYPE       4
+#define LCD_PANEL_RESOLUTION_RECORD_TYPE      5
+#define ATOM_RECORD_END_TYPE                  0xFF
+
+/****************************Spread Spectrum Info Table Definitions **********************/
+
+/* ucTableFormatRevision=1 */
+/* ucTableContentRevision=2 */
+typedef struct _ATOM_SPREAD_SPECTRUM_ASSIGNMENT {
+       USHORT usSpreadSpectrumPercentage;
+       UCHAR ucSpreadSpectrumType;     /* Bit1=0 Down Spread,=1 Center Spread. Bit1=1 Ext. =0 Int. Others:TBD */
+       UCHAR ucSS_Step;
+       UCHAR ucSS_Delay;
+       UCHAR ucSS_Id;
+       UCHAR ucRecommandedRef_Div;
+       UCHAR ucSS_Range;       /* it was reserved for V11 */
+} ATOM_SPREAD_SPECTRUM_ASSIGNMENT;
+
+#define ATOM_MAX_SS_ENTRY                      16
+#define ATOM_DP_SS_ID1                                                                                          0x0f1  /*  SS modulation freq=30k */
+#define ATOM_DP_SS_ID2                                                                                          0x0f2  /*  SS modulation freq=33k */
+
+#define ATOM_SS_DOWN_SPREAD_MODE_MASK          0x00000000
+#define ATOM_SS_DOWN_SPREAD_MODE               0x00000000
+#define ATOM_SS_CENTRE_SPREAD_MODE_MASK        0x00000001
+#define ATOM_SS_CENTRE_SPREAD_MODE             0x00000001
+#define ATOM_INTERNAL_SS_MASK                  0x00000000
+#define ATOM_EXTERNAL_SS_MASK                  0x00000002
+#define EXEC_SS_STEP_SIZE_SHIFT                2
+#define EXEC_SS_DELAY_SHIFT                    4
+#define ACTIVEDATA_TO_BLON_DELAY_SHIFT         4
+
+typedef struct _ATOM_SPREAD_SPECTRUM_INFO {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       ATOM_SPREAD_SPECTRUM_ASSIGNMENT asSS_Info[ATOM_MAX_SS_ENTRY];
+} ATOM_SPREAD_SPECTRUM_INFO;
+
+/****************************************************************************/
+/*  Structure used in AnalogTV_InfoTable (Top level) */
+/****************************************************************************/
+/* ucTVBootUpDefaultStd definiton: */
+
+/* ATOM_TV_NTSC                1 */
+/* ATOM_TV_NTSCJ               2 */
+/* ATOM_TV_PAL                 3 */
+/* ATOM_TV_PALM                4 */
+/* ATOM_TV_PALCN               5 */
+/* ATOM_TV_PALN                6 */
+/* ATOM_TV_PAL60               7 */
+/* ATOM_TV_SECAM               8 */
+
+/* ucTVSuppportedStd definition: */
+#define NTSC_SUPPORT          0x1
+#define NTSCJ_SUPPORT         0x2
+
+#define PAL_SUPPORT           0x4
+#define PALM_SUPPORT          0x8
+#define PALCN_SUPPORT         0x10
+#define PALN_SUPPORT          0x20
+#define PAL60_SUPPORT         0x40
+#define SECAM_SUPPORT         0x80
+
+#define MAX_SUPPORTED_TV_TIMING    2
+
+typedef struct _ATOM_ANALOG_TV_INFO {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       UCHAR ucTV_SupportedStandard;
+       UCHAR ucTV_BootUpDefaultStandard;
+       UCHAR ucExt_TV_ASIC_ID;
+       UCHAR ucExt_TV_ASIC_SlaveAddr;
+       /*ATOM_DTD_FORMAT          aModeTimings[MAX_SUPPORTED_TV_TIMING]; */
+       ATOM_MODE_TIMING aModeTimings[MAX_SUPPORTED_TV_TIMING];
+} ATOM_ANALOG_TV_INFO;
+
+/**************************************************************************/
+/*  VRAM usage and their defintions */
+
+/*  One chunk of VRAM used by Bios are for HWICON surfaces,EDID data. */
+/*  Current Mode timing and Dail Timing and/or STD timing data EACH device. They can be broken down as below. */
+/*  All the addresses below are the offsets from the frame buffer start.They all MUST be Dword aligned! */
+/*  To driver: The physical address of this memory portion=mmFB_START(4K aligned)+ATOMBIOS_VRAM_USAGE_START_ADDR+ATOM_x_ADDR */
+/*  To Bios:  ATOMBIOS_VRAM_USAGE_START_ADDR+ATOM_x_ADDR->MM_INDEX */
+
+#ifndef VESA_MEMORY_IN_64K_BLOCK
+#define VESA_MEMORY_IN_64K_BLOCK        0x100  /* 256*64K=16Mb (Max. VESA memory is 16Mb!) */
+#endif
+
+#define ATOM_EDID_RAW_DATASIZE          256    /* In Bytes */
+#define ATOM_HWICON_SURFACE_SIZE        4096   /* In Bytes */
+#define ATOM_HWICON_INFOTABLE_SIZE      32
+#define MAX_DTD_MODE_IN_VRAM            6
+#define ATOM_DTD_MODE_SUPPORT_TBL_SIZE  (MAX_DTD_MODE_IN_VRAM*28)      /* 28= (SIZEOF ATOM_DTD_FORMAT) */
+#define ATOM_STD_MODE_SUPPORT_TBL_SIZE  (32*8) /* 32 is a predefined number,8= (SIZEOF ATOM_STD_FORMAT) */
+#define DFP_ENCODER_TYPE_OFFSET                                        0x80
+#define DP_ENCODER_LANE_NUM_OFFSET                     0x84
+#define DP_ENCODER_LINK_RATE_OFFSET                    0x88
+
+#define ATOM_HWICON1_SURFACE_ADDR       0
+#define ATOM_HWICON2_SURFACE_ADDR       (ATOM_HWICON1_SURFACE_ADDR + ATOM_HWICON_SURFACE_SIZE)
+#define ATOM_HWICON_INFOTABLE_ADDR      (ATOM_HWICON2_SURFACE_ADDR + ATOM_HWICON_SURFACE_SIZE)
+#define ATOM_CRT1_EDID_ADDR             (ATOM_HWICON_INFOTABLE_ADDR + ATOM_HWICON_INFOTABLE_SIZE)
+#define ATOM_CRT1_DTD_MODE_TBL_ADDR     (ATOM_CRT1_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
+#define ATOM_CRT1_STD_MODE_TBL_ADDR        (ATOM_CRT1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_LCD1_EDID_ADDR             (ATOM_CRT1_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_LCD1_DTD_MODE_TBL_ADDR     (ATOM_LCD1_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
+#define ATOM_LCD1_STD_MODE_TBL_ADDR    (ATOM_LCD1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_TV1_DTD_MODE_TBL_ADDR      (ATOM_LCD1_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_DFP1_EDID_ADDR             (ATOM_TV1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_DFP1_DTD_MODE_TBL_ADDR     (ATOM_DFP1_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
+#define ATOM_DFP1_STD_MODE_TBL_ADDR        (ATOM_DFP1_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_CRT2_EDID_ADDR             (ATOM_DFP1_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_CRT2_DTD_MODE_TBL_ADDR     (ATOM_CRT2_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
+#define ATOM_CRT2_STD_MODE_TBL_ADDR        (ATOM_CRT2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_LCD2_EDID_ADDR             (ATOM_CRT2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_LCD2_DTD_MODE_TBL_ADDR     (ATOM_LCD2_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
+#define ATOM_LCD2_STD_MODE_TBL_ADDR    (ATOM_LCD2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_TV2_EDID_ADDR              (ATOM_LCD2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_TV2_DTD_MODE_TBL_ADDR      (ATOM_TV2_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
+#define ATOM_TV2_STD_MODE_TBL_ADDR       (ATOM_TV2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_DFP2_EDID_ADDR             (ATOM_TV2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_DFP2_DTD_MODE_TBL_ADDR     (ATOM_DFP2_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
+#define ATOM_DFP2_STD_MODE_TBL_ADDR     (ATOM_DFP2_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_CV_EDID_ADDR               (ATOM_DFP2_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_CV_DTD_MODE_TBL_ADDR       (ATOM_CV_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
+#define ATOM_CV_STD_MODE_TBL_ADDR       (ATOM_CV_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_DFP3_EDID_ADDR             (ATOM_CV_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_DFP3_DTD_MODE_TBL_ADDR     (ATOM_DFP3_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
+#define ATOM_DFP3_STD_MODE_TBL_ADDR     (ATOM_DFP3_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_DFP4_EDID_ADDR             (ATOM_DFP3_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_DFP4_DTD_MODE_TBL_ADDR     (ATOM_DFP4_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
+#define ATOM_DFP4_STD_MODE_TBL_ADDR     (ATOM_DFP4_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_DFP5_EDID_ADDR             (ATOM_DFP4_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+#define ATOM_DFP5_DTD_MODE_TBL_ADDR     (ATOM_DFP5_EDID_ADDR + ATOM_EDID_RAW_DATASIZE)
+#define ATOM_DFP5_STD_MODE_TBL_ADDR     (ATOM_DFP5_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_DP_TRAINING_TBL_ADDR      (ATOM_DFP5_STD_MODE_TBL_ADDR+ATOM_STD_MODE_SUPPORT_TBL_SIZE)
+
+#define ATOM_STACK_STORAGE_START        (ATOM_DP_TRAINING_TBL_ADDR + 256)
+#define ATOM_STACK_STORAGE_END          (ATOM_STACK_STORAGE_START + 512)
+
+/* The size below is in Kb! */
+#define ATOM_VRAM_RESERVE_SIZE         ((((ATOM_STACK_STORAGE_END - ATOM_HWICON1_SURFACE_ADDR)>>10)+4)&0xFFFC)
+
+#define        ATOM_VRAM_OPERATION_FLAGS_MASK         0xC0000000L
+#define ATOM_VRAM_OPERATION_FLAGS_SHIFT        30
+#define        ATOM_VRAM_BLOCK_NEEDS_NO_RESERVATION   0x1
+#define        ATOM_VRAM_BLOCK_NEEDS_RESERVATION      0x0
+
+/***********************************************************************************/
+/*  Structure used in VRAM_UsageByFirmwareTable */
+/*  Note1: This table is filled by SetBiosReservationStartInFB in CoreCommSubs.asm */
+/*         at running time. */
+/*  note2: From RV770, the memory is more than 32bit addressable, so we will change */
+/*         ucTableFormatRevision=1,ucTableContentRevision=4, the strcuture remains */
+/*         exactly same as 1.1 and 1.2 (1.3 is never in use), but ulStartAddrUsedByFirmware */
+/*         (in offset to start of memory address) is KB aligned instead of byte aligend. */
+/***********************************************************************************/
+#define ATOM_MAX_FIRMWARE_VRAM_USAGE_INFO                      1
+
+typedef struct _ATOM_FIRMWARE_VRAM_RESERVE_INFO {
+       ULONG ulStartAddrUsedByFirmware;
+       USHORT usFirmwareUseInKb;
+       USHORT usReserved;
+} ATOM_FIRMWARE_VRAM_RESERVE_INFO;
+
+typedef struct _ATOM_VRAM_USAGE_BY_FIRMWARE {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       ATOM_FIRMWARE_VRAM_RESERVE_INFO
+           asFirmwareVramReserveInfo[ATOM_MAX_FIRMWARE_VRAM_USAGE_INFO];
+} ATOM_VRAM_USAGE_BY_FIRMWARE;
+
+/****************************************************************************/
+/*  Structure used in GPIO_Pin_LUTTable */
+/****************************************************************************/
+typedef struct _ATOM_GPIO_PIN_ASSIGNMENT {
+       USHORT usGpioPin_AIndex;
+       UCHAR ucGpioPinBitShift;
+       UCHAR ucGPIO_ID;
+} ATOM_GPIO_PIN_ASSIGNMENT;
+
+typedef struct _ATOM_GPIO_PIN_LUT {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       ATOM_GPIO_PIN_ASSIGNMENT asGPIO_Pin[1];
+} ATOM_GPIO_PIN_LUT;
+
+/****************************************************************************/
+/*  Structure used in ComponentVideoInfoTable */
+/****************************************************************************/
+#define GPIO_PIN_ACTIVE_HIGH          0x1
+
+#define MAX_SUPPORTED_CV_STANDARDS    5
+
+/*  definitions for ATOM_D_INFO.ucSettings */
+#define ATOM_GPIO_SETTINGS_BITSHIFT_MASK  0x1F /*  [4:0] */
+#define ATOM_GPIO_SETTINGS_RESERVED_MASK  0x60 /*  [6:5] = must be zeroed out */
+#define ATOM_GPIO_SETTINGS_ACTIVE_MASK    0x80 /*  [7] */
+
+typedef struct _ATOM_GPIO_INFO {
+       USHORT usAOffset;
+       UCHAR ucSettings;
+       UCHAR ucReserved;
+} ATOM_GPIO_INFO;
+
+/*  definitions for ATOM_COMPONENT_VIDEO_INFO.ucMiscInfo (bit vector) */
+#define ATOM_CV_RESTRICT_FORMAT_SELECTION           0x2
+
+/*  definitions for ATOM_COMPONENT_VIDEO_INFO.uc480i/uc480p/uc720p/uc1080i */
+#define ATOM_GPIO_DEFAULT_MODE_EN                   0x80       /* [7]; */
+#define ATOM_GPIO_SETTING_PERMODE_MASK              0x7F       /* [6:0] */
+
+/*  definitions for ATOM_COMPONENT_VIDEO_INFO.ucLetterBoxMode */
+/* Line 3 out put 5V. */
+#define ATOM_CV_LINE3_ASPECTRATIO_16_9_GPIO_A       0x01       /* represent gpio 3 state for 16:9 */
+#define ATOM_CV_LINE3_ASPECTRATIO_16_9_GPIO_B       0x02       /* represent gpio 4 state for 16:9 */
+#define ATOM_CV_LINE3_ASPECTRATIO_16_9_GPIO_SHIFT   0x0
+
+/* Line 3 out put 2.2V */
+#define ATOM_CV_LINE3_ASPECTRATIO_4_3_LETBOX_GPIO_A 0x04       /* represent gpio 3 state for 4:3 Letter box */
+#define ATOM_CV_LINE3_ASPECTRATIO_4_3_LETBOX_GPIO_B 0x08       /* represent gpio 4 state for 4:3 Letter box */
+#define ATOM_CV_LINE3_ASPECTRATIO_4_3_LETBOX_GPIO_SHIFT 0x2
+
+/* Line 3 out put 0V */
+#define ATOM_CV_LINE3_ASPECTRATIO_4_3_GPIO_A        0x10       /* represent gpio 3 state for 4:3 */
+#define ATOM_CV_LINE3_ASPECTRATIO_4_3_GPIO_B        0x20       /* represent gpio 4 state for 4:3 */
+#define ATOM_CV_LINE3_ASPECTRATIO_4_3_GPIO_SHIFT    0x4
+
+#define ATOM_CV_LINE3_ASPECTRATIO_MASK              0x3F       /*  bit [5:0] */
+
+#define ATOM_CV_LINE3_ASPECTRATIO_EXIST             0x80       /* bit 7 */
+
+/* GPIO bit index in gpio setting per mode value, also represend the block no. in gpio blocks. */
+#define ATOM_GPIO_INDEX_LINE3_ASPECRATIO_GPIO_A   3    /* bit 3 in uc480i/uc480p/uc720p/uc1080i, which represend the default gpio bit setting for the mode. */
+#define ATOM_GPIO_INDEX_LINE3_ASPECRATIO_GPIO_B   4    /* bit 4 in uc480i/uc480p/uc720p/uc1080i, which represend the default gpio bit setting for the mode. */
+
+typedef struct _ATOM_COMPONENT_VIDEO_INFO {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       USHORT usMask_PinRegisterIndex;
+       USHORT usEN_PinRegisterIndex;
+       USHORT usY_PinRegisterIndex;
+       USHORT usA_PinRegisterIndex;
+       UCHAR ucBitShift;
+       UCHAR ucPinActiveState; /* ucPinActiveState: Bit0=1 active high, =0 active low */
+       ATOM_DTD_FORMAT sReserved;      /*  must be zeroed out */
+       UCHAR ucMiscInfo;
+       UCHAR uc480i;
+       UCHAR uc480p;
+       UCHAR uc720p;
+       UCHAR uc1080i;
+       UCHAR ucLetterBoxMode;
+       UCHAR ucReserved[3];
+       UCHAR ucNumOfWbGpioBlocks;      /* For Component video D-Connector support. If zere, NTSC type connector */
+       ATOM_GPIO_INFO aWbGpioStateBlock[MAX_SUPPORTED_CV_STANDARDS];
+       ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_CV_STANDARDS];
+} ATOM_COMPONENT_VIDEO_INFO;
+
+/* ucTableFormatRevision=2 */
+/* ucTableContentRevision=1 */
+typedef struct _ATOM_COMPONENT_VIDEO_INFO_V21 {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       UCHAR ucMiscInfo;
+       UCHAR uc480i;
+       UCHAR uc480p;
+       UCHAR uc720p;
+       UCHAR uc1080i;
+       UCHAR ucReserved;
+       UCHAR ucLetterBoxMode;
+       UCHAR ucNumOfWbGpioBlocks;      /* For Component video D-Connector support. If zere, NTSC type connector */
+       ATOM_GPIO_INFO aWbGpioStateBlock[MAX_SUPPORTED_CV_STANDARDS];
+       ATOM_DTD_FORMAT aModeTimings[MAX_SUPPORTED_CV_STANDARDS];
+} ATOM_COMPONENT_VIDEO_INFO_V21;
+
+#define ATOM_COMPONENT_VIDEO_INFO_LAST  ATOM_COMPONENT_VIDEO_INFO_V21
+
+/****************************************************************************/
+/*  Structure used in object_InfoTable */
+/****************************************************************************/
+typedef struct _ATOM_OBJECT_HEADER {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       USHORT usDeviceSupport;
+       USHORT usConnectorObjectTableOffset;
+       USHORT usRouterObjectTableOffset;
+       USHORT usEncoderObjectTableOffset;
+       USHORT usProtectionObjectTableOffset;   /* only available when Protection block is independent. */
+       USHORT usDisplayPathTableOffset;
+} ATOM_OBJECT_HEADER;
+
+typedef struct _ATOM_DISPLAY_OBJECT_PATH {
+       USHORT usDeviceTag;     /* supported device */
+       USHORT usSize;          /* the size of ATOM_DISPLAY_OBJECT_PATH */
+       USHORT usConnObjectId;  /* Connector Object ID */
+       USHORT usGPUObjectId;   /* GPU ID */
+       USHORT usGraphicObjIds[1];      /* 1st Encoder Obj source from GPU to last Graphic Obj destinate to connector. */
+} ATOM_DISPLAY_OBJECT_PATH;
+
+typedef struct _ATOM_DISPLAY_OBJECT_PATH_TABLE {
+       UCHAR ucNumOfDispPath;
+       UCHAR ucVersion;
+       UCHAR ucPadding[2];
+       ATOM_DISPLAY_OBJECT_PATH asDispPath[1];
+} ATOM_DISPLAY_OBJECT_PATH_TABLE;
+
+typedef struct _ATOM_OBJECT    /* each object has this structure */
+{
+       USHORT usObjectID;
+       USHORT usSrcDstTableOffset;
+       USHORT usRecordOffset;  /* this pointing to a bunch of records defined below */
+       USHORT usReserved;
+} ATOM_OBJECT;
+
+typedef struct _ATOM_OBJECT_TABLE      /* Above 4 object table offset pointing to a bunch of objects all have this structure */
+{
+       UCHAR ucNumberOfObjects;
+       UCHAR ucPadding[3];
+       ATOM_OBJECT asObjects[1];
+} ATOM_OBJECT_TABLE;
+
+typedef struct _ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT      /* usSrcDstTableOffset pointing to this structure */
+{
+       UCHAR ucNumberOfSrc;
+       USHORT usSrcObjectID[1];
+       UCHAR ucNumberOfDst;
+       USHORT usDstObjectID[1];
+} ATOM_SRC_DST_TABLE_FOR_ONE_OBJECT;
+
+/* Related definitions, all records are differnt but they have a commond header */
+typedef struct _ATOM_COMMON_RECORD_HEADER {
+       UCHAR ucRecordType;     /* An emun to indicate the record type */
+       UCHAR ucRecordSize;     /* The size of the whole record in byte */
+} ATOM_COMMON_RECORD_HEADER;
+
+#define ATOM_I2C_RECORD_TYPE                           1
+#define ATOM_HPD_INT_RECORD_TYPE                       2
+#define ATOM_OUTPUT_PROTECTION_RECORD_TYPE             3
+#define ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE          4
+#define        ATOM_CONNECTOR_DVI_EXT_INPUT_RECORD_TYPE             5  /* Obsolete, switch to use GPIO_CNTL_RECORD_TYPE */
+#define ATOM_ENCODER_FPGA_CONTROL_RECORD_TYPE          6       /* Obsolete, switch to use GPIO_CNTL_RECORD_TYPE */
+#define ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD_TYPE      7
+#define ATOM_JTAG_RECORD_TYPE                          8       /* Obsolete, switch to use GPIO_CNTL_RECORD_TYPE */
+#define ATOM_OBJECT_GPIO_CNTL_RECORD_TYPE              9
+#define ATOM_ENCODER_DVO_CF_RECORD_TYPE               10
+#define ATOM_CONNECTOR_CF_RECORD_TYPE                 11
+#define        ATOM_CONNECTOR_HARDCODE_DTD_RECORD_TYPE       12
+#define ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD_TYPE  13
+#define ATOM_ROUTER_DDC_PATH_SELECT_RECORD_TYPE                                14
+#define ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD_TYPE                                 15
+
+/* Must be updated when new record type is added,equal to that record definition! */
+#define ATOM_MAX_OBJECT_RECORD_NUMBER             ATOM_CONNECTOR_CF_RECORD_TYPE
+
+typedef struct _ATOM_I2C_RECORD {
+       ATOM_COMMON_RECORD_HEADER sheader;
+       ATOM_I2C_ID_CONFIG sucI2cId;
+       UCHAR ucI2CAddr;        /* The slave address, it's 0 when the record is attached to connector for DDC */
+} ATOM_I2C_RECORD;
+
+typedef struct _ATOM_HPD_INT_RECORD {
+       ATOM_COMMON_RECORD_HEADER sheader;
+       UCHAR ucHPDIntGPIOID;   /* Corresponding block in GPIO_PIN_INFO table gives the pin info */
+       UCHAR ucPluggged_PinState;
+} ATOM_HPD_INT_RECORD;
+
+typedef struct _ATOM_OUTPUT_PROTECTION_RECORD {
+       ATOM_COMMON_RECORD_HEADER sheader;
+       UCHAR ucProtectionFlag;
+       UCHAR ucReserved;
+} ATOM_OUTPUT_PROTECTION_RECORD;
+
+typedef struct _ATOM_CONNECTOR_DEVICE_TAG {
+       ULONG ulACPIDeviceEnum; /* Reserved for now */
+       USHORT usDeviceID;      /* This Id is same as "ATOM_DEVICE_XXX_SUPPORT" */
+       USHORT usPadding;
+} ATOM_CONNECTOR_DEVICE_TAG;
+
+typedef struct _ATOM_CONNECTOR_DEVICE_TAG_RECORD {
+       ATOM_COMMON_RECORD_HEADER sheader;
+       UCHAR ucNumberOfDevice;
+       UCHAR ucReserved;
+       ATOM_CONNECTOR_DEVICE_TAG asDeviceTag[1];       /* This Id is same as "ATOM_DEVICE_XXX_SUPPORT", 1 is only for allocation */
+} ATOM_CONNECTOR_DEVICE_TAG_RECORD;
+
+typedef struct _ATOM_CONNECTOR_DVI_EXT_INPUT_RECORD {
+       ATOM_COMMON_RECORD_HEADER sheader;
+       UCHAR ucConfigGPIOID;
+       UCHAR ucConfigGPIOState;        /* Set to 1 when it's active high to enable external flow in */
+       UCHAR ucFlowinGPIPID;
+       UCHAR ucExtInGPIPID;
+} ATOM_CONNECTOR_DVI_EXT_INPUT_RECORD;
+
+typedef struct _ATOM_ENCODER_FPGA_CONTROL_RECORD {
+       ATOM_COMMON_RECORD_HEADER sheader;
+       UCHAR ucCTL1GPIO_ID;
+       UCHAR ucCTL1GPIOState;  /* Set to 1 when it's active high */
+       UCHAR ucCTL2GPIO_ID;
+       UCHAR ucCTL2GPIOState;  /* Set to 1 when it's active high */
+       UCHAR ucCTL3GPIO_ID;
+       UCHAR ucCTL3GPIOState;  /* Set to 1 when it's active high */
+       UCHAR ucCTLFPGA_IN_ID;
+       UCHAR ucPadding[3];
+} ATOM_ENCODER_FPGA_CONTROL_RECORD;
+
+typedef struct _ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD {
+       ATOM_COMMON_RECORD_HEADER sheader;
+       UCHAR ucGPIOID;         /* Corresponding block in GPIO_PIN_INFO table gives the pin info */
+       UCHAR ucTVActiveState;  /* Indicating when the pin==0 or 1 when TV is connected */
+} ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD;
+
+typedef struct _ATOM_JTAG_RECORD {
+       ATOM_COMMON_RECORD_HEADER sheader;
+       UCHAR ucTMSGPIO_ID;
+       UCHAR ucTMSGPIOState;   /* Set to 1 when it's active high */
+       UCHAR ucTCKGPIO_ID;
+       UCHAR ucTCKGPIOState;   /* Set to 1 when it's active high */
+       UCHAR ucTDOGPIO_ID;
+       UCHAR ucTDOGPIOState;   /* Set to 1 when it's active high */
+       UCHAR ucTDIGPIO_ID;
+       UCHAR ucTDIGPIOState;   /* Set to 1 when it's active high */
+       UCHAR ucPadding[2];
+} ATOM_JTAG_RECORD;
+
+/* The following generic object gpio pin control record type will replace JTAG_RECORD/FPGA_CONTROL_RECORD/DVI_EXT_INPUT_RECORD above gradually */
+typedef struct _ATOM_GPIO_PIN_CONTROL_PAIR {
+       UCHAR ucGPIOID;         /*  GPIO_ID, find the corresponding ID in GPIO_LUT table */
+       UCHAR ucGPIO_PinState;  /*  Pin state showing how to set-up the pin */
+} ATOM_GPIO_PIN_CONTROL_PAIR;
+
+typedef struct _ATOM_OBJECT_GPIO_CNTL_RECORD {
+       ATOM_COMMON_RECORD_HEADER sheader;
+       UCHAR ucFlags;          /*  Future expnadibility */
+       UCHAR ucNumberOfPins;   /*  Number of GPIO pins used to control the object */
+       ATOM_GPIO_PIN_CONTROL_PAIR asGpio[1];   /*  the real gpio pin pair determined by number of pins ucNumberOfPins */
+} ATOM_OBJECT_GPIO_CNTL_RECORD;
+
+/* Definitions for GPIO pin state */
+#define GPIO_PIN_TYPE_INPUT             0x00
+#define GPIO_PIN_TYPE_OUTPUT            0x10
+#define GPIO_PIN_TYPE_HW_CONTROL        0x20
+
+/* For GPIO_PIN_TYPE_OUTPUT the following is defined */
+#define GPIO_PIN_OUTPUT_STATE_MASK      0x01
+#define GPIO_PIN_OUTPUT_STATE_SHIFT     0
+#define GPIO_PIN_STATE_ACTIVE_LOW       0x0
+#define GPIO_PIN_STATE_ACTIVE_HIGH      0x1
+
+typedef struct _ATOM_ENCODER_DVO_CF_RECORD {
+       ATOM_COMMON_RECORD_HEADER sheader;
+       ULONG ulStrengthControl;        /*  DVOA strength control for CF */
+       UCHAR ucPadding[2];
+} ATOM_ENCODER_DVO_CF_RECORD;
+
+/*  value for ATOM_CONNECTOR_CF_RECORD.ucConnectedDvoBundle */
+#define ATOM_CONNECTOR_CF_RECORD_CONNECTED_UPPER12BITBUNDLEA   1
+#define ATOM_CONNECTOR_CF_RECORD_CONNECTED_LOWER12BITBUNDLEB   2
+
+typedef struct _ATOM_CONNECTOR_CF_RECORD {
+       ATOM_COMMON_RECORD_HEADER sheader;
+       USHORT usMaxPixClk;
+       UCHAR ucFlowCntlGpioId;
+       UCHAR ucSwapCntlGpioId;
+       UCHAR ucConnectedDvoBundle;
+       UCHAR ucPadding;
+} ATOM_CONNECTOR_CF_RECORD;
+
+typedef struct _ATOM_CONNECTOR_HARDCODE_DTD_RECORD {
+       ATOM_COMMON_RECORD_HEADER sheader;
+       ATOM_DTD_FORMAT asTiming;
+} ATOM_CONNECTOR_HARDCODE_DTD_RECORD;
+
+typedef struct _ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD {
+       ATOM_COMMON_RECORD_HEADER sheader;      /* ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD_TYPE */
+       UCHAR ucSubConnectorType;       /* CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D|X_ID_DUAL_LINK_DVI_D|HDMI_TYPE_A */
+       UCHAR ucReserved;
+} ATOM_CONNECTOR_PCIE_SUBCONNECTOR_RECORD;
+
+typedef struct _ATOM_ROUTER_DDC_PATH_SELECT_RECORD {
+       ATOM_COMMON_RECORD_HEADER sheader;
+       UCHAR ucMuxType;        /* decide the number of ucMuxState, =0, no pin state, =1: single state with complement, >1: multiple state */
+       UCHAR ucMuxControlPin;
+       UCHAR ucMuxState[2];    /* for alligment purpose */
+} ATOM_ROUTER_DDC_PATH_SELECT_RECORD;
+
+typedef struct _ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD {
+       ATOM_COMMON_RECORD_HEADER sheader;
+       UCHAR ucMuxType;
+       UCHAR ucMuxControlPin;
+       UCHAR ucMuxState[2];    /* for alligment purpose */
+} ATOM_ROUTER_DATA_CLOCK_PATH_SELECT_RECORD;
+
+/*  define ucMuxType */
+#define ATOM_ROUTER_MUX_PIN_STATE_MASK                                                         0x0f
+#define ATOM_ROUTER_MUX_PIN_SINGLE_STATE_COMPLEMENT            0x01
+
+/****************************************************************************/
+/*  ASIC voltage data table */
+/****************************************************************************/
+typedef struct _ATOM_VOLTAGE_INFO_HEADER {
+       USHORT usVDDCBaseLevel; /* In number of 50mv unit */
+       USHORT usReserved;      /* For possible extension table offset */
+       UCHAR ucNumOfVoltageEntries;
+       UCHAR ucBytesPerVoltageEntry;
+       UCHAR ucVoltageStep;    /* Indicating in how many mv increament is one step, 0.5mv unit */
+       UCHAR ucDefaultVoltageEntry;
+       UCHAR ucVoltageControlI2cLine;
+       UCHAR ucVoltageControlAddress;
+       UCHAR ucVoltageControlOffset;
+} ATOM_VOLTAGE_INFO_HEADER;
+
+typedef struct _ATOM_VOLTAGE_INFO {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       ATOM_VOLTAGE_INFO_HEADER viHeader;
+       UCHAR ucVoltageEntries[64];     /* 64 is for allocation, the actual number of entry is present at ucNumOfVoltageEntries*ucBytesPerVoltageEntry */
+} ATOM_VOLTAGE_INFO;
+
+typedef struct _ATOM_VOLTAGE_FORMULA {
+       USHORT usVoltageBaseLevel;      /*  In number of 1mv unit */
+       USHORT usVoltageStep;   /*  Indicating in how many mv increament is one step, 1mv unit */
+       UCHAR ucNumOfVoltageEntries;    /*  Number of Voltage Entry, which indicate max Voltage */
+       UCHAR ucFlag;           /*  bit0=0 :step is 1mv =1 0.5mv */
+       UCHAR ucBaseVID;        /*  if there is no lookup table, VID= BaseVID + ( Vol - BaseLevle ) /VoltageStep */
+       UCHAR ucReserved;
+       UCHAR ucVIDAdjustEntries[32];   /*  32 is for allocation, the actual number of entry is present at ucNumOfVoltageEntries */
+} ATOM_VOLTAGE_FORMULA;
+
+typedef struct _ATOM_VOLTAGE_CONTROL {
+       UCHAR ucVoltageControlId;       /* Indicate it is controlled by I2C or GPIO or HW state machine */
+       UCHAR ucVoltageControlI2cLine;
+       UCHAR ucVoltageControlAddress;
+       UCHAR ucVoltageControlOffset;
+       USHORT usGpioPin_AIndex;        /* GPIO_PAD register index */
+       UCHAR ucGpioPinBitShift[9];     /* at most 8 pin support 255 VIDs, termintate with 0xff */
+       UCHAR ucReserved;
+} ATOM_VOLTAGE_CONTROL;
+
+/*  Define ucVoltageControlId */
+#define        VOLTAGE_CONTROLLED_BY_HW                                                        0x00
+#define        VOLTAGE_CONTROLLED_BY_I2C_MASK                          0x7F
+#define        VOLTAGE_CONTROLLED_BY_GPIO                                              0x80
+#define        VOLTAGE_CONTROL_ID_LM64                                                         0x01    /* I2C control, used for R5xx Core Voltage */
+#define        VOLTAGE_CONTROL_ID_DAC                                                          0x02    /* I2C control, used for R5xx/R6xx MVDDC,MVDDQ or VDDCI */
+#define        VOLTAGE_CONTROL_ID_VT116xM                                              0x03    /* I2C control, used for R6xx Core Voltage */
+#define VOLTAGE_CONTROL_ID_DS4402                                                      0x04
+
+typedef struct _ATOM_VOLTAGE_OBJECT {
+       UCHAR ucVoltageType;    /* Indicate Voltage Source: VDDC, MVDDC, MVDDQ or MVDDCI */
+       UCHAR ucSize;           /* Size of Object */
+       ATOM_VOLTAGE_CONTROL asControl; /* describ how to control */
+       ATOM_VOLTAGE_FORMULA asFormula; /* Indicate How to convert real Voltage to VID */
+} ATOM_VOLTAGE_OBJECT;
+
+typedef struct _ATOM_VOLTAGE_OBJECT_INFO {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       ATOM_VOLTAGE_OBJECT asVoltageObj[3];    /* Info for Voltage control */
+} ATOM_VOLTAGE_OBJECT_INFO;
+
+typedef struct _ATOM_LEAKID_VOLTAGE {
+       UCHAR ucLeakageId;
+       UCHAR ucReserved;
+       USHORT usVoltage;
+} ATOM_LEAKID_VOLTAGE;
+
+typedef struct _ATOM_ASIC_PROFILE_VOLTAGE {
+       UCHAR ucProfileId;
+       UCHAR ucReserved;
+       USHORT usSize;
+       USHORT usEfuseSpareStartAddr;
+       USHORT usFuseIndex[8];  /* from LSB to MSB, Max 8bit,end of 0xffff if less than 8 efuse id, */
+       ATOM_LEAKID_VOLTAGE asLeakVol[2];       /* Leakid and relatd voltage */
+} ATOM_ASIC_PROFILE_VOLTAGE;
+
+/* ucProfileId */
+#define        ATOM_ASIC_PROFILE_ID_EFUSE_VOLTAGE                      1
+#define        ATOM_ASIC_PROFILE_ID_EFUSE_PERFORMANCE_VOLTAGE                  1
+#define        ATOM_ASIC_PROFILE_ID_EFUSE_THERMAL_VOLTAGE                                      2
+
+typedef struct _ATOM_ASIC_PROFILING_INFO {
+       ATOM_COMMON_TABLE_HEADER asHeader;
+       ATOM_ASIC_PROFILE_VOLTAGE asVoltage;
+} ATOM_ASIC_PROFILING_INFO;
+
+typedef struct _ATOM_POWER_SOURCE_OBJECT {
+       UCHAR ucPwrSrcId;       /*  Power source */
+       UCHAR ucPwrSensorType;  /*  GPIO, I2C or none */
+       UCHAR ucPwrSensId;      /*  if GPIO detect, it is GPIO id,  if I2C detect, it is I2C id */
+       UCHAR ucPwrSensSlaveAddr;       /*  Slave address if I2C detect */
+       UCHAR ucPwrSensRegIndex;        /*  I2C register Index if I2C detect */
+       UCHAR ucPwrSensRegBitMask;      /*  detect which bit is used if I2C detect */
+       UCHAR ucPwrSensActiveState;     /*  high active or low active */
+       UCHAR ucReserve[3];     /*  reserve */
+       USHORT usSensPwr;       /*  in unit of watt */
+} ATOM_POWER_SOURCE_OBJECT;
+
+typedef struct _ATOM_POWER_SOURCE_INFO {
+       ATOM_COMMON_TABLE_HEADER asHeader;
+       UCHAR asPwrbehave[16];
+       ATOM_POWER_SOURCE_OBJECT asPwrObj[1];
+} ATOM_POWER_SOURCE_INFO;
+
+/* Define ucPwrSrcId */
+#define POWERSOURCE_PCIE_ID1                                           0x00
+#define POWERSOURCE_6PIN_CONNECTOR_ID1 0x01
+#define POWERSOURCE_8PIN_CONNECTOR_ID1 0x02
+#define POWERSOURCE_6PIN_CONNECTOR_ID2 0x04
+#define POWERSOURCE_8PIN_CONNECTOR_ID2 0x08
+
+/* define ucPwrSensorId */
+#define POWER_SENSOR_ALWAYS                                                    0x00
+#define POWER_SENSOR_GPIO                                                              0x01
+#define POWER_SENSOR_I2C                                                               0x02
+
+/**************************************************************************/
+/*  This portion is only used when ext thermal chip or engine/memory clock SS chip is populated on a design */
+/* Memory SS Info Table */
+/* Define Memory Clock SS chip ID */
+#define ICS91719  1
+#define ICS91720  2
+
+/* Define one structure to inform SW a "block of data" writing to external SS chip via I2C protocol */
+typedef struct _ATOM_I2C_DATA_RECORD {
+       UCHAR ucNunberOfBytes;  /* Indicates how many bytes SW needs to write to the external ASIC for one block, besides to "Start" and "Stop" */
+       UCHAR ucI2CData[1];     /* I2C data in bytes, should be less than 16 bytes usually */
+} ATOM_I2C_DATA_RECORD;
+
+/* Define one structure to inform SW how many blocks of data writing to external SS chip via I2C protocol, in addition to other information */
+typedef struct _ATOM_I2C_DEVICE_SETUP_INFO {
+       ATOM_I2C_ID_CONFIG_ACCESS sucI2cId;     /* I2C line and HW/SW assisted cap. */
+       UCHAR ucSSChipID;       /* SS chip being used */
+       UCHAR ucSSChipSlaveAddr;        /* Slave Address to set up this SS chip */
+       UCHAR ucNumOfI2CDataRecords;    /* number of data block */
+       ATOM_I2C_DATA_RECORD asI2CData[1];
+} ATOM_I2C_DEVICE_SETUP_INFO;
+
+/* ========================================================================================== */
+typedef struct _ATOM_ASIC_MVDD_INFO {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       ATOM_I2C_DEVICE_SETUP_INFO asI2CSetup[1];
+} ATOM_ASIC_MVDD_INFO;
+
+/* ========================================================================================== */
+#define ATOM_MCLK_SS_INFO         ATOM_ASIC_MVDD_INFO
+
+/* ========================================================================================== */
+/**************************************************************************/
+
+typedef struct _ATOM_ASIC_SS_ASSIGNMENT {
+       ULONG ulTargetClockRange;       /* Clock Out frequence (VCO ), in unit of 10Khz */
+       USHORT usSpreadSpectrumPercentage;      /* in unit of 0.01% */
+       USHORT usSpreadRateInKhz;       /* in unit of kHz, modulation freq */
+       UCHAR ucClockIndication;        /* Indicate which clock source needs SS */
+       UCHAR ucSpreadSpectrumMode;     /* Bit1=0 Down Spread,=1 Center Spread. */
+       UCHAR ucReserved[2];
+} ATOM_ASIC_SS_ASSIGNMENT;
+
+/* Define ucSpreadSpectrumType */
+#define ASIC_INTERNAL_MEMORY_SS                        1
+#define ASIC_INTERNAL_ENGINE_SS                        2
+#define ASIC_INTERNAL_UVD_SS                           3
+
+typedef struct _ATOM_ASIC_INTERNAL_SS_INFO {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       ATOM_ASIC_SS_ASSIGNMENT asSpreadSpectrum[4];
+} ATOM_ASIC_INTERNAL_SS_INFO;
+
+/* ==============================Scratch Pad Definition Portion=============================== */
+#define ATOM_DEVICE_CONNECT_INFO_DEF  0
+#define ATOM_ROM_LOCATION_DEF         1
+#define ATOM_TV_STANDARD_DEF          2
+#define ATOM_ACTIVE_INFO_DEF          3
+#define ATOM_LCD_INFO_DEF             4
+#define ATOM_DOS_REQ_INFO_DEF         5
+#define ATOM_ACC_CHANGE_INFO_DEF      6
+#define ATOM_DOS_MODE_INFO_DEF        7
+#define ATOM_I2C_CHANNEL_STATUS_DEF   8
+#define ATOM_I2C_CHANNEL_STATUS1_DEF  9
+
+/*  BIOS_0_SCRATCH Definition */
+#define ATOM_S0_CRT1_MONO               0x00000001L
+#define ATOM_S0_CRT1_COLOR              0x00000002L
+#define ATOM_S0_CRT1_MASK               (ATOM_S0_CRT1_MONO+ATOM_S0_CRT1_COLOR)
+
+#define ATOM_S0_TV1_COMPOSITE_A         0x00000004L
+#define ATOM_S0_TV1_SVIDEO_A            0x00000008L
+#define ATOM_S0_TV1_MASK_A              (ATOM_S0_TV1_COMPOSITE_A+ATOM_S0_TV1_SVIDEO_A)
+
+#define ATOM_S0_CV_A                    0x00000010L
+#define ATOM_S0_CV_DIN_A                0x00000020L
+#define ATOM_S0_CV_MASK_A               (ATOM_S0_CV_A+ATOM_S0_CV_DIN_A)
+
+#define ATOM_S0_CRT2_MONO               0x00000100L
+#define ATOM_S0_CRT2_COLOR              0x00000200L
+#define ATOM_S0_CRT2_MASK               (ATOM_S0_CRT2_MONO+ATOM_S0_CRT2_COLOR)
+
+#define ATOM_S0_TV1_COMPOSITE           0x00000400L
+#define ATOM_S0_TV1_SVIDEO              0x00000800L
+#define ATOM_S0_TV1_SCART               0x00004000L
+#define ATOM_S0_TV1_MASK                (ATOM_S0_TV1_COMPOSITE+ATOM_S0_TV1_SVIDEO+ATOM_S0_TV1_SCART)
+
+#define ATOM_S0_CV                      0x00001000L
+#define ATOM_S0_CV_DIN                  0x00002000L
+#define ATOM_S0_CV_MASK                 (ATOM_S0_CV+ATOM_S0_CV_DIN)
+
+#define ATOM_S0_DFP1                    0x00010000L
+#define ATOM_S0_DFP2                    0x00020000L
+#define ATOM_S0_LCD1                    0x00040000L
+#define ATOM_S0_LCD2                    0x00080000L
+#define ATOM_S0_TV2                     0x00100000L
+#define ATOM_S0_DFP3                   0x00200000L
+#define ATOM_S0_DFP4                   0x00400000L
+#define ATOM_S0_DFP5                   0x00800000L
+
+#define ATOM_S0_DFP_MASK \
+       (ATOM_S0_DFP1 | ATOM_S0_DFP2 | ATOM_S0_DFP3 | ATOM_S0_DFP4 | ATOM_S0_DFP5)
+
+#define ATOM_S0_FAD_REGISTER_BUG        0x02000000L    /*  If set, indicates we are running a PCIE asic with */
+                                                   /*  the FAD/HDP reg access bug.  Bit is read by DAL */
+
+#define ATOM_S0_THERMAL_STATE_MASK      0x1C000000L
+#define ATOM_S0_THERMAL_STATE_SHIFT     26
+
+#define ATOM_S0_SYSTEM_POWER_STATE_MASK 0xE0000000L
+#define ATOM_S0_SYSTEM_POWER_STATE_SHIFT 29
+
+#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_AC     1
+#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_DC     2
+#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_LITEAC 3
+
+/* Byte aligned defintion for BIOS usage */
+#define ATOM_S0_CRT1_MONOb0             0x01
+#define ATOM_S0_CRT1_COLORb0            0x02
+#define ATOM_S0_CRT1_MASKb0             (ATOM_S0_CRT1_MONOb0+ATOM_S0_CRT1_COLORb0)
+
+#define ATOM_S0_TV1_COMPOSITEb0         0x04
+#define ATOM_S0_TV1_SVIDEOb0            0x08
+#define ATOM_S0_TV1_MASKb0              (ATOM_S0_TV1_COMPOSITEb0+ATOM_S0_TV1_SVIDEOb0)
+
+#define ATOM_S0_CVb0                    0x10
+#define ATOM_S0_CV_DINb0                0x20
+#define ATOM_S0_CV_MASKb0               (ATOM_S0_CVb0+ATOM_S0_CV_DINb0)
+
+#define ATOM_S0_CRT2_MONOb1             0x01
+#define ATOM_S0_CRT2_COLORb1            0x02
+#define ATOM_S0_CRT2_MASKb1             (ATOM_S0_CRT2_MONOb1+ATOM_S0_CRT2_COLORb1)
+
+#define ATOM_S0_TV1_COMPOSITEb1         0x04
+#define ATOM_S0_TV1_SVIDEOb1            0x08
+#define ATOM_S0_TV1_SCARTb1             0x40
+#define ATOM_S0_TV1_MASKb1              (ATOM_S0_TV1_COMPOSITEb1+ATOM_S0_TV1_SVIDEOb1+ATOM_S0_TV1_SCARTb1)
+
+#define ATOM_S0_CVb1                    0x10
+#define ATOM_S0_CV_DINb1                0x20
+#define ATOM_S0_CV_MASKb1               (ATOM_S0_CVb1+ATOM_S0_CV_DINb1)
+
+#define ATOM_S0_DFP1b2                  0x01
+#define ATOM_S0_DFP2b2                  0x02
+#define ATOM_S0_LCD1b2                  0x04
+#define ATOM_S0_LCD2b2                  0x08
+#define ATOM_S0_TV2b2                   0x10
+#define ATOM_S0_DFP3b2                                                                 0x20
+
+#define ATOM_S0_THERMAL_STATE_MASKb3    0x1C
+#define ATOM_S0_THERMAL_STATE_SHIFTb3   2
+
+#define ATOM_S0_SYSTEM_POWER_STATE_MASKb3 0xE0
+#define ATOM_S0_LCD1_SHIFT              18
+
+/*  BIOS_1_SCRATCH Definition */
+#define ATOM_S1_ROM_LOCATION_MASK       0x0000FFFFL
+#define ATOM_S1_PCI_BUS_DEV_MASK        0xFFFF0000L
+
+/*       BIOS_2_SCRATCH Definition */
+#define ATOM_S2_TV1_STANDARD_MASK       0x0000000FL
+#define ATOM_S2_CURRENT_BL_LEVEL_MASK   0x0000FF00L
+#define ATOM_S2_CURRENT_BL_LEVEL_SHIFT  8
+
+#define ATOM_S2_CRT1_DPMS_STATE         0x00010000L
+#define ATOM_S2_LCD1_DPMS_STATE                0x00020000L
+#define ATOM_S2_TV1_DPMS_STATE          0x00040000L
+#define ATOM_S2_DFP1_DPMS_STATE         0x00080000L
+#define ATOM_S2_CRT2_DPMS_STATE         0x00100000L
+#define ATOM_S2_LCD2_DPMS_STATE         0x00200000L
+#define ATOM_S2_TV2_DPMS_STATE          0x00400000L
+#define ATOM_S2_DFP2_DPMS_STATE         0x00800000L
+#define ATOM_S2_CV_DPMS_STATE           0x01000000L
+#define ATOM_S2_DFP3_DPMS_STATE                                        0x02000000L
+#define ATOM_S2_DFP4_DPMS_STATE                                        0x04000000L
+#define ATOM_S2_DFP5_DPMS_STATE                                        0x08000000L
+
+#define ATOM_S2_DFP_DPM_STATE \
+       (ATOM_S2_DFP1_DPMS_STATE | ATOM_S2_DFP2_DPMS_STATE | \
+        ATOM_S2_DFP3_DPMS_STATE | ATOM_S2_DFP4_DPMS_STATE | \
+        ATOM_S2_DFP5_DPMS_STATE)
+
+#define ATOM_S2_DEVICE_DPMS_STATE \
+       (ATOM_S2_CRT1_DPMS_STATE + ATOM_S2_LCD1_DPMS_STATE + \
+        ATOM_S2_TV1_DPMS_STATE + ATOM_S2_DFP_DPMS_STATE + \
+        ATOM_S2_CRT2_DPMS_STATE + ATOM_S2_LCD2_DPMS_STATE + \
+        ATOM_S2_TV2_DPMS_STATE + ATOM_S2_CV_DPMS_STATE)
+
+#define ATOM_S2_FORCEDLOWPWRMODE_STATE_MASK       0x0C000000L
+#define ATOM_S2_FORCEDLOWPWRMODE_STATE_MASK_SHIFT 26
+#define ATOM_S2_FORCEDLOWPWRMODE_STATE_CHANGE     0x10000000L
+
+#define ATOM_S2_VRI_BRIGHT_ENABLE       0x20000000L
+
+#define ATOM_S2_DISPLAY_ROTATION_0_DEGREE     0x0
+#define ATOM_S2_DISPLAY_ROTATION_90_DEGREE    0x1
+#define ATOM_S2_DISPLAY_ROTATION_180_DEGREE   0x2
+#define ATOM_S2_DISPLAY_ROTATION_270_DEGREE   0x3
+#define ATOM_S2_DISPLAY_ROTATION_DEGREE_SHIFT 30
+#define ATOM_S2_DISPLAY_ROTATION_ANGLE_MASK   0xC0000000L
+
+/* Byte aligned defintion for BIOS usage */
+#define ATOM_S2_TV1_STANDARD_MASKb0     0x0F
+#define ATOM_S2_CURRENT_BL_LEVEL_MASKb1 0xFF
+#define ATOM_S2_CRT1_DPMS_STATEb2       0x01
+#define ATOM_S2_LCD1_DPMS_STATEb2       0x02
+#define ATOM_S2_TV1_DPMS_STATEb2        0x04
+#define ATOM_S2_DFP1_DPMS_STATEb2       0x08
+#define ATOM_S2_CRT2_DPMS_STATEb2       0x10
+#define ATOM_S2_LCD2_DPMS_STATEb2       0x20
+#define ATOM_S2_TV2_DPMS_STATEb2        0x40
+#define ATOM_S2_DFP2_DPMS_STATEb2       0x80
+#define ATOM_S2_CV_DPMS_STATEb3         0x01
+#define ATOM_S2_DFP3_DPMS_STATEb3                              0x02
+#define ATOM_S2_DFP4_DPMS_STATEb3                              0x04
+#define ATOM_S2_DFP5_DPMS_STATEb3                              0x08
+
+#define ATOM_S2_DEVICE_DPMS_MASKw1      0x3FF
+#define ATOM_S2_FORCEDLOWPWRMODE_STATE_MASKb3     0x0C
+#define ATOM_S2_FORCEDLOWPWRMODE_STATE_CHANGEb3   0x10
+#define ATOM_S2_VRI_BRIGHT_ENABLEb3     0x20
+#define ATOM_S2_ROTATION_STATE_MASKb3   0xC0
+
+/*  BIOS_3_SCRATCH Definition */
+#define ATOM_S3_CRT1_ACTIVE             0x00000001L
+#define ATOM_S3_LCD1_ACTIVE             0x00000002L
+#define ATOM_S3_TV1_ACTIVE              0x00000004L
+#define ATOM_S3_DFP1_ACTIVE             0x00000008L
+#define ATOM_S3_CRT2_ACTIVE             0x00000010L
+#define ATOM_S3_LCD2_ACTIVE             0x00000020L
+#define ATOM_S3_TV2_ACTIVE              0x00000040L
+#define ATOM_S3_DFP2_ACTIVE             0x00000080L
+#define ATOM_S3_CV_ACTIVE               0x00000100L
+#define ATOM_S3_DFP3_ACTIVE                                                    0x00000200L
+#define ATOM_S3_DFP4_ACTIVE                                                    0x00000400L
+#define ATOM_S3_DFP5_ACTIVE                                                    0x00000800L
+
+#define ATOM_S3_DEVICE_ACTIVE_MASK      0x000003FFL
+
+#define ATOM_S3_LCD_FULLEXPANSION_ACTIVE         0x00001000L
+#define ATOM_S3_LCD_EXPANSION_ASPEC_RATIO_ACTIVE 0x00002000L
+
+#define ATOM_S3_CRT1_CRTC_ACTIVE        0x00010000L
+#define ATOM_S3_LCD1_CRTC_ACTIVE        0x00020000L
+#define ATOM_S3_TV1_CRTC_ACTIVE         0x00040000L
+#define ATOM_S3_DFP1_CRTC_ACTIVE        0x00080000L
+#define ATOM_S3_CRT2_CRTC_ACTIVE        0x00100000L
+#define ATOM_S3_LCD2_CRTC_ACTIVE        0x00200000L
+#define ATOM_S3_TV2_CRTC_ACTIVE         0x00400000L
+#define ATOM_S3_DFP2_CRTC_ACTIVE        0x00800000L
+#define ATOM_S3_CV_CRTC_ACTIVE          0x01000000L
+#define ATOM_S3_DFP3_CRTC_ACTIVE                               0x02000000L
+#define ATOM_S3_DFP4_CRTC_ACTIVE                               0x04000000L
+#define ATOM_S3_DFP5_CRTC_ACTIVE                               0x08000000L
+
+#define ATOM_S3_DEVICE_CRTC_ACTIVE_MASK 0x0FFF0000L
+#define ATOM_S3_ASIC_GUI_ENGINE_HUNG    0x20000000L
+#define ATOM_S3_ALLOW_FAST_PWR_SWITCH   0x40000000L
+#define ATOM_S3_RQST_GPU_USE_MIN_PWR    0x80000000L
+
+/* Byte aligned defintion for BIOS usage */
+#define ATOM_S3_CRT1_ACTIVEb0           0x01
+#define ATOM_S3_LCD1_ACTIVEb0           0x02
+#define ATOM_S3_TV1_ACTIVEb0            0x04
+#define ATOM_S3_DFP1_ACTIVEb0           0x08
+#define ATOM_S3_CRT2_ACTIVEb0           0x10
+#define ATOM_S3_LCD2_ACTIVEb0           0x20
+#define ATOM_S3_TV2_ACTIVEb0            0x40
+#define ATOM_S3_DFP2_ACTIVEb0           0x80
+#define ATOM_S3_CV_ACTIVEb1             0x01
+#define ATOM_S3_DFP3_ACTIVEb1                                          0x02
+#define ATOM_S3_DFP4_ACTIVEb1                                          0x04
+#define ATOM_S3_DFP5_ACTIVEb1                                          0x08
+
+#define ATOM_S3_ACTIVE_CRTC1w0          0xFFF
+
+#define ATOM_S3_CRT1_CRTC_ACTIVEb2      0x01
+#define ATOM_S3_LCD1_CRTC_ACTIVEb2      0x02
+#define ATOM_S3_TV1_CRTC_ACTIVEb2       0x04
+#define ATOM_S3_DFP1_CRTC_ACTIVEb2      0x08
+#define ATOM_S3_CRT2_CRTC_ACTIVEb2      0x10
+#define ATOM_S3_LCD2_CRTC_ACTIVEb2      0x20
+#define ATOM_S3_TV2_CRTC_ACTIVEb2       0x40
+#define ATOM_S3_DFP2_CRTC_ACTIVEb2      0x80
+#define ATOM_S3_CV_CRTC_ACTIVEb3        0x01
+#define ATOM_S3_DFP3_CRTC_ACTIVEb3                     0x02
+#define ATOM_S3_DFP4_CRTC_ACTIVEb3                     0x04
+#define ATOM_S3_DFP5_CRTC_ACTIVEb3                     0x08
+
+#define ATOM_S3_ACTIVE_CRTC2w1          0xFFF
+
+#define ATOM_S3_ASIC_GUI_ENGINE_HUNGb3 0x20
+#define ATOM_S3_ALLOW_FAST_PWR_SWITCHb3 0x40
+#define ATOM_S3_RQST_GPU_USE_MIN_PWRb3  0x80
+
+/*  BIOS_4_SCRATCH Definition */
+#define ATOM_S4_LCD1_PANEL_ID_MASK      0x000000FFL
+#define ATOM_S4_LCD1_REFRESH_MASK       0x0000FF00L
+#define ATOM_S4_LCD1_REFRESH_SHIFT      8
+
+/* Byte aligned defintion for BIOS usage */
+#define ATOM_S4_LCD1_PANEL_ID_MASKb0     0x0FF
+#define ATOM_S4_LCD1_REFRESH_MASKb1              ATOM_S4_LCD1_PANEL_ID_MASKb0
+#define ATOM_S4_VRAM_INFO_MASKb2        ATOM_S4_LCD1_PANEL_ID_MASKb0
+
+/*  BIOS_5_SCRATCH Definition, BIOS_5_SCRATCH is used by Firmware only !!!! */
+#define ATOM_S5_DOS_REQ_CRT1b0          0x01
+#define ATOM_S5_DOS_REQ_LCD1b0          0x02
+#define ATOM_S5_DOS_REQ_TV1b0           0x04
+#define ATOM_S5_DOS_REQ_DFP1b0          0x08
+#define ATOM_S5_DOS_REQ_CRT2b0          0x10
+#define ATOM_S5_DOS_REQ_LCD2b0          0x20
+#define ATOM_S5_DOS_REQ_TV2b0           0x40
+#define ATOM_S5_DOS_REQ_DFP2b0          0x80
+#define ATOM_S5_DOS_REQ_CVb1            0x01
+#define ATOM_S5_DOS_REQ_DFP3b1                                 0x02
+#define ATOM_S5_DOS_REQ_DFP4b1                                 0x04
+#define ATOM_S5_DOS_REQ_DFP5b1                                 0x08
+
+#define ATOM_S5_DOS_REQ_DEVICEw0        0x03FF
+
+#define ATOM_S5_DOS_REQ_CRT1            0x0001
+#define ATOM_S5_DOS_REQ_LCD1            0x0002
+#define ATOM_S5_DOS_REQ_TV1             0x0004
+#define ATOM_S5_DOS_REQ_DFP1            0x0008
+#define ATOM_S5_DOS_REQ_CRT2            0x0010
+#define ATOM_S5_DOS_REQ_LCD2            0x0020
+#define ATOM_S5_DOS_REQ_TV2             0x0040
+#define ATOM_S5_DOS_REQ_DFP2            0x0080
+#define ATOM_S5_DOS_REQ_CV              0x0100
+#define ATOM_S5_DOS_REQ_DFP3                                           0x0200
+#define ATOM_S5_DOS_REQ_DFP4                                           0x0400
+#define ATOM_S5_DOS_REQ_DFP5                                           0x0800
+
+#define ATOM_S5_DOS_FORCE_CRT1b2        ATOM_S5_DOS_REQ_CRT1b0
+#define ATOM_S5_DOS_FORCE_TV1b2         ATOM_S5_DOS_REQ_TV1b0
+#define ATOM_S5_DOS_FORCE_CRT2b2        ATOM_S5_DOS_REQ_CRT2b0
+#define ATOM_S5_DOS_FORCE_CVb3          ATOM_S5_DOS_REQ_CVb1
+#define ATOM_S5_DOS_FORCE_DEVICEw1 \
+       (ATOM_S5_DOS_FORCE_CRT1b2 + ATOM_S5_DOS_FORCE_TV1b2 + \
+        ATOM_S5_DOS_FORCE_CRT2b2 + (ATOM_S5_DOS_FORCE_CVb3 << 8))
+
+/*  BIOS_6_SCRATCH Definition */
+#define ATOM_S6_DEVICE_CHANGE           0x00000001L
+#define ATOM_S6_SCALER_CHANGE           0x00000002L
+#define ATOM_S6_LID_CHANGE              0x00000004L
+#define ATOM_S6_DOCKING_CHANGE          0x00000008L
+#define ATOM_S6_ACC_MODE                0x00000010L
+#define ATOM_S6_EXT_DESKTOP_MODE        0x00000020L
+#define ATOM_S6_LID_STATE               0x00000040L
+#define ATOM_S6_DOCK_STATE              0x00000080L
+#define ATOM_S6_CRITICAL_STATE          0x00000100L
+#define ATOM_S6_HW_I2C_BUSY_STATE       0x00000200L
+#define ATOM_S6_THERMAL_STATE_CHANGE    0x00000400L
+#define ATOM_S6_INTERRUPT_SET_BY_BIOS   0x00000800L
+#define ATOM_S6_REQ_LCD_EXPANSION_FULL         0x00001000L     /* Normal expansion Request bit for LCD */
+#define ATOM_S6_REQ_LCD_EXPANSION_ASPEC_RATIO  0x00002000L     /* Aspect ratio expansion Request bit for LCD */
+
+#define ATOM_S6_DISPLAY_STATE_CHANGE    0x00004000L    /* This bit is recycled when ATOM_BIOS_INFO_BIOS_SCRATCH6_SCL2_REDEFINE is set,previously it's SCL2_H_expansion */
+#define ATOM_S6_I2C_STATE_CHANGE        0x00008000L    /* This bit is recycled,when ATOM_BIOS_INFO_BIOS_SCRATCH6_SCL2_REDEFINE is set,previously it's SCL2_V_expansion */
+
+#define ATOM_S6_ACC_REQ_CRT1            0x00010000L
+#define ATOM_S6_ACC_REQ_LCD1            0x00020000L
+#define ATOM_S6_ACC_REQ_TV1             0x00040000L
+#define ATOM_S6_ACC_REQ_DFP1            0x00080000L
+#define ATOM_S6_ACC_REQ_CRT2            0x00100000L
+#define ATOM_S6_ACC_REQ_LCD2            0x00200000L
+#define ATOM_S6_ACC_REQ_TV2             0x00400000L
+#define ATOM_S6_ACC_REQ_DFP2            0x00800000L
+#define ATOM_S6_ACC_REQ_CV              0x01000000L
+#define ATOM_S6_ACC_REQ_DFP3                                           0x02000000L
+#define ATOM_S6_ACC_REQ_DFP4                                           0x04000000L
+#define ATOM_S6_ACC_REQ_DFP5                                           0x08000000L
+
+#define ATOM_S6_ACC_REQ_MASK                0x0FFF0000L
+#define ATOM_S6_SYSTEM_POWER_MODE_CHANGE    0x10000000L
+#define ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH    0x20000000L
+#define ATOM_S6_VRI_BRIGHTNESS_CHANGE       0x40000000L
+#define ATOM_S6_CONFIG_DISPLAY_CHANGE_MASK  0x80000000L
+
+/* Byte aligned defintion for BIOS usage */
+#define ATOM_S6_DEVICE_CHANGEb0         0x01
+#define ATOM_S6_SCALER_CHANGEb0         0x02
+#define ATOM_S6_LID_CHANGEb0            0x04
+#define ATOM_S6_DOCKING_CHANGEb0        0x08
+#define ATOM_S6_ACC_MODEb0              0x10
+#define ATOM_S6_EXT_DESKTOP_MODEb0      0x20
+#define ATOM_S6_LID_STATEb0             0x40
+#define ATOM_S6_DOCK_STATEb0            0x80
+#define ATOM_S6_CRITICAL_STATEb1        0x01
+#define ATOM_S6_HW_I2C_BUSY_STATEb1     0x02
+#define ATOM_S6_THERMAL_STATE_CHANGEb1  0x04
+#define ATOM_S6_INTERRUPT_SET_BY_BIOSb1 0x08
+#define ATOM_S6_REQ_LCD_EXPANSION_FULLb1        0x10
+#define ATOM_S6_REQ_LCD_EXPANSION_ASPEC_RATIOb1 0x20
+
+#define ATOM_S6_ACC_REQ_CRT1b2          0x01
+#define ATOM_S6_ACC_REQ_LCD1b2          0x02
+#define ATOM_S6_ACC_REQ_TV1b2           0x04
+#define ATOM_S6_ACC_REQ_DFP1b2          0x08
+#define ATOM_S6_ACC_REQ_CRT2b2          0x10
+#define ATOM_S6_ACC_REQ_LCD2b2          0x20
+#define ATOM_S6_ACC_REQ_TV2b2           0x40
+#define ATOM_S6_ACC_REQ_DFP2b2          0x80
+#define ATOM_S6_ACC_REQ_CVb3            0x01
+#define ATOM_S6_ACC_REQ_DFP3b3                                 0x02
+#define ATOM_S6_ACC_REQ_DFP4b3                                 0x04
+#define ATOM_S6_ACC_REQ_DFP5b3                                 0x08
+
+#define ATOM_S6_ACC_REQ_DEVICEw1        ATOM_S5_DOS_REQ_DEVICEw0
+#define ATOM_S6_SYSTEM_POWER_MODE_CHANGEb3 0x10
+#define ATOM_S6_ACC_BLOCK_DISPLAY_SWITCHb3 0x20
+#define ATOM_S6_VRI_BRIGHTNESS_CHANGEb3    0x40
+#define ATOM_S6_CONFIG_DISPLAY_CHANGEb3    0x80
+
+#define ATOM_S6_DEVICE_CHANGE_SHIFT             0
+#define ATOM_S6_SCALER_CHANGE_SHIFT             1
+#define ATOM_S6_LID_CHANGE_SHIFT                2
+#define ATOM_S6_DOCKING_CHANGE_SHIFT            3
+#define ATOM_S6_ACC_MODE_SHIFT                  4
+#define ATOM_S6_EXT_DESKTOP_MODE_SHIFT          5
+#define ATOM_S6_LID_STATE_SHIFT                 6
+#define ATOM_S6_DOCK_STATE_SHIFT                7
+#define ATOM_S6_CRITICAL_STATE_SHIFT            8
+#define ATOM_S6_HW_I2C_BUSY_STATE_SHIFT         9
+#define ATOM_S6_THERMAL_STATE_CHANGE_SHIFT      10
+#define ATOM_S6_INTERRUPT_SET_BY_BIOS_SHIFT     11
+#define ATOM_S6_REQ_SCALER_SHIFT                12
+#define ATOM_S6_REQ_SCALER_ARATIO_SHIFT         13
+#define ATOM_S6_DISPLAY_STATE_CHANGE_SHIFT      14
+#define ATOM_S6_I2C_STATE_CHANGE_SHIFT          15
+#define ATOM_S6_SYSTEM_POWER_MODE_CHANGE_SHIFT  28
+#define ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH_SHIFT  29
+#define ATOM_S6_VRI_BRIGHTNESS_CHANGE_SHIFT     30
+#define ATOM_S6_CONFIG_DISPLAY_CHANGE_SHIFT     31
+
+/*  BIOS_7_SCRATCH Definition, BIOS_7_SCRATCH is used by Firmware only !!!! */
+#define ATOM_S7_DOS_MODE_TYPEb0             0x03
+#define ATOM_S7_DOS_MODE_VGAb0              0x00
+#define ATOM_S7_DOS_MODE_VESAb0             0x01
+#define ATOM_S7_DOS_MODE_EXTb0              0x02
+#define ATOM_S7_DOS_MODE_PIXEL_DEPTHb0      0x0C
+#define ATOM_S7_DOS_MODE_PIXEL_FORMATb0     0xF0
+#define ATOM_S7_DOS_8BIT_DAC_ENb1           0x01
+#define ATOM_S7_DOS_MODE_NUMBERw1           0x0FFFF
+
+#define ATOM_S7_DOS_8BIT_DAC_EN_SHIFT       8
+
+/*  BIOS_8_SCRATCH Definition */
+#define ATOM_S8_I2C_CHANNEL_BUSY_MASK       0x00000FFFF
+#define ATOM_S8_I2C_HW_ENGINE_BUSY_MASK     0x0FFFF0000
+
+#define ATOM_S8_I2C_CHANNEL_BUSY_SHIFT      0
+#define ATOM_S8_I2C_ENGINE_BUSY_SHIFT       16
+
+/*  BIOS_9_SCRATCH Definition */
+#ifndef ATOM_S9_I2C_CHANNEL_COMPLETED_MASK
+#define ATOM_S9_I2C_CHANNEL_COMPLETED_MASK  0x0000FFFF
+#endif
+#ifndef ATOM_S9_I2C_CHANNEL_ABORTED_MASK
+#define ATOM_S9_I2C_CHANNEL_ABORTED_MASK    0xFFFF0000
+#endif
+#ifndef ATOM_S9_I2C_CHANNEL_COMPLETED_SHIFT
+#define ATOM_S9_I2C_CHANNEL_COMPLETED_SHIFT 0
+#endif
+#ifndef ATOM_S9_I2C_CHANNEL_ABORTED_SHIFT
+#define ATOM_S9_I2C_CHANNEL_ABORTED_SHIFT   16
+#endif
+
+#define ATOM_FLAG_SET                         0x20
+#define ATOM_FLAG_CLEAR                       0
+#define CLEAR_ATOM_S6_ACC_MODE \
+       ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
+        ATOM_S6_ACC_MODE_SHIFT | ATOM_FLAG_CLEAR)
+#define SET_ATOM_S6_DEVICE_CHANGE \
+       ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
+        ATOM_S6_DEVICE_CHANGE_SHIFT | ATOM_FLAG_SET)
+#define SET_ATOM_S6_VRI_BRIGHTNESS_CHANGE \
+       ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
+        ATOM_S6_VRI_BRIGHTNESS_CHANGE_SHIFT | ATOM_FLAG_SET)
+#define SET_ATOM_S6_SCALER_CHANGE \
+       ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
+        ATOM_S6_SCALER_CHANGE_SHIFT | ATOM_FLAG_SET)
+#define SET_ATOM_S6_LID_CHANGE \
+       ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
+        ATOM_S6_LID_CHANGE_SHIFT | ATOM_FLAG_SET)
+
+#define SET_ATOM_S6_LID_STATE \
+       ((ATOM_ACC_CHANGE_INFO_DEF << 8) |\
+        ATOM_S6_LID_STATE_SHIFT | ATOM_FLAG_SET)
+#define CLEAR_ATOM_S6_LID_STATE \
+       ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
+        ATOM_S6_LID_STATE_SHIFT | ATOM_FLAG_CLEAR)
+
+#define SET_ATOM_S6_DOCK_CHANGE \
+       ((ATOM_ACC_CHANGE_INFO_DEF << 8)| \
+        ATOM_S6_DOCKING_CHANGE_SHIFT | ATOM_FLAG_SET)
+#define SET_ATOM_S6_DOCK_STATE \
+       ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
+        ATOM_S6_DOCK_STATE_SHIFT | ATOM_FLAG_SET)
+#define CLEAR_ATOM_S6_DOCK_STATE \
+       ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
+        ATOM_S6_DOCK_STATE_SHIFT | ATOM_FLAG_CLEAR)
+
+#define SET_ATOM_S6_THERMAL_STATE_CHANGE \
+       ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
+        ATOM_S6_THERMAL_STATE_CHANGE_SHIFT | ATOM_FLAG_SET)
+#define SET_ATOM_S6_SYSTEM_POWER_MODE_CHANGE \
+       ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
+        ATOM_S6_SYSTEM_POWER_MODE_CHANGE_SHIFT | ATOM_FLAG_SET)
+#define SET_ATOM_S6_INTERRUPT_SET_BY_BIOS \
+       ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
+        ATOM_S6_INTERRUPT_SET_BY_BIOS_SHIFT | ATOM_FLAG_SET)
+
+#define SET_ATOM_S6_CRITICAL_STATE \
+       ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
+        ATOM_S6_CRITICAL_STATE_SHIFT | ATOM_FLAG_SET)
+#define CLEAR_ATOM_S6_CRITICAL_STATE \
+       ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
+        ATOM_S6_CRITICAL_STATE_SHIFT | ATOM_FLAG_CLEAR)
+
+#define SET_ATOM_S6_REQ_SCALER \
+       ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
+        ATOM_S6_REQ_SCALER_SHIFT | ATOM_FLAG_SET)
+#define CLEAR_ATOM_S6_REQ_SCALER \
+       ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
+        ATOM_S6_REQ_SCALER_SHIFT | ATOM_FLAG_CLEAR )
+
+#define SET_ATOM_S6_REQ_SCALER_ARATIO \
+       ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
+        ATOM_S6_REQ_SCALER_ARATIO_SHIFT | ATOM_FLAG_SET )
+#define CLEAR_ATOM_S6_REQ_SCALER_ARATIO \
+       ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
+        ATOM_S6_REQ_SCALER_ARATIO_SHIFT | ATOM_FLAG_CLEAR )
+
+#define SET_ATOM_S6_I2C_STATE_CHANGE \
+       ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
+        ATOM_S6_I2C_STATE_CHANGE_SHIFT | ATOM_FLAG_SET )
+
+#define SET_ATOM_S6_DISPLAY_STATE_CHANGE \
+       ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
+        ATOM_S6_DISPLAY_STATE_CHANGE_SHIFT | ATOM_FLAG_SET )
+
+#define SET_ATOM_S6_DEVICE_RECONFIG \
+       ((ATOM_ACC_CHANGE_INFO_DEF << 8) | \
+        ATOM_S6_CONFIG_DISPLAY_CHANGE_SHIFT | ATOM_FLAG_SET)
+#define CLEAR_ATOM_S0_LCD1 \
+       ((ATOM_DEVICE_CONNECT_INFO_DEF << 8 ) | \
+        ATOM_S0_LCD1_SHIFT | ATOM_FLAG_CLEAR )
+#define SET_ATOM_S7_DOS_8BIT_DAC_EN \
+       ((ATOM_DOS_MODE_INFO_DEF << 8) | \
+        ATOM_S7_DOS_8BIT_DAC_EN_SHIFT | ATOM_FLAG_SET )
+#define CLEAR_ATOM_S7_DOS_8BIT_DAC_EN \
+       ((ATOM_DOS_MODE_INFO_DEF << 8) | \
+        ATOM_S7_DOS_8BIT_DAC_EN_SHIFT | ATOM_FLAG_CLEAR )
+
+/****************************************************************************/
+/* Portion II: Definitinos only used in Driver */
+/****************************************************************************/
+
+/*  Macros used by driver */
+
+#define        GetIndexIntoMasterTable(MasterOrData, FieldName) (((char *)(&((ATOM_MASTER_LIST_OF_##MasterOrData##_TABLES *)0)->FieldName)-(char *)0)/sizeof(USHORT))
+
+#define GET_COMMAND_TABLE_COMMANDSET_REVISION(TABLE_HEADER_OFFSET) ((((ATOM_COMMON_TABLE_HEADER*)TABLE_HEADER_OFFSET)->ucTableFormatRevision)&0x3F)
+#define GET_COMMAND_TABLE_PARAMETER_REVISION(TABLE_HEADER_OFFSET)  ((((ATOM_COMMON_TABLE_HEADER*)TABLE_HEADER_OFFSET)->ucTableContentRevision)&0x3F)
+
+#define GET_DATA_TABLE_MAJOR_REVISION GET_COMMAND_TABLE_COMMANDSET_REVISION
+#define GET_DATA_TABLE_MINOR_REVISION GET_COMMAND_TABLE_PARAMETER_REVISION
+
+/****************************************************************************/
+/* Portion III: Definitinos only used in VBIOS */
+/****************************************************************************/
+#define ATOM_DAC_SRC                                   0x80
+#define ATOM_SRC_DAC1                                  0
+#define ATOM_SRC_DAC2                                  0x80
+
+#ifdef UEFI_BUILD
+#define        USHORT  UTEMP
+#endif
+
+typedef struct _MEMORY_PLLINIT_PARAMETERS {
+       ULONG ulTargetMemoryClock;      /* In 10Khz unit */
+       UCHAR ucAction;         /* not define yet */
+       UCHAR ucFbDiv_Hi;       /* Fbdiv Hi byte */
+       UCHAR ucFbDiv;          /* FB value */
+       UCHAR ucPostDiv;        /* Post div */
+} MEMORY_PLLINIT_PARAMETERS;
+
+#define MEMORY_PLLINIT_PS_ALLOCATION  MEMORY_PLLINIT_PARAMETERS
+
+#define        GPIO_PIN_WRITE                                                                                                  0x01
+#define        GPIO_PIN_READ                                                                                                           0x00
+
+typedef struct _GPIO_PIN_CONTROL_PARAMETERS {
+       UCHAR ucGPIO_ID;        /* return value, read from GPIO pins */
+       UCHAR ucGPIOBitShift;   /* define which bit in uGPIOBitVal need to be update */
+       UCHAR ucGPIOBitVal;     /* Set/Reset corresponding bit defined in ucGPIOBitMask */
+       UCHAR ucAction;         /* =GPIO_PIN_WRITE: Read; =GPIO_PIN_READ: Write */
+} GPIO_PIN_CONTROL_PARAMETERS;
+
+typedef struct _ENABLE_SCALER_PARAMETERS {
+       UCHAR ucScaler;         /*  ATOM_SCALER1, ATOM_SCALER2 */
+       UCHAR ucEnable;         /*  ATOM_SCALER_DISABLE or ATOM_SCALER_CENTER or ATOM_SCALER_EXPANSION */
+       UCHAR ucTVStandard;     /*  */
+       UCHAR ucPadding[1];
+} ENABLE_SCALER_PARAMETERS;
+#define ENABLE_SCALER_PS_ALLOCATION ENABLE_SCALER_PARAMETERS
+
+/* ucEnable: */
+#define SCALER_BYPASS_AUTO_CENTER_NO_REPLICATION    0
+#define SCALER_BYPASS_AUTO_CENTER_AUTO_REPLICATION  1
+#define SCALER_ENABLE_2TAP_ALPHA_MODE               2
+#define SCALER_ENABLE_MULTITAP_MODE                 3
+
+typedef struct _ENABLE_HARDWARE_ICON_CURSOR_PARAMETERS {
+       ULONG usHWIconHorzVertPosn;     /*  Hardware Icon Vertical position */
+       UCHAR ucHWIconVertOffset;       /*  Hardware Icon Vertical offset */
+       UCHAR ucHWIconHorzOffset;       /*  Hardware Icon Horizontal offset */
+       UCHAR ucSelection;      /*  ATOM_CURSOR1 or ATOM_ICON1 or ATOM_CURSOR2 or ATOM_ICON2 */
+       UCHAR ucEnable;         /*  ATOM_ENABLE or ATOM_DISABLE */
+} ENABLE_HARDWARE_ICON_CURSOR_PARAMETERS;
+
+typedef struct _ENABLE_HARDWARE_ICON_CURSOR_PS_ALLOCATION {
+       ENABLE_HARDWARE_ICON_CURSOR_PARAMETERS sEnableIcon;
+       ENABLE_CRTC_PARAMETERS sReserved;
+} ENABLE_HARDWARE_ICON_CURSOR_PS_ALLOCATION;
+
+typedef struct _ENABLE_GRAPH_SURFACE_PARAMETERS {
+       USHORT usHight;         /*  Image Hight */
+       USHORT usWidth;         /*  Image Width */
+       UCHAR ucSurface;        /*  Surface 1 or 2 */
+       UCHAR ucPadding[3];
+} ENABLE_GRAPH_SURFACE_PARAMETERS;
+
+typedef struct _ENABLE_GRAPH_SURFACE_PARAMETERS_V1_2 {
+       USHORT usHight;         /*  Image Hight */
+       USHORT usWidth;         /*  Image Width */
+       UCHAR ucSurface;        /*  Surface 1 or 2 */
+       UCHAR ucEnable;         /*  ATOM_ENABLE or ATOM_DISABLE */
+       UCHAR ucPadding[2];
+} ENABLE_GRAPH_SURFACE_PARAMETERS_V1_2;
+
+typedef struct _ENABLE_GRAPH_SURFACE_PS_ALLOCATION {
+       ENABLE_GRAPH_SURFACE_PARAMETERS sSetSurface;
+       ENABLE_YUV_PS_ALLOCATION sReserved;     /*  Don't set this one */
+} ENABLE_GRAPH_SURFACE_PS_ALLOCATION;
+
+typedef struct _MEMORY_CLEAN_UP_PARAMETERS {
+       USHORT usMemoryStart;   /* in 8Kb boundry, offset from memory base address */
+       USHORT usMemorySize;    /* 8Kb blocks aligned */
+} MEMORY_CLEAN_UP_PARAMETERS;
+#define MEMORY_CLEAN_UP_PS_ALLOCATION MEMORY_CLEAN_UP_PARAMETERS
+
+typedef struct _GET_DISPLAY_SURFACE_SIZE_PARAMETERS {
+       USHORT usX_Size;        /* When use as input parameter, usX_Size indicates which CRTC */
+       USHORT usY_Size;
+} GET_DISPLAY_SURFACE_SIZE_PARAMETERS;
+
+typedef struct _INDIRECT_IO_ACCESS {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       UCHAR IOAccessSequence[256];
+} INDIRECT_IO_ACCESS;
+
+#define INDIRECT_READ              0x00
+#define INDIRECT_WRITE             0x80
+
+#define INDIRECT_IO_MM             0
+#define INDIRECT_IO_PLL            1
+#define INDIRECT_IO_MC             2
+#define INDIRECT_IO_PCIE           3
+#define INDIRECT_IO_PCIEP          4
+#define INDIRECT_IO_NBMISC         5
+
+#define INDIRECT_IO_PLL_READ       INDIRECT_IO_PLL   | INDIRECT_READ
+#define INDIRECT_IO_PLL_WRITE      INDIRECT_IO_PLL   | INDIRECT_WRITE
+#define INDIRECT_IO_MC_READ        INDIRECT_IO_MC    | INDIRECT_READ
+#define INDIRECT_IO_MC_WRITE       INDIRECT_IO_MC    | INDIRECT_WRITE
+#define INDIRECT_IO_PCIE_READ      INDIRECT_IO_PCIE  | INDIRECT_READ
+#define INDIRECT_IO_PCIE_WRITE     INDIRECT_IO_PCIE  | INDIRECT_WRITE
+#define INDIRECT_IO_PCIEP_READ     INDIRECT_IO_PCIEP | INDIRECT_READ
+#define INDIRECT_IO_PCIEP_WRITE    INDIRECT_IO_PCIEP | INDIRECT_WRITE
+#define INDIRECT_IO_NBMISC_READ    INDIRECT_IO_NBMISC | INDIRECT_READ
+#define INDIRECT_IO_NBMISC_WRITE   INDIRECT_IO_NBMISC | INDIRECT_WRITE
+
+typedef struct _ATOM_OEM_INFO {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       ATOM_I2C_ID_CONFIG_ACCESS sucI2cId;
+} ATOM_OEM_INFO;
+
+typedef struct _ATOM_TV_MODE {
+       UCHAR ucVMode_Num;      /* Video mode number */
+       UCHAR ucTV_Mode_Num;    /* Internal TV mode number */
+} ATOM_TV_MODE;
+
+typedef struct _ATOM_BIOS_INT_TVSTD_MODE {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       USHORT usTV_Mode_LUT_Offset;    /*  Pointer to standard to internal number conversion table */
+       USHORT usTV_FIFO_Offset;        /*  Pointer to FIFO entry table */
+       USHORT usNTSC_Tbl_Offset;       /*  Pointer to SDTV_Mode_NTSC table */
+       USHORT usPAL_Tbl_Offset;        /*  Pointer to SDTV_Mode_PAL table */
+       USHORT usCV_Tbl_Offset; /*  Pointer to SDTV_Mode_PAL table */
+} ATOM_BIOS_INT_TVSTD_MODE;
+
+typedef struct _ATOM_TV_MODE_SCALER_PTR {
+       USHORT ucFilter0_Offset;        /* Pointer to filter format 0 coefficients */
+       USHORT usFilter1_Offset;        /* Pointer to filter format 0 coefficients */
+       UCHAR ucTV_Mode_Num;
+} ATOM_TV_MODE_SCALER_PTR;
+
+typedef struct _ATOM_STANDARD_VESA_TIMING {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       ATOM_DTD_FORMAT aModeTimings[16];       /*  16 is not the real array number, just for initial allocation */
+} ATOM_STANDARD_VESA_TIMING;
+
+typedef struct _ATOM_STD_FORMAT {
+       USHORT usSTD_HDisp;
+       USHORT usSTD_VDisp;
+       USHORT usSTD_RefreshRate;
+       USHORT usReserved;
+} ATOM_STD_FORMAT;
+
+typedef struct _ATOM_VESA_TO_EXTENDED_MODE {
+       USHORT usVESA_ModeNumber;
+       USHORT usExtendedModeNumber;
+} ATOM_VESA_TO_EXTENDED_MODE;
+
+typedef struct _ATOM_VESA_TO_INTENAL_MODE_LUT {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       ATOM_VESA_TO_EXTENDED_MODE asVESA_ToExtendedModeInfo[76];
+} ATOM_VESA_TO_INTENAL_MODE_LUT;
+
+/*************** ATOM Memory Related Data Structure ***********************/
+typedef struct _ATOM_MEMORY_VENDOR_BLOCK {
+       UCHAR ucMemoryType;
+       UCHAR ucMemoryVendor;
+       UCHAR ucAdjMCId;
+       UCHAR ucDynClkId;
+       ULONG ulDllResetClkRange;
+} ATOM_MEMORY_VENDOR_BLOCK;
+
+typedef struct _ATOM_MEMORY_SETTING_ID_CONFIG {
+#if ATOM_BIG_ENDIAN
+       ULONG ucMemBlkId:8;
+       ULONG ulMemClockRange:24;
+#else
+       ULONG ulMemClockRange:24;
+       ULONG ucMemBlkId:8;
+#endif
+} ATOM_MEMORY_SETTING_ID_CONFIG;
+
+typedef union _ATOM_MEMORY_SETTING_ID_CONFIG_ACCESS {
+       ATOM_MEMORY_SETTING_ID_CONFIG slAccess;
+       ULONG ulAccess;
+} ATOM_MEMORY_SETTING_ID_CONFIG_ACCESS;
+
+typedef struct _ATOM_MEMORY_SETTING_DATA_BLOCK {
+       ATOM_MEMORY_SETTING_ID_CONFIG_ACCESS ulMemoryID;
+       ULONG aulMemData[1];
+} ATOM_MEMORY_SETTING_DATA_BLOCK;
+
+typedef struct _ATOM_INIT_REG_INDEX_FORMAT {
+       USHORT usRegIndex;      /*  MC register index */
+       UCHAR ucPreRegDataLength;       /*  offset in ATOM_INIT_REG_DATA_BLOCK.saRegDataBuf */
+} ATOM_INIT_REG_INDEX_FORMAT;
+
+typedef struct _ATOM_INIT_REG_BLOCK {
+       USHORT usRegIndexTblSize;       /* size of asRegIndexBuf */
+       USHORT usRegDataBlkSize;        /* size of ATOM_MEMORY_SETTING_DATA_BLOCK */
+       ATOM_INIT_REG_INDEX_FORMAT asRegIndexBuf[1];
+       ATOM_MEMORY_SETTING_DATA_BLOCK asRegDataBuf[1];
+} ATOM_INIT_REG_BLOCK;
+
+#define END_OF_REG_INDEX_BLOCK  0x0ffff
+#define END_OF_REG_DATA_BLOCK   0x00000000
+#define ATOM_INIT_REG_MASK_FLAG 0x80
+#define        CLOCK_RANGE_HIGHEST                     0x00ffffff
+
+#define VALUE_DWORD             SIZEOF ULONG
+#define VALUE_SAME_AS_ABOVE     0
+#define VALUE_MASK_DWORD        0x84
+
+#define INDEX_ACCESS_RANGE_BEGIN           (VALUE_DWORD + 1)
+#define INDEX_ACCESS_RANGE_END             (INDEX_ACCESS_RANGE_BEGIN + 1)
+#define VALUE_INDEX_ACCESS_SINGLE          (INDEX_ACCESS_RANGE_END + 1)
+
+typedef struct _ATOM_MC_INIT_PARAM_TABLE {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       USHORT usAdjustARB_SEQDataOffset;
+       USHORT usMCInitMemTypeTblOffset;
+       USHORT usMCInitCommonTblOffset;
+       USHORT usMCInitPowerDownTblOffset;
+       ULONG ulARB_SEQDataBuf[32];
+       ATOM_INIT_REG_BLOCK asMCInitMemType;
+       ATOM_INIT_REG_BLOCK asMCInitCommon;
+} ATOM_MC_INIT_PARAM_TABLE;
+
+#define _4Mx16              0x2
+#define _4Mx32              0x3
+#define _8Mx16              0x12
+#define _8Mx32              0x13
+#define _16Mx16             0x22
+#define _16Mx32             0x23
+#define _32Mx16             0x32
+#define _32Mx32             0x33
+#define _64Mx8              0x41
+#define _64Mx16             0x42
+
+#define SAMSUNG             0x1
+#define INFINEON            0x2
+#define ELPIDA              0x3
+#define ETRON               0x4
+#define NANYA               0x5
+#define HYNIX               0x6
+#define MOSEL               0x7
+#define WINBOND             0x8
+#define ESMT                0x9
+#define MICRON              0xF
+
+#define QIMONDA             INFINEON
+#define PROMOS              MOSEL
+
+/* ///////////Support for GDDR5 MC uCode to reside in upper 64K of ROM///////////// */
+
+#define UCODE_ROM_START_ADDRESS                0x1c000
+#define        UCODE_SIGNATURE                 0x4375434d      /*  'MCuC' - MC uCode */
+
+/* uCode block header for reference */
+
+typedef struct _MCuCodeHeader {
+       ULONG ulSignature;
+       UCHAR ucRevision;
+       UCHAR ucChecksum;
+       UCHAR ucReserved1;
+       UCHAR ucReserved2;
+       USHORT usParametersLength;
+       USHORT usUCodeLength;
+       USHORT usReserved1;
+       USHORT usReserved2;
+} MCuCodeHeader;
+
+/* //////////////////////////////////////////////////////////////////////////////// */
+
+#define ATOM_MAX_NUMBER_OF_VRAM_MODULE 16
+
+#define ATOM_VRAM_MODULE_MEMORY_VENDOR_ID_MASK 0xF
+typedef struct _ATOM_VRAM_MODULE_V1 {
+       ULONG ulReserved;
+       USHORT usEMRSValue;
+       USHORT usMRSValue;
+       USHORT usReserved;
+       UCHAR ucExtMemoryID;    /*  An external indicator (by hardcode, callback or pin) to tell what is the current memory module */
+       UCHAR ucMemoryType;     /*  [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4;[3:0] reserved; */
+       UCHAR ucMemoryVenderID; /*  Predefined,never change across designs or memory type/vender */
+       UCHAR ucMemoryDeviceCfg;        /*  [7:4]=0x0:4M;=0x1:8M;=0x2:16M;0x3:32M....[3:0]=0x0:x4;=0x1:x8;=0x2:x16;=0x3:x32... */
+       UCHAR ucRow;            /*  Number of Row,in power of 2; */
+       UCHAR ucColumn;         /*  Number of Column,in power of 2; */
+       UCHAR ucBank;           /*  Nunber of Bank; */
+       UCHAR ucRank;           /*  Number of Rank, in power of 2 */
+       UCHAR ucChannelNum;     /*  Number of channel; */
+       UCHAR ucChannelConfig;  /*  [3:0]=Indication of what channel combination;[4:7]=Channel bit width, in number of 2 */
+       UCHAR ucDefaultMVDDQ_ID;        /*  Default MVDDQ setting for this memory block, ID linking to MVDDQ info table to find real set-up data; */
+       UCHAR ucDefaultMVDDC_ID;        /*  Default MVDDC setting for this memory block, ID linking to MVDDC info table to find real set-up data; */
+       UCHAR ucReserved[2];
+} ATOM_VRAM_MODULE_V1;
+
+typedef struct _ATOM_VRAM_MODULE_V2 {
+       ULONG ulReserved;
+       ULONG ulFlags;          /*  To enable/disable functionalities based on memory type */
+       ULONG ulEngineClock;    /*  Override of default engine clock for particular memory type */
+       ULONG ulMemoryClock;    /*  Override of default memory clock for particular memory type */
+       USHORT usEMRS2Value;    /*  EMRS2 Value is used for GDDR2 and GDDR4 memory type */
+       USHORT usEMRS3Value;    /*  EMRS3 Value is used for GDDR2 and GDDR4 memory type */
+       USHORT usEMRSValue;
+       USHORT usMRSValue;
+       USHORT usReserved;
+       UCHAR ucExtMemoryID;    /*  An external indicator (by hardcode, callback or pin) to tell what is the current memory module */
+       UCHAR ucMemoryType;     /*  [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4;[3:0] - must not be used for now; */
+       UCHAR ucMemoryVenderID; /*  Predefined,never change across designs or memory type/vender. If not predefined, vendor detection table gets executed */
+       UCHAR ucMemoryDeviceCfg;        /*  [7:4]=0x0:4M;=0x1:8M;=0x2:16M;0x3:32M....[3:0]=0x0:x4;=0x1:x8;=0x2:x16;=0x3:x32... */
+       UCHAR ucRow;            /*  Number of Row,in power of 2; */
+       UCHAR ucColumn;         /*  Number of Column,in power of 2; */
+       UCHAR ucBank;           /*  Nunber of Bank; */
+       UCHAR ucRank;           /*  Number of Rank, in power of 2 */
+       UCHAR ucChannelNum;     /*  Number of channel; */
+       UCHAR ucChannelConfig;  /*  [3:0]=Indication of what channel combination;[4:7]=Channel bit width, in number of 2 */
+       UCHAR ucDefaultMVDDQ_ID;        /*  Default MVDDQ setting for this memory block, ID linking to MVDDQ info table to find real set-up data; */
+       UCHAR ucDefaultMVDDC_ID;        /*  Default MVDDC setting for this memory block, ID linking to MVDDC info table to find real set-up data; */
+       UCHAR ucRefreshRateFactor;
+       UCHAR ucReserved[3];
+} ATOM_VRAM_MODULE_V2;
+
+typedef struct _ATOM_MEMORY_TIMING_FORMAT {
+       ULONG ulClkRange;       /*  memory clock in 10kHz unit, when target memory clock is below this clock, use this memory timing */
+       union {
+               USHORT usMRS;   /*  mode register */
+               USHORT usDDR3_MR0;
+       };
+       union {
+               USHORT usEMRS;  /*  extended mode register */
+               USHORT usDDR3_MR1;
+       };
+       UCHAR ucCL;             /*  CAS latency */
+       UCHAR ucWL;             /*  WRITE Latency */
+       UCHAR uctRAS;           /*  tRAS */
+       UCHAR uctRC;            /*  tRC */
+       UCHAR uctRFC;           /*  tRFC */
+       UCHAR uctRCDR;          /*  tRCDR */
+       UCHAR uctRCDW;          /*  tRCDW */
+       UCHAR uctRP;            /*  tRP */
+       UCHAR uctRRD;           /*  tRRD */
+       UCHAR uctWR;            /*  tWR */
+       UCHAR uctWTR;           /*  tWTR */
+       UCHAR uctPDIX;          /*  tPDIX */
+       UCHAR uctFAW;           /*  tFAW */
+       UCHAR uctAOND;          /*  tAOND */
+       union {
+               struct {
+                       UCHAR ucflag;   /*  flag to control memory timing calculation. bit0= control EMRS2 Infineon */
+                       UCHAR ucReserved;
+               };
+               USHORT usDDR3_MR2;
+       };
+} ATOM_MEMORY_TIMING_FORMAT;
+
+typedef struct _ATOM_MEMORY_TIMING_FORMAT_V1 {
+       ULONG ulClkRange;       /*  memory clock in 10kHz unit, when target memory clock is below this clock, use this memory timing */
+       USHORT usMRS;           /*  mode register */
+       USHORT usEMRS;          /*  extended mode register */
+       UCHAR ucCL;             /*  CAS latency */
+       UCHAR ucWL;             /*  WRITE Latency */
+       UCHAR uctRAS;           /*  tRAS */
+       UCHAR uctRC;            /*  tRC */
+       UCHAR uctRFC;           /*  tRFC */
+       UCHAR uctRCDR;          /*  tRCDR */
+       UCHAR uctRCDW;          /*  tRCDW */
+       UCHAR uctRP;            /*  tRP */
+       UCHAR uctRRD;           /*  tRRD */
+       UCHAR uctWR;            /*  tWR */
+       UCHAR uctWTR;           /*  tWTR */
+       UCHAR uctPDIX;          /*  tPDIX */
+       UCHAR uctFAW;           /*  tFAW */
+       UCHAR uctAOND;          /*  tAOND */
+       UCHAR ucflag;           /*  flag to control memory timing calculation. bit0= control EMRS2 Infineon */
+/* ///////////////////////GDDR parameters/////////////////////////////////// */
+       UCHAR uctCCDL;          /*  */
+       UCHAR uctCRCRL;         /*  */
+       UCHAR uctCRCWL;         /*  */
+       UCHAR uctCKE;           /*  */
+       UCHAR uctCKRSE;         /*  */
+       UCHAR uctCKRSX;         /*  */
+       UCHAR uctFAW32;         /*  */
+       UCHAR ucReserved1;      /*  */
+       UCHAR ucReserved2;      /*  */
+       UCHAR ucTerminator;
+} ATOM_MEMORY_TIMING_FORMAT_V1;
+
+typedef struct _ATOM_MEMORY_FORMAT {
+       ULONG ulDllDisClock;    /*  memory DLL will be disable when target memory clock is below this clock */
+       union {
+               USHORT usEMRS2Value;    /*  EMRS2 Value is used for GDDR2 and GDDR4 memory type */
+               USHORT usDDR3_Reserved; /*  Not used for DDR3 memory */
+       };
+       union {
+               USHORT usEMRS3Value;    /*  EMRS3 Value is used for GDDR2 and GDDR4 memory type */
+               USHORT usDDR3_MR3;      /*  Used for DDR3 memory */
+       };
+       UCHAR ucMemoryType;     /*  [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4;[3:0] - must not be used for now; */
+       UCHAR ucMemoryVenderID; /*  Predefined,never change across designs or memory type/vender. If not predefined, vendor detection table gets executed */
+       UCHAR ucRow;            /*  Number of Row,in power of 2; */
+       UCHAR ucColumn;         /*  Number of Column,in power of 2; */
+       UCHAR ucBank;           /*  Nunber of Bank; */
+       UCHAR ucRank;           /*  Number of Rank, in power of 2 */
+       UCHAR ucBurstSize;      /*  burst size, 0= burst size=4  1= burst size=8 */
+       UCHAR ucDllDisBit;      /*  position of DLL Enable/Disable bit in EMRS ( Extended Mode Register ) */
+       UCHAR ucRefreshRateFactor;      /*  memory refresh rate in unit of ms */
+       UCHAR ucDensity;        /*  _8Mx32, _16Mx32, _16Mx16, _32Mx16 */
+       UCHAR ucPreamble;       /* [7:4] Write Preamble, [3:0] Read Preamble */
+       UCHAR ucMemAttrib;      /*  Memory Device Addribute, like RDBI/WDBI etc */
+       ATOM_MEMORY_TIMING_FORMAT asMemTiming[5];       /* Memory Timing block sort from lower clock to higher clock */
+} ATOM_MEMORY_FORMAT;
+
+typedef struct _ATOM_VRAM_MODULE_V3 {
+       ULONG ulChannelMapCfg;  /*  board dependent paramenter:Channel combination */
+       USHORT usSize;          /*  size of ATOM_VRAM_MODULE_V3 */
+       USHORT usDefaultMVDDQ;  /*  board dependent parameter:Default Memory Core Voltage */
+       USHORT usDefaultMVDDC;  /*  board dependent parameter:Default Memory IO Voltage */
+       UCHAR ucExtMemoryID;    /*  An external indicator (by hardcode, callback or pin) to tell what is the current memory module */
+       UCHAR ucChannelNum;     /*  board dependent parameter:Number of channel; */
+       UCHAR ucChannelSize;    /*  board dependent parameter:32bit or 64bit */
+       UCHAR ucVREFI;          /*  board dependnt parameter: EXT or INT +160mv to -140mv */
+       UCHAR ucNPL_RT;         /*  board dependent parameter:NPL round trip delay, used for calculate memory timing parameters */
+       UCHAR ucFlag;           /*  To enable/disable functionalities based on memory type */
+       ATOM_MEMORY_FORMAT asMemory;    /*  describ all of video memory parameters from memory spec */
+} ATOM_VRAM_MODULE_V3;
+
+/* ATOM_VRAM_MODULE_V3.ucNPL_RT */
+#define NPL_RT_MASK                                                                                                                    0x0f
+#define BATTERY_ODT_MASK                                                                                               0xc0
+
+#define ATOM_VRAM_MODULE                ATOM_VRAM_MODULE_V3
+
+typedef struct _ATOM_VRAM_MODULE_V4 {
+       ULONG ulChannelMapCfg;  /*  board dependent parameter: Channel combination */
+       USHORT usModuleSize;    /*  size of ATOM_VRAM_MODULE_V4, make it easy for VBIOS to look for next entry of VRAM_MODULE */
+       USHORT usPrivateReserved;       /*  BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! */
+       /*  MC_ARB_RAMCFG (includes NOOFBANK,NOOFRANKS,NOOFROWS,NOOFCOLS) */
+       USHORT usReserved;
+       UCHAR ucExtMemoryID;    /*  An external indicator (by hardcode, callback or pin) to tell what is the current memory module */
+       UCHAR ucMemoryType;     /*  [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4; 0x5:DDR5 [3:0] - Must be 0x0 for now; */
+       UCHAR ucChannelNum;     /*  Number of channels present in this module config */
+       UCHAR ucChannelWidth;   /*  0 - 32 bits; 1 - 64 bits */
+       UCHAR ucDensity;        /*  _8Mx32, _16Mx32, _16Mx16, _32Mx16 */
+       UCHAR ucFlag;           /*  To enable/disable functionalities based on memory type */
+       UCHAR ucMisc;           /*  bit0: 0 - single rank; 1 - dual rank;   bit2: 0 - burstlength 4, 1 - burstlength 8 */
+       UCHAR ucVREFI;          /*  board dependent parameter */
+       UCHAR ucNPL_RT;         /*  board dependent parameter:NPL round trip delay, used for calculate memory timing parameters */
+       UCHAR ucPreamble;       /*  [7:4] Write Preamble, [3:0] Read Preamble */
+       UCHAR ucMemorySize;     /*  BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! */
+       /*  Total memory size in unit of 16MB for CONFIG_MEMSIZE - bit[23:0] zeros */
+       UCHAR ucReserved[3];
+
+/* compare with V3, we flat the struct by merging ATOM_MEMORY_FORMAT (as is) into V4 as the same level */
+       union {
+               USHORT usEMRS2Value;    /*  EMRS2 Value is used for GDDR2 and GDDR4 memory type */
+               USHORT usDDR3_Reserved;
+       };
+       union {
+               USHORT usEMRS3Value;    /*  EMRS3 Value is used for GDDR2 and GDDR4 memory type */
+               USHORT usDDR3_MR3;      /*  Used for DDR3 memory */
+       };
+       UCHAR ucMemoryVenderID; /*  Predefined, If not predefined, vendor detection table gets executed */
+       UCHAR ucRefreshRateFactor;      /*  [1:0]=RefreshFactor (00=8ms, 01=16ms, 10=32ms,11=64ms) */
+       UCHAR ucReserved2[2];
+       ATOM_MEMORY_TIMING_FORMAT asMemTiming[5];       /* Memory Timing block sort from lower clock to higher clock */
+} ATOM_VRAM_MODULE_V4;
+
+#define VRAM_MODULE_V4_MISC_RANK_MASK       0x3
+#define VRAM_MODULE_V4_MISC_DUAL_RANK       0x1
+#define VRAM_MODULE_V4_MISC_BL_MASK         0x4
+#define VRAM_MODULE_V4_MISC_BL8             0x4
+#define VRAM_MODULE_V4_MISC_DUAL_CS         0x10
+
+typedef struct _ATOM_VRAM_MODULE_V5 {
+       ULONG ulChannelMapCfg;  /*  board dependent parameter: Channel combination */
+       USHORT usModuleSize;    /*  size of ATOM_VRAM_MODULE_V4, make it easy for VBIOS to look for next entry of VRAM_MODULE */
+       USHORT usPrivateReserved;       /*  BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! */
+       /*  MC_ARB_RAMCFG (includes NOOFBANK,NOOFRANKS,NOOFROWS,NOOFCOLS) */
+       USHORT usReserved;
+       UCHAR ucExtMemoryID;    /*  An external indicator (by hardcode, callback or pin) to tell what is the current memory module */
+       UCHAR ucMemoryType;     /*  [7:4]=0x1:DDR1;=0x2:DDR2;=0x3:DDR3;=0x4:DDR4; 0x5:DDR5 [3:0] - Must be 0x0 for now; */
+       UCHAR ucChannelNum;     /*  Number of channels present in this module config */
+       UCHAR ucChannelWidth;   /*  0 - 32 bits; 1 - 64 bits */
+       UCHAR ucDensity;        /*  _8Mx32, _16Mx32, _16Mx16, _32Mx16 */
+       UCHAR ucFlag;           /*  To enable/disable functionalities based on memory type */
+       UCHAR ucMisc;           /*  bit0: 0 - single rank; 1 - dual rank;   bit2: 0 - burstlength 4, 1 - burstlength 8 */
+       UCHAR ucVREFI;          /*  board dependent parameter */
+       UCHAR ucNPL_RT;         /*  board dependent parameter:NPL round trip delay, used for calculate memory timing parameters */
+       UCHAR ucPreamble;       /*  [7:4] Write Preamble, [3:0] Read Preamble */
+       UCHAR ucMemorySize;     /*  BIOS internal reserved space to optimize code size, updated by the compiler, shouldn't be modified manually!! */
+       /*  Total memory size in unit of 16MB for CONFIG_MEMSIZE - bit[23:0] zeros */
+       UCHAR ucReserved[3];
+
+/* compare with V3, we flat the struct by merging ATOM_MEMORY_FORMAT (as is) into V4 as the same level */
+       USHORT usEMRS2Value;    /*  EMRS2 Value is used for GDDR2 and GDDR4 memory type */
+       USHORT usEMRS3Value;    /*  EMRS3 Value is used for GDDR2 and GDDR4 memory type */
+       UCHAR ucMemoryVenderID; /*  Predefined, If not predefined, vendor detection table gets executed */
+       UCHAR ucRefreshRateFactor;      /*  [1:0]=RefreshFactor (00=8ms, 01=16ms, 10=32ms,11=64ms) */
+       UCHAR ucFIFODepth;      /*  FIFO depth supposes to be detected during vendor detection, but if we dont do vendor detection we have to hardcode FIFO Depth */
+       UCHAR ucCDR_Bandwidth;  /*  [0:3]=Read CDR bandwidth, [4:7] - Write CDR Bandwidth */
+       ATOM_MEMORY_TIMING_FORMAT_V1 asMemTiming[5];    /* Memory Timing block sort from lower clock to higher clock */
+} ATOM_VRAM_MODULE_V5;
+
+typedef struct _ATOM_VRAM_INFO_V2 {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       UCHAR ucNumOfVRAMModule;
+       ATOM_VRAM_MODULE aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE];     /*  just for allocation, real number of blocks is in ucNumOfVRAMModule; */
+} ATOM_VRAM_INFO_V2;
+
+typedef struct _ATOM_VRAM_INFO_V3 {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       USHORT usMemAdjustTblOffset;    /*  offset of ATOM_INIT_REG_BLOCK structure for memory vendor specific MC adjust setting */
+       USHORT usMemClkPatchTblOffset;  /*      offset of ATOM_INIT_REG_BLOCK structure for memory clock specific MC setting */
+       USHORT usRerseved;
+       UCHAR aVID_PinsShift[9];        /*  8 bit strap maximum+terminator */
+       UCHAR ucNumOfVRAMModule;
+       ATOM_VRAM_MODULE aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE];     /*  just for allocation, real number of blocks is in ucNumOfVRAMModule; */
+       ATOM_INIT_REG_BLOCK asMemPatch; /*  for allocation */
+       /*      ATOM_INIT_REG_BLOCK                              aMemAdjust; */
+} ATOM_VRAM_INFO_V3;
+
+#define        ATOM_VRAM_INFO_LAST          ATOM_VRAM_INFO_V3
+
+typedef struct _ATOM_VRAM_INFO_V4 {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       USHORT usMemAdjustTblOffset;    /*  offset of ATOM_INIT_REG_BLOCK structure for memory vendor specific MC adjust setting */
+       USHORT usMemClkPatchTblOffset;  /*      offset of ATOM_INIT_REG_BLOCK structure for memory clock specific MC setting */
+       USHORT usRerseved;
+       UCHAR ucMemDQ7_0ByteRemap;      /*  DQ line byte remap, =0: Memory Data line BYTE0, =1: BYTE1, =2: BYTE2, =3: BYTE3 */
+       ULONG ulMemDQ7_0BitRemap;       /*  each DQ line ( 7~0) use 3bits, like: DQ0=Bit[2:0], DQ1:[5:3], ... DQ7:[23:21] */
+       UCHAR ucReservde[4];
+       UCHAR ucNumOfVRAMModule;
+       ATOM_VRAM_MODULE_V4 aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE];  /*  just for allocation, real number of blocks is in ucNumOfVRAMModule; */
+       ATOM_INIT_REG_BLOCK asMemPatch; /*  for allocation */
+       /*      ATOM_INIT_REG_BLOCK                              aMemAdjust; */
+} ATOM_VRAM_INFO_V4;
+
+typedef struct _ATOM_VRAM_GPIO_DETECTION_INFO {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       UCHAR aVID_PinsShift[9];        /* 8 bit strap maximum+terminator */
+} ATOM_VRAM_GPIO_DETECTION_INFO;
+
+typedef struct _ATOM_MEMORY_TRAINING_INFO {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       UCHAR ucTrainingLoop;
+       UCHAR ucReserved[3];
+       ATOM_INIT_REG_BLOCK asMemTrainingSetting;
+} ATOM_MEMORY_TRAINING_INFO;
+
+typedef struct SW_I2C_CNTL_DATA_PARAMETERS {
+       UCHAR ucControl;
+       UCHAR ucData;
+       UCHAR ucSatus;
+       UCHAR ucTemp;
+} SW_I2C_CNTL_DATA_PARAMETERS;
+
+#define SW_I2C_CNTL_DATA_PS_ALLOCATION  SW_I2C_CNTL_DATA_PARAMETERS
+
+typedef struct _SW_I2C_IO_DATA_PARAMETERS {
+       USHORT GPIO_Info;
+       UCHAR ucAct;
+       UCHAR ucData;
+} SW_I2C_IO_DATA_PARAMETERS;
+
+#define SW_I2C_IO_DATA_PS_ALLOCATION  SW_I2C_IO_DATA_PARAMETERS
+
+/****************************SW I2C CNTL DEFINITIONS**********************/
+#define SW_I2C_IO_RESET       0
+#define SW_I2C_IO_GET         1
+#define SW_I2C_IO_DRIVE       2
+#define SW_I2C_IO_SET         3
+#define SW_I2C_IO_START       4
+
+#define SW_I2C_IO_CLOCK       0
+#define SW_I2C_IO_DATA        0x80
+
+#define SW_I2C_IO_ZERO        0
+#define SW_I2C_IO_ONE         0x100
+
+#define SW_I2C_CNTL_READ      0
+#define SW_I2C_CNTL_WRITE     1
+#define SW_I2C_CNTL_START     2
+#define SW_I2C_CNTL_STOP      3
+#define SW_I2C_CNTL_OPEN      4
+#define SW_I2C_CNTL_CLOSE     5
+#define SW_I2C_CNTL_WRITE1BIT 6
+
+/* ==============================VESA definition Portion=============================== */
+#define VESA_OEM_PRODUCT_REV                               '01.00'
+#define VESA_MODE_ATTRIBUTE_MODE_SUPPORT            0xBB       /* refer to VBE spec p.32, no TTY support */
+#define VESA_MODE_WIN_ATTRIBUTE                                                     7
+#define VESA_WIN_SIZE                                                                                       64
+
+typedef struct _PTR_32_BIT_STRUCTURE {
+       USHORT Offset16;
+       USHORT Segment16;
+} PTR_32_BIT_STRUCTURE;
+
+typedef union _PTR_32_BIT_UNION {
+       PTR_32_BIT_STRUCTURE SegmentOffset;
+       ULONG Ptr32_Bit;
+} PTR_32_BIT_UNION;
+
+typedef struct _VBE_1_2_INFO_BLOCK_UPDATABLE {
+       UCHAR VbeSignature[4];
+       USHORT VbeVersion;
+       PTR_32_BIT_UNION OemStringPtr;
+       UCHAR Capabilities[4];
+       PTR_32_BIT_UNION VideoModePtr;
+       USHORT TotalMemory;
+} VBE_1_2_INFO_BLOCK_UPDATABLE;
+
+typedef struct _VBE_2_0_INFO_BLOCK_UPDATABLE {
+       VBE_1_2_INFO_BLOCK_UPDATABLE CommonBlock;
+       USHORT OemSoftRev;
+       PTR_32_BIT_UNION OemVendorNamePtr;
+       PTR_32_BIT_UNION OemProductNamePtr;
+       PTR_32_BIT_UNION OemProductRevPtr;
+} VBE_2_0_INFO_BLOCK_UPDATABLE;
+
+typedef union _VBE_VERSION_UNION {
+       VBE_2_0_INFO_BLOCK_UPDATABLE VBE_2_0_InfoBlock;
+       VBE_1_2_INFO_BLOCK_UPDATABLE VBE_1_2_InfoBlock;
+} VBE_VERSION_UNION;
+
+typedef struct _VBE_INFO_BLOCK {
+       VBE_VERSION_UNION UpdatableVBE_Info;
+       UCHAR Reserved[222];
+       UCHAR OemData[256];
+} VBE_INFO_BLOCK;
+
+typedef struct _VBE_FP_INFO {
+       USHORT HSize;
+       USHORT VSize;
+       USHORT FPType;
+       UCHAR RedBPP;
+       UCHAR GreenBPP;
+       UCHAR BlueBPP;
+       UCHAR ReservedBPP;
+       ULONG RsvdOffScrnMemSize;
+       ULONG RsvdOffScrnMEmPtr;
+       UCHAR Reserved[14];
+} VBE_FP_INFO;
+
+typedef struct _VESA_MODE_INFO_BLOCK {
+/*  Mandatory information for all VBE revisions */
+       USHORT ModeAttributes;  /*                  dw      ?       ; mode attributes */
+       UCHAR WinAAttributes;   /*                    db      ?       ; window A attributes */
+       UCHAR WinBAttributes;   /*                    db      ?       ; window B attributes */
+       USHORT WinGranularity;  /*                    dw      ?       ; window granularity */
+       USHORT WinSize;         /*                    dw      ?       ; window size */
+       USHORT WinASegment;     /*                    dw      ?       ; window A start segment */
+       USHORT WinBSegment;     /*                    dw      ?       ; window B start segment */
+       ULONG WinFuncPtr;       /*                    dd      ?       ; real mode pointer to window function */
+       USHORT BytesPerScanLine;        /*                    dw      ?       ; bytes per scan line */
+
+/* ; Mandatory information for VBE 1.2 and above */
+       USHORT XResolution;     /*                         dw      ?       ; horizontal resolution in pixels or characters */
+       USHORT YResolution;     /*                   dw      ?       ; vertical resolution in pixels or characters */
+       UCHAR XCharSize;        /*                   db      ?       ; character cell width in pixels */
+       UCHAR YCharSize;        /*                   db      ?       ; character cell height in pixels */
+       UCHAR NumberOfPlanes;   /*                   db      ?       ; number of memory planes */
+       UCHAR BitsPerPixel;     /*                   db      ?       ; bits per pixel */
+       UCHAR NumberOfBanks;    /*                   db      ?       ; number of banks */
+       UCHAR MemoryModel;      /*                   db      ?       ; memory model type */
+       UCHAR BankSize;         /*                   db      ?       ; bank size in KB */
+       UCHAR NumberOfImagePages;       /*            db    ?       ; number of images */
+       UCHAR ReservedForPageFunction;  /* db  1       ; reserved for page function */
+
+/* ; Direct Color fields(required for direct/6 and YUV/7 memory models) */
+       UCHAR RedMaskSize;      /*           db      ?       ; size of direct color red mask in bits */
+       UCHAR RedFieldPosition; /*           db      ?       ; bit position of lsb of red mask */
+       UCHAR GreenMaskSize;    /*           db      ?       ; size of direct color green mask in bits */
+       UCHAR GreenFieldPosition;       /*           db      ?       ; bit position of lsb of green mask */
+       UCHAR BlueMaskSize;     /*           db      ?       ; size of direct color blue mask in bits */
+       UCHAR BlueFieldPosition;        /*           db      ?       ; bit position of lsb of blue mask */
+       UCHAR RsvdMaskSize;     /*           db      ?       ; size of direct color reserved mask in bits */
+       UCHAR RsvdFieldPosition;        /*           db      ?       ; bit position of lsb of reserved mask */
+       UCHAR DirectColorModeInfo;      /*           db      ?       ; direct color mode attributes */
+
+/* ; Mandatory information for VBE 2.0 and above */
+       ULONG PhysBasePtr;      /*           dd      ?       ; physical address for flat memory frame buffer */
+       ULONG Reserved_1;       /*           dd      0       ; reserved - always set to 0 */
+       USHORT Reserved_2;      /*     dw    0       ; reserved - always set to 0 */
+
+/* ; Mandatory information for VBE 3.0 and above */
+       USHORT LinBytesPerScanLine;     /*         dw      ?       ; bytes per scan line for linear modes */
+       UCHAR BnkNumberOfImagePages;    /*         db      ?       ; number of images for banked modes */
+       UCHAR LinNumberOfImagPages;     /*         db      ?       ; number of images for linear modes */
+       UCHAR LinRedMaskSize;   /*         db      ?       ; size of direct color red mask(linear modes) */
+       UCHAR LinRedFieldPosition;      /*         db      ?       ; bit position of lsb of red mask(linear modes) */
+       UCHAR LinGreenMaskSize; /*         db      ?       ; size of direct color green mask(linear modes) */
+       UCHAR LinGreenFieldPosition;    /*         db      ?       ; bit position of lsb of green mask(linear modes) */
+       UCHAR LinBlueMaskSize;  /*         db      ?       ; size of direct color blue mask(linear modes) */
+       UCHAR LinBlueFieldPosition;     /*         db      ?       ; bit position of lsb of blue mask(linear modes) */
+       UCHAR LinRsvdMaskSize;  /*         db      ?       ; size of direct color reserved mask(linear modes) */
+       UCHAR LinRsvdFieldPosition;     /*         db      ?       ; bit position of lsb of reserved mask(linear modes) */
+       ULONG MaxPixelClock;    /*         dd      ?       ; maximum pixel clock(in Hz) for graphics mode */
+       UCHAR Reserved;         /*         db      190 dup (0) */
+} VESA_MODE_INFO_BLOCK;
+
+/*  BIOS function CALLS */
+#define ATOM_BIOS_EXTENDED_FUNCTION_CODE        0xA0   /*  ATI Extended Function code */
+#define ATOM_BIOS_FUNCTION_COP_MODE             0x00
+#define ATOM_BIOS_FUNCTION_SHORT_QUERY1         0x04
+#define ATOM_BIOS_FUNCTION_SHORT_QUERY2         0x05
+#define ATOM_BIOS_FUNCTION_SHORT_QUERY3         0x06
+#define ATOM_BIOS_FUNCTION_GET_DDC              0x0B
+#define ATOM_BIOS_FUNCTION_ASIC_DSTATE          0x0E
+#define ATOM_BIOS_FUNCTION_DEBUG_PLAY           0x0F
+#define ATOM_BIOS_FUNCTION_STV_STD              0x16
+#define ATOM_BIOS_FUNCTION_DEVICE_DET           0x17
+#define ATOM_BIOS_FUNCTION_DEVICE_SWITCH        0x18
+
+#define ATOM_BIOS_FUNCTION_PANEL_CONTROL        0x82
+#define ATOM_BIOS_FUNCTION_OLD_DEVICE_DET       0x83
+#define ATOM_BIOS_FUNCTION_OLD_DEVICE_SWITCH    0x84
+#define ATOM_BIOS_FUNCTION_HW_ICON              0x8A
+#define ATOM_BIOS_FUNCTION_SET_CMOS             0x8B
+#define SUB_FUNCTION_UPDATE_DISPLAY_INFO        0x8000 /*  Sub function 80 */
+#define SUB_FUNCTION_UPDATE_EXPANSION_INFO      0x8100 /*  Sub function 80 */
+
+#define ATOM_BIOS_FUNCTION_DISPLAY_INFO         0x8D
+#define ATOM_BIOS_FUNCTION_DEVICE_ON_OFF        0x8E
+#define ATOM_BIOS_FUNCTION_VIDEO_STATE          0x8F
+#define ATOM_SUB_FUNCTION_GET_CRITICAL_STATE    0x0300 /*  Sub function 03 */
+#define ATOM_SUB_FUNCTION_GET_LIDSTATE          0x0700 /*  Sub function 7 */
+#define ATOM_SUB_FUNCTION_THERMAL_STATE_NOTICE  0x1400 /*  Notify caller the current thermal state */
+#define ATOM_SUB_FUNCTION_CRITICAL_STATE_NOTICE 0x8300 /*  Notify caller the current critical state */
+#define ATOM_SUB_FUNCTION_SET_LIDSTATE          0x8500 /*  Sub function 85 */
+#define ATOM_SUB_FUNCTION_GET_REQ_DISPLAY_FROM_SBIOS_MODE 0x8900       /*  Sub function 89 */
+#define ATOM_SUB_FUNCTION_INFORM_ADC_SUPPORT    0x9400 /*  Notify caller that ADC is supported */
+
+#define ATOM_BIOS_FUNCTION_VESA_DPMS            0x4F10 /*  Set DPMS */
+#define ATOM_SUB_FUNCTION_SET_DPMS              0x0001 /*  BL: Sub function 01 */
+#define ATOM_SUB_FUNCTION_GET_DPMS              0x0002 /*  BL: Sub function 02 */
+#define ATOM_PARAMETER_VESA_DPMS_ON             0x0000 /*  BH Parameter for DPMS ON. */
+#define ATOM_PARAMETER_VESA_DPMS_STANDBY        0x0100 /*  BH Parameter for DPMS STANDBY */
+#define ATOM_PARAMETER_VESA_DPMS_SUSPEND        0x0200 /*  BH Parameter for DPMS SUSPEND */
+#define ATOM_PARAMETER_VESA_DPMS_OFF            0x0400 /*  BH Parameter for DPMS OFF */
+#define ATOM_PARAMETER_VESA_DPMS_REDUCE_ON      0x0800 /*  BH Parameter for DPMS REDUCE ON (NOT SUPPORTED) */
+
+#define ATOM_BIOS_RETURN_CODE_MASK              0x0000FF00L
+#define ATOM_BIOS_REG_HIGH_MASK                 0x0000FF00L
+#define ATOM_BIOS_REG_LOW_MASK                  0x000000FFL
+
+/*  structure used for VBIOS only */
+
+/* DispOutInfoTable */
+typedef struct _ASIC_TRANSMITTER_INFO {
+       USHORT usTransmitterObjId;
+       USHORT usSupportDevice;
+       UCHAR ucTransmitterCmdTblId;
+       UCHAR ucConfig;
+       UCHAR ucEncoderID;      /* available 1st encoder ( default ) */
+       UCHAR ucOptionEncoderID;        /* available 2nd encoder ( optional ) */
+       UCHAR uc2ndEncoderID;
+       UCHAR ucReserved;
+} ASIC_TRANSMITTER_INFO;
+
+typedef struct _ASIC_ENCODER_INFO {
+       UCHAR ucEncoderID;
+       UCHAR ucEncoderConfig;
+       USHORT usEncoderCmdTblId;
+} ASIC_ENCODER_INFO;
+
+typedef struct _ATOM_DISP_OUT_INFO {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       USHORT ptrTransmitterInfo;
+       USHORT ptrEncoderInfo;
+       ASIC_TRANSMITTER_INFO asTransmitterInfo[1];
+       ASIC_ENCODER_INFO asEncoderInfo[1];
+} ATOM_DISP_OUT_INFO;
+
+/*  DispDevicePriorityInfo */
+typedef struct _ATOM_DISPLAY_DEVICE_PRIORITY_INFO {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       USHORT asDevicePriority[16];
+} ATOM_DISPLAY_DEVICE_PRIORITY_INFO;
+
+/* ProcessAuxChannelTransactionTable */
+typedef struct _PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS {
+       USHORT lpAuxRequest;
+       USHORT lpDataOut;
+       UCHAR ucChannelID;
+       union {
+               UCHAR ucReplyStatus;
+               UCHAR ucDelay;
+       };
+       UCHAR ucDataOutLen;
+       UCHAR ucReserved;
+} PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS;
+
+#define PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION                  PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS
+
+/* GetSinkType */
+
+typedef struct _DP_ENCODER_SERVICE_PARAMETERS {
+       USHORT ucLinkClock;
+       union {
+               UCHAR ucConfig; /*  for DP training command */
+               UCHAR ucI2cId;  /*  use for GET_SINK_TYPE command */
+       };
+       UCHAR ucAction;
+       UCHAR ucStatus;
+       UCHAR ucLaneNum;
+       UCHAR ucReserved[2];
+} DP_ENCODER_SERVICE_PARAMETERS;
+
+/*  ucAction */
+#define ATOM_DP_ACTION_GET_SINK_TYPE                                                   0x01
+#define ATOM_DP_ACTION_TRAINING_START                                                  0x02
+#define ATOM_DP_ACTION_TRAINING_COMPLETE                                       0x03
+#define ATOM_DP_ACTION_TRAINING_PATTERN_SEL                            0x04
+#define ATOM_DP_ACTION_SET_VSWING_PREEMP                                       0x05
+#define ATOM_DP_ACTION_GET_VSWING_PREEMP                                       0x06
+#define ATOM_DP_ACTION_BLANKING                   0x07
+
+/*  ucConfig */
+#define ATOM_DP_CONFIG_ENCODER_SEL_MASK                                                0x03
+#define ATOM_DP_CONFIG_DIG1_ENCODER                                                            0x00
+#define ATOM_DP_CONFIG_DIG2_ENCODER                                                            0x01
+#define ATOM_DP_CONFIG_EXTERNAL_ENCODER                                                0x02
+#define ATOM_DP_CONFIG_LINK_SEL_MASK                                                   0x04
+#define ATOM_DP_CONFIG_LINK_A                                                                                  0x00
+#define ATOM_DP_CONFIG_LINK_B                                                                                  0x04
+
+#define DP_ENCODER_SERVICE_PS_ALLOCATION                               WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS
+
+/*  DP_TRAINING_TABLE */
+#define DPCD_SET_LINKRATE_LANENUM_PATTERN1_TBL_ADDR                            ATOM_DP_TRAINING_TBL_ADDR
+#define DPCD_SET_SS_CNTL_TBL_ADDR                                                                                                      (ATOM_DP_TRAINING_TBL_ADDR + 8 )
+#define DPCD_SET_LANE_VSWING_PREEMP_TBL_ADDR                                                   (ATOM_DP_TRAINING_TBL_ADDR + 16)
+#define DPCD_SET_TRAINING_PATTERN0_TBL_ADDR                                                            (ATOM_DP_TRAINING_TBL_ADDR + 24)
+#define DPCD_SET_TRAINING_PATTERN2_TBL_ADDR                                                            (ATOM_DP_TRAINING_TBL_ADDR + 32)
+#define DPCD_GET_LINKRATE_LANENUM_SS_TBL_ADDR                                                  (ATOM_DP_TRAINING_TBL_ADDR + 40)
+#define        DPCD_GET_LANE_STATUS_ADJUST_TBL_ADDR                                                    (ATOM_DP_TRAINING_TBL_ADDR + 48)
+#define DP_I2C_AUX_DDC_WRITE_START_TBL_ADDR                                                            (ATOM_DP_TRAINING_TBL_ADDR + 60)
+#define DP_I2C_AUX_DDC_WRITE_TBL_ADDR                                                                                  (ATOM_DP_TRAINING_TBL_ADDR + 64)
+#define DP_I2C_AUX_DDC_READ_START_TBL_ADDR                                                             (ATOM_DP_TRAINING_TBL_ADDR + 72)
+#define DP_I2C_AUX_DDC_READ_TBL_ADDR                                                                                   (ATOM_DP_TRAINING_TBL_ADDR + 76)
+#define DP_I2C_AUX_DDC_READ_END_TBL_ADDR                                                                       (ATOM_DP_TRAINING_TBL_ADDR + 80)
+
+typedef struct _PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS {
+       UCHAR ucI2CSpeed;
+       union {
+               UCHAR ucRegIndex;
+               UCHAR ucStatus;
+       };
+       USHORT lpI2CDataOut;
+       UCHAR ucFlag;
+       UCHAR ucTransBytes;
+       UCHAR ucSlaveAddr;
+       UCHAR ucLineNumber;
+} PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS;
+
+#define PROCESS_I2C_CHANNEL_TRANSACTION_PS_ALLOCATION       PROCESS_I2C_CHANNEL_TRANSACTION_PARAMETERS
+
+/* ucFlag */
+#define HW_I2C_WRITE        1
+#define HW_I2C_READ         0
+
+/****************************************************************************/
+/* Portion VI: Definitinos being oboselete */
+/****************************************************************************/
+
+/* ========================================================================================== */
+/* Remove the definitions below when driver is ready! */
+typedef struct _ATOM_DAC_INFO {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       USHORT usMaxFrequency;  /*  in 10kHz unit */
+       USHORT usReserved;
+} ATOM_DAC_INFO;
+
+typedef struct _COMPASSIONATE_DATA {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+
+       /* ==============================  DAC1 portion */
+       UCHAR ucDAC1_BG_Adjustment;
+       UCHAR ucDAC1_DAC_Adjustment;
+       USHORT usDAC1_FORCE_Data;
+       /* ==============================  DAC2 portion */
+       UCHAR ucDAC2_CRT2_BG_Adjustment;
+       UCHAR ucDAC2_CRT2_DAC_Adjustment;
+       USHORT usDAC2_CRT2_FORCE_Data;
+       USHORT usDAC2_CRT2_MUX_RegisterIndex;
+       UCHAR ucDAC2_CRT2_MUX_RegisterInfo;     /* Bit[4:0]=Bit position,Bit[7]=1:Active High;=0 Active Low */
+       UCHAR ucDAC2_NTSC_BG_Adjustment;
+       UCHAR ucDAC2_NTSC_DAC_Adjustment;
+       USHORT usDAC2_TV1_FORCE_Data;
+       USHORT usDAC2_TV1_MUX_RegisterIndex;
+       UCHAR ucDAC2_TV1_MUX_RegisterInfo;      /* Bit[4:0]=Bit position,Bit[7]=1:Active High;=0 Active Low */
+       UCHAR ucDAC2_CV_BG_Adjustment;
+       UCHAR ucDAC2_CV_DAC_Adjustment;
+       USHORT usDAC2_CV_FORCE_Data;
+       USHORT usDAC2_CV_MUX_RegisterIndex;
+       UCHAR ucDAC2_CV_MUX_RegisterInfo;       /* Bit[4:0]=Bit position,Bit[7]=1:Active High;=0 Active Low */
+       UCHAR ucDAC2_PAL_BG_Adjustment;
+       UCHAR ucDAC2_PAL_DAC_Adjustment;
+       USHORT usDAC2_TV2_FORCE_Data;
+} COMPASSIONATE_DATA;
+
+/****************************Supported Device Info Table Definitions**********************/
+/*   ucConnectInfo: */
+/*     [7:4] - connector type */
+/*       = 1   - VGA connector */
+/*       = 2   - DVI-I */
+/*       = 3   - DVI-D */
+/*       = 4   - DVI-A */
+/*       = 5   - SVIDEO */
+/*       = 6   - COMPOSITE */
+/*       = 7   - LVDS */
+/*       = 8   - DIGITAL LINK */
+/*       = 9   - SCART */
+/*       = 0xA - HDMI_type A */
+/*       = 0xB - HDMI_type B */
+/*       = 0xE - Special case1 (DVI+DIN) */
+/*       Others=TBD */
+/*     [3:0] - DAC Associated */
+/*       = 0   - no DAC */
+/*       = 1   - DACA */
+/*       = 2   - DACB */
+/*       = 3   - External DAC */
+/*       Others=TBD */
+/*  */
+
+typedef struct _ATOM_CONNECTOR_INFO {
+#if ATOM_BIG_ENDIAN
+       UCHAR bfConnectorType:4;
+       UCHAR bfAssociatedDAC:4;
+#else
+       UCHAR bfAssociatedDAC:4;
+       UCHAR bfConnectorType:4;
+#endif
+} ATOM_CONNECTOR_INFO;
+
+typedef union _ATOM_CONNECTOR_INFO_ACCESS {
+       ATOM_CONNECTOR_INFO sbfAccess;
+       UCHAR ucAccess;
+} ATOM_CONNECTOR_INFO_ACCESS;
+
+typedef struct _ATOM_CONNECTOR_INFO_I2C {
+       ATOM_CONNECTOR_INFO_ACCESS sucConnectorInfo;
+       ATOM_I2C_ID_CONFIG_ACCESS sucI2cId;
+} ATOM_CONNECTOR_INFO_I2C;
+
+typedef struct _ATOM_SUPPORTED_DEVICES_INFO {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       USHORT usDeviceSupport;
+       ATOM_CONNECTOR_INFO_I2C asConnInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO];
+} ATOM_SUPPORTED_DEVICES_INFO;
+
+#define NO_INT_SRC_MAPPED       0xFF
+
+typedef struct _ATOM_CONNECTOR_INC_SRC_BITMAP {
+       UCHAR ucIntSrcBitmap;
+} ATOM_CONNECTOR_INC_SRC_BITMAP;
+
+typedef struct _ATOM_SUPPORTED_DEVICES_INFO_2 {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       USHORT usDeviceSupport;
+       ATOM_CONNECTOR_INFO_I2C asConnInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO_2];
+       ATOM_CONNECTOR_INC_SRC_BITMAP
+           asIntSrcInfo[ATOM_MAX_SUPPORTED_DEVICE_INFO_2];
+} ATOM_SUPPORTED_DEVICES_INFO_2;
+
+typedef struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       USHORT usDeviceSupport;
+       ATOM_CONNECTOR_INFO_I2C asConnInfo[ATOM_MAX_SUPPORTED_DEVICE];
+       ATOM_CONNECTOR_INC_SRC_BITMAP asIntSrcInfo[ATOM_MAX_SUPPORTED_DEVICE];
+} ATOM_SUPPORTED_DEVICES_INFO_2d1;
+
+#define ATOM_SUPPORTED_DEVICES_INFO_LAST ATOM_SUPPORTED_DEVICES_INFO_2d1
+
+typedef struct _ATOM_MISC_CONTROL_INFO {
+       USHORT usFrequency;
+       UCHAR ucPLL_ChargePump; /*  PLL charge-pump gain control */
+       UCHAR ucPLL_DutyCycle;  /*  PLL duty cycle control */
+       UCHAR ucPLL_VCO_Gain;   /*  PLL VCO gain control */
+       UCHAR ucPLL_VoltageSwing;       /*  PLL driver voltage swing control */
+} ATOM_MISC_CONTROL_INFO;
+
+#define ATOM_MAX_MISC_INFO       4
+
+typedef struct _ATOM_TMDS_INFO {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       USHORT usMaxFrequency;  /*  in 10Khz */
+       ATOM_MISC_CONTROL_INFO asMiscInfo[ATOM_MAX_MISC_INFO];
+} ATOM_TMDS_INFO;
+
+typedef struct _ATOM_ENCODER_ANALOG_ATTRIBUTE {
+       UCHAR ucTVStandard;     /* Same as TV standards defined above, */
+       UCHAR ucPadding[1];
+} ATOM_ENCODER_ANALOG_ATTRIBUTE;
+
+typedef struct _ATOM_ENCODER_DIGITAL_ATTRIBUTE {
+       UCHAR ucAttribute;      /* Same as other digital encoder attributes defined above */
+       UCHAR ucPadding[1];
+} ATOM_ENCODER_DIGITAL_ATTRIBUTE;
+
+typedef union _ATOM_ENCODER_ATTRIBUTE {
+       ATOM_ENCODER_ANALOG_ATTRIBUTE sAlgAttrib;
+       ATOM_ENCODER_DIGITAL_ATTRIBUTE sDigAttrib;
+} ATOM_ENCODER_ATTRIBUTE;
+
+typedef struct _DVO_ENCODER_CONTROL_PARAMETERS {
+       USHORT usPixelClock;
+       USHORT usEncoderID;
+       UCHAR ucDeviceType;     /* Use ATOM_DEVICE_xxx1_Index to indicate device type only. */
+       UCHAR ucAction;         /* ATOM_ENABLE/ATOM_DISABLE/ATOM_HPD_INIT */
+       ATOM_ENCODER_ATTRIBUTE usDevAttr;
+} DVO_ENCODER_CONTROL_PARAMETERS;
+
+typedef struct _DVO_ENCODER_CONTROL_PS_ALLOCATION {
+       DVO_ENCODER_CONTROL_PARAMETERS sDVOEncoder;
+       WRITE_ONE_BYTE_HW_I2C_DATA_PS_ALLOCATION sReserved;     /* Caller doesn't need to init this portion */
+} DVO_ENCODER_CONTROL_PS_ALLOCATION;
+
+#define ATOM_XTMDS_ASIC_SI164_ID        1
+#define ATOM_XTMDS_ASIC_SI178_ID        2
+#define ATOM_XTMDS_ASIC_TFP513_ID       3
+#define ATOM_XTMDS_SUPPORTED_SINGLELINK 0x00000001
+#define ATOM_XTMDS_SUPPORTED_DUALLINK   0x00000002
+#define ATOM_XTMDS_MVPU_FPGA            0x00000004
+
+typedef struct _ATOM_XTMDS_INFO {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       USHORT usSingleLinkMaxFrequency;
+       ATOM_I2C_ID_CONFIG_ACCESS sucI2cId;     /* Point the ID on which I2C is used to control external chip */
+       UCHAR ucXtransimitterID;
+       UCHAR ucSupportedLink;  /*  Bit field, bit0=1, single link supported;bit1=1,dual link supported */
+       UCHAR ucSequnceAlterID; /*  Even with the same external TMDS asic, it's possible that the program seqence alters */
+       /*  due to design. This ID is used to alert driver that the sequence is not "standard"! */
+       UCHAR ucMasterAddress;  /*  Address to control Master xTMDS Chip */
+       UCHAR ucSlaveAddress;   /*  Address to control Slave xTMDS Chip */
+} ATOM_XTMDS_INFO;
+
+typedef struct _DFP_DPMS_STATUS_CHANGE_PARAMETERS {
+       UCHAR ucEnable;         /*  ATOM_ENABLE=On or ATOM_DISABLE=Off */
+       UCHAR ucDevice;         /*  ATOM_DEVICE_DFP1_INDEX.... */
+       UCHAR ucPadding[2];
+} DFP_DPMS_STATUS_CHANGE_PARAMETERS;
+
+/****************************Legacy Power Play Table Definitions **********************/
+
+/* Definitions for ulPowerPlayMiscInfo */
+#define ATOM_PM_MISCINFO_SPLIT_CLOCK                     0x00000000L
+#define ATOM_PM_MISCINFO_USING_MCLK_SRC                  0x00000001L
+#define ATOM_PM_MISCINFO_USING_SCLK_SRC                  0x00000002L
+
+#define ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT            0x00000004L
+#define ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH        0x00000008L
+
+#define ATOM_PM_MISCINFO_LOAD_PERFORMANCE_EN             0x00000010L
+
+#define ATOM_PM_MISCINFO_ENGINE_CLOCK_CONTRL_EN          0x00000020L
+#define ATOM_PM_MISCINFO_MEMORY_CLOCK_CONTRL_EN          0x00000040L
+#define ATOM_PM_MISCINFO_PROGRAM_VOLTAGE                 0x00000080L   /* When this bit set, ucVoltageDropIndex is not an index for GPIO pin, but a voltage ID that SW needs program */
+
+#define ATOM_PM_MISCINFO_ASIC_REDUCED_SPEED_SCLK_EN      0x00000100L
+#define ATOM_PM_MISCINFO_ASIC_DYNAMIC_VOLTAGE_EN         0x00000200L
+#define ATOM_PM_MISCINFO_ASIC_SLEEP_MODE_EN              0x00000400L
+#define ATOM_PM_MISCINFO_LOAD_BALANCE_EN                 0x00000800L
+#define ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE     0x00001000L
+#define ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE 0x00002000L
+#define ATOM_PM_MISCINFO_LOW_LCD_REFRESH_RATE            0x00004000L
+
+#define ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE             0x00008000L
+#define ATOM_PM_MISCINFO_OVER_CLOCK_MODE                 0x00010000L
+#define ATOM_PM_MISCINFO_OVER_DRIVE_MODE                 0x00020000L
+#define ATOM_PM_MISCINFO_POWER_SAVING_MODE               0x00040000L
+#define ATOM_PM_MISCINFO_THERMAL_DIODE_MODE              0x00080000L
+
+#define ATOM_PM_MISCINFO_FRAME_MODULATION_MASK           0x00300000L   /* 0-FM Disable, 1-2 level FM, 2-4 level FM, 3-Reserved */
+#define ATOM_PM_MISCINFO_FRAME_MODULATION_SHIFT          20
+
+#define ATOM_PM_MISCINFO_DYN_CLK_3D_IDLE                 0x00400000L
+#define ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_2      0x00800000L
+#define ATOM_PM_MISCINFO_DYNAMIC_CLOCK_DIVIDER_BY_4      0x01000000L
+#define ATOM_PM_MISCINFO_DYNAMIC_HDP_BLOCK_EN            0x02000000L   /* When set, Dynamic */
+#define ATOM_PM_MISCINFO_DYNAMIC_MC_HOST_BLOCK_EN        0x04000000L   /* When set, Dynamic */
+#define ATOM_PM_MISCINFO_3D_ACCELERATION_EN              0x08000000L   /* When set, This mode is for acceleated 3D mode */
+
+#define ATOM_PM_MISCINFO_POWERPLAY_SETTINGS_GROUP_MASK   0x70000000L   /* 1-Optimal Battery Life Group, 2-High Battery, 3-Balanced, 4-High Performance, 5- Optimal Performance (Default state with Default clocks) */
+#define ATOM_PM_MISCINFO_POWERPLAY_SETTINGS_GROUP_SHIFT  28
+#define ATOM_PM_MISCINFO_ENABLE_BACK_BIAS                0x80000000L
+
+#define ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE            0x00000001L
+#define ATOM_PM_MISCINFO2_MULTI_DISPLAY_SUPPORT          0x00000002L
+#define ATOM_PM_MISCINFO2_DYNAMIC_BACK_BIAS_EN           0x00000004L
+#define ATOM_PM_MISCINFO2_FS3D_OVERDRIVE_INFO            0x00000008L
+#define ATOM_PM_MISCINFO2_FORCEDLOWPWR_MODE              0x00000010L
+#define ATOM_PM_MISCINFO2_VDDCI_DYNAMIC_VOLTAGE_EN       0x00000020L
+#define ATOM_PM_MISCINFO2_VIDEO_PLAYBACK_CAPABLE         0x00000040L   /* If this bit is set in multi-pp mode, then driver will pack up one with the minior power consumption. */
+                                                                     /* If it's not set in any pp mode, driver will use its default logic to pick a pp mode in video playback */
+#define ATOM_PM_MISCINFO2_NOT_VALID_ON_DC                0x00000080L
+#define ATOM_PM_MISCINFO2_STUTTER_MODE_EN                0x00000100L
+#define ATOM_PM_MISCINFO2_UVD_SUPPORT_MODE               0x00000200L
+
+/* ucTableFormatRevision=1 */
+/* ucTableContentRevision=1 */
+typedef struct _ATOM_POWERMODE_INFO {
+       ULONG ulMiscInfo;       /* The power level should be arranged in ascending order */
+       ULONG ulReserved1;      /*  must set to 0 */
+       ULONG ulReserved2;      /*  must set to 0 */
+       USHORT usEngineClock;
+       USHORT usMemoryClock;
+       UCHAR ucVoltageDropIndex;       /*  index to GPIO table */
+       UCHAR ucSelectedPanel_RefreshRate;      /*  panel refresh rate */
+       UCHAR ucMinTemperature;
+       UCHAR ucMaxTemperature;
+       UCHAR ucNumPciELanes;   /*  number of PCIE lanes */
+} ATOM_POWERMODE_INFO;
+
+/* ucTableFormatRevision=2 */
+/* ucTableContentRevision=1 */
+typedef struct _ATOM_POWERMODE_INFO_V2 {
+       ULONG ulMiscInfo;       /* The power level should be arranged in ascending order */
+       ULONG ulMiscInfo2;
+       ULONG ulEngineClock;
+       ULONG ulMemoryClock;
+       UCHAR ucVoltageDropIndex;       /*  index to GPIO table */
+       UCHAR ucSelectedPanel_RefreshRate;      /*  panel refresh rate */
+       UCHAR ucMinTemperature;
+       UCHAR ucMaxTemperature;
+       UCHAR ucNumPciELanes;   /*  number of PCIE lanes */
+} ATOM_POWERMODE_INFO_V2;
+
+/* ucTableFormatRevision=2 */
+/* ucTableContentRevision=2 */
+typedef struct _ATOM_POWERMODE_INFO_V3 {
+       ULONG ulMiscInfo;       /* The power level should be arranged in ascending order */
+       ULONG ulMiscInfo2;
+       ULONG ulEngineClock;
+       ULONG ulMemoryClock;
+       UCHAR ucVoltageDropIndex;       /*  index to Core (VDDC) votage table */
+       UCHAR ucSelectedPanel_RefreshRate;      /*  panel refresh rate */
+       UCHAR ucMinTemperature;
+       UCHAR ucMaxTemperature;
+       UCHAR ucNumPciELanes;   /*  number of PCIE lanes */
+       UCHAR ucVDDCI_VoltageDropIndex; /*  index to VDDCI votage table */
+} ATOM_POWERMODE_INFO_V3;
+
+#define ATOM_MAX_NUMBEROF_POWER_BLOCK  8
+
+#define ATOM_PP_OVERDRIVE_INTBITMAP_AUXWIN            0x01
+#define ATOM_PP_OVERDRIVE_INTBITMAP_OVERDRIVE         0x02
+
+#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_LM63      0x01
+#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_ADM1032   0x02
+#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_ADM1030   0x03
+#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_MUA6649   0x04
+#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_LM64      0x05
+#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_F75375    0x06
+#define ATOM_PP_OVERDRIVE_THERMALCONTROLLER_ASC7512   0x07     /*  Andigilog */
+
+typedef struct _ATOM_POWERPLAY_INFO {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       UCHAR ucOverdriveThermalController;
+       UCHAR ucOverdriveI2cLine;
+       UCHAR ucOverdriveIntBitmap;
+       UCHAR ucOverdriveControllerAddress;
+       UCHAR ucSizeOfPowerModeEntry;
+       UCHAR ucNumOfPowerModeEntries;
+       ATOM_POWERMODE_INFO asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK];
+} ATOM_POWERPLAY_INFO;
+
+typedef struct _ATOM_POWERPLAY_INFO_V2 {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       UCHAR ucOverdriveThermalController;
+       UCHAR ucOverdriveI2cLine;
+       UCHAR ucOverdriveIntBitmap;
+       UCHAR ucOverdriveControllerAddress;
+       UCHAR ucSizeOfPowerModeEntry;
+       UCHAR ucNumOfPowerModeEntries;
+       ATOM_POWERMODE_INFO_V2 asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK];
+} ATOM_POWERPLAY_INFO_V2;
+
+typedef struct _ATOM_POWERPLAY_INFO_V3 {
+       ATOM_COMMON_TABLE_HEADER sHeader;
+       UCHAR ucOverdriveThermalController;
+       UCHAR ucOverdriveI2cLine;
+       UCHAR ucOverdriveIntBitmap;
+       UCHAR ucOverdriveControllerAddress;
+       UCHAR ucSizeOfPowerModeEntry;
+       UCHAR ucNumOfPowerModeEntries;
+       ATOM_POWERMODE_INFO_V3 asPowerPlayInfo[ATOM_MAX_NUMBEROF_POWER_BLOCK];
+} ATOM_POWERPLAY_INFO_V3;
+
+/**************************************************************************/
+
+/*  Following definitions are for compatiblity issue in different SW components. */
+#define ATOM_MASTER_DATA_TABLE_REVISION   0x01
+#define Object_Info                                                                                            Object_Header
+#define        AdjustARB_SEQ                                                                                   MC_InitParameter
+#define        VRAM_GPIO_DetectionInfo                                         VoltageObjectInfo
+#define        ASIC_VDDCI_Info                   ASIC_ProfilingInfo
+#define ASIC_MVDDQ_Info                                                                                MemoryTrainingInfo
+#define SS_Info                           PPLL_SS_Info
+#define ASIC_MVDDC_Info                   ASIC_InternalSS_Info
+#define DispDevicePriorityInfo                                         SaveRestoreInfo
+#define DispOutInfo                                                                                            TV_VideoMode
+
+#define ATOM_ENCODER_OBJECT_TABLE         ATOM_OBJECT_TABLE
+#define ATOM_CONNECTOR_OBJECT_TABLE       ATOM_OBJECT_TABLE
+
+/* New device naming, remove them when both DAL/VBIOS is ready */
+#define DFP2I_OUTPUT_CONTROL_PARAMETERS    CRT1_OUTPUT_CONTROL_PARAMETERS
+#define DFP2I_OUTPUT_CONTROL_PS_ALLOCATION DFP2I_OUTPUT_CONTROL_PARAMETERS
+
+#define DFP1X_OUTPUT_CONTROL_PARAMETERS    CRT1_OUTPUT_CONTROL_PARAMETERS
+#define DFP1X_OUTPUT_CONTROL_PS_ALLOCATION DFP1X_OUTPUT_CONTROL_PARAMETERS
+
+#define DFP1I_OUTPUT_CONTROL_PARAMETERS    DFP1_OUTPUT_CONTROL_PARAMETERS
+#define DFP1I_OUTPUT_CONTROL_PS_ALLOCATION DFP1_OUTPUT_CONTROL_PS_ALLOCATION
+
+#define ATOM_DEVICE_DFP1I_SUPPORT          ATOM_DEVICE_DFP1_SUPPORT
+#define ATOM_DEVICE_DFP1X_SUPPORT          ATOM_DEVICE_DFP2_SUPPORT
+
+#define ATOM_DEVICE_DFP1I_INDEX            ATOM_DEVICE_DFP1_INDEX
+#define ATOM_DEVICE_DFP1X_INDEX            ATOM_DEVICE_DFP2_INDEX
+
+#define ATOM_DEVICE_DFP2I_INDEX            0x00000009
+#define ATOM_DEVICE_DFP2I_SUPPORT          (0x1L << ATOM_DEVICE_DFP2I_INDEX)
+
+#define ATOM_S0_DFP1I                      ATOM_S0_DFP1
+#define ATOM_S0_DFP1X                      ATOM_S0_DFP2
+
+#define ATOM_S0_DFP2I                      0x00200000L
+#define ATOM_S0_DFP2Ib2                    0x20
+
+#define ATOM_S2_DFP1I_DPMS_STATE           ATOM_S2_DFP1_DPMS_STATE
+#define ATOM_S2_DFP1X_DPMS_STATE           ATOM_S2_DFP2_DPMS_STATE
+
+#define ATOM_S2_DFP2I_DPMS_STATE           0x02000000L
+#define ATOM_S2_DFP2I_DPMS_STATEb3         0x02
+
+#define ATOM_S3_DFP2I_ACTIVEb1             0x02
+
+#define ATOM_S3_DFP1I_ACTIVE               ATOM_S3_DFP1_ACTIVE
+#define ATOM_S3_DFP1X_ACTIVE               ATOM_S3_DFP2_ACTIVE
+
+#define ATOM_S3_DFP2I_ACTIVE               0x00000200L
+
+#define ATOM_S3_DFP1I_CRTC_ACTIVE          ATOM_S3_DFP1_CRTC_ACTIVE
+#define ATOM_S3_DFP1X_CRTC_ACTIVE          ATOM_S3_DFP2_CRTC_ACTIVE
+#define ATOM_S3_DFP2I_CRTC_ACTIVE          0x02000000L
+
+#define ATOM_S3_DFP2I_CRTC_ACTIVEb3        0x02
+#define ATOM_S5_DOS_REQ_DFP2Ib1            0x02
+
+#define ATOM_S5_DOS_REQ_DFP2I              0x0200
+#define ATOM_S6_ACC_REQ_DFP1I              ATOM_S6_ACC_REQ_DFP1
+#define ATOM_S6_ACC_REQ_DFP1X              ATOM_S6_ACC_REQ_DFP2
+
+#define ATOM_S6_ACC_REQ_DFP2Ib3            0x02
+#define ATOM_S6_ACC_REQ_DFP2I              0x02000000L
+
+#define TMDS1XEncoderControl               DVOEncoderControl
+#define DFP1XOutputControl                 DVOOutputControl
+
+#define ExternalDFPOutputControl           DFP1XOutputControl
+#define EnableExternalTMDS_Encoder         TMDS1XEncoderControl
+
+#define DFP1IOutputControl                 TMDSAOutputControl
+#define DFP2IOutputControl                 LVTMAOutputControl
+
+#define DAC1_ENCODER_CONTROL_PARAMETERS    DAC_ENCODER_CONTROL_PARAMETERS
+#define DAC1_ENCODER_CONTROL_PS_ALLOCATION DAC_ENCODER_CONTROL_PS_ALLOCATION
+
+#define DAC2_ENCODER_CONTROL_PARAMETERS    DAC_ENCODER_CONTROL_PARAMETERS
+#define DAC2_ENCODER_CONTROL_PS_ALLOCATION DAC_ENCODER_CONTROL_PS_ALLOCATION
+
+#define ucDac1Standard  ucDacStandard
+#define ucDac2Standard  ucDacStandard
+
+#define TMDS1EncoderControl TMDSAEncoderControl
+#define TMDS2EncoderControl LVTMAEncoderControl
+
+#define DFP1OutputControl   TMDSAOutputControl
+#define DFP2OutputControl   LVTMAOutputControl
+#define CRT1OutputControl   DAC1OutputControl
+#define CRT2OutputControl   DAC2OutputControl
+
+/* These two lines will be removed for sure in a few days, will follow up with Michael V. */
+#define EnableLVDS_SS   EnableSpreadSpectrumOnPPLL
+#define ENABLE_LVDS_SS_PARAMETERS_V3  ENABLE_SPREAD_SPECTRUM_ON_PPLL
+
+/*********************************************************************************/
+
+#pragma pack()                 /*  BIOS data must use byte aligment */
+
+#endif /* _ATOMBIOS_H */
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
new file mode 100644 (file)
index 0000000..c0080cc
--- /dev/null
@@ -0,0 +1,695 @@
+/*
+ * Copyright 2007-8 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ */
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/radeon_drm.h>
+#include "radeon_fixed.h"
+#include "radeon.h"
+#include "atom.h"
+#include "atom-bits.h"
+
+static void atombios_lock_crtc(struct drm_crtc *crtc, int lock)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       int index =
+           GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters);
+       ENABLE_CRTC_PS_ALLOCATION args;
+
+       memset(&args, 0, sizeof(args));
+
+       args.ucCRTC = radeon_crtc->crtc_id;
+       args.ucEnable = lock;
+
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+static void atombios_enable_crtc(struct drm_crtc *crtc, int state)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC);
+       ENABLE_CRTC_PS_ALLOCATION args;
+
+       memset(&args, 0, sizeof(args));
+
+       args.ucCRTC = radeon_crtc->crtc_id;
+       args.ucEnable = state;
+
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+static void atombios_enable_crtc_memreq(struct drm_crtc *crtc, int state)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       int index = GetIndexIntoMasterTable(COMMAND, EnableCRTCMemReq);
+       ENABLE_CRTC_PS_ALLOCATION args;
+
+       memset(&args, 0, sizeof(args));
+
+       args.ucCRTC = radeon_crtc->crtc_id;
+       args.ucEnable = state;
+
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+static void atombios_blank_crtc(struct drm_crtc *crtc, int state)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC);
+       BLANK_CRTC_PS_ALLOCATION args;
+
+       memset(&args, 0, sizeof(args));
+
+       args.ucCRTC = radeon_crtc->crtc_id;
+       args.ucBlanking = state;
+
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               if (ASIC_IS_DCE3(rdev))
+                       atombios_enable_crtc_memreq(crtc, 1);
+               atombios_enable_crtc(crtc, 1);
+               atombios_blank_crtc(crtc, 0);
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               atombios_blank_crtc(crtc, 1);
+               atombios_enable_crtc(crtc, 0);
+               if (ASIC_IS_DCE3(rdev))
+                       atombios_enable_crtc_memreq(crtc, 0);
+               break;
+       }
+
+       if (mode != DRM_MODE_DPMS_OFF) {
+               radeon_crtc_load_lut(crtc);
+       }
+}
+
+static void
+atombios_set_crtc_dtd_timing(struct drm_crtc *crtc,
+                            SET_CRTC_USING_DTD_TIMING_PARAMETERS * crtc_param)
+{
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       SET_CRTC_USING_DTD_TIMING_PARAMETERS conv_param;
+       int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming);
+
+       conv_param.usH_Size = cpu_to_le16(crtc_param->usH_Size);
+       conv_param.usH_Blanking_Time =
+           cpu_to_le16(crtc_param->usH_Blanking_Time);
+       conv_param.usV_Size = cpu_to_le16(crtc_param->usV_Size);
+       conv_param.usV_Blanking_Time =
+           cpu_to_le16(crtc_param->usV_Blanking_Time);
+       conv_param.usH_SyncOffset = cpu_to_le16(crtc_param->usH_SyncOffset);
+       conv_param.usH_SyncWidth = cpu_to_le16(crtc_param->usH_SyncWidth);
+       conv_param.usV_SyncOffset = cpu_to_le16(crtc_param->usV_SyncOffset);
+       conv_param.usV_SyncWidth = cpu_to_le16(crtc_param->usV_SyncWidth);
+       conv_param.susModeMiscInfo.usAccess =
+           cpu_to_le16(crtc_param->susModeMiscInfo.usAccess);
+       conv_param.ucCRTC = crtc_param->ucCRTC;
+
+       printk("executing set crtc dtd timing\n");
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&conv_param);
+}
+
+void atombios_crtc_set_timing(struct drm_crtc *crtc,
+                             SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION *
+                             crtc_param)
+{
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION conv_param;
+       int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing);
+
+       conv_param.usH_Total = cpu_to_le16(crtc_param->usH_Total);
+       conv_param.usH_Disp = cpu_to_le16(crtc_param->usH_Disp);
+       conv_param.usH_SyncStart = cpu_to_le16(crtc_param->usH_SyncStart);
+       conv_param.usH_SyncWidth = cpu_to_le16(crtc_param->usH_SyncWidth);
+       conv_param.usV_Total = cpu_to_le16(crtc_param->usV_Total);
+       conv_param.usV_Disp = cpu_to_le16(crtc_param->usV_Disp);
+       conv_param.usV_SyncStart = cpu_to_le16(crtc_param->usV_SyncStart);
+       conv_param.usV_SyncWidth = cpu_to_le16(crtc_param->usV_SyncWidth);
+       conv_param.susModeMiscInfo.usAccess =
+           cpu_to_le16(crtc_param->susModeMiscInfo.usAccess);
+       conv_param.ucCRTC = crtc_param->ucCRTC;
+       conv_param.ucOverscanRight = crtc_param->ucOverscanRight;
+       conv_param.ucOverscanLeft = crtc_param->ucOverscanLeft;
+       conv_param.ucOverscanBottom = crtc_param->ucOverscanBottom;
+       conv_param.ucOverscanTop = crtc_param->ucOverscanTop;
+       conv_param.ucReserved = crtc_param->ucReserved;
+
+       printk("executing set crtc timing\n");
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&conv_param);
+}
+
+void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct drm_encoder *encoder = NULL;
+       struct radeon_encoder *radeon_encoder = NULL;
+       uint8_t frev, crev;
+       int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock);
+       SET_PIXEL_CLOCK_PS_ALLOCATION args;
+       PIXEL_CLOCK_PARAMETERS *spc1_ptr;
+       PIXEL_CLOCK_PARAMETERS_V2 *spc2_ptr;
+       PIXEL_CLOCK_PARAMETERS_V3 *spc3_ptr;
+       uint32_t sclock = mode->clock;
+       uint32_t ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
+       struct radeon_pll *pll;
+       int pll_flags = 0;
+
+       memset(&args, 0, sizeof(args));
+
+       if (ASIC_IS_AVIVO(rdev)) {
+               uint32_t ss_cntl;
+
+               if (ASIC_IS_DCE32(rdev) && mode->clock > 200000)        /* range limits??? */
+                       pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
+               else
+                       pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
+
+               /* disable spread spectrum clocking for now -- thanks Hedy Lamarr */
+               if (radeon_crtc->crtc_id == 0) {
+                       ss_cntl = RREG32(AVIVO_P1PLL_INT_SS_CNTL);
+                       WREG32(AVIVO_P1PLL_INT_SS_CNTL, ss_cntl & ~1);
+               } else {
+                       ss_cntl = RREG32(AVIVO_P2PLL_INT_SS_CNTL);
+                       WREG32(AVIVO_P2PLL_INT_SS_CNTL, ss_cntl & ~1);
+               }
+       } else {
+               pll_flags |= RADEON_PLL_LEGACY;
+
+               if (mode->clock > 200000)       /* range limits??? */
+                       pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
+               else
+                       pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
+
+       }
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               if (encoder->crtc == crtc) {
+                       if (!ASIC_IS_AVIVO(rdev)) {
+                               if (encoder->encoder_type !=
+                                   DRM_MODE_ENCODER_DAC)
+                                       pll_flags |= RADEON_PLL_NO_ODD_POST_DIV;
+                               if (!ASIC_IS_AVIVO(rdev)
+                                   && (encoder->encoder_type ==
+                                       DRM_MODE_ENCODER_LVDS))
+                                       pll_flags |= RADEON_PLL_USE_REF_DIV;
+                       }
+                       radeon_encoder = to_radeon_encoder(encoder);
+               }
+       }
+
+       if (radeon_crtc->crtc_id == 0)
+               pll = &rdev->clock.p1pll;
+       else
+               pll = &rdev->clock.p2pll;
+
+       radeon_compute_pll(pll, mode->clock, &sclock, &fb_div, &frac_fb_div,
+                          &ref_div, &post_div, pll_flags);
+
+       atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev,
+                             &crev);
+
+       switch (frev) {
+       case 1:
+               switch (crev) {
+               case 1:
+                       spc1_ptr = (PIXEL_CLOCK_PARAMETERS *) & args.sPCLKInput;
+                       spc1_ptr->usPixelClock = cpu_to_le16(sclock);
+                       spc1_ptr->usRefDiv = cpu_to_le16(ref_div);
+                       spc1_ptr->usFbDiv = cpu_to_le16(fb_div);
+                       spc1_ptr->ucFracFbDiv = frac_fb_div;
+                       spc1_ptr->ucPostDiv = post_div;
+                       spc1_ptr->ucPpll =
+                           radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
+                       spc1_ptr->ucCRTC = radeon_crtc->crtc_id;
+                       spc1_ptr->ucRefDivSrc = 1;
+                       break;
+               case 2:
+                       spc2_ptr =
+                           (PIXEL_CLOCK_PARAMETERS_V2 *) & args.sPCLKInput;
+                       spc2_ptr->usPixelClock = cpu_to_le16(sclock);
+                       spc2_ptr->usRefDiv = cpu_to_le16(ref_div);
+                       spc2_ptr->usFbDiv = cpu_to_le16(fb_div);
+                       spc2_ptr->ucFracFbDiv = frac_fb_div;
+                       spc2_ptr->ucPostDiv = post_div;
+                       spc2_ptr->ucPpll =
+                           radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
+                       spc2_ptr->ucCRTC = radeon_crtc->crtc_id;
+                       spc2_ptr->ucRefDivSrc = 1;
+                       break;
+               case 3:
+                       if (!encoder)
+                               return;
+                       spc3_ptr =
+                           (PIXEL_CLOCK_PARAMETERS_V3 *) & args.sPCLKInput;
+                       spc3_ptr->usPixelClock = cpu_to_le16(sclock);
+                       spc3_ptr->usRefDiv = cpu_to_le16(ref_div);
+                       spc3_ptr->usFbDiv = cpu_to_le16(fb_div);
+                       spc3_ptr->ucFracFbDiv = frac_fb_div;
+                       spc3_ptr->ucPostDiv = post_div;
+                       spc3_ptr->ucPpll =
+                           radeon_crtc->crtc_id ? ATOM_PPLL2 : ATOM_PPLL1;
+                       spc3_ptr->ucMiscInfo = (radeon_crtc->crtc_id << 2);
+                       spc3_ptr->ucTransmitterId = radeon_encoder->encoder_id;
+                       spc3_ptr->ucEncoderMode =
+                           atombios_get_encoder_mode(encoder);
+                       break;
+               default:
+                       DRM_ERROR("Unknown table version %d %d\n", frev, crev);
+                       return;
+               }
+               break;
+       default:
+               DRM_ERROR("Unknown table version %d %d\n", frev, crev);
+               return;
+       }
+
+       printk("executing set pll\n");
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
+                          struct drm_framebuffer *old_fb)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_framebuffer *radeon_fb;
+       struct drm_gem_object *obj;
+       struct drm_radeon_gem_object *obj_priv;
+       uint64_t fb_location;
+       uint32_t fb_format, fb_pitch_pixels;
+
+       if (!crtc->fb)
+               return -EINVAL;
+
+       radeon_fb = to_radeon_framebuffer(crtc->fb);
+
+       obj = radeon_fb->obj;
+       obj_priv = obj->driver_private;
+
+       if (radeon_gem_object_pin(obj, RADEON_GEM_DOMAIN_VRAM, &fb_location)) {
+               return -EINVAL;
+       }
+
+       switch (crtc->fb->bits_per_pixel) {
+       case 15:
+               fb_format =
+                   AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |
+                   AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555;
+               break;
+       case 16:
+               fb_format =
+                   AVIVO_D1GRPH_CONTROL_DEPTH_16BPP |
+                   AVIVO_D1GRPH_CONTROL_16BPP_RGB565;
+               break;
+       case 24:
+       case 32:
+               fb_format =
+                   AVIVO_D1GRPH_CONTROL_DEPTH_32BPP |
+                   AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888;
+               break;
+       default:
+               DRM_ERROR("Unsupported screen depth %d\n",
+                         crtc->fb->bits_per_pixel);
+               return -EINVAL;
+       }
+
+       /* TODO tiling */
+       if (radeon_crtc->crtc_id == 0)
+               WREG32(AVIVO_D1VGA_CONTROL, 0);
+       else
+               WREG32(AVIVO_D2VGA_CONTROL, 0);
+       WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset,
+              (u32) fb_location);
+       WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS +
+              radeon_crtc->crtc_offset, (u32) fb_location);
+       WREG32(AVIVO_D1GRPH_CONTROL + radeon_crtc->crtc_offset, fb_format);
+
+       WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_X + radeon_crtc->crtc_offset, 0);
+       WREG32(AVIVO_D1GRPH_SURFACE_OFFSET_Y + radeon_crtc->crtc_offset, 0);
+       WREG32(AVIVO_D1GRPH_X_START + radeon_crtc->crtc_offset, 0);
+       WREG32(AVIVO_D1GRPH_Y_START + radeon_crtc->crtc_offset, 0);
+       WREG32(AVIVO_D1GRPH_X_END + radeon_crtc->crtc_offset, crtc->fb->width);
+       WREG32(AVIVO_D1GRPH_Y_END + radeon_crtc->crtc_offset, crtc->fb->height);
+
+       fb_pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8);
+       WREG32(AVIVO_D1GRPH_PITCH + radeon_crtc->crtc_offset, fb_pitch_pixels);
+       WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1);
+
+       WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset,
+              crtc->mode.vdisplay);
+       x &= ~3;
+       y &= ~1;
+       WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset,
+              (x << 16) | y);
+       WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
+              (crtc->mode.hdisplay << 16) | crtc->mode.vdisplay);
+
+       if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)
+               WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset,
+                      AVIVO_D1MODE_INTERLEAVE_EN);
+       else
+               WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
+
+       if (old_fb && old_fb != crtc->fb) {
+               radeon_fb = to_radeon_framebuffer(old_fb);
+               radeon_gem_object_unpin(radeon_fb->obj);
+       }
+       return 0;
+}
+
+int atombios_crtc_mode_set(struct drm_crtc *crtc,
+                          struct drm_display_mode *mode,
+                          struct drm_display_mode *adjusted_mode,
+                          int x, int y, struct drm_framebuffer *old_fb)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct drm_encoder *encoder;
+       SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION crtc_timing;
+
+       /* TODO color tiling */
+       memset(&crtc_timing, 0, sizeof(crtc_timing));
+
+       /* TODO tv */
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+
+       }
+
+       crtc_timing.ucCRTC = radeon_crtc->crtc_id;
+       crtc_timing.usH_Total = adjusted_mode->crtc_htotal;
+       crtc_timing.usH_Disp = adjusted_mode->crtc_hdisplay;
+       crtc_timing.usH_SyncStart = adjusted_mode->crtc_hsync_start;
+       crtc_timing.usH_SyncWidth =
+           adjusted_mode->crtc_hsync_end - adjusted_mode->crtc_hsync_start;
+
+       crtc_timing.usV_Total = adjusted_mode->crtc_vtotal;
+       crtc_timing.usV_Disp = adjusted_mode->crtc_vdisplay;
+       crtc_timing.usV_SyncStart = adjusted_mode->crtc_vsync_start;
+       crtc_timing.usV_SyncWidth =
+           adjusted_mode->crtc_vsync_end - adjusted_mode->crtc_vsync_start;
+
+       if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
+               crtc_timing.susModeMiscInfo.usAccess |= ATOM_VSYNC_POLARITY;
+
+       if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
+               crtc_timing.susModeMiscInfo.usAccess |= ATOM_HSYNC_POLARITY;
+
+       if (adjusted_mode->flags & DRM_MODE_FLAG_CSYNC)
+               crtc_timing.susModeMiscInfo.usAccess |= ATOM_COMPOSITESYNC;
+
+       if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
+               crtc_timing.susModeMiscInfo.usAccess |= ATOM_INTERLACE;
+
+       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               crtc_timing.susModeMiscInfo.usAccess |= ATOM_DOUBLE_CLOCK_MODE;
+
+       atombios_crtc_set_pll(crtc, adjusted_mode);
+       atombios_crtc_set_timing(crtc, &crtc_timing);
+
+       if (ASIC_IS_AVIVO(rdev))
+               atombios_crtc_set_base(crtc, x, y, old_fb);
+       else {
+               if (radeon_crtc->crtc_id == 0) {
+                       SET_CRTC_USING_DTD_TIMING_PARAMETERS crtc_dtd_timing;
+                       memset(&crtc_dtd_timing, 0, sizeof(crtc_dtd_timing));
+
+                       /* setup FP shadow regs on R4xx */
+                       crtc_dtd_timing.ucCRTC = radeon_crtc->crtc_id;
+                       crtc_dtd_timing.usH_Size = adjusted_mode->crtc_hdisplay;
+                       crtc_dtd_timing.usV_Size = adjusted_mode->crtc_vdisplay;
+                       crtc_dtd_timing.usH_Blanking_Time =
+                           adjusted_mode->crtc_hblank_end -
+                           adjusted_mode->crtc_hdisplay;
+                       crtc_dtd_timing.usV_Blanking_Time =
+                           adjusted_mode->crtc_vblank_end -
+                           adjusted_mode->crtc_vdisplay;
+                       crtc_dtd_timing.usH_SyncOffset =
+                           adjusted_mode->crtc_hsync_start -
+                           adjusted_mode->crtc_hdisplay;
+                       crtc_dtd_timing.usV_SyncOffset =
+                           adjusted_mode->crtc_vsync_start -
+                           adjusted_mode->crtc_vdisplay;
+                       crtc_dtd_timing.usH_SyncWidth =
+                           adjusted_mode->crtc_hsync_end -
+                           adjusted_mode->crtc_hsync_start;
+                       crtc_dtd_timing.usV_SyncWidth =
+                           adjusted_mode->crtc_vsync_end -
+                           adjusted_mode->crtc_vsync_start;
+                       /* crtc_dtd_timing.ucH_Border = adjusted_mode->crtc_hborder; */
+                       /* crtc_dtd_timing.ucV_Border = adjusted_mode->crtc_vborder; */
+
+                       if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
+                               crtc_dtd_timing.susModeMiscInfo.usAccess |=
+                                   ATOM_VSYNC_POLARITY;
+
+                       if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
+                               crtc_dtd_timing.susModeMiscInfo.usAccess |=
+                                   ATOM_HSYNC_POLARITY;
+
+                       if (adjusted_mode->flags & DRM_MODE_FLAG_CSYNC)
+                               crtc_dtd_timing.susModeMiscInfo.usAccess |=
+                                   ATOM_COMPOSITESYNC;
+
+                       if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
+                               crtc_dtd_timing.susModeMiscInfo.usAccess |=
+                                   ATOM_INTERLACE;
+
+                       if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)
+                               crtc_dtd_timing.susModeMiscInfo.usAccess |=
+                                   ATOM_DOUBLE_CLOCK_MODE;
+
+                       atombios_set_crtc_dtd_timing(crtc, &crtc_dtd_timing);
+               }
+               radeon_crtc_set_base(crtc, x, y, old_fb);
+               radeon_legacy_atom_set_surface(crtc);
+       }
+       return 0;
+}
+
+static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc,
+                                    struct drm_display_mode *mode,
+                                    struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static void atombios_crtc_prepare(struct drm_crtc *crtc)
+{
+       atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+       atombios_lock_crtc(crtc, 1);
+}
+
+static void atombios_crtc_commit(struct drm_crtc *crtc)
+{
+       atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+       atombios_lock_crtc(crtc, 0);
+}
+
+static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
+       .dpms = atombios_crtc_dpms,
+       .mode_fixup = atombios_crtc_mode_fixup,
+       .mode_set = atombios_crtc_mode_set,
+       .mode_set_base = atombios_crtc_set_base,
+       .prepare = atombios_crtc_prepare,
+       .commit = atombios_crtc_commit,
+};
+
+void radeon_atombios_init_crtc(struct drm_device *dev,
+                              struct radeon_crtc *radeon_crtc)
+{
+       if (radeon_crtc->crtc_id == 1)
+               radeon_crtc->crtc_offset =
+                   AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL;
+       drm_crtc_helper_add(&radeon_crtc->base, &atombios_helper_funcs);
+}
+
+void radeon_init_disp_bw_avivo(struct drm_device *dev,
+                              struct drm_display_mode *mode1,
+                              uint32_t pixel_bytes1,
+                              struct drm_display_mode *mode2,
+                              uint32_t pixel_bytes2)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       fixed20_12 min_mem_eff;
+       fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff;
+       fixed20_12 sclk_ff, mclk_ff;
+       uint32_t dc_lb_memory_split, temp;
+
+       min_mem_eff.full = rfixed_const_8(0);
+       if (rdev->disp_priority == 2) {
+               uint32_t mc_init_misc_lat_timer = 0;
+               if (rdev->family == CHIP_RV515)
+                       mc_init_misc_lat_timer =
+                           RREG32_MC(RV515_MC_INIT_MISC_LAT_TIMER);
+               else if (rdev->family == CHIP_RS690)
+                       mc_init_misc_lat_timer =
+                           RREG32_MC(RS690_MC_INIT_MISC_LAT_TIMER);
+
+               mc_init_misc_lat_timer &=
+                   ~(R300_MC_DISP1R_INIT_LAT_MASK <<
+                     R300_MC_DISP1R_INIT_LAT_SHIFT);
+               mc_init_misc_lat_timer &=
+                   ~(R300_MC_DISP0R_INIT_LAT_MASK <<
+                     R300_MC_DISP0R_INIT_LAT_SHIFT);
+
+               if (mode2)
+                       mc_init_misc_lat_timer |=
+                           (1 << R300_MC_DISP1R_INIT_LAT_SHIFT);
+               if (mode1)
+                       mc_init_misc_lat_timer |=
+                           (1 << R300_MC_DISP0R_INIT_LAT_SHIFT);
+
+               if (rdev->family == CHIP_RV515)
+                       WREG32_MC(RV515_MC_INIT_MISC_LAT_TIMER,
+                                 mc_init_misc_lat_timer);
+               else if (rdev->family == CHIP_RS690)
+                       WREG32_MC(RS690_MC_INIT_MISC_LAT_TIMER,
+                                 mc_init_misc_lat_timer);
+       }
+
+       /*
+        * determine is there is enough bw for current mode
+        */
+       temp_ff.full = rfixed_const(100);
+       mclk_ff.full = rfixed_const(rdev->clock.default_mclk);
+       mclk_ff.full = rfixed_div(mclk_ff, temp_ff);
+       sclk_ff.full = rfixed_const(rdev->clock.default_sclk);
+       sclk_ff.full = rfixed_div(sclk_ff, temp_ff);
+
+       temp = (rdev->mc.vram_width / 8) * (rdev->mc.vram_is_ddr ? 2 : 1);
+       temp_ff.full = rfixed_const(temp);
+       mem_bw.full = rfixed_mul(mclk_ff, temp_ff);
+       mem_bw.full = rfixed_mul(mem_bw, min_mem_eff);
+
+       pix_clk.full = 0;
+       pix_clk2.full = 0;
+       peak_disp_bw.full = 0;
+       if (mode1) {
+               temp_ff.full = rfixed_const(1000);
+               pix_clk.full = rfixed_const(mode1->clock);      /* convert to fixed point */
+               pix_clk.full = rfixed_div(pix_clk, temp_ff);
+               temp_ff.full = rfixed_const(pixel_bytes1);
+               peak_disp_bw.full += rfixed_mul(pix_clk, temp_ff);
+       }
+       if (mode2) {
+               temp_ff.full = rfixed_const(1000);
+               pix_clk2.full = rfixed_const(mode2->clock);     /* convert to fixed point */
+               pix_clk2.full = rfixed_div(pix_clk2, temp_ff);
+               temp_ff.full = rfixed_const(pixel_bytes2);
+               peak_disp_bw.full += rfixed_mul(pix_clk2, temp_ff);
+       }
+
+       if (peak_disp_bw.full >= mem_bw.full) {
+               DRM_ERROR
+                   ("You may not have enough display bandwidth for current mode\n"
+                    "If you have flickering problem, try to lower resolution, refresh rate, or color depth\n");
+               printk("peak disp bw %d, mem_bw %d\n",
+                      rfixed_trunc(peak_disp_bw), rfixed_trunc(mem_bw));
+       }
+
+       /*
+        * Line Buffer Setup
+        * There is a single line buffer shared by both display controllers.
+        * DC_LB_MEMORY_SPLIT controls how that line buffer is shared between the display
+        * controllers.  The paritioning can either be done manually or via one of four
+        * preset allocations specified in bits 1:0:
+        * 0 - line buffer is divided in half and shared between each display controller
+        * 1 - D1 gets 3/4 of the line buffer, D2 gets 1/4
+        * 2 - D1 gets the whole buffer
+        * 3 - D1 gets 1/4 of the line buffer, D2 gets 3/4
+        * Setting bit 2 of DC_LB_MEMORY_SPLIT controls switches to manual allocation mode.
+        * In manual allocation mode, D1 always starts at 0, D1 end/2 is specified in bits
+        * 14:4; D2 allocation follows D1.
+        */
+
+       /* is auto or manual better ? */
+       dc_lb_memory_split =
+           RREG32(AVIVO_DC_LB_MEMORY_SPLIT) & ~AVIVO_DC_LB_MEMORY_SPLIT_MASK;
+       dc_lb_memory_split &= ~AVIVO_DC_LB_MEMORY_SPLIT_SHIFT_MODE;
+#if 1
+       /* auto */
+       if (mode1 && mode2) {
+               if (mode1->hdisplay > mode2->hdisplay) {
+                       if (mode1->hdisplay > 2560)
+                               dc_lb_memory_split |=
+                                   AVIVO_DC_LB_MEMORY_SPLIT_D1_3Q_D2_1Q;
+                       else
+                               dc_lb_memory_split |=
+                                   AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF;
+               } else if (mode2->hdisplay > mode1->hdisplay) {
+                       if (mode2->hdisplay > 2560)
+                               dc_lb_memory_split |=
+                                   AVIVO_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q;
+                       else
+                               dc_lb_memory_split |=
+                                   AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF;
+               } else
+                       dc_lb_memory_split |=
+                           AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF;
+       } else if (mode1) {
+               dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_D1_ONLY;
+       } else if (mode2) {
+               dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q;
+       }
+#else
+       /* manual */
+       dc_lb_memory_split |= AVIVO_DC_LB_MEMORY_SPLIT_SHIFT_MODE;
+       dc_lb_memory_split &=
+           ~(AVIVO_DC_LB_DISP1_END_ADR_MASK <<
+             AVIVO_DC_LB_DISP1_END_ADR_SHIFT);
+       if (mode1) {
+               dc_lb_memory_split |=
+                   ((((mode1->hdisplay / 2) + 64) & AVIVO_DC_LB_DISP1_END_ADR_MASK)
+                    << AVIVO_DC_LB_DISP1_END_ADR_SHIFT);
+       } else if (mode2) {
+               dc_lb_memory_split |= (0 << AVIVO_DC_LB_DISP1_END_ADR_SHIFT);
+       }
+#endif
+       WREG32(AVIVO_DC_LB_MEMORY_SPLIT, dc_lb_memory_split);
+}
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
new file mode 100644 (file)
index 0000000..5225f5b
--- /dev/null
@@ -0,0 +1,1524 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ *          Jerome Glisse
+ */
+#include <linux/seq_file.h>
+#include "drmP.h"
+#include "drm.h"
+#include "radeon_drm.h"
+#include "radeon_microcode.h"
+#include "radeon_reg.h"
+#include "radeon.h"
+
+/* This files gather functions specifics to:
+ * r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280
+ *
+ * Some of these functions might be used by newer ASICs.
+ */
+void r100_hdp_reset(struct radeon_device *rdev);
+void r100_gpu_init(struct radeon_device *rdev);
+int r100_gui_wait_for_idle(struct radeon_device *rdev);
+int r100_mc_wait_for_idle(struct radeon_device *rdev);
+void r100_gpu_wait_for_vsync(struct radeon_device *rdev);
+void r100_gpu_wait_for_vsync2(struct radeon_device *rdev);
+int r100_debugfs_mc_info_init(struct radeon_device *rdev);
+
+
+/*
+ * PCI GART
+ */
+void r100_pci_gart_tlb_flush(struct radeon_device *rdev)
+{
+       /* TODO: can we do somethings here ? */
+       /* It seems hw only cache one entry so we should discard this
+        * entry otherwise if first GPU GART read hit this entry it
+        * could end up in wrong address. */
+}
+
+int r100_pci_gart_enable(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+       int r;
+
+       /* Initialize common gart structure */
+       r = radeon_gart_init(rdev);
+       if (r) {
+               return r;
+       }
+       if (rdev->gart.table.ram.ptr == NULL) {
+               rdev->gart.table_size = rdev->gart.num_gpu_pages * 4;
+               r = radeon_gart_table_ram_alloc(rdev);
+               if (r) {
+                       return r;
+               }
+       }
+       /* discard memory request outside of configured range */
+       tmp = RREG32(RADEON_AIC_CNTL) | RADEON_DIS_OUT_OF_PCI_GART_ACCESS;
+       WREG32(RADEON_AIC_CNTL, tmp);
+       /* set address range for PCI address translate */
+       WREG32(RADEON_AIC_LO_ADDR, rdev->mc.gtt_location);
+       tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1;
+       WREG32(RADEON_AIC_HI_ADDR, tmp);
+       /* Enable bus mastering */
+       tmp = RREG32(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
+       WREG32(RADEON_BUS_CNTL, tmp);
+       /* set PCI GART page-table base address */
+       WREG32(RADEON_AIC_PT_BASE, rdev->gart.table_addr);
+       tmp = RREG32(RADEON_AIC_CNTL) | RADEON_PCIGART_TRANSLATE_EN;
+       WREG32(RADEON_AIC_CNTL, tmp);
+       r100_pci_gart_tlb_flush(rdev);
+       rdev->gart.ready = true;
+       return 0;
+}
+
+void r100_pci_gart_disable(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+
+       /* discard memory request outside of configured range */
+       tmp = RREG32(RADEON_AIC_CNTL) | RADEON_DIS_OUT_OF_PCI_GART_ACCESS;
+       WREG32(RADEON_AIC_CNTL, tmp & ~RADEON_PCIGART_TRANSLATE_EN);
+       WREG32(RADEON_AIC_LO_ADDR, 0);
+       WREG32(RADEON_AIC_HI_ADDR, 0);
+}
+
+int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)
+{
+       if (i < 0 || i > rdev->gart.num_gpu_pages) {
+               return -EINVAL;
+       }
+       rdev->gart.table.ram.ptr[i] = cpu_to_le32((uint32_t)addr);
+       return 0;
+}
+
+int r100_gart_enable(struct radeon_device *rdev)
+{
+       if (rdev->flags & RADEON_IS_AGP) {
+               r100_pci_gart_disable(rdev);
+               return 0;
+       }
+       return r100_pci_gart_enable(rdev);
+}
+
+
+/*
+ * MC
+ */
+void r100_mc_disable_clients(struct radeon_device *rdev)
+{
+       uint32_t ov0_scale_cntl, crtc_ext_cntl, crtc_gen_cntl, crtc2_gen_cntl;
+
+       /* FIXME: is this function correct for rs100,rs200,rs300 ? */
+       if (r100_gui_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait GUI idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+
+       /* stop display and memory access */
+       ov0_scale_cntl = RREG32(RADEON_OV0_SCALE_CNTL);
+       WREG32(RADEON_OV0_SCALE_CNTL, ov0_scale_cntl & ~RADEON_SCALER_ENABLE);
+       crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL);
+       WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl | RADEON_CRTC_DISPLAY_DIS);
+       crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL);
+
+       r100_gpu_wait_for_vsync(rdev);
+
+       WREG32(RADEON_CRTC_GEN_CNTL,
+              (crtc_gen_cntl & ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_ICON_EN)) |
+              RADEON_CRTC_DISP_REQ_EN_B | RADEON_CRTC_EXT_DISP_EN);
+
+       if (!(rdev->flags & RADEON_SINGLE_CRTC)) {
+               crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL);
+
+               r100_gpu_wait_for_vsync2(rdev);
+               WREG32(RADEON_CRTC2_GEN_CNTL,
+                      (crtc2_gen_cntl &
+                       ~(RADEON_CRTC2_CUR_EN | RADEON_CRTC2_ICON_EN)) |
+                      RADEON_CRTC2_DISP_REQ_EN_B);
+       }
+
+       udelay(500);
+}
+
+void r100_mc_setup(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+       int r;
+
+       r = r100_debugfs_mc_info_init(rdev);
+       if (r) {
+               DRM_ERROR("Failed to register debugfs file for R100 MC !\n");
+       }
+       /* Write VRAM size in case we are limiting it */
+       WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size);
+       tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1;
+       tmp = REG_SET(RADEON_MC_FB_TOP, tmp >> 16);
+       tmp |= REG_SET(RADEON_MC_FB_START, rdev->mc.vram_location >> 16);
+       WREG32(RADEON_MC_FB_LOCATION, tmp);
+
+       /* Enable bus mastering */
+       tmp = RREG32(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
+       WREG32(RADEON_BUS_CNTL, tmp);
+
+       if (rdev->flags & RADEON_IS_AGP) {
+               tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1;
+               tmp = REG_SET(RADEON_MC_AGP_TOP, tmp >> 16);
+               tmp |= REG_SET(RADEON_MC_AGP_START, rdev->mc.gtt_location >> 16);
+               WREG32(RADEON_MC_AGP_LOCATION, tmp);
+               WREG32(RADEON_AGP_BASE, rdev->mc.agp_base);
+       } else {
+               WREG32(RADEON_MC_AGP_LOCATION, 0x0FFFFFFF);
+               WREG32(RADEON_AGP_BASE, 0);
+       }
+
+       tmp = RREG32(RADEON_HOST_PATH_CNTL) & RADEON_HDP_APER_CNTL;
+       tmp |= (7 << 28);
+       WREG32(RADEON_HOST_PATH_CNTL, tmp | RADEON_HDP_SOFT_RESET | RADEON_HDP_READ_BUFFER_INVALIDATE);
+       (void)RREG32(RADEON_HOST_PATH_CNTL);
+       WREG32(RADEON_HOST_PATH_CNTL, tmp);
+       (void)RREG32(RADEON_HOST_PATH_CNTL);
+}
+
+int r100_mc_init(struct radeon_device *rdev)
+{
+       int r;
+
+       if (r100_debugfs_rbbm_init(rdev)) {
+               DRM_ERROR("Failed to register debugfs file for RBBM !\n");
+       }
+
+       r100_gpu_init(rdev);
+       /* Disable gart which also disable out of gart access */
+       r100_pci_gart_disable(rdev);
+
+       /* Setup GPU memory space */
+       rdev->mc.vram_location = 0xFFFFFFFFUL;
+       rdev->mc.gtt_location = 0xFFFFFFFFUL;
+       if (rdev->flags & RADEON_IS_AGP) {
+               r = radeon_agp_init(rdev);
+               if (r) {
+                       printk(KERN_WARNING "[drm] Disabling AGP\n");
+                       rdev->flags &= ~RADEON_IS_AGP;
+                       rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024;
+               } else {
+                       rdev->mc.gtt_location = rdev->mc.agp_base;
+               }
+       }
+       r = radeon_mc_setup(rdev);
+       if (r) {
+               return r;
+       }
+
+       r100_mc_disable_clients(rdev);
+       if (r100_mc_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait MC idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+
+       r100_mc_setup(rdev);
+       return 0;
+}
+
+void r100_mc_fini(struct radeon_device *rdev)
+{
+       r100_pci_gart_disable(rdev);
+       radeon_gart_table_ram_free(rdev);
+       radeon_gart_fini(rdev);
+}
+
+
+/*
+ * Fence emission
+ */
+void r100_fence_ring_emit(struct radeon_device *rdev,
+                         struct radeon_fence *fence)
+{
+       /* Who ever call radeon_fence_emit should call ring_lock and ask
+        * for enough space (today caller are ib schedule and buffer move) */
+       /* Wait until IDLE & CLEAN */
+       radeon_ring_write(rdev, PACKET0(0x1720, 0));
+       radeon_ring_write(rdev, (1 << 16) | (1 << 17));
+       /* Emit fence sequence & fire IRQ */
+       radeon_ring_write(rdev, PACKET0(rdev->fence_drv.scratch_reg, 0));
+       radeon_ring_write(rdev, fence->seq);
+       radeon_ring_write(rdev, PACKET0(RADEON_GEN_INT_STATUS, 0));
+       radeon_ring_write(rdev, RADEON_SW_INT_FIRE);
+}
+
+
+/*
+ * Writeback
+ */
+int r100_wb_init(struct radeon_device *rdev)
+{
+       int r;
+
+       if (rdev->wb.wb_obj == NULL) {
+               r = radeon_object_create(rdev, NULL, 4096,
+                                        true,
+                                        RADEON_GEM_DOMAIN_GTT,
+                                        false, &rdev->wb.wb_obj);
+               if (r) {
+                       DRM_ERROR("radeon: failed to create WB buffer (%d).\n", r);
+                       return r;
+               }
+               r = radeon_object_pin(rdev->wb.wb_obj,
+                                     RADEON_GEM_DOMAIN_GTT,
+                                     &rdev->wb.gpu_addr);
+               if (r) {
+                       DRM_ERROR("radeon: failed to pin WB buffer (%d).\n", r);
+                       return r;
+               }
+               r = radeon_object_kmap(rdev->wb.wb_obj, (void **)&rdev->wb.wb);
+               if (r) {
+                       DRM_ERROR("radeon: failed to map WB buffer (%d).\n", r);
+                       return r;
+               }
+       }
+       WREG32(0x774, rdev->wb.gpu_addr);
+       WREG32(0x70C, rdev->wb.gpu_addr + 1024);
+       WREG32(0x770, 0xff);
+       return 0;
+}
+
+void r100_wb_fini(struct radeon_device *rdev)
+{
+       if (rdev->wb.wb_obj) {
+               radeon_object_kunmap(rdev->wb.wb_obj);
+               radeon_object_unpin(rdev->wb.wb_obj);
+               radeon_object_unref(&rdev->wb.wb_obj);
+               rdev->wb.wb = NULL;
+               rdev->wb.wb_obj = NULL;
+       }
+}
+
+int r100_copy_blit(struct radeon_device *rdev,
+                  uint64_t src_offset,
+                  uint64_t dst_offset,
+                  unsigned num_pages,
+                  struct radeon_fence *fence)
+{
+       uint32_t cur_pages;
+       uint32_t stride_bytes = PAGE_SIZE;
+       uint32_t pitch;
+       uint32_t stride_pixels;
+       unsigned ndw;
+       int num_loops;
+       int r = 0;
+
+       /* radeon limited to 16k stride */
+       stride_bytes &= 0x3fff;
+       /* radeon pitch is /64 */
+       pitch = stride_bytes / 64;
+       stride_pixels = stride_bytes / 4;
+       num_loops = DIV_ROUND_UP(num_pages, 8191);
+
+       /* Ask for enough room for blit + flush + fence */
+       ndw = 64 + (10 * num_loops);
+       r = radeon_ring_lock(rdev, ndw);
+       if (r) {
+               DRM_ERROR("radeon: moving bo (%d) asking for %u dw.\n", r, ndw);
+               return -EINVAL;
+       }
+       while (num_pages > 0) {
+               cur_pages = num_pages;
+               if (cur_pages > 8191) {
+                       cur_pages = 8191;
+               }
+               num_pages -= cur_pages;
+
+               /* pages are in Y direction - height
+                  page width in X direction - width */
+               radeon_ring_write(rdev, PACKET3(PACKET3_BITBLT_MULTI, 8));
+               radeon_ring_write(rdev,
+                                 RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
+                                 RADEON_GMC_DST_PITCH_OFFSET_CNTL |
+                                 RADEON_GMC_SRC_CLIPPING |
+                                 RADEON_GMC_DST_CLIPPING |
+                                 RADEON_GMC_BRUSH_NONE |
+                                 (RADEON_COLOR_FORMAT_ARGB8888 << 8) |
+                                 RADEON_GMC_SRC_DATATYPE_COLOR |
+                                 RADEON_ROP3_S |
+                                 RADEON_DP_SRC_SOURCE_MEMORY |
+                                 RADEON_GMC_CLR_CMP_CNTL_DIS |
+                                 RADEON_GMC_WR_MSK_DIS);
+               radeon_ring_write(rdev, (pitch << 22) | (src_offset >> 10));
+               radeon_ring_write(rdev, (pitch << 22) | (dst_offset >> 10));
+               radeon_ring_write(rdev, (0x1fff) | (0x1fff << 16));
+               radeon_ring_write(rdev, 0);
+               radeon_ring_write(rdev, (0x1fff) | (0x1fff << 16));
+               radeon_ring_write(rdev, num_pages);
+               radeon_ring_write(rdev, num_pages);
+               radeon_ring_write(rdev, cur_pages | (stride_pixels << 16));
+       }
+       radeon_ring_write(rdev, PACKET0(RADEON_DSTCACHE_CTLSTAT, 0));
+       radeon_ring_write(rdev, RADEON_RB2D_DC_FLUSH_ALL);
+       radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0));
+       radeon_ring_write(rdev,
+                         RADEON_WAIT_2D_IDLECLEAN |
+                         RADEON_WAIT_HOST_IDLECLEAN |
+                         RADEON_WAIT_DMA_GUI_IDLE);
+       if (fence) {
+               r = radeon_fence_emit(rdev, fence);
+       }
+       radeon_ring_unlock_commit(rdev);
+       return r;
+}
+
+
+/*
+ * CP
+ */
+void r100_ring_start(struct radeon_device *rdev)
+{
+       int r;
+
+       r = radeon_ring_lock(rdev, 2);
+       if (r) {
+               return;
+       }
+       radeon_ring_write(rdev, PACKET0(RADEON_ISYNC_CNTL, 0));
+       radeon_ring_write(rdev,
+                         RADEON_ISYNC_ANY2D_IDLE3D |
+                         RADEON_ISYNC_ANY3D_IDLE2D |
+                         RADEON_ISYNC_WAIT_IDLEGUI |
+                         RADEON_ISYNC_CPSCRATCH_IDLEGUI);
+       radeon_ring_unlock_commit(rdev);
+}
+
+static void r100_cp_load_microcode(struct radeon_device *rdev)
+{
+       int i;
+
+       if (r100_gui_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait GUI idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+
+       WREG32(RADEON_CP_ME_RAM_ADDR, 0);
+       if ((rdev->family == CHIP_R100) || (rdev->family == CHIP_RV100) ||
+           (rdev->family == CHIP_RV200) || (rdev->family == CHIP_RS100) ||
+           (rdev->family == CHIP_RS200)) {
+               DRM_INFO("Loading R100 Microcode\n");
+               for (i = 0; i < 256; i++) {
+                       WREG32(RADEON_CP_ME_RAM_DATAH, R100_cp_microcode[i][1]);
+                       WREG32(RADEON_CP_ME_RAM_DATAL, R100_cp_microcode[i][0]);
+               }
+       } else if ((rdev->family == CHIP_R200) ||
+                  (rdev->family == CHIP_RV250) ||
+                  (rdev->family == CHIP_RV280) ||
+                  (rdev->family == CHIP_RS300)) {
+               DRM_INFO("Loading R200 Microcode\n");
+               for (i = 0; i < 256; i++) {
+                       WREG32(RADEON_CP_ME_RAM_DATAH, R200_cp_microcode[i][1]);
+                       WREG32(RADEON_CP_ME_RAM_DATAL, R200_cp_microcode[i][0]);
+               }
+       } else if ((rdev->family == CHIP_R300) ||
+                  (rdev->family == CHIP_R350) ||
+                  (rdev->family == CHIP_RV350) ||
+                  (rdev->family == CHIP_RV380) ||
+                  (rdev->family == CHIP_RS400) ||
+                  (rdev->family == CHIP_RS480)) {
+               DRM_INFO("Loading R300 Microcode\n");
+               for (i = 0; i < 256; i++) {
+                       WREG32(RADEON_CP_ME_RAM_DATAH, R300_cp_microcode[i][1]);
+                       WREG32(RADEON_CP_ME_RAM_DATAL, R300_cp_microcode[i][0]);
+               }
+       } else if ((rdev->family == CHIP_R420) ||
+                  (rdev->family == CHIP_R423) ||
+                  (rdev->family == CHIP_RV410)) {
+               DRM_INFO("Loading R400 Microcode\n");
+               for (i = 0; i < 256; i++) {
+                       WREG32(RADEON_CP_ME_RAM_DATAH, R420_cp_microcode[i][1]);
+                       WREG32(RADEON_CP_ME_RAM_DATAL, R420_cp_microcode[i][0]);
+               }
+       } else if ((rdev->family == CHIP_RS690) ||
+                  (rdev->family == CHIP_RS740)) {
+               DRM_INFO("Loading RS690/RS740 Microcode\n");
+               for (i = 0; i < 256; i++) {
+                       WREG32(RADEON_CP_ME_RAM_DATAH, RS690_cp_microcode[i][1]);
+                       WREG32(RADEON_CP_ME_RAM_DATAL, RS690_cp_microcode[i][0]);
+               }
+       } else if (rdev->family == CHIP_RS600) {
+               DRM_INFO("Loading RS600 Microcode\n");
+               for (i = 0; i < 256; i++) {
+                       WREG32(RADEON_CP_ME_RAM_DATAH, RS600_cp_microcode[i][1]);
+                       WREG32(RADEON_CP_ME_RAM_DATAL, RS600_cp_microcode[i][0]);
+               }
+       } else if ((rdev->family == CHIP_RV515) ||
+                  (rdev->family == CHIP_R520) ||
+                  (rdev->family == CHIP_RV530) ||
+                  (rdev->family == CHIP_R580) ||
+                  (rdev->family == CHIP_RV560) ||
+                  (rdev->family == CHIP_RV570)) {
+               DRM_INFO("Loading R500 Microcode\n");
+               for (i = 0; i < 256; i++) {
+                       WREG32(RADEON_CP_ME_RAM_DATAH, R520_cp_microcode[i][1]);
+                       WREG32(RADEON_CP_ME_RAM_DATAL, R520_cp_microcode[i][0]);
+               }
+       }
+}
+
+int r100_cp_init(struct radeon_device *rdev, unsigned ring_size)
+{
+       unsigned rb_bufsz;
+       unsigned rb_blksz;
+       unsigned max_fetch;
+       unsigned pre_write_timer;
+       unsigned pre_write_limit;
+       unsigned indirect2_start;
+       unsigned indirect1_start;
+       uint32_t tmp;
+       int r;
+
+       if (r100_debugfs_cp_init(rdev)) {
+               DRM_ERROR("Failed to register debugfs file for CP !\n");
+       }
+       /* Reset CP */
+       tmp = RREG32(RADEON_CP_CSQ_STAT);
+       if ((tmp & (1 << 31))) {
+               DRM_INFO("radeon: cp busy (0x%08X) resetting\n", tmp);
+               WREG32(RADEON_CP_CSQ_MODE, 0);
+               WREG32(RADEON_CP_CSQ_CNTL, 0);
+               WREG32(RADEON_RBBM_SOFT_RESET, RADEON_SOFT_RESET_CP);
+               tmp = RREG32(RADEON_RBBM_SOFT_RESET);
+               mdelay(2);
+               WREG32(RADEON_RBBM_SOFT_RESET, 0);
+               tmp = RREG32(RADEON_RBBM_SOFT_RESET);
+               mdelay(2);
+               tmp = RREG32(RADEON_CP_CSQ_STAT);
+               if ((tmp & (1 << 31))) {
+                       DRM_INFO("radeon: cp reset failed (0x%08X)\n", tmp);
+               }
+       } else {
+               DRM_INFO("radeon: cp idle (0x%08X)\n", tmp);
+       }
+       /* Align ring size */
+       rb_bufsz = drm_order(ring_size / 8);
+       ring_size = (1 << (rb_bufsz + 1)) * 4;
+       r100_cp_load_microcode(rdev);
+       r = radeon_ring_init(rdev, ring_size);
+       if (r) {
+               return r;
+       }
+       /* Each time the cp read 1024 bytes (16 dword/quadword) update
+        * the rptr copy in system ram */
+       rb_blksz = 9;
+       /* cp will read 128bytes at a time (4 dwords) */
+       max_fetch = 1;
+       rdev->cp.align_mask = 16 - 1;
+       /* Write to CP_RB_WPTR will be delayed for pre_write_timer clocks */
+       pre_write_timer = 64;
+       /* Force CP_RB_WPTR write if written more than one time before the
+        * delay expire
+        */
+       pre_write_limit = 0;
+       /* Setup the cp cache like this (cache size is 96 dwords) :
+        *      RING            0  to 15
+        *      INDIRECT1       16 to 79
+        *      INDIRECT2       80 to 95
+        * So ring cache size is 16dwords (> (2 * max_fetch = 2 * 4dwords))
+        *    indirect1 cache size is 64dwords (> (2 * max_fetch = 2 * 4dwords))
+        *    indirect2 cache size is 16dwords (> (2 * max_fetch = 2 * 4dwords))
+        * Idea being that most of the gpu cmd will be through indirect1 buffer
+        * so it gets the bigger cache.
+        */
+       indirect2_start = 80;
+       indirect1_start = 16;
+       /* cp setup */
+       WREG32(0x718, pre_write_timer | (pre_write_limit << 28));
+       WREG32(RADEON_CP_RB_CNTL,
+              REG_SET(RADEON_RB_BUFSZ, rb_bufsz) |
+              REG_SET(RADEON_RB_BLKSZ, rb_blksz) |
+              REG_SET(RADEON_MAX_FETCH, max_fetch) |
+              RADEON_RB_NO_UPDATE);
+       /* Set ring address */
+       DRM_INFO("radeon: ring at 0x%016lX\n", (unsigned long)rdev->cp.gpu_addr);
+       WREG32(RADEON_CP_RB_BASE, rdev->cp.gpu_addr);
+       /* Force read & write ptr to 0 */
+       tmp = RREG32(RADEON_CP_RB_CNTL);
+       WREG32(RADEON_CP_RB_CNTL, tmp | RADEON_RB_RPTR_WR_ENA);
+       WREG32(RADEON_CP_RB_RPTR_WR, 0);
+       WREG32(RADEON_CP_RB_WPTR, 0);
+       WREG32(RADEON_CP_RB_CNTL, tmp);
+       udelay(10);
+       rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR);
+       rdev->cp.wptr = RREG32(RADEON_CP_RB_WPTR);
+       /* Set cp mode to bus mastering & enable cp*/
+       WREG32(RADEON_CP_CSQ_MODE,
+              REG_SET(RADEON_INDIRECT2_START, indirect2_start) |
+              REG_SET(RADEON_INDIRECT1_START, indirect1_start));
+       WREG32(0x718, 0);
+       WREG32(0x744, 0x00004D4D);
+       WREG32(RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIBM_INDBM);
+       radeon_ring_start(rdev);
+       r = radeon_ring_test(rdev);
+       if (r) {
+               DRM_ERROR("radeon: cp isn't working (%d).\n", r);
+               return r;
+       }
+       rdev->cp.ready = true;
+       return 0;
+}
+
+void r100_cp_fini(struct radeon_device *rdev)
+{
+       /* Disable ring */
+       rdev->cp.ready = false;
+       WREG32(RADEON_CP_CSQ_CNTL, 0);
+       radeon_ring_fini(rdev);
+       DRM_INFO("radeon: cp finalized\n");
+}
+
+void r100_cp_disable(struct radeon_device *rdev)
+{
+       /* Disable ring */
+       rdev->cp.ready = false;
+       WREG32(RADEON_CP_CSQ_MODE, 0);
+       WREG32(RADEON_CP_CSQ_CNTL, 0);
+       if (r100_gui_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait GUI idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+}
+
+int r100_cp_reset(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+       bool reinit_cp;
+       int i;
+
+       reinit_cp = rdev->cp.ready;
+       rdev->cp.ready = false;
+       WREG32(RADEON_CP_CSQ_MODE, 0);
+       WREG32(RADEON_CP_CSQ_CNTL, 0);
+       WREG32(RADEON_RBBM_SOFT_RESET, RADEON_SOFT_RESET_CP);
+       (void)RREG32(RADEON_RBBM_SOFT_RESET);
+       udelay(200);
+       WREG32(RADEON_RBBM_SOFT_RESET, 0);
+       /* Wait to prevent race in RBBM_STATUS */
+       mdelay(1);
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               tmp = RREG32(RADEON_RBBM_STATUS);
+               if (!(tmp & (1 << 16))) {
+                       DRM_INFO("CP reset succeed (RBBM_STATUS=0x%08X)\n",
+                                tmp);
+                       if (reinit_cp) {
+                               return r100_cp_init(rdev, rdev->cp.ring_size);
+                       }
+                       return 0;
+               }
+               DRM_UDELAY(1);
+       }
+       tmp = RREG32(RADEON_RBBM_STATUS);
+       DRM_ERROR("Failed to reset CP (RBBM_STATUS=0x%08X)!\n", tmp);
+       return -1;
+}
+
+
+/*
+ * CS functions
+ */
+int r100_cs_parse_packet0(struct radeon_cs_parser *p,
+                         struct radeon_cs_packet *pkt,
+                         unsigned *auth, unsigned n,
+                         radeon_packet0_check_t check)
+{
+       unsigned reg;
+       unsigned i, j, m;
+       unsigned idx;
+       int r;
+
+       idx = pkt->idx + 1;
+       reg = pkt->reg;
+       if (pkt->one_reg_wr) {
+               if ((reg >> 7) > n) {
+                       return -EINVAL;
+               }
+       } else {
+               if (((reg + (pkt->count << 2)) >> 7) > n) {
+                       return -EINVAL;
+               }
+       }
+       for (i = 0; i <= pkt->count; i++, idx++) {
+               j = (reg >> 7);
+               m = 1 << ((reg >> 2) & 31);
+               if (auth[j] & m) {
+                       r = check(p, pkt, idx, reg);
+                       if (r) {
+                               return r;
+                       }
+               }
+               if (pkt->one_reg_wr) {
+                       if (!(auth[j] & m)) {
+                               break;
+                       }
+               } else {
+                       reg += 4;
+               }
+       }
+       return 0;
+}
+
+int r100_cs_parse_packet3(struct radeon_cs_parser *p,
+                         struct radeon_cs_packet *pkt,
+                         unsigned *auth, unsigned n,
+                         radeon_packet3_check_t check)
+{
+       unsigned i, m;
+
+       if ((pkt->opcode >> 5) > n) {
+               return -EINVAL;
+       }
+       i = pkt->opcode >> 5;
+       m = 1 << (pkt->opcode & 31);
+       if (auth[i] & m) {
+               return check(p, pkt);
+       }
+       return 0;
+}
+
+void r100_cs_dump_packet(struct radeon_cs_parser *p,
+                        struct radeon_cs_packet *pkt)
+{
+       struct radeon_cs_chunk *ib_chunk;
+       volatile uint32_t *ib;
+       unsigned i;
+       unsigned idx;
+
+       ib = p->ib->ptr;
+       ib_chunk = &p->chunks[p->chunk_ib_idx];
+       idx = pkt->idx;
+       for (i = 0; i <= (pkt->count + 1); i++, idx++) {
+               DRM_INFO("ib[%d]=0x%08X\n", idx, ib[idx]);
+       }
+}
+
+/**
+ * r100_cs_packet_parse() - parse cp packet and point ib index to next packet
+ * @parser:    parser structure holding parsing context.
+ * @pkt:       where to store packet informations
+ *
+ * Assume that chunk_ib_index is properly set. Will return -EINVAL
+ * if packet is bigger than remaining ib size. or if packets is unknown.
+ **/
+int r100_cs_packet_parse(struct radeon_cs_parser *p,
+                        struct radeon_cs_packet *pkt,
+                        unsigned idx)
+{
+       struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx];
+       uint32_t header = ib_chunk->kdata[idx];
+
+       if (idx >= ib_chunk->length_dw) {
+               DRM_ERROR("Can not parse packet at %d after CS end %d !\n",
+                         idx, ib_chunk->length_dw);
+               return -EINVAL;
+       }
+       pkt->idx = idx;
+       pkt->type = CP_PACKET_GET_TYPE(header);
+       pkt->count = CP_PACKET_GET_COUNT(header);
+       switch (pkt->type) {
+       case PACKET_TYPE0:
+               pkt->reg = CP_PACKET0_GET_REG(header);
+               pkt->one_reg_wr = CP_PACKET0_GET_ONE_REG_WR(header);
+               break;
+       case PACKET_TYPE3:
+               pkt->opcode = CP_PACKET3_GET_OPCODE(header);
+               break;
+       case PACKET_TYPE2:
+               pkt->count = -1;
+               break;
+       default:
+               DRM_ERROR("Unknown packet type %d at %d !\n", pkt->type, idx);
+               return -EINVAL;
+       }
+       if ((pkt->count + 1 + pkt->idx) >= ib_chunk->length_dw) {
+               DRM_ERROR("Packet (%d:%d:%d) end after CS buffer (%d) !\n",
+                         pkt->idx, pkt->type, pkt->count, ib_chunk->length_dw);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/**
+ * r100_cs_packet_next_reloc() - parse next packet which should be reloc packet3
+ * @parser:            parser structure holding parsing context.
+ * @data:              pointer to relocation data
+ * @offset_start:      starting offset
+ * @offset_mask:       offset mask (to align start offset on)
+ * @reloc:             reloc informations
+ *
+ * Check next packet is relocation packet3, do bo validation and compute
+ * GPU offset using the provided start.
+ **/
+int r100_cs_packet_next_reloc(struct radeon_cs_parser *p,
+                             struct radeon_cs_reloc **cs_reloc)
+{
+       struct radeon_cs_chunk *ib_chunk;
+       struct radeon_cs_chunk *relocs_chunk;
+       struct radeon_cs_packet p3reloc;
+       unsigned idx;
+       int r;
+
+       if (p->chunk_relocs_idx == -1) {
+               DRM_ERROR("No relocation chunk !\n");
+               return -EINVAL;
+       }
+       *cs_reloc = NULL;
+       ib_chunk = &p->chunks[p->chunk_ib_idx];
+       relocs_chunk = &p->chunks[p->chunk_relocs_idx];
+       r = r100_cs_packet_parse(p, &p3reloc, p->idx);
+       if (r) {
+               return r;
+       }
+       p->idx += p3reloc.count + 2;
+       if (p3reloc.type != PACKET_TYPE3 || p3reloc.opcode != PACKET3_NOP) {
+               DRM_ERROR("No packet3 for relocation for packet at %d.\n",
+                         p3reloc.idx);
+               r100_cs_dump_packet(p, &p3reloc);
+               return -EINVAL;
+       }
+       idx = ib_chunk->kdata[p3reloc.idx + 1];
+       if (idx >= relocs_chunk->length_dw) {
+               DRM_ERROR("Relocs at %d after relocations chunk end %d !\n",
+                         idx, relocs_chunk->length_dw);
+               r100_cs_dump_packet(p, &p3reloc);
+               return -EINVAL;
+       }
+       /* FIXME: we assume reloc size is 4 dwords */
+       *cs_reloc = p->relocs_ptr[(idx / 4)];
+       return 0;
+}
+
+static int r100_packet0_check(struct radeon_cs_parser *p,
+                             struct radeon_cs_packet *pkt)
+{
+       struct radeon_cs_chunk *ib_chunk;
+       struct radeon_cs_reloc *reloc;
+       volatile uint32_t *ib;
+       uint32_t tmp;
+       unsigned reg;
+       unsigned i;
+       unsigned idx;
+       bool onereg;
+       int r;
+
+       ib = p->ib->ptr;
+       ib_chunk = &p->chunks[p->chunk_ib_idx];
+       idx = pkt->idx + 1;
+       reg = pkt->reg;
+       onereg = false;
+       if (CP_PACKET0_GET_ONE_REG_WR(ib_chunk->kdata[pkt->idx])) {
+               onereg = true;
+       }
+       for (i = 0; i <= pkt->count; i++, idx++, reg += 4) {
+               switch (reg) {
+               /* FIXME: only allow PACKET3 blit? easier to check for out of
+                * range access */
+               case RADEON_DST_PITCH_OFFSET:
+               case RADEON_SRC_PITCH_OFFSET:
+                       r = r100_cs_packet_next_reloc(p, &reloc);
+                       if (r) {
+                               DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
+                                         idx, reg);
+                               r100_cs_dump_packet(p, pkt);
+                               return r;
+                       }
+                       tmp = ib_chunk->kdata[idx] & 0x003fffff;
+                       tmp += (((u32)reloc->lobj.gpu_offset) >> 10);
+                       ib[idx] = (ib_chunk->kdata[idx] & 0xffc00000) | tmp;
+                       break;
+               case RADEON_RB3D_DEPTHOFFSET:
+               case RADEON_RB3D_COLOROFFSET:
+               case R300_RB3D_COLOROFFSET0:
+               case R300_ZB_DEPTHOFFSET:
+               case R200_PP_TXOFFSET_0:
+               case R200_PP_TXOFFSET_1:
+               case R200_PP_TXOFFSET_2:
+               case R200_PP_TXOFFSET_3:
+               case R200_PP_TXOFFSET_4:
+               case R200_PP_TXOFFSET_5:
+               case RADEON_PP_TXOFFSET_0:
+               case RADEON_PP_TXOFFSET_1:
+               case RADEON_PP_TXOFFSET_2:
+               case R300_TX_OFFSET_0:
+               case R300_TX_OFFSET_0+4:
+               case R300_TX_OFFSET_0+8:
+               case R300_TX_OFFSET_0+12:
+               case R300_TX_OFFSET_0+16:
+               case R300_TX_OFFSET_0+20:
+               case R300_TX_OFFSET_0+24:
+               case R300_TX_OFFSET_0+28:
+               case R300_TX_OFFSET_0+32:
+               case R300_TX_OFFSET_0+36:
+               case R300_TX_OFFSET_0+40:
+               case R300_TX_OFFSET_0+44:
+               case R300_TX_OFFSET_0+48:
+               case R300_TX_OFFSET_0+52:
+               case R300_TX_OFFSET_0+56:
+               case R300_TX_OFFSET_0+60:
+                       r = r100_cs_packet_next_reloc(p, &reloc);
+                       if (r) {
+                               DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
+                                         idx, reg);
+                               r100_cs_dump_packet(p, pkt);
+                               return r;
+                       }
+                       ib[idx] = ib_chunk->kdata[idx] + ((u32)reloc->lobj.gpu_offset);
+                       break;
+               default:
+                       /* FIXME: we don't want to allow anyothers packet */
+                       break;
+               }
+               if (onereg) {
+                       /* FIXME: forbid onereg write to register on relocate */
+                       break;
+               }
+       }
+       return 0;
+}
+
+static int r100_packet3_check(struct radeon_cs_parser *p,
+                             struct radeon_cs_packet *pkt)
+{
+       struct radeon_cs_chunk *ib_chunk;
+       struct radeon_cs_reloc *reloc;
+       unsigned idx;
+       unsigned i, c;
+       volatile uint32_t *ib;
+       int r;
+
+       ib = p->ib->ptr;
+       ib_chunk = &p->chunks[p->chunk_ib_idx];
+       idx = pkt->idx + 1;
+       switch (pkt->opcode) {
+       case PACKET3_3D_LOAD_VBPNTR:
+               c = ib_chunk->kdata[idx++];
+               for (i = 0; i < (c - 1); i += 2, idx += 3) {
+                       r = r100_cs_packet_next_reloc(p, &reloc);
+                       if (r) {
+                               DRM_ERROR("No reloc for packet3 %d\n",
+                                         pkt->opcode);
+                               r100_cs_dump_packet(p, pkt);
+                               return r;
+                       }
+                       ib[idx+1] = ib_chunk->kdata[idx+1] + ((u32)reloc->lobj.gpu_offset);
+                       r = r100_cs_packet_next_reloc(p, &reloc);
+                       if (r) {
+                               DRM_ERROR("No reloc for packet3 %d\n",
+                                         pkt->opcode);
+                               r100_cs_dump_packet(p, pkt);
+                               return r;
+                       }
+                       ib[idx+2] = ib_chunk->kdata[idx+2] + ((u32)reloc->lobj.gpu_offset);
+               }
+               if (c & 1) {
+                       r = r100_cs_packet_next_reloc(p, &reloc);
+                       if (r) {
+                               DRM_ERROR("No reloc for packet3 %d\n",
+                                         pkt->opcode);
+                               r100_cs_dump_packet(p, pkt);
+                               return r;
+                       }
+                       ib[idx+1] = ib_chunk->kdata[idx+1] + ((u32)reloc->lobj.gpu_offset);
+               }
+               break;
+       case PACKET3_INDX_BUFFER:
+               r = r100_cs_packet_next_reloc(p, &reloc);
+               if (r) {
+                       DRM_ERROR("No reloc for packet3 %d\n", pkt->opcode);
+                       r100_cs_dump_packet(p, pkt);
+                       return r;
+               }
+               ib[idx+1] = ib_chunk->kdata[idx+1] + ((u32)reloc->lobj.gpu_offset);
+               break;
+       case 0x23:
+               /* FIXME: cleanup */
+               /* 3D_RNDR_GEN_INDX_PRIM on r100/r200 */
+               r = r100_cs_packet_next_reloc(p, &reloc);
+               if (r) {
+                       DRM_ERROR("No reloc for packet3 %d\n", pkt->opcode);
+                       r100_cs_dump_packet(p, pkt);
+                       return r;
+               }
+               ib[idx] = ib_chunk->kdata[idx] + ((u32)reloc->lobj.gpu_offset);
+               break;
+       case PACKET3_3D_DRAW_IMMD:
+               /* triggers drawing using in-packet vertex data */
+       case PACKET3_3D_DRAW_IMMD_2:
+               /* triggers drawing using in-packet vertex data */
+       case PACKET3_3D_DRAW_VBUF_2:
+               /* triggers drawing of vertex buffers setup elsewhere */
+       case PACKET3_3D_DRAW_INDX_2:
+               /* triggers drawing using indices to vertex buffer */
+       case PACKET3_3D_DRAW_VBUF:
+               /* triggers drawing of vertex buffers setup elsewhere */
+       case PACKET3_3D_DRAW_INDX:
+               /* triggers drawing using indices to vertex buffer */
+       case PACKET3_NOP:
+               break;
+       default:
+               DRM_ERROR("Packet3 opcode %x not supported\n", pkt->opcode);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int r100_cs_parse(struct radeon_cs_parser *p)
+{
+       struct radeon_cs_packet pkt;
+       int r;
+
+       do {
+               r = r100_cs_packet_parse(p, &pkt, p->idx);
+               if (r) {
+                       return r;
+               }
+               p->idx += pkt.count + 2;
+               switch (pkt.type) {
+               case PACKET_TYPE0:
+                       r = r100_packet0_check(p, &pkt);
+                       break;
+               case PACKET_TYPE2:
+                       break;
+               case PACKET_TYPE3:
+                       r = r100_packet3_check(p, &pkt);
+                       break;
+               default:
+                       DRM_ERROR("Unknown packet type %d !\n",
+                                       pkt.type);
+                       return -EINVAL;
+               }
+               if (r) {
+                       return r;
+               }
+       } while (p->idx < p->chunks[p->chunk_ib_idx].length_dw);
+       return 0;
+}
+
+
+/*
+ * Global GPU functions
+ */
+void r100_errata(struct radeon_device *rdev)
+{
+       rdev->pll_errata = 0;
+
+       if (rdev->family == CHIP_RV200 || rdev->family == CHIP_RS200) {
+               rdev->pll_errata |= CHIP_ERRATA_PLL_DUMMYREADS;
+       }
+
+       if (rdev->family == CHIP_RV100 ||
+           rdev->family == CHIP_RS100 ||
+           rdev->family == CHIP_RS200) {
+               rdev->pll_errata |= CHIP_ERRATA_PLL_DELAY;
+       }
+}
+
+/* Wait for vertical sync on primary CRTC */
+void r100_gpu_wait_for_vsync(struct radeon_device *rdev)
+{
+       uint32_t crtc_gen_cntl, tmp;
+       int i;
+
+       crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL);
+       if ((crtc_gen_cntl & RADEON_CRTC_DISP_REQ_EN_B) ||
+           !(crtc_gen_cntl & RADEON_CRTC_EN)) {
+               return;
+       }
+       /* Clear the CRTC_VBLANK_SAVE bit */
+       WREG32(RADEON_CRTC_STATUS, RADEON_CRTC_VBLANK_SAVE_CLEAR);
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               tmp = RREG32(RADEON_CRTC_STATUS);
+               if (tmp & RADEON_CRTC_VBLANK_SAVE) {
+                       return;
+               }
+               DRM_UDELAY(1);
+       }
+}
+
+/* Wait for vertical sync on secondary CRTC */
+void r100_gpu_wait_for_vsync2(struct radeon_device *rdev)
+{
+       uint32_t crtc2_gen_cntl, tmp;
+       int i;
+
+       crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL);
+       if ((crtc2_gen_cntl & RADEON_CRTC2_DISP_REQ_EN_B) ||
+           !(crtc2_gen_cntl & RADEON_CRTC2_EN))
+               return;
+
+       /* Clear the CRTC_VBLANK_SAVE bit */
+       WREG32(RADEON_CRTC2_STATUS, RADEON_CRTC2_VBLANK_SAVE_CLEAR);
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               tmp = RREG32(RADEON_CRTC2_STATUS);
+               if (tmp & RADEON_CRTC2_VBLANK_SAVE) {
+                       return;
+               }
+               DRM_UDELAY(1);
+       }
+}
+
+int r100_rbbm_fifo_wait_for_entry(struct radeon_device *rdev, unsigned n)
+{
+       unsigned i;
+       uint32_t tmp;
+
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               tmp = RREG32(RADEON_RBBM_STATUS) & RADEON_RBBM_FIFOCNT_MASK;
+               if (tmp >= n) {
+                       return 0;
+               }
+               DRM_UDELAY(1);
+       }
+       return -1;
+}
+
+int r100_gui_wait_for_idle(struct radeon_device *rdev)
+{
+       unsigned i;
+       uint32_t tmp;
+
+       if (r100_rbbm_fifo_wait_for_entry(rdev, 64)) {
+               printk(KERN_WARNING "radeon: wait for empty RBBM fifo failed !"
+                      " Bad things might happen.\n");
+       }
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               tmp = RREG32(RADEON_RBBM_STATUS);
+               if (!(tmp & (1 << 31))) {
+                       return 0;
+               }
+               DRM_UDELAY(1);
+       }
+       return -1;
+}
+
+int r100_mc_wait_for_idle(struct radeon_device *rdev)
+{
+       unsigned i;
+       uint32_t tmp;
+
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               /* read MC_STATUS */
+               tmp = RREG32(0x0150);
+               if (tmp & (1 << 2)) {
+                       return 0;
+               }
+               DRM_UDELAY(1);
+       }
+       return -1;
+}
+
+void r100_gpu_init(struct radeon_device *rdev)
+{
+       /* TODO: anythings to do here ? pipes ? */
+       r100_hdp_reset(rdev);
+}
+
+void r100_hdp_reset(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+
+       tmp = RREG32(RADEON_HOST_PATH_CNTL) & RADEON_HDP_APER_CNTL;
+       tmp |= (7 << 28);
+       WREG32(RADEON_HOST_PATH_CNTL, tmp | RADEON_HDP_SOFT_RESET | RADEON_HDP_READ_BUFFER_INVALIDATE);
+       (void)RREG32(RADEON_HOST_PATH_CNTL);
+       udelay(200);
+       WREG32(RADEON_RBBM_SOFT_RESET, 0);
+       WREG32(RADEON_HOST_PATH_CNTL, tmp);
+       (void)RREG32(RADEON_HOST_PATH_CNTL);
+}
+
+int r100_rb2d_reset(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+       int i;
+
+       WREG32(RADEON_RBBM_SOFT_RESET, RADEON_SOFT_RESET_E2);
+       (void)RREG32(RADEON_RBBM_SOFT_RESET);
+       udelay(200);
+       WREG32(RADEON_RBBM_SOFT_RESET, 0);
+       /* Wait to prevent race in RBBM_STATUS */
+       mdelay(1);
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               tmp = RREG32(RADEON_RBBM_STATUS);
+               if (!(tmp & (1 << 26))) {
+                       DRM_INFO("RB2D reset succeed (RBBM_STATUS=0x%08X)\n",
+                                tmp);
+                       return 0;
+               }
+               DRM_UDELAY(1);
+       }
+       tmp = RREG32(RADEON_RBBM_STATUS);
+       DRM_ERROR("Failed to reset RB2D (RBBM_STATUS=0x%08X)!\n", tmp);
+       return -1;
+}
+
+int r100_gpu_reset(struct radeon_device *rdev)
+{
+       uint32_t status;
+
+       /* reset order likely matter */
+       status = RREG32(RADEON_RBBM_STATUS);
+       /* reset HDP */
+       r100_hdp_reset(rdev);
+       /* reset rb2d */
+       if (status & ((1 << 17) | (1 << 18) | (1 << 27))) {
+               r100_rb2d_reset(rdev);
+       }
+       /* TODO: reset 3D engine */
+       /* reset CP */
+       status = RREG32(RADEON_RBBM_STATUS);
+       if (status & (1 << 16)) {
+               r100_cp_reset(rdev);
+       }
+       /* Check if GPU is idle */
+       status = RREG32(RADEON_RBBM_STATUS);
+       if (status & (1 << 31)) {
+               DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status);
+               return -1;
+       }
+       DRM_INFO("GPU reset succeed (RBBM_STATUS=0x%08X)\n", status);
+       return 0;
+}
+
+
+/*
+ * VRAM info
+ */
+static void r100_vram_get_type(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+
+       rdev->mc.vram_is_ddr = false;
+       if (rdev->flags & RADEON_IS_IGP)
+               rdev->mc.vram_is_ddr = true;
+       else if (RREG32(RADEON_MEM_SDRAM_MODE_REG) & RADEON_MEM_CFG_TYPE_DDR)
+               rdev->mc.vram_is_ddr = true;
+       if ((rdev->family == CHIP_RV100) ||
+           (rdev->family == CHIP_RS100) ||
+           (rdev->family == CHIP_RS200)) {
+               tmp = RREG32(RADEON_MEM_CNTL);
+               if (tmp & RV100_HALF_MODE) {
+                       rdev->mc.vram_width = 32;
+               } else {
+                       rdev->mc.vram_width = 64;
+               }
+               if (rdev->flags & RADEON_SINGLE_CRTC) {
+                       rdev->mc.vram_width /= 4;
+                       rdev->mc.vram_is_ddr = true;
+               }
+       } else if (rdev->family <= CHIP_RV280) {
+               tmp = RREG32(RADEON_MEM_CNTL);
+               if (tmp & RADEON_MEM_NUM_CHANNELS_MASK) {
+                       rdev->mc.vram_width = 128;
+               } else {
+                       rdev->mc.vram_width = 64;
+               }
+       } else {
+               /* newer IGPs */
+               rdev->mc.vram_width = 128;
+       }
+}
+
+void r100_vram_info(struct radeon_device *rdev)
+{
+       r100_vram_get_type(rdev);
+
+       if (rdev->flags & RADEON_IS_IGP) {
+               uint32_t tom;
+               /* read NB_TOM to get the amount of ram stolen for the GPU */
+               tom = RREG32(RADEON_NB_TOM);
+               rdev->mc.vram_size = (((tom >> 16) - (tom & 0xffff) + 1) << 16);
+               WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size);
+       } else {
+               rdev->mc.vram_size = RREG32(RADEON_CONFIG_MEMSIZE);
+               /* Some production boards of m6 will report 0
+                * if it's 8 MB
+                */
+               if (rdev->mc.vram_size == 0) {
+                       rdev->mc.vram_size = 8192 * 1024;
+                       WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size);
+               }
+       }
+
+       rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
+       rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
+       if (rdev->mc.aper_size > rdev->mc.vram_size) {
+               /* Why does some hw doesn't have CONFIG_MEMSIZE properly
+                * setup ? */
+               rdev->mc.vram_size = rdev->mc.aper_size;
+               WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size);
+       }
+}
+
+
+/*
+ * Indirect registers accessor
+ */
+void r100_pll_errata_after_index(struct radeon_device *rdev)
+{
+       if (!(rdev->pll_errata & CHIP_ERRATA_PLL_DUMMYREADS)) {
+               return;
+       }
+       (void)RREG32(RADEON_CLOCK_CNTL_DATA);
+       (void)RREG32(RADEON_CRTC_GEN_CNTL);
+}
+
+static void r100_pll_errata_after_data(struct radeon_device *rdev)
+{
+       /* This workarounds is necessary on RV100, RS100 and RS200 chips
+        * or the chip could hang on a subsequent access
+        */
+       if (rdev->pll_errata & CHIP_ERRATA_PLL_DELAY) {
+               udelay(5000);
+       }
+
+       /* This function is required to workaround a hardware bug in some (all?)
+        * revisions of the R300.  This workaround should be called after every
+        * CLOCK_CNTL_INDEX register access.  If not, register reads afterward
+        * may not be correct.
+        */
+       if (rdev->pll_errata & CHIP_ERRATA_R300_CG) {
+               uint32_t save, tmp;
+
+               save = RREG32(RADEON_CLOCK_CNTL_INDEX);
+               tmp = save & ~(0x3f | RADEON_PLL_WR_EN);
+               WREG32(RADEON_CLOCK_CNTL_INDEX, tmp);
+               tmp = RREG32(RADEON_CLOCK_CNTL_DATA);
+               WREG32(RADEON_CLOCK_CNTL_INDEX, save);
+       }
+}
+
+uint32_t r100_pll_rreg(struct radeon_device *rdev, uint32_t reg)
+{
+       uint32_t data;
+
+       WREG8(RADEON_CLOCK_CNTL_INDEX, reg & 0x3f);
+       r100_pll_errata_after_index(rdev);
+       data = RREG32(RADEON_CLOCK_CNTL_DATA);
+       r100_pll_errata_after_data(rdev);
+       return data;
+}
+
+void r100_pll_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
+{
+       WREG8(RADEON_CLOCK_CNTL_INDEX, ((reg & 0x3f) | RADEON_PLL_WR_EN));
+       r100_pll_errata_after_index(rdev);
+       WREG32(RADEON_CLOCK_CNTL_DATA, v);
+       r100_pll_errata_after_data(rdev);
+}
+
+uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg)
+{
+       if (reg < 0x10000)
+               return readl(((void __iomem *)rdev->rmmio) + reg);
+       else {
+               writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX);
+               return readl(((void __iomem *)rdev->rmmio) + RADEON_MM_DATA);
+       }
+}
+
+void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
+{
+       if (reg < 0x10000)
+               writel(v, ((void __iomem *)rdev->rmmio) + reg);
+       else {
+               writel(reg, ((void __iomem *)rdev->rmmio) + RADEON_MM_INDEX);
+               writel(v, ((void __iomem *)rdev->rmmio) + RADEON_MM_DATA);
+       }
+}
+
+/*
+ * Debugfs info
+ */
+#if defined(CONFIG_DEBUG_FS)
+static int r100_debugfs_rbbm_info(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t reg, value;
+       unsigned i;
+
+       seq_printf(m, "RBBM_STATUS 0x%08x\n", RREG32(RADEON_RBBM_STATUS));
+       seq_printf(m, "RBBM_CMDFIFO_STAT 0x%08x\n", RREG32(0xE7C));
+       seq_printf(m, "CP_STAT 0x%08x\n", RREG32(RADEON_CP_STAT));
+       for (i = 0; i < 64; i++) {
+               WREG32(RADEON_RBBM_CMDFIFO_ADDR, i | 0x100);
+               reg = (RREG32(RADEON_RBBM_CMDFIFO_DATA) - 1) >> 2;
+               WREG32(RADEON_RBBM_CMDFIFO_ADDR, i);
+               value = RREG32(RADEON_RBBM_CMDFIFO_DATA);
+               seq_printf(m, "[0x%03X] 0x%04X=0x%08X\n", i, reg, value);
+       }
+       return 0;
+}
+
+static int r100_debugfs_cp_ring_info(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t rdp, wdp;
+       unsigned count, i, j;
+
+       radeon_ring_free_size(rdev);
+       rdp = RREG32(RADEON_CP_RB_RPTR);
+       wdp = RREG32(RADEON_CP_RB_WPTR);
+       count = (rdp + rdev->cp.ring_size - wdp) & rdev->cp.ptr_mask;
+       seq_printf(m, "CP_STAT 0x%08x\n", RREG32(RADEON_CP_STAT));
+       seq_printf(m, "CP_RB_WPTR 0x%08x\n", wdp);
+       seq_printf(m, "CP_RB_RPTR 0x%08x\n", rdp);
+       seq_printf(m, "%u free dwords in ring\n", rdev->cp.ring_free_dw);
+       seq_printf(m, "%u dwords in ring\n", count);
+       for (j = 0; j <= count; j++) {
+               i = (rdp + j) & rdev->cp.ptr_mask;
+               seq_printf(m, "r[%04d]=0x%08x\n", i, rdev->cp.ring[i]);
+       }
+       return 0;
+}
+
+
+static int r100_debugfs_cp_csq_fifo(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t csq_stat, csq2_stat, tmp;
+       unsigned r_rptr, r_wptr, ib1_rptr, ib1_wptr, ib2_rptr, ib2_wptr;
+       unsigned i;
+
+       seq_printf(m, "CP_STAT 0x%08x\n", RREG32(RADEON_CP_STAT));
+       seq_printf(m, "CP_CSQ_MODE 0x%08x\n", RREG32(RADEON_CP_CSQ_MODE));
+       csq_stat = RREG32(RADEON_CP_CSQ_STAT);
+       csq2_stat = RREG32(RADEON_CP_CSQ2_STAT);
+       r_rptr = (csq_stat >> 0) & 0x3ff;
+       r_wptr = (csq_stat >> 10) & 0x3ff;
+       ib1_rptr = (csq_stat >> 20) & 0x3ff;
+       ib1_wptr = (csq2_stat >> 0) & 0x3ff;
+       ib2_rptr = (csq2_stat >> 10) & 0x3ff;
+       ib2_wptr = (csq2_stat >> 20) & 0x3ff;
+       seq_printf(m, "CP_CSQ_STAT 0x%08x\n", csq_stat);
+       seq_printf(m, "CP_CSQ2_STAT 0x%08x\n", csq2_stat);
+       seq_printf(m, "Ring rptr %u\n", r_rptr);
+       seq_printf(m, "Ring wptr %u\n", r_wptr);
+       seq_printf(m, "Indirect1 rptr %u\n", ib1_rptr);
+       seq_printf(m, "Indirect1 wptr %u\n", ib1_wptr);
+       seq_printf(m, "Indirect2 rptr %u\n", ib2_rptr);
+       seq_printf(m, "Indirect2 wptr %u\n", ib2_wptr);
+       /* FIXME: 0, 128, 640 depends on fifo setup see cp_init_kms
+        * 128 = indirect1_start * 8 & 640 = indirect2_start * 8 */
+       seq_printf(m, "Ring fifo:\n");
+       for (i = 0; i < 256; i++) {
+               WREG32(RADEON_CP_CSQ_ADDR, i << 2);
+               tmp = RREG32(RADEON_CP_CSQ_DATA);
+               seq_printf(m, "rfifo[%04d]=0x%08X\n", i, tmp);
+       }
+       seq_printf(m, "Indirect1 fifo:\n");
+       for (i = 256; i <= 512; i++) {
+               WREG32(RADEON_CP_CSQ_ADDR, i << 2);
+               tmp = RREG32(RADEON_CP_CSQ_DATA);
+               seq_printf(m, "ib1fifo[%04d]=0x%08X\n", i, tmp);
+       }
+       seq_printf(m, "Indirect2 fifo:\n");
+       for (i = 640; i < ib1_wptr; i++) {
+               WREG32(RADEON_CP_CSQ_ADDR, i << 2);
+               tmp = RREG32(RADEON_CP_CSQ_DATA);
+               seq_printf(m, "ib2fifo[%04d]=0x%08X\n", i, tmp);
+       }
+       return 0;
+}
+
+static int r100_debugfs_mc_info(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t tmp;
+
+       tmp = RREG32(RADEON_CONFIG_MEMSIZE);
+       seq_printf(m, "CONFIG_MEMSIZE 0x%08x\n", tmp);
+       tmp = RREG32(RADEON_MC_FB_LOCATION);
+       seq_printf(m, "MC_FB_LOCATION 0x%08x\n", tmp);
+       tmp = RREG32(RADEON_BUS_CNTL);
+       seq_printf(m, "BUS_CNTL 0x%08x\n", tmp);
+       tmp = RREG32(RADEON_MC_AGP_LOCATION);
+       seq_printf(m, "MC_AGP_LOCATION 0x%08x\n", tmp);
+       tmp = RREG32(RADEON_AGP_BASE);
+       seq_printf(m, "AGP_BASE 0x%08x\n", tmp);
+       tmp = RREG32(RADEON_HOST_PATH_CNTL);
+       seq_printf(m, "HOST_PATH_CNTL 0x%08x\n", tmp);
+       tmp = RREG32(0x01D0);
+       seq_printf(m, "AIC_CTRL 0x%08x\n", tmp);
+       tmp = RREG32(RADEON_AIC_LO_ADDR);
+       seq_printf(m, "AIC_LO_ADDR 0x%08x\n", tmp);
+       tmp = RREG32(RADEON_AIC_HI_ADDR);
+       seq_printf(m, "AIC_HI_ADDR 0x%08x\n", tmp);
+       tmp = RREG32(0x01E4);
+       seq_printf(m, "AIC_TLB_ADDR 0x%08x\n", tmp);
+       return 0;
+}
+
+static struct drm_info_list r100_debugfs_rbbm_list[] = {
+       {"r100_rbbm_info", r100_debugfs_rbbm_info, 0, NULL},
+};
+
+static struct drm_info_list r100_debugfs_cp_list[] = {
+       {"r100_cp_ring_info", r100_debugfs_cp_ring_info, 0, NULL},
+       {"r100_cp_csq_fifo", r100_debugfs_cp_csq_fifo, 0, NULL},
+};
+
+static struct drm_info_list r100_debugfs_mc_info_list[] = {
+       {"r100_mc_info", r100_debugfs_mc_info, 0, NULL},
+};
+#endif
+
+int r100_debugfs_rbbm_init(struct radeon_device *rdev)
+{
+#if defined(CONFIG_DEBUG_FS)
+       return radeon_debugfs_add_files(rdev, r100_debugfs_rbbm_list, 1);
+#else
+       return 0;
+#endif
+}
+
+int r100_debugfs_cp_init(struct radeon_device *rdev)
+{
+#if defined(CONFIG_DEBUG_FS)
+       return radeon_debugfs_add_files(rdev, r100_debugfs_cp_list, 2);
+#else
+       return 0;
+#endif
+}
+
+int r100_debugfs_mc_info_init(struct radeon_device *rdev)
+{
+#if defined(CONFIG_DEBUG_FS)
+       return radeon_debugfs_add_files(rdev, r100_debugfs_mc_info_list, 1);
+#else
+       return 0;
+#endif
+}
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
new file mode 100644 (file)
index 0000000..f5870a0
--- /dev/null
@@ -0,0 +1,1116 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ *          Jerome Glisse
+ */
+#include <linux/seq_file.h>
+#include "drmP.h"
+#include "drm.h"
+#include "radeon_reg.h"
+#include "radeon.h"
+
+/* r300,r350,rv350,rv370,rv380 depends on : */
+void r100_hdp_reset(struct radeon_device *rdev);
+int r100_cp_reset(struct radeon_device *rdev);
+int r100_rb2d_reset(struct radeon_device *rdev);
+int r100_cp_init(struct radeon_device *rdev, unsigned ring_size);
+int r100_pci_gart_enable(struct radeon_device *rdev);
+void r100_pci_gart_disable(struct radeon_device *rdev);
+void r100_mc_setup(struct radeon_device *rdev);
+void r100_mc_disable_clients(struct radeon_device *rdev);
+int r100_gui_wait_for_idle(struct radeon_device *rdev);
+int r100_cs_packet_parse(struct radeon_cs_parser *p,
+                        struct radeon_cs_packet *pkt,
+                        unsigned idx);
+int r100_cs_packet_next_reloc(struct radeon_cs_parser *p,
+                             struct radeon_cs_reloc **cs_reloc);
+int r100_cs_parse_packet0(struct radeon_cs_parser *p,
+                         struct radeon_cs_packet *pkt,
+                         unsigned *auth, unsigned n,
+                         radeon_packet0_check_t check);
+int r100_cs_parse_packet3(struct radeon_cs_parser *p,
+                         struct radeon_cs_packet *pkt,
+                         unsigned *auth, unsigned n,
+                         radeon_packet3_check_t check);
+void r100_cs_dump_packet(struct radeon_cs_parser *p,
+                        struct radeon_cs_packet *pkt);
+
+/* This files gather functions specifics to:
+ * r300,r350,rv350,rv370,rv380
+ *
+ * Some of these functions might be used by newer ASICs.
+ */
+void r300_gpu_init(struct radeon_device *rdev);
+int r300_mc_wait_for_idle(struct radeon_device *rdev);
+int rv370_debugfs_pcie_gart_info_init(struct radeon_device *rdev);
+
+
+/*
+ * rv370,rv380 PCIE GART
+ */
+void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+       int i;
+
+       /* Workaround HW bug do flush 2 times */
+       for (i = 0; i < 2; i++) {
+               tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL);
+               WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp | RADEON_PCIE_TX_GART_INVALIDATE_TLB);
+               (void)RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL);
+               WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp);
+               mb();
+       }
+}
+
+int rv370_pcie_gart_enable(struct radeon_device *rdev)
+{
+       uint32_t table_addr;
+       uint32_t tmp;
+       int r;
+
+       /* Initialize common gart structure */
+       r = radeon_gart_init(rdev);
+       if (r) {
+               return r;
+       }
+       r = rv370_debugfs_pcie_gart_info_init(rdev);
+       if (r) {
+               DRM_ERROR("Failed to register debugfs file for PCIE gart !\n");
+       }
+       rdev->gart.table_size = rdev->gart.num_gpu_pages * 4;
+       r = radeon_gart_table_vram_alloc(rdev);
+       if (r) {
+               return r;
+       }
+       /* discard memory request outside of configured range */
+       tmp = RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD;
+       WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp);
+       WREG32_PCIE(RADEON_PCIE_TX_GART_START_LO, rdev->mc.gtt_location);
+       tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 4096;
+       WREG32_PCIE(RADEON_PCIE_TX_GART_END_LO, tmp);
+       WREG32_PCIE(RADEON_PCIE_TX_GART_START_HI, 0);
+       WREG32_PCIE(RADEON_PCIE_TX_GART_END_HI, 0);
+       table_addr = rdev->gart.table_addr;
+       WREG32_PCIE(RADEON_PCIE_TX_GART_BASE, table_addr);
+       /* FIXME: setup default page */
+       WREG32_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_LO, rdev->mc.vram_location);
+       WREG32_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_HI, 0);
+       /* Clear error */
+       WREG32_PCIE(0x18, 0);
+       tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL);
+       tmp |= RADEON_PCIE_TX_GART_EN;
+       tmp |= RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD;
+       WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp);
+       rv370_pcie_gart_tlb_flush(rdev);
+       DRM_INFO("PCIE GART of %uM enabled (table at 0x%08X).\n",
+                rdev->mc.gtt_size >> 20, table_addr);
+       rdev->gart.ready = true;
+       return 0;
+}
+
+void rv370_pcie_gart_disable(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+
+       tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL);
+       tmp |= RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD;
+       WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp & ~RADEON_PCIE_TX_GART_EN);
+       if (rdev->gart.table.vram.robj) {
+               radeon_object_kunmap(rdev->gart.table.vram.robj);
+               radeon_object_unpin(rdev->gart.table.vram.robj);
+       }
+}
+
+int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)
+{
+       void __iomem *ptr = (void *)rdev->gart.table.vram.ptr;
+
+       if (i < 0 || i > rdev->gart.num_gpu_pages) {
+               return -EINVAL;
+       }
+       addr = (((u32)addr) >> 8) | ((upper_32_bits(addr) & 0xff) << 4) | 0xC;
+       writel(cpu_to_le32(addr), ((void __iomem *)ptr) + (i * 4));
+       return 0;
+}
+
+int r300_gart_enable(struct radeon_device *rdev)
+{
+#if __OS_HAS_AGP
+       if (rdev->flags & RADEON_IS_AGP) {
+               if (rdev->family > CHIP_RV350) {
+                       rv370_pcie_gart_disable(rdev);
+               } else {
+                       r100_pci_gart_disable(rdev);
+               }
+               return 0;
+       }
+#endif
+       if (rdev->flags & RADEON_IS_PCIE) {
+               rdev->asic->gart_disable = &rv370_pcie_gart_disable;
+               rdev->asic->gart_tlb_flush = &rv370_pcie_gart_tlb_flush;
+               rdev->asic->gart_set_page = &rv370_pcie_gart_set_page;
+               return rv370_pcie_gart_enable(rdev);
+       }
+       return r100_pci_gart_enable(rdev);
+}
+
+
+/*
+ * MC
+ */
+int r300_mc_init(struct radeon_device *rdev)
+{
+       int r;
+
+       if (r100_debugfs_rbbm_init(rdev)) {
+               DRM_ERROR("Failed to register debugfs file for RBBM !\n");
+       }
+
+       r300_gpu_init(rdev);
+       r100_pci_gart_disable(rdev);
+       if (rdev->flags & RADEON_IS_PCIE) {
+               rv370_pcie_gart_disable(rdev);
+       }
+
+       /* Setup GPU memory space */
+       rdev->mc.vram_location = 0xFFFFFFFFUL;
+       rdev->mc.gtt_location = 0xFFFFFFFFUL;
+       if (rdev->flags & RADEON_IS_AGP) {
+               r = radeon_agp_init(rdev);
+               if (r) {
+                       printk(KERN_WARNING "[drm] Disabling AGP\n");
+                       rdev->flags &= ~RADEON_IS_AGP;
+                       rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024;
+               } else {
+                       rdev->mc.gtt_location = rdev->mc.agp_base;
+               }
+       }
+       r = radeon_mc_setup(rdev);
+       if (r) {
+               return r;
+       }
+
+       /* Program GPU memory space */
+       r100_mc_disable_clients(rdev);
+       if (r300_mc_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait MC idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+       r100_mc_setup(rdev);
+       return 0;
+}
+
+void r300_mc_fini(struct radeon_device *rdev)
+{
+       if (rdev->flags & RADEON_IS_PCIE) {
+               rv370_pcie_gart_disable(rdev);
+               radeon_gart_table_vram_free(rdev);
+       } else {
+               r100_pci_gart_disable(rdev);
+               radeon_gart_table_ram_free(rdev);
+       }
+       radeon_gart_fini(rdev);
+}
+
+
+/*
+ * Fence emission
+ */
+void r300_fence_ring_emit(struct radeon_device *rdev,
+                         struct radeon_fence *fence)
+{
+       /* Who ever call radeon_fence_emit should call ring_lock and ask
+        * for enough space (today caller are ib schedule and buffer move) */
+       /* Write SC register so SC & US assert idle */
+       radeon_ring_write(rdev, PACKET0(0x43E0, 0));
+       radeon_ring_write(rdev, 0);
+       radeon_ring_write(rdev, PACKET0(0x43E4, 0));
+       radeon_ring_write(rdev, 0);
+       /* Flush 3D cache */
+       radeon_ring_write(rdev, PACKET0(0x4E4C, 0));
+       radeon_ring_write(rdev, (2 << 0));
+       radeon_ring_write(rdev, PACKET0(0x4F18, 0));
+       radeon_ring_write(rdev, (1 << 0));
+       /* Wait until IDLE & CLEAN */
+       radeon_ring_write(rdev, PACKET0(0x1720, 0));
+       radeon_ring_write(rdev, (1 << 17) | (1 << 16)  | (1 << 9));
+       /* Emit fence sequence & fire IRQ */
+       radeon_ring_write(rdev, PACKET0(rdev->fence_drv.scratch_reg, 0));
+       radeon_ring_write(rdev, fence->seq);
+       radeon_ring_write(rdev, PACKET0(RADEON_GEN_INT_STATUS, 0));
+       radeon_ring_write(rdev, RADEON_SW_INT_FIRE);
+}
+
+
+/*
+ * Global GPU functions
+ */
+int r300_copy_dma(struct radeon_device *rdev,
+                 uint64_t src_offset,
+                 uint64_t dst_offset,
+                 unsigned num_pages,
+                 struct radeon_fence *fence)
+{
+       uint32_t size;
+       uint32_t cur_size;
+       int i, num_loops;
+       int r = 0;
+
+       /* radeon pitch is /64 */
+       size = num_pages << PAGE_SHIFT;
+       num_loops = DIV_ROUND_UP(size, 0x1FFFFF);
+       r = radeon_ring_lock(rdev, num_loops * 4 + 64);
+       if (r) {
+               DRM_ERROR("radeon: moving bo (%d).\n", r);
+               return r;
+       }
+       /* Must wait for 2D idle & clean before DMA or hangs might happen */
+       radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0));
+       radeon_ring_write(rdev, (1 << 16));
+       for (i = 0; i < num_loops; i++) {
+               cur_size = size;
+               if (cur_size > 0x1FFFFF) {
+                       cur_size = 0x1FFFFF;
+               }
+               size -= cur_size;
+               radeon_ring_write(rdev, PACKET0(0x720, 2));
+               radeon_ring_write(rdev, src_offset);
+               radeon_ring_write(rdev, dst_offset);
+               radeon_ring_write(rdev, cur_size | (1 << 31) | (1 << 30));
+               src_offset += cur_size;
+               dst_offset += cur_size;
+       }
+       radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0));
+       radeon_ring_write(rdev, RADEON_WAIT_DMA_GUI_IDLE);
+       if (fence) {
+               r = radeon_fence_emit(rdev, fence);
+       }
+       radeon_ring_unlock_commit(rdev);
+       return r;
+}
+
+void r300_ring_start(struct radeon_device *rdev)
+{
+       unsigned gb_tile_config;
+       int r;
+
+       /* Sub pixel 1/12 so we can have 4K rendering according to doc */
+       gb_tile_config = (R300_ENABLE_TILING | R300_TILE_SIZE_16);
+       switch (rdev->num_gb_pipes) {
+       case 2:
+               gb_tile_config |= R300_PIPE_COUNT_R300;
+               break;
+       case 3:
+               gb_tile_config |= R300_PIPE_COUNT_R420_3P;
+               break;
+       case 4:
+               gb_tile_config |= R300_PIPE_COUNT_R420;
+               break;
+       case 1:
+       default:
+               gb_tile_config |= R300_PIPE_COUNT_RV350;
+               break;
+       }
+
+       r = radeon_ring_lock(rdev, 64);
+       if (r) {
+               return;
+       }
+       radeon_ring_write(rdev, PACKET0(RADEON_ISYNC_CNTL, 0));
+       radeon_ring_write(rdev,
+                         RADEON_ISYNC_ANY2D_IDLE3D |
+                         RADEON_ISYNC_ANY3D_IDLE2D |
+                         RADEON_ISYNC_WAIT_IDLEGUI |
+                         RADEON_ISYNC_CPSCRATCH_IDLEGUI);
+       radeon_ring_write(rdev, PACKET0(R300_GB_TILE_CONFIG, 0));
+       radeon_ring_write(rdev, gb_tile_config);
+       radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0));
+       radeon_ring_write(rdev,
+                         RADEON_WAIT_2D_IDLECLEAN |
+                         RADEON_WAIT_3D_IDLECLEAN);
+       radeon_ring_write(rdev, PACKET0(0x170C, 0));
+       radeon_ring_write(rdev, 1 << 31);
+       radeon_ring_write(rdev, PACKET0(R300_GB_SELECT, 0));
+       radeon_ring_write(rdev, 0);
+       radeon_ring_write(rdev, PACKET0(R300_GB_ENABLE, 0));
+       radeon_ring_write(rdev, 0);
+       radeon_ring_write(rdev, PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0));
+       radeon_ring_write(rdev, R300_RB3D_DC_FLUSH | R300_RB3D_DC_FREE);
+       radeon_ring_write(rdev, PACKET0(R300_RB3D_ZCACHE_CTLSTAT, 0));
+       radeon_ring_write(rdev, R300_ZC_FLUSH | R300_ZC_FREE);
+       radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0));
+       radeon_ring_write(rdev,
+                         RADEON_WAIT_2D_IDLECLEAN |
+                         RADEON_WAIT_3D_IDLECLEAN);
+       radeon_ring_write(rdev, PACKET0(R300_GB_AA_CONFIG, 0));
+       radeon_ring_write(rdev, 0);
+       radeon_ring_write(rdev, PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0));
+       radeon_ring_write(rdev, R300_RB3D_DC_FLUSH | R300_RB3D_DC_FREE);
+       radeon_ring_write(rdev, PACKET0(R300_RB3D_ZCACHE_CTLSTAT, 0));
+       radeon_ring_write(rdev, R300_ZC_FLUSH | R300_ZC_FREE);
+       radeon_ring_write(rdev, PACKET0(R300_GB_MSPOS0, 0));
+       radeon_ring_write(rdev,
+                         ((6 << R300_MS_X0_SHIFT) |
+                          (6 << R300_MS_Y0_SHIFT) |
+                          (6 << R300_MS_X1_SHIFT) |
+                          (6 << R300_MS_Y1_SHIFT) |
+                          (6 << R300_MS_X2_SHIFT) |
+                          (6 << R300_MS_Y2_SHIFT) |
+                          (6 << R300_MSBD0_Y_SHIFT) |
+                          (6 << R300_MSBD0_X_SHIFT)));
+       radeon_ring_write(rdev, PACKET0(R300_GB_MSPOS1, 0));
+       radeon_ring_write(rdev,
+                         ((6 << R300_MS_X3_SHIFT) |
+                          (6 << R300_MS_Y3_SHIFT) |
+                          (6 << R300_MS_X4_SHIFT) |
+                          (6 << R300_MS_Y4_SHIFT) |
+                          (6 << R300_MS_X5_SHIFT) |
+                          (6 << R300_MS_Y5_SHIFT) |
+                          (6 << R300_MSBD1_SHIFT)));
+       radeon_ring_write(rdev, PACKET0(R300_GA_ENHANCE, 0));
+       radeon_ring_write(rdev, R300_GA_DEADLOCK_CNTL | R300_GA_FASTSYNC_CNTL);
+       radeon_ring_write(rdev, PACKET0(R300_GA_POLY_MODE, 0));
+       radeon_ring_write(rdev,
+                         R300_FRONT_PTYPE_TRIANGE | R300_BACK_PTYPE_TRIANGE);
+       radeon_ring_write(rdev, PACKET0(R300_GA_ROUND_MODE, 0));
+       radeon_ring_write(rdev,
+                         R300_GEOMETRY_ROUND_NEAREST |
+                         R300_COLOR_ROUND_NEAREST);
+       radeon_ring_unlock_commit(rdev);
+}
+
+void r300_errata(struct radeon_device *rdev)
+{
+       rdev->pll_errata = 0;
+
+       if (rdev->family == CHIP_R300 &&
+           (RREG32(RADEON_CONFIG_CNTL) & RADEON_CFG_ATI_REV_ID_MASK) == RADEON_CFG_ATI_REV_A11) {
+               rdev->pll_errata |= CHIP_ERRATA_R300_CG;
+       }
+}
+
+int r300_mc_wait_for_idle(struct radeon_device *rdev)
+{
+       unsigned i;
+       uint32_t tmp;
+
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               /* read MC_STATUS */
+               tmp = RREG32(0x0150);
+               if (tmp & (1 << 4)) {
+                       return 0;
+               }
+               DRM_UDELAY(1);
+       }
+       return -1;
+}
+
+void r300_gpu_init(struct radeon_device *rdev)
+{
+       uint32_t gb_tile_config, tmp;
+
+       r100_hdp_reset(rdev);
+       /* FIXME: rv380 one pipes ? */
+       if ((rdev->family == CHIP_R300) || (rdev->family == CHIP_R350)) {
+               /* r300,r350 */
+               rdev->num_gb_pipes = 2;
+       } else {
+               /* rv350,rv370,rv380 */
+               rdev->num_gb_pipes = 1;
+       }
+       gb_tile_config = (R300_ENABLE_TILING | R300_TILE_SIZE_16);
+       switch (rdev->num_gb_pipes) {
+       case 2:
+               gb_tile_config |= R300_PIPE_COUNT_R300;
+               break;
+       case 3:
+               gb_tile_config |= R300_PIPE_COUNT_R420_3P;
+               break;
+       case 4:
+               gb_tile_config |= R300_PIPE_COUNT_R420;
+               break;
+       case 1:
+       default:
+               gb_tile_config |= R300_PIPE_COUNT_RV350;
+               break;
+       }
+       WREG32(R300_GB_TILE_CONFIG, gb_tile_config);
+
+       if (r100_gui_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait GUI idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+
+       tmp = RREG32(0x170C);
+       WREG32(0x170C, tmp | (1 << 31));
+
+       WREG32(R300_RB2D_DSTCACHE_MODE,
+              R300_DC_AUTOFLUSH_ENABLE |
+              R300_DC_DC_DISABLE_IGNORE_PE);
+
+       if (r100_gui_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait GUI idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+       if (r300_mc_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait MC idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+       DRM_INFO("radeon: %d pipes initialized.\n", rdev->num_gb_pipes);
+}
+
+int r300_ga_reset(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+       bool reinit_cp;
+       int i;
+
+       reinit_cp = rdev->cp.ready;
+       rdev->cp.ready = false;
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               WREG32(RADEON_CP_CSQ_MODE, 0);
+               WREG32(RADEON_CP_CSQ_CNTL, 0);
+               WREG32(RADEON_RBBM_SOFT_RESET, 0x32005);
+               (void)RREG32(RADEON_RBBM_SOFT_RESET);
+               udelay(200);
+               WREG32(RADEON_RBBM_SOFT_RESET, 0);
+               /* Wait to prevent race in RBBM_STATUS */
+               mdelay(1);
+               tmp = RREG32(RADEON_RBBM_STATUS);
+               if (tmp & ((1 << 20) | (1 << 26))) {
+                       DRM_ERROR("VAP & CP still busy (RBBM_STATUS=0x%08X)", tmp);
+                       /* GA still busy soft reset it */
+                       WREG32(0x429C, 0x200);
+                       WREG32(R300_VAP_PVS_STATE_FLUSH_REG, 0);
+                       WREG32(0x43E0, 0);
+                       WREG32(0x43E4, 0);
+                       WREG32(0x24AC, 0);
+               }
+               /* Wait to prevent race in RBBM_STATUS */
+               mdelay(1);
+               tmp = RREG32(RADEON_RBBM_STATUS);
+               if (!(tmp & ((1 << 20) | (1 << 26)))) {
+                       break;
+               }
+       }
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               tmp = RREG32(RADEON_RBBM_STATUS);
+               if (!(tmp & ((1 << 20) | (1 << 26)))) {
+                       DRM_INFO("GA reset succeed (RBBM_STATUS=0x%08X)\n",
+                                tmp);
+                       if (reinit_cp) {
+                               return r100_cp_init(rdev, rdev->cp.ring_size);
+                       }
+                       return 0;
+               }
+               DRM_UDELAY(1);
+       }
+       tmp = RREG32(RADEON_RBBM_STATUS);
+       DRM_ERROR("Failed to reset GA ! (RBBM_STATUS=0x%08X)\n", tmp);
+       return -1;
+}
+
+int r300_gpu_reset(struct radeon_device *rdev)
+{
+       uint32_t status;
+
+       /* reset order likely matter */
+       status = RREG32(RADEON_RBBM_STATUS);
+       /* reset HDP */
+       r100_hdp_reset(rdev);
+       /* reset rb2d */
+       if (status & ((1 << 17) | (1 << 18) | (1 << 27))) {
+               r100_rb2d_reset(rdev);
+       }
+       /* reset GA */
+       if (status & ((1 << 20) | (1 << 26))) {
+               r300_ga_reset(rdev);
+       }
+       /* reset CP */
+       status = RREG32(RADEON_RBBM_STATUS);
+       if (status & (1 << 16)) {
+               r100_cp_reset(rdev);
+       }
+       /* Check if GPU is idle */
+       status = RREG32(RADEON_RBBM_STATUS);
+       if (status & (1 << 31)) {
+               DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status);
+               return -1;
+       }
+       DRM_INFO("GPU reset succeed (RBBM_STATUS=0x%08X)\n", status);
+       return 0;
+}
+
+
+/*
+ * r300,r350,rv350,rv380 VRAM info
+ */
+void r300_vram_info(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+
+       /* DDR for all card after R300 & IGP */
+       rdev->mc.vram_is_ddr = true;
+       tmp = RREG32(RADEON_MEM_CNTL);
+       if (tmp & R300_MEM_NUM_CHANNELS_MASK) {
+               rdev->mc.vram_width = 128;
+       } else {
+               rdev->mc.vram_width = 64;
+       }
+       rdev->mc.vram_size = RREG32(RADEON_CONFIG_MEMSIZE);
+
+       rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
+       rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
+}
+
+
+/*
+ * Indirect registers accessor
+ */
+uint32_t rv370_pcie_rreg(struct radeon_device *rdev, uint32_t reg)
+{
+       uint32_t r;
+
+       WREG8(RADEON_PCIE_INDEX, ((reg) & 0xff));
+       (void)RREG32(RADEON_PCIE_INDEX);
+       r = RREG32(RADEON_PCIE_DATA);
+       return r;
+}
+
+void rv370_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
+{
+       WREG8(RADEON_PCIE_INDEX, ((reg) & 0xff));
+       (void)RREG32(RADEON_PCIE_INDEX);
+       WREG32(RADEON_PCIE_DATA, (v));
+       (void)RREG32(RADEON_PCIE_DATA);
+}
+
+/*
+ * PCIE Lanes
+ */
+
+void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes)
+{
+       uint32_t link_width_cntl, mask;
+
+       if (rdev->flags & RADEON_IS_IGP)
+               return;
+
+       if (!(rdev->flags & RADEON_IS_PCIE))
+               return;
+
+       /* FIXME wait for idle */
+
+       switch (lanes) {
+       case 0:
+               mask = RADEON_PCIE_LC_LINK_WIDTH_X0;
+               break;
+       case 1:
+               mask = RADEON_PCIE_LC_LINK_WIDTH_X1;
+               break;
+       case 2:
+               mask = RADEON_PCIE_LC_LINK_WIDTH_X2;
+               break;
+       case 4:
+               mask = RADEON_PCIE_LC_LINK_WIDTH_X4;
+               break;
+       case 8:
+               mask = RADEON_PCIE_LC_LINK_WIDTH_X8;
+               break;
+       case 12:
+               mask = RADEON_PCIE_LC_LINK_WIDTH_X12;
+               break;
+       case 16:
+       default:
+               mask = RADEON_PCIE_LC_LINK_WIDTH_X16;
+               break;
+       }
+
+       link_width_cntl = RREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL);
+
+       if ((link_width_cntl & RADEON_PCIE_LC_LINK_WIDTH_RD_MASK) ==
+           (mask << RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT))
+               return;
+
+       link_width_cntl &= ~(RADEON_PCIE_LC_LINK_WIDTH_MASK |
+                            RADEON_PCIE_LC_RECONFIG_NOW |
+                            RADEON_PCIE_LC_RECONFIG_LATER |
+                            RADEON_PCIE_LC_SHORT_RECONFIG_EN);
+       link_width_cntl |= mask;
+       WREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);
+       WREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL, (link_width_cntl |
+                                                    RADEON_PCIE_LC_RECONFIG_NOW));
+
+       /* wait for lane set to complete */
+       link_width_cntl = RREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL);
+       while (link_width_cntl == 0xffffffff)
+               link_width_cntl = RREG32_PCIE(RADEON_PCIE_LC_LINK_WIDTH_CNTL);
+
+}
+
+
+/*
+ * Debugfs info
+ */
+#if defined(CONFIG_DEBUG_FS)
+static int rv370_debugfs_pcie_gart_info(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t tmp;
+
+       tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL);
+       seq_printf(m, "PCIE_TX_GART_CNTL 0x%08x\n", tmp);
+       tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_BASE);
+       seq_printf(m, "PCIE_TX_GART_BASE 0x%08x\n", tmp);
+       tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_START_LO);
+       seq_printf(m, "PCIE_TX_GART_START_LO 0x%08x\n", tmp);
+       tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_START_HI);
+       seq_printf(m, "PCIE_TX_GART_START_HI 0x%08x\n", tmp);
+       tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_END_LO);
+       seq_printf(m, "PCIE_TX_GART_END_LO 0x%08x\n", tmp);
+       tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_END_HI);
+       seq_printf(m, "PCIE_TX_GART_END_HI 0x%08x\n", tmp);
+       tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_ERROR);
+       seq_printf(m, "PCIE_TX_GART_ERROR 0x%08x\n", tmp);
+       return 0;
+}
+
+static struct drm_info_list rv370_pcie_gart_info_list[] = {
+       {"rv370_pcie_gart_info", rv370_debugfs_pcie_gart_info, 0, NULL},
+};
+#endif
+
+int rv370_debugfs_pcie_gart_info_init(struct radeon_device *rdev)
+{
+#if defined(CONFIG_DEBUG_FS)
+       return radeon_debugfs_add_files(rdev, rv370_pcie_gart_info_list, 1);
+#else
+       return 0;
+#endif
+}
+
+
+/*
+ * CS functions
+ */
+struct r300_cs_track_cb {
+       struct radeon_object    *robj;
+       unsigned                pitch;
+       unsigned                cpp;
+       unsigned                offset;
+};
+
+struct r300_cs_track {
+       unsigned                num_cb;
+       unsigned                maxy;
+       struct r300_cs_track_cb cb[4];
+       struct r300_cs_track_cb zb;
+       bool                    z_enabled;
+};
+
+int r300_cs_track_check(struct radeon_device *rdev, struct r300_cs_track *track)
+{
+       unsigned i;
+       unsigned long size;
+
+       for (i = 0; i < track->num_cb; i++) {
+               if (track->cb[i].robj == NULL) {
+                       DRM_ERROR("[drm] No buffer for color buffer %d !\n", i);
+                       return -EINVAL;
+               }
+               size = track->cb[i].pitch * track->cb[i].cpp * track->maxy;
+               size += track->cb[i].offset;
+               if (size > radeon_object_size(track->cb[i].robj)) {
+                       DRM_ERROR("[drm] Buffer too small for color buffer %d "
+                                 "(need %lu have %lu) !\n", i, size,
+                                 radeon_object_size(track->cb[i].robj));
+                       DRM_ERROR("[drm] color buffer %d (%u %u %u %u)\n",
+                                 i, track->cb[i].pitch, track->cb[i].cpp,
+                                 track->cb[i].offset, track->maxy);
+                       return -EINVAL;
+               }
+       }
+       if (track->z_enabled) {
+               if (track->zb.robj == NULL) {
+                       DRM_ERROR("[drm] No buffer for z buffer !\n");
+                       return -EINVAL;
+               }
+               size = track->zb.pitch * track->zb.cpp * track->maxy;
+               size += track->zb.offset;
+               if (size > radeon_object_size(track->zb.robj)) {
+                       DRM_ERROR("[drm] Buffer too small for z buffer "
+                                 "(need %lu have %lu) !\n", size,
+                                 radeon_object_size(track->zb.robj));
+                       return -EINVAL;
+               }
+       }
+       return 0;
+}
+
+static inline void r300_cs_track_clear(struct r300_cs_track *track)
+{
+       unsigned i;
+
+       track->num_cb = 4;
+       track->maxy = 4096;
+       for (i = 0; i < track->num_cb; i++) {
+               track->cb[i].robj = NULL;
+               track->cb[i].pitch = 8192;
+               track->cb[i].cpp = 16;
+               track->cb[i].offset = 0;
+       }
+       track->z_enabled = true;
+       track->zb.robj = NULL;
+       track->zb.pitch = 8192;
+       track->zb.cpp = 4;
+       track->zb.offset = 0;
+}
+
+static unsigned r300_auth_reg[] = {
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFBF, 0xFFFFFFFF, 0xFFFFFFBF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0x17FF1FFF, 0xFFFFFFFC, 0xFFFFFFFF, 0xFF30FFBF,
+       0xFFFFFFF8, 0xC3E6FFFF, 0xFFFFF6DF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFF03F,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFCFCC, 0xF00E9FFF, 0x007C0000,
+       0xF0000078, 0xFF000009, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFF7FF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+       0xFFFFFC78, 0xFFFFFFFF, 0xFFFFFFFC, 0xFFFFFFFF,
+       0x38FF8F50, 0xFFF88082, 0xF000000C, 0xFAE009FF,
+       0x00000000, 0x00000000, 0xFFFF0000, 0x00000000,
+       0x00000000, 0x0000C100, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0xFFFF0000, 0xFFFFFFFF, 0xFF80FFFF,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x0003FC01, 0xFFFFFFF8, 0xFE800B19,
+};
+
+static int r300_packet0_check(struct radeon_cs_parser *p,
+               struct radeon_cs_packet *pkt,
+               unsigned idx, unsigned reg)
+{
+       struct radeon_cs_chunk *ib_chunk;
+       struct radeon_cs_reloc *reloc;
+       struct r300_cs_track *track;
+       volatile uint32_t *ib;
+       uint32_t tmp;
+       unsigned i;
+       int r;
+
+       ib = p->ib->ptr;
+       ib_chunk = &p->chunks[p->chunk_ib_idx];
+       track = (struct r300_cs_track *)p->track;
+       switch (reg) {
+       case RADEON_DST_PITCH_OFFSET:
+       case RADEON_SRC_PITCH_OFFSET:
+               r = r100_cs_packet_next_reloc(p, &reloc);
+               if (r) {
+                       DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
+                                       idx, reg);
+                       r100_cs_dump_packet(p, pkt);
+                       return r;
+               }
+               tmp = ib_chunk->kdata[idx] & 0x003fffff;
+               tmp += (((u32)reloc->lobj.gpu_offset) >> 10);
+               ib[idx] = (ib_chunk->kdata[idx] & 0xffc00000) | tmp;
+               break;
+       case R300_RB3D_COLOROFFSET0:
+       case R300_RB3D_COLOROFFSET1:
+       case R300_RB3D_COLOROFFSET2:
+       case R300_RB3D_COLOROFFSET3:
+               i = (reg - R300_RB3D_COLOROFFSET0) >> 2;
+               r = r100_cs_packet_next_reloc(p, &reloc);
+               if (r) {
+                       DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
+                                       idx, reg);
+                       r100_cs_dump_packet(p, pkt);
+                       return r;
+               }
+               track->cb[i].robj = reloc->robj;
+               track->cb[i].offset = ib_chunk->kdata[idx];
+               ib[idx] = ib_chunk->kdata[idx] + ((u32)reloc->lobj.gpu_offset);
+               break;
+       case R300_ZB_DEPTHOFFSET:
+               r = r100_cs_packet_next_reloc(p, &reloc);
+               if (r) {
+                       DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
+                                       idx, reg);
+                       r100_cs_dump_packet(p, pkt);
+                       return r;
+               }
+               track->zb.robj = reloc->robj;
+               track->zb.offset = ib_chunk->kdata[idx];
+               ib[idx] = ib_chunk->kdata[idx] + ((u32)reloc->lobj.gpu_offset);
+               break;
+       case R300_TX_OFFSET_0:
+       case R300_TX_OFFSET_0+4:
+       case R300_TX_OFFSET_0+8:
+       case R300_TX_OFFSET_0+12:
+       case R300_TX_OFFSET_0+16:
+       case R300_TX_OFFSET_0+20:
+       case R300_TX_OFFSET_0+24:
+       case R300_TX_OFFSET_0+28:
+       case R300_TX_OFFSET_0+32:
+       case R300_TX_OFFSET_0+36:
+       case R300_TX_OFFSET_0+40:
+       case R300_TX_OFFSET_0+44:
+       case R300_TX_OFFSET_0+48:
+       case R300_TX_OFFSET_0+52:
+       case R300_TX_OFFSET_0+56:
+       case R300_TX_OFFSET_0+60:
+               r = r100_cs_packet_next_reloc(p, &reloc);
+               if (r) {
+                       DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
+                                       idx, reg);
+                       r100_cs_dump_packet(p, pkt);
+                       return r;
+               }
+               ib[idx] = ib_chunk->kdata[idx] + ((u32)reloc->lobj.gpu_offset);
+               break;
+       /* Tracked registers */
+       case 0x43E4:
+               /* SC_SCISSOR1 */
+
+               track->maxy = ((ib_chunk->kdata[idx] >> 13) & 0x1FFF) + 1;
+               if (p->rdev->family < CHIP_RV515) {
+                       track->maxy -= 1440;
+               }
+               break;
+       case 0x4E00:
+               /* RB3D_CCTL */
+               track->num_cb = ((ib_chunk->kdata[idx] >> 5) & 0x3) + 1;
+               break;
+       case 0x4E38:
+       case 0x4E3C:
+       case 0x4E40:
+       case 0x4E44:
+               /* RB3D_COLORPITCH0 */
+               /* RB3D_COLORPITCH1 */
+               /* RB3D_COLORPITCH2 */
+               /* RB3D_COLORPITCH3 */
+               i = (reg - 0x4E38) >> 2;
+               track->cb[i].pitch = ib_chunk->kdata[idx] & 0x3FFE;
+               switch (((ib_chunk->kdata[idx] >> 21) & 0xF)) {
+               case 9:
+               case 11:
+               case 12:
+                       track->cb[i].cpp = 1;
+                       break;
+               case 3:
+               case 4:
+               case 13:
+               case 15:
+                       track->cb[i].cpp = 2;
+                       break;
+               case 6:
+                       track->cb[i].cpp = 4;
+                       break;
+               case 10:
+                       track->cb[i].cpp = 8;
+                       break;
+               case 7:
+                       track->cb[i].cpp = 16;
+                       break;
+               default:
+                       DRM_ERROR("Invalid color buffer format (%d) !\n",
+                                 ((ib_chunk->kdata[idx] >> 21) & 0xF));
+                       return -EINVAL;
+               }
+               break;
+       case 0x4F00:
+               /* ZB_CNTL */
+               if (ib_chunk->kdata[idx] & 2) {
+                       track->z_enabled = true;
+               } else {
+                       track->z_enabled = false;
+               }
+               break;
+       case 0x4F10:
+               /* ZB_FORMAT */
+               switch ((ib_chunk->kdata[idx] & 0xF)) {
+               case 0:
+               case 1:
+                       track->zb.cpp = 2;
+                       break;
+               case 2:
+                       track->zb.cpp = 4;
+                       break;
+               default:
+                       DRM_ERROR("Invalid z buffer format (%d) !\n",
+                                 (ib_chunk->kdata[idx] & 0xF));
+                       return -EINVAL;
+               }
+               break;
+       case 0x4F24:
+               /* ZB_DEPTHPITCH */
+               track->zb.pitch = ib_chunk->kdata[idx] & 0x3FFC;
+               break;
+       default:
+               printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n", reg, idx);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int r300_packet3_check(struct radeon_cs_parser *p,
+                             struct radeon_cs_packet *pkt)
+{
+       struct radeon_cs_chunk *ib_chunk;
+       struct radeon_cs_reloc *reloc;
+       struct r300_cs_track *track;
+       volatile uint32_t *ib;
+       unsigned idx;
+       unsigned i, c;
+       int r;
+
+       ib = p->ib->ptr;
+       ib_chunk = &p->chunks[p->chunk_ib_idx];
+       idx = pkt->idx + 1;
+       track = (struct r300_cs_track *)p->track;
+       switch (pkt->opcode) {
+       case PACKET3_3D_LOAD_VBPNTR:
+               c = ib_chunk->kdata[idx++];
+               for (i = 0; i < (c - 1); i += 2, idx += 3) {
+                       r = r100_cs_packet_next_reloc(p, &reloc);
+                       if (r) {
+                               DRM_ERROR("No reloc for packet3 %d\n",
+                                         pkt->opcode);
+                               r100_cs_dump_packet(p, pkt);
+                               return r;
+                       }
+                       ib[idx+1] = ib_chunk->kdata[idx+1] + ((u32)reloc->lobj.gpu_offset);
+                       r = r100_cs_packet_next_reloc(p, &reloc);
+                       if (r) {
+                               DRM_ERROR("No reloc for packet3 %d\n",
+                                         pkt->opcode);
+                               r100_cs_dump_packet(p, pkt);
+                               return r;
+                       }
+                       ib[idx+2] = ib_chunk->kdata[idx+2] + ((u32)reloc->lobj.gpu_offset);
+               }
+               if (c & 1) {
+                       r = r100_cs_packet_next_reloc(p, &reloc);
+                       if (r) {
+                               DRM_ERROR("No reloc for packet3 %d\n",
+                                         pkt->opcode);
+                               r100_cs_dump_packet(p, pkt);
+                               return r;
+                       }
+                       ib[idx+1] = ib_chunk->kdata[idx+1] + ((u32)reloc->lobj.gpu_offset);
+               }
+               break;
+       case PACKET3_INDX_BUFFER:
+               r = r100_cs_packet_next_reloc(p, &reloc);
+               if (r) {
+                       DRM_ERROR("No reloc for packet3 %d\n", pkt->opcode);
+                       r100_cs_dump_packet(p, pkt);
+                       return r;
+               }
+               ib[idx+1] = ib_chunk->kdata[idx+1] + ((u32)reloc->lobj.gpu_offset);
+               break;
+       /* Draw packet */
+       case PACKET3_3D_DRAW_VBUF:
+       case PACKET3_3D_DRAW_IMMD:
+       case PACKET3_3D_DRAW_INDX:
+       case PACKET3_3D_DRAW_VBUF_2:
+       case PACKET3_3D_DRAW_IMMD_2:
+       case PACKET3_3D_DRAW_INDX_2:
+               r = r300_cs_track_check(p->rdev, track);
+               if (r) {
+                       return r;
+               }
+               break;
+       case PACKET3_NOP:
+               break;
+       default:
+               DRM_ERROR("Packet3 opcode %x not supported\n", pkt->opcode);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int r300_cs_parse(struct radeon_cs_parser *p)
+{
+       struct radeon_cs_packet pkt;
+       struct r300_cs_track track;
+       int r;
+
+       r300_cs_track_clear(&track);
+       p->track = &track;
+       do {
+               r = r100_cs_packet_parse(p, &pkt, p->idx);
+               if (r) {
+                       return r;
+               }
+               p->idx += pkt.count + 2;
+               switch (pkt.type) {
+               case PACKET_TYPE0:
+                       r = r100_cs_parse_packet0(p, &pkt,
+                                                 r300_auth_reg,
+                                                 ARRAY_SIZE(r300_auth_reg),
+                                                 &r300_packet0_check);
+                       break;
+               case PACKET_TYPE2:
+                       break;
+               case PACKET_TYPE3:
+                       r = r300_packet3_check(p, &pkt);
+                       break;
+               default:
+                       DRM_ERROR("Unknown packet type %d !\n", pkt.type);
+                       return -EINVAL;
+               }
+               if (r) {
+                       return r;
+               }
+       } while (p->idx < p->chunks[p->chunk_ib_idx].length_dw);
+       return 0;
+}
index bdbc95fa6721907e26d7f53a40a6e1f59657f39b..70f48609515e2c1c69b19e83a7cc5ce6595399f9 100644 (file)
@@ -1,30 +1,34 @@
-/**************************************************************************
-
-Copyright (C) 2004-2005 Nicolai Haehnle et al.
-
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and associated documentation files (the "Software"),
-to deal in the Software without restriction, including without limitation
-on the rights to use, copy, modify, merge, publish, distribute, sub
-license, and/or sell copies of the Software, and to permit persons to whom
-the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice (including the next
-paragraph) shall be included in all copies or substantial portions of the
-Software.
+/*
+ * Copyright 2005 Nicolai Haehnle et al.
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Nicolai Haehnle
+ *          Jerome Glisse
+ */
+#ifndef _R300_REG_H_
+#define _R300_REG_H_
 
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
-THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
-DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-USE OR OTHER DEALINGS IN THE SOFTWARE.
 
-**************************************************************************/
 
-#ifndef _R300_REG_H
-#define _R300_REG_H
 
 #define R300_MC_INIT_MISC_LAT_TIMER    0x180
 #      define R300_MC_MISC__MC_CPR_INIT_LAT_SHIFT      0
diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c
new file mode 100644 (file)
index 0000000..dea497a
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ *          Jerome Glisse
+ */
+#include <linux/seq_file.h>
+#include "drmP.h"
+#include "radeon_reg.h"
+#include "radeon.h"
+
+/* r420,r423,rv410 depends on : */
+void r100_pci_gart_disable(struct radeon_device *rdev);
+void r100_hdp_reset(struct radeon_device *rdev);
+void r100_mc_setup(struct radeon_device *rdev);
+int r100_gui_wait_for_idle(struct radeon_device *rdev);
+void r100_mc_disable_clients(struct radeon_device *rdev);
+void r300_vram_info(struct radeon_device *rdev);
+int r300_mc_wait_for_idle(struct radeon_device *rdev);
+int rv370_pcie_gart_enable(struct radeon_device *rdev);
+void rv370_pcie_gart_disable(struct radeon_device *rdev);
+
+/* This files gather functions specifics to :
+ * r420,r423,rv410
+ *
+ * Some of these functions might be used by newer ASICs.
+ */
+void r420_gpu_init(struct radeon_device *rdev);
+int r420_debugfs_pipes_info_init(struct radeon_device *rdev);
+
+
+/*
+ * MC
+ */
+int r420_mc_init(struct radeon_device *rdev)
+{
+       int r;
+
+       if (r100_debugfs_rbbm_init(rdev)) {
+               DRM_ERROR("Failed to register debugfs file for RBBM !\n");
+       }
+       if (r420_debugfs_pipes_info_init(rdev)) {
+               DRM_ERROR("Failed to register debugfs file for pipes !\n");
+       }
+
+       r420_gpu_init(rdev);
+       r100_pci_gart_disable(rdev);
+       if (rdev->flags & RADEON_IS_PCIE) {
+               rv370_pcie_gart_disable(rdev);
+       }
+
+       /* Setup GPU memory space */
+       rdev->mc.vram_location = 0xFFFFFFFFUL;
+       rdev->mc.gtt_location = 0xFFFFFFFFUL;
+       if (rdev->flags & RADEON_IS_AGP) {
+               r = radeon_agp_init(rdev);
+               if (r) {
+                       printk(KERN_WARNING "[drm] Disabling AGP\n");
+                       rdev->flags &= ~RADEON_IS_AGP;
+                       rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024;
+               } else {
+                       rdev->mc.gtt_location = rdev->mc.agp_base;
+               }
+       }
+       r = radeon_mc_setup(rdev);
+       if (r) {
+               return r;
+       }
+
+       /* Program GPU memory space */
+       r100_mc_disable_clients(rdev);
+       if (r300_mc_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait MC idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+       r100_mc_setup(rdev);
+       return 0;
+}
+
+void r420_mc_fini(struct radeon_device *rdev)
+{
+       rv370_pcie_gart_disable(rdev);
+       radeon_gart_table_vram_free(rdev);
+       radeon_gart_fini(rdev);
+}
+
+
+/*
+ * Global GPU functions
+ */
+void r420_errata(struct radeon_device *rdev)
+{
+       rdev->pll_errata = 0;
+}
+
+void r420_pipes_init(struct radeon_device *rdev)
+{
+       unsigned tmp;
+       unsigned gb_pipe_select;
+       unsigned num_pipes;
+
+       /* GA_ENHANCE workaround TCL deadlock issue */
+       WREG32(0x4274, (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3));
+       /* get max number of pipes */
+       gb_pipe_select = RREG32(0x402C);
+       num_pipes = ((gb_pipe_select >> 12) & 3) + 1;
+       rdev->num_gb_pipes = num_pipes;
+       tmp = 0;
+       switch (num_pipes) {
+       default:
+               /* force to 1 pipe */
+               num_pipes = 1;
+       case 1:
+               tmp = (0 << 1);
+               break;
+       case 2:
+               tmp = (3 << 1);
+               break;
+       case 3:
+               tmp = (6 << 1);
+               break;
+       case 4:
+               tmp = (7 << 1);
+               break;
+       }
+       WREG32(0x42C8, (1 << num_pipes) - 1);
+       /* Sub pixel 1/12 so we can have 4K rendering according to doc */
+       tmp |= (1 << 4) | (1 << 0);
+       WREG32(0x4018, tmp);
+       if (r100_gui_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait GUI idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+
+       tmp = RREG32(0x170C);
+       WREG32(0x170C, tmp | (1 << 31));
+
+       WREG32(R300_RB2D_DSTCACHE_MODE,
+              RREG32(R300_RB2D_DSTCACHE_MODE) |
+              R300_DC_AUTOFLUSH_ENABLE |
+              R300_DC_DC_DISABLE_IGNORE_PE);
+
+       if (r100_gui_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait GUI idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+       DRM_INFO("radeon: %d pipes initialized.\n", rdev->num_gb_pipes);
+}
+
+void r420_gpu_init(struct radeon_device *rdev)
+{
+       r100_hdp_reset(rdev);
+       r420_pipes_init(rdev);
+       if (r300_mc_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait MC idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+}
+
+
+/*
+ * r420,r423,rv410 VRAM info
+ */
+void r420_vram_info(struct radeon_device *rdev)
+{
+       r300_vram_info(rdev);
+}
+
+
+/*
+ * Debugfs info
+ */
+#if defined(CONFIG_DEBUG_FS)
+static int r420_debugfs_pipes_info(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t tmp;
+
+       tmp = RREG32(R400_GB_PIPE_SELECT);
+       seq_printf(m, "GB_PIPE_SELECT 0x%08x\n", tmp);
+       tmp = RREG32(R300_GB_TILE_CONFIG);
+       seq_printf(m, "GB_TILE_CONFIG 0x%08x\n", tmp);
+       tmp = RREG32(R300_DST_PIPE_CONFIG);
+       seq_printf(m, "DST_PIPE_CONFIG 0x%08x\n", tmp);
+       return 0;
+}
+
+static struct drm_info_list r420_pipes_info_list[] = {
+       {"r420_pipes_info", r420_debugfs_pipes_info, 0, NULL},
+};
+#endif
+
+int r420_debugfs_pipes_info_init(struct radeon_device *rdev)
+{
+#if defined(CONFIG_DEBUG_FS)
+       return radeon_debugfs_add_files(rdev, r420_pipes_info_list, 1);
+#else
+       return 0;
+#endif
+}
diff --git a/drivers/gpu/drm/radeon/r500_reg.h b/drivers/gpu/drm/radeon/r500_reg.h
new file mode 100644 (file)
index 0000000..9070a1c
--- /dev/null
@@ -0,0 +1,749 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ *          Jerome Glisse
+ */
+#ifndef __R500_REG_H__
+#define __R500_REG_H__
+
+/* pipe config regs */
+#define R300_GA_POLY_MODE                              0x4288
+#       define R300_FRONT_PTYPE_POINT                   (0 << 4)
+#       define R300_FRONT_PTYPE_LINE                    (1 << 4)
+#       define R300_FRONT_PTYPE_TRIANGE                 (2 << 4)
+#       define R300_BACK_PTYPE_POINT                    (0 << 7)
+#       define R300_BACK_PTYPE_LINE                     (1 << 7)
+#       define R300_BACK_PTYPE_TRIANGE                  (2 << 7)
+#define R300_GA_ROUND_MODE                             0x428c
+#       define R300_GEOMETRY_ROUND_TRUNC                (0 << 0)
+#       define R300_GEOMETRY_ROUND_NEAREST              (1 << 0)
+#       define R300_COLOR_ROUND_TRUNC                   (0 << 2)
+#       define R300_COLOR_ROUND_NEAREST                 (1 << 2)
+#define R300_GB_MSPOS0                                 0x4010
+#       define R300_MS_X0_SHIFT                         0
+#       define R300_MS_Y0_SHIFT                         4
+#       define R300_MS_X1_SHIFT                         8
+#       define R300_MS_Y1_SHIFT                         12
+#       define R300_MS_X2_SHIFT                         16
+#       define R300_MS_Y2_SHIFT                         20
+#       define R300_MSBD0_Y_SHIFT                       24
+#       define R300_MSBD0_X_SHIFT                       28
+#define R300_GB_MSPOS1                                 0x4014
+#       define R300_MS_X3_SHIFT                         0
+#       define R300_MS_Y3_SHIFT                         4
+#       define R300_MS_X4_SHIFT                         8
+#       define R300_MS_Y4_SHIFT                         12
+#       define R300_MS_X5_SHIFT                         16
+#       define R300_MS_Y5_SHIFT                         20
+#       define R300_MSBD1_SHIFT                         24
+
+#define R300_GA_ENHANCE                                        0x4274
+#       define R300_GA_DEADLOCK_CNTL                    (1 << 0)
+#       define R300_GA_FASTSYNC_CNTL                    (1 << 1)
+#define R300_RB3D_DSTCACHE_CTLSTAT              0x4e4c
+#      define R300_RB3D_DC_FLUSH               (2 << 0)
+#      define R300_RB3D_DC_FREE                (2 << 2)
+#      define R300_RB3D_DC_FINISH              (1 << 4)
+#define R300_RB3D_ZCACHE_CTLSTAT                       0x4f18
+#       define R300_ZC_FLUSH                            (1 << 0)
+#       define R300_ZC_FREE                             (1 << 1)
+#       define R300_ZC_FLUSH_ALL                        0x3
+#define R400_GB_PIPE_SELECT             0x402c
+#define R500_DYN_SCLK_PWMEM_PIPE        0x000d /* PLL */
+#define R500_SU_REG_DEST                0x42c8
+#define R300_GB_TILE_CONFIG             0x4018
+#       define R300_ENABLE_TILING       (1 << 0)
+#       define R300_PIPE_COUNT_RV350    (0 << 1)
+#       define R300_PIPE_COUNT_R300     (3 << 1)
+#       define R300_PIPE_COUNT_R420_3P  (6 << 1)
+#       define R300_PIPE_COUNT_R420     (7 << 1)
+#       define R300_TILE_SIZE_8         (0 << 4)
+#       define R300_TILE_SIZE_16        (1 << 4)
+#       define R300_TILE_SIZE_32        (2 << 4)
+#       define R300_SUBPIXEL_1_12       (0 << 16)
+#       define R300_SUBPIXEL_1_16       (1 << 16)
+#define R300_DST_PIPE_CONFIG            0x170c
+#       define R300_PIPE_AUTO_CONFIG    (1 << 31)
+#define R300_RB2D_DSTCACHE_MODE         0x3428
+#       define R300_DC_AUTOFLUSH_ENABLE (1 << 8)
+#       define R300_DC_DC_DISABLE_IGNORE_PE (1 << 17)
+
+#define RADEON_CP_STAT         0x7C0
+#define RADEON_RBBM_CMDFIFO_ADDR       0xE70
+#define RADEON_RBBM_CMDFIFO_DATA       0xE74
+#define RADEON_ISYNC_CNTL              0x1724
+#      define RADEON_ISYNC_ANY2D_IDLE3D        (1 << 0)
+#      define RADEON_ISYNC_ANY3D_IDLE2D        (1 << 1)
+#      define RADEON_ISYNC_TRIG2D_IDLE3D       (1 << 2)
+#      define RADEON_ISYNC_TRIG3D_IDLE2D       (1 << 3)
+#      define RADEON_ISYNC_WAIT_IDLEGUI        (1 << 4)
+#      define RADEON_ISYNC_CPSCRATCH_IDLEGUI   (1 << 5)
+
+#define RS480_NB_MC_INDEX               0x168
+#      define RS480_NB_MC_IND_WR_EN    (1 << 8)
+#define RS480_NB_MC_DATA                0x16c
+
+/*
+ * RS690
+ */
+#define RS690_MCCFG_FB_LOCATION                0x100
+#define                RS690_MC_FB_START_MASK          0x0000FFFF
+#define                RS690_MC_FB_START_SHIFT         0
+#define                RS690_MC_FB_TOP_MASK            0xFFFF0000
+#define                RS690_MC_FB_TOP_SHIFT           16
+#define RS690_MCCFG_AGP_LOCATION       0x101
+#define                RS690_MC_AGP_START_MASK         0x0000FFFF
+#define                RS690_MC_AGP_START_SHIFT        0
+#define                RS690_MC_AGP_TOP_MASK           0xFFFF0000
+#define                RS690_MC_AGP_TOP_SHIFT          16
+#define RS690_MCCFG_AGP_BASE           0x102
+#define RS690_MCCFG_AGP_BASE_2         0x103
+#define RS690_MC_INIT_MISC_LAT_TIMER            0x104
+#define RS690_HDP_FB_LOCATION          0x0134
+#define RS690_MC_INDEX                         0x78
+#      define RS690_MC_INDEX_MASK              0x1ff
+#      define RS690_MC_INDEX_WR_EN             (1 << 9)
+#      define RS690_MC_INDEX_WR_ACK            0x7f
+#define RS690_MC_DATA                          0x7c
+#define RS690_MC_STATUS                         0x90
+#define RS690_MC_STATUS_IDLE                    (1 << 0)
+#define RS480_AGP_BASE_2               0x0164
+#define RS480_MC_MISC_CNTL              0x18
+#      define RS480_DISABLE_GTW        (1 << 1)
+#      define RS480_GART_INDEX_REG_EN  (1 << 12)
+#      define RS690_BLOCK_GFX_D3_EN    (1 << 14)
+#define RS480_GART_FEATURE_ID           0x2b
+#      define RS480_HANG_EN            (1 << 11)
+#      define RS480_TLB_ENABLE         (1 << 18)
+#      define RS480_P2P_ENABLE         (1 << 19)
+#      define RS480_GTW_LAC_EN         (1 << 25)
+#      define RS480_2LEVEL_GART        (0 << 30)
+#      define RS480_1LEVEL_GART        (1 << 30)
+#      define RS480_PDC_EN             (1 << 31)
+#define RS480_GART_BASE                 0x2c
+#define RS480_GART_CACHE_CNTRL          0x2e
+#      define RS480_GART_CACHE_INVALIDATE (1 << 0) /* wait for it to clear */
+#define RS480_AGP_ADDRESS_SPACE_SIZE    0x38
+#      define RS480_GART_EN            (1 << 0)
+#      define RS480_VA_SIZE_32MB       (0 << 1)
+#      define RS480_VA_SIZE_64MB       (1 << 1)
+#      define RS480_VA_SIZE_128MB      (2 << 1)
+#      define RS480_VA_SIZE_256MB      (3 << 1)
+#      define RS480_VA_SIZE_512MB      (4 << 1)
+#      define RS480_VA_SIZE_1GB        (5 << 1)
+#      define RS480_VA_SIZE_2GB        (6 << 1)
+#define RS480_AGP_MODE_CNTL             0x39
+#      define RS480_POST_GART_Q_SIZE   (1 << 18)
+#      define RS480_NONGART_SNOOP      (1 << 19)
+#      define RS480_AGP_RD_BUF_SIZE    (1 << 20)
+#      define RS480_REQ_TYPE_SNOOP_SHIFT 22
+#      define RS480_REQ_TYPE_SNOOP_MASK  0x3
+#      define RS480_REQ_TYPE_SNOOP_DIS (1 << 24)
+
+#define RS690_AIC_CTRL_SCRATCH         0x3A
+#      define RS690_DIS_OUT_OF_PCI_GART_ACCESS (1 << 1)
+
+/*
+ * RS600
+ */
+#define RS600_MC_STATUS                         0x0
+#define RS600_MC_STATUS_IDLE                    (1 << 0)
+#define RS600_MC_INDEX                          0x70
+#       define RS600_MC_ADDR_MASK               0xffff
+#       define RS600_MC_IND_SEQ_RBS_0           (1 << 16)
+#       define RS600_MC_IND_SEQ_RBS_1           (1 << 17)
+#       define RS600_MC_IND_SEQ_RBS_2           (1 << 18)
+#       define RS600_MC_IND_SEQ_RBS_3           (1 << 19)
+#       define RS600_MC_IND_AIC_RBS             (1 << 20)
+#       define RS600_MC_IND_CITF_ARB0           (1 << 21)
+#       define RS600_MC_IND_CITF_ARB1           (1 << 22)
+#       define RS600_MC_IND_WR_EN               (1 << 23)
+#define RS600_MC_DATA                           0x74
+#define RS600_MC_STATUS                         0x0
+#       define RS600_MC_IDLE                    (1 << 1)
+#define RS600_MC_FB_LOCATION                    0x4
+#define                RS600_MC_FB_START_MASK          0x0000FFFF
+#define                RS600_MC_FB_START_SHIFT         0
+#define                RS600_MC_FB_TOP_MASK            0xFFFF0000
+#define                RS600_MC_FB_TOP_SHIFT           16
+#define RS600_MC_AGP_LOCATION                   0x5
+#define                RS600_MC_AGP_START_MASK         0x0000FFFF
+#define                RS600_MC_AGP_START_SHIFT        0
+#define                RS600_MC_AGP_TOP_MASK           0xFFFF0000
+#define                RS600_MC_AGP_TOP_SHIFT          16
+#define RS600_MC_AGP_BASE                          0x6
+#define RS600_MC_AGP_BASE_2                        0x7
+#define RS600_MC_CNTL1                          0x9
+#       define RS600_ENABLE_PAGE_TABLES         (1 << 26)
+#define RS600_MC_PT0_CNTL                       0x100
+#       define RS600_ENABLE_PT                  (1 << 0)
+#       define RS600_EFFECTIVE_L2_CACHE_SIZE(x) ((x) << 15)
+#       define RS600_EFFECTIVE_L2_QUEUE_SIZE(x) ((x) << 21)
+#       define RS600_INVALIDATE_ALL_L1_TLBS     (1 << 28)
+#       define RS600_INVALIDATE_L2_CACHE        (1 << 29)
+#define RS600_MC_PT0_CONTEXT0_CNTL              0x102
+#       define RS600_ENABLE_PAGE_TABLE          (1 << 0)
+#       define RS600_PAGE_TABLE_TYPE_FLAT       (0 << 1)
+#define RS600_MC_PT0_SYSTEM_APERTURE_LOW_ADDR   0x112
+#define RS600_MC_PT0_SYSTEM_APERTURE_HIGH_ADDR  0x114
+#define RS600_MC_PT0_CONTEXT0_DEFAULT_READ_ADDR 0x11c
+#define RS600_MC_PT0_CONTEXT0_FLAT_BASE_ADDR    0x12c
+#define RS600_MC_PT0_CONTEXT0_FLAT_START_ADDR   0x13c
+#define RS600_MC_PT0_CONTEXT0_FLAT_END_ADDR     0x14c
+#define RS600_MC_PT0_CLIENT0_CNTL               0x16c
+#       define RS600_ENABLE_TRANSLATION_MODE_OVERRIDE       (1 << 0)
+#       define RS600_TRANSLATION_MODE_OVERRIDE              (1 << 1)
+#       define RS600_SYSTEM_ACCESS_MODE_MASK                (3 << 8)
+#       define RS600_SYSTEM_ACCESS_MODE_PA_ONLY             (0 << 8)
+#       define RS600_SYSTEM_ACCESS_MODE_USE_SYS_MAP         (1 << 8)
+#       define RS600_SYSTEM_ACCESS_MODE_IN_SYS              (2 << 8)
+#       define RS600_SYSTEM_ACCESS_MODE_NOT_IN_SYS          (3 << 8)
+#       define RS600_SYSTEM_APERTURE_UNMAPPED_ACCESS_PASSTHROUGH        (0 << 10)
+#       define RS600_SYSTEM_APERTURE_UNMAPPED_ACCESS_DEFAULT_PAGE       (1 << 10)
+#       define RS600_EFFECTIVE_L1_CACHE_SIZE(x) ((x) << 11)
+#       define RS600_ENABLE_FRAGMENT_PROCESSING (1 << 14)
+#       define RS600_EFFECTIVE_L1_QUEUE_SIZE(x) ((x) << 15)
+#       define RS600_INVALIDATE_L1_TLB          (1 << 20)
+/* rs600/rs690/rs740 */
+#      define RS600_BUS_MASTER_DIS             (1 << 14)
+#      define RS600_MSI_REARM                  (1 << 20)
+/* see RS400_MSI_REARM in AIC_CNTL for rs480 */
+
+
+
+#define RV515_MC_FB_LOCATION           0x01
+#define                RV515_MC_FB_START_MASK          0x0000FFFF
+#define                RV515_MC_FB_START_SHIFT         0
+#define                RV515_MC_FB_TOP_MASK            0xFFFF0000
+#define                RV515_MC_FB_TOP_SHIFT           16
+#define RV515_MC_AGP_LOCATION          0x02
+#define                RV515_MC_AGP_START_MASK         0x0000FFFF
+#define                RV515_MC_AGP_START_SHIFT        0
+#define                RV515_MC_AGP_TOP_MASK           0xFFFF0000
+#define                RV515_MC_AGP_TOP_SHIFT          16
+#define RV515_MC_AGP_BASE              0x03
+#define RV515_MC_AGP_BASE_2            0x04
+
+#define R520_MC_FB_LOCATION            0x04
+#define                R520_MC_FB_START_MASK           0x0000FFFF
+#define                R520_MC_FB_START_SHIFT          0
+#define                R520_MC_FB_TOP_MASK             0xFFFF0000
+#define                R520_MC_FB_TOP_SHIFT            16
+#define R520_MC_AGP_LOCATION           0x05
+#define                R520_MC_AGP_START_MASK          0x0000FFFF
+#define                R520_MC_AGP_START_SHIFT         0
+#define                R520_MC_AGP_TOP_MASK            0xFFFF0000
+#define                R520_MC_AGP_TOP_SHIFT           16
+#define R520_MC_AGP_BASE               0x06
+#define R520_MC_AGP_BASE_2             0x07
+
+
+#define AVIVO_MC_INDEX                                         0x0070
+#define R520_MC_STATUS 0x00
+#define R520_MC_STATUS_IDLE (1<<1)
+#define RV515_MC_STATUS 0x08
+#define RV515_MC_STATUS_IDLE (1<<4)
+#define RV515_MC_INIT_MISC_LAT_TIMER            0x09
+#define AVIVO_MC_DATA                                          0x0074
+
+#define R520_MC_IND_INDEX 0x70
+#define R520_MC_IND_WR_EN (1 << 24)
+#define R520_MC_IND_DATA  0x74
+
+#define RV515_MC_CNTL          0x5
+#      define RV515_MEM_NUM_CHANNELS_MASK  0x3
+#define R520_MC_CNTL0          0x8
+#      define R520_MEM_NUM_CHANNELS_MASK  (0x3 << 24)
+#      define R520_MEM_NUM_CHANNELS_SHIFT  24
+#      define R520_MC_CHANNEL_SIZE  (1 << 23)
+
+#define AVIVO_CP_DYN_CNTL                              0x000f /* PLL */
+#       define AVIVO_CP_FORCEON                        (1 << 0)
+#define AVIVO_E2_DYN_CNTL                              0x0011 /* PLL */
+#       define AVIVO_E2_FORCEON                        (1 << 0)
+#define AVIVO_IDCT_DYN_CNTL                            0x0013 /* PLL */
+#       define AVIVO_IDCT_FORCEON                      (1 << 0)
+
+#define AVIVO_HDP_FB_LOCATION 0x134
+
+#define AVIVO_VGA_RENDER_CONTROL                               0x0300
+#       define AVIVO_VGA_VSTATUS_CNTL_MASK                      (3 << 16)
+#define AVIVO_D1VGA_CONTROL                                    0x0330
+#       define AVIVO_DVGA_CONTROL_MODE_ENABLE (1<<0)
+#       define AVIVO_DVGA_CONTROL_TIMING_SELECT (1<<8)
+#       define AVIVO_DVGA_CONTROL_SYNC_POLARITY_SELECT (1<<9)
+#       define AVIVO_DVGA_CONTROL_OVERSCAN_TIMING_SELECT (1<<10)
+#       define AVIVO_DVGA_CONTROL_OVERSCAN_COLOR_EN (1<<16)
+#       define AVIVO_DVGA_CONTROL_ROTATE (1<<24)
+#define AVIVO_D2VGA_CONTROL                                    0x0338
+
+#define AVIVO_EXT1_PPLL_REF_DIV_SRC                             0x400
+#define AVIVO_EXT1_PPLL_REF_DIV                                 0x404
+#define AVIVO_EXT1_PPLL_UPDATE_LOCK                             0x408
+#define AVIVO_EXT1_PPLL_UPDATE_CNTL                             0x40c
+
+#define AVIVO_EXT2_PPLL_REF_DIV_SRC                             0x410
+#define AVIVO_EXT2_PPLL_REF_DIV                                 0x414
+#define AVIVO_EXT2_PPLL_UPDATE_LOCK                             0x418
+#define AVIVO_EXT2_PPLL_UPDATE_CNTL                             0x41c
+
+#define AVIVO_EXT1_PPLL_FB_DIV                                   0x430
+#define AVIVO_EXT2_PPLL_FB_DIV                                   0x434
+
+#define AVIVO_EXT1_PPLL_POST_DIV_SRC                                 0x438
+#define AVIVO_EXT1_PPLL_POST_DIV                                     0x43c
+
+#define AVIVO_EXT2_PPLL_POST_DIV_SRC                                 0x440
+#define AVIVO_EXT2_PPLL_POST_DIV                                     0x444
+
+#define AVIVO_EXT1_PPLL_CNTL                                    0x448
+#define AVIVO_EXT2_PPLL_CNTL                                    0x44c
+
+#define AVIVO_P1PLL_CNTL                                        0x450
+#define AVIVO_P2PLL_CNTL                                        0x454
+#define AVIVO_P1PLL_INT_SS_CNTL                                 0x458
+#define AVIVO_P2PLL_INT_SS_CNTL                                 0x45c
+#define AVIVO_P1PLL_TMDSA_CNTL                                  0x460
+#define AVIVO_P2PLL_LVTMA_CNTL                                  0x464
+
+#define AVIVO_PCLK_CRTC1_CNTL                                   0x480
+#define AVIVO_PCLK_CRTC2_CNTL                                   0x484
+
+#define AVIVO_D1CRTC_H_TOTAL                                   0x6000
+#define AVIVO_D1CRTC_H_BLANK_START_END                          0x6004
+#define AVIVO_D1CRTC_H_SYNC_A                                   0x6008
+#define AVIVO_D1CRTC_H_SYNC_A_CNTL                              0x600c
+#define AVIVO_D1CRTC_H_SYNC_B                                   0x6010
+#define AVIVO_D1CRTC_H_SYNC_B_CNTL                              0x6014
+
+#define AVIVO_D1CRTC_V_TOTAL                                   0x6020
+#define AVIVO_D1CRTC_V_BLANK_START_END                          0x6024
+#define AVIVO_D1CRTC_V_SYNC_A                                   0x6028
+#define AVIVO_D1CRTC_V_SYNC_A_CNTL                              0x602c
+#define AVIVO_D1CRTC_V_SYNC_B                                   0x6030
+#define AVIVO_D1CRTC_V_SYNC_B_CNTL                              0x6034
+
+#define AVIVO_D1CRTC_CONTROL                                    0x6080
+#       define AVIVO_CRTC_EN                                    (1 << 0)
+#define AVIVO_D1CRTC_BLANK_CONTROL                              0x6084
+#define AVIVO_D1CRTC_INTERLACE_CONTROL                          0x6088
+#define AVIVO_D1CRTC_INTERLACE_STATUS                           0x608c
+#define AVIVO_D1CRTC_STEREO_CONTROL                             0x60c4
+
+/* master controls */
+#define AVIVO_DC_CRTC_MASTER_EN                                 0x60f8
+#define AVIVO_DC_CRTC_TV_CONTROL                                0x60fc
+
+#define AVIVO_D1GRPH_ENABLE                                     0x6100
+#define AVIVO_D1GRPH_CONTROL                                    0x6104
+#       define AVIVO_D1GRPH_CONTROL_DEPTH_8BPP                  (0 << 0)
+#       define AVIVO_D1GRPH_CONTROL_DEPTH_16BPP                 (1 << 0)
+#       define AVIVO_D1GRPH_CONTROL_DEPTH_32BPP                 (2 << 0)
+#       define AVIVO_D1GRPH_CONTROL_DEPTH_64BPP                 (3 << 0)
+
+#       define AVIVO_D1GRPH_CONTROL_8BPP_INDEXED                (0 << 8)
+
+#       define AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555              (0 << 8)
+#       define AVIVO_D1GRPH_CONTROL_16BPP_RGB565                (1 << 8)
+#       define AVIVO_D1GRPH_CONTROL_16BPP_ARGB4444              (2 << 8)
+#       define AVIVO_D1GRPH_CONTROL_16BPP_AI88                  (3 << 8)
+#       define AVIVO_D1GRPH_CONTROL_16BPP_MONO16                (4 << 8)
+
+#       define AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888              (0 << 8)
+#       define AVIVO_D1GRPH_CONTROL_32BPP_ARGB2101010           (1 << 8)
+#       define AVIVO_D1GRPH_CONTROL_32BPP_DIGITAL               (2 << 8)
+#       define AVIVO_D1GRPH_CONTROL_32BPP_8B_ARGB2101010        (3 << 8)
+
+
+#       define AVIVO_D1GRPH_CONTROL_64BPP_ARGB16161616          (0 << 8)
+
+#       define AVIVO_D1GRPH_SWAP_RB                             (1 << 16)
+#       define AVIVO_D1GRPH_TILED                               (1 << 20)
+#       define AVIVO_D1GRPH_MACRO_ADDRESS_MODE                  (1 << 21)
+
+#define AVIVO_D1GRPH_LUT_SEL                                    0x6108
+#define AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS                    0x6110
+#define AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS                  0x6118
+#define AVIVO_D1GRPH_PITCH                                      0x6120
+#define AVIVO_D1GRPH_SURFACE_OFFSET_X                           0x6124
+#define AVIVO_D1GRPH_SURFACE_OFFSET_Y                           0x6128
+#define AVIVO_D1GRPH_X_START                                    0x612c
+#define AVIVO_D1GRPH_Y_START                                    0x6130
+#define AVIVO_D1GRPH_X_END                                      0x6134
+#define AVIVO_D1GRPH_Y_END                                      0x6138
+#define AVIVO_D1GRPH_UPDATE                                     0x6144
+#       define AVIVO_D1GRPH_UPDATE_LOCK                         (1 << 16)
+#define AVIVO_D1GRPH_FLIP_CONTROL                               0x6148
+
+#define AVIVO_D1CUR_CONTROL                     0x6400
+#       define AVIVO_D1CURSOR_EN                (1 << 0)
+#       define AVIVO_D1CURSOR_MODE_SHIFT        8
+#       define AVIVO_D1CURSOR_MODE_MASK         (3 << 8)
+#       define AVIVO_D1CURSOR_MODE_24BPP        2
+#define AVIVO_D1CUR_SURFACE_ADDRESS             0x6408
+#define AVIVO_D1CUR_SIZE                        0x6410
+#define AVIVO_D1CUR_POSITION                    0x6414
+#define AVIVO_D1CUR_HOT_SPOT                    0x6418
+#define AVIVO_D1CUR_UPDATE                      0x6424
+#       define AVIVO_D1CURSOR_UPDATE_LOCK       (1 << 16)
+
+#define AVIVO_DC_LUT_RW_SELECT                  0x6480
+#define AVIVO_DC_LUT_RW_MODE                    0x6484
+#define AVIVO_DC_LUT_RW_INDEX                   0x6488
+#define AVIVO_DC_LUT_SEQ_COLOR                  0x648c
+#define AVIVO_DC_LUT_PWL_DATA                   0x6490
+#define AVIVO_DC_LUT_30_COLOR                   0x6494
+#define AVIVO_DC_LUT_READ_PIPE_SELECT           0x6498
+#define AVIVO_DC_LUT_WRITE_EN_MASK              0x649c
+#define AVIVO_DC_LUT_AUTOFILL                   0x64a0
+
+#define AVIVO_DC_LUTA_CONTROL                   0x64c0
+#define AVIVO_DC_LUTA_BLACK_OFFSET_BLUE         0x64c4
+#define AVIVO_DC_LUTA_BLACK_OFFSET_GREEN        0x64c8
+#define AVIVO_DC_LUTA_BLACK_OFFSET_RED          0x64cc
+#define AVIVO_DC_LUTA_WHITE_OFFSET_BLUE         0x64d0
+#define AVIVO_DC_LUTA_WHITE_OFFSET_GREEN        0x64d4
+#define AVIVO_DC_LUTA_WHITE_OFFSET_RED          0x64d8
+
+#define AVIVO_DC_LB_MEMORY_SPLIT                0x6520
+#       define AVIVO_DC_LB_MEMORY_SPLIT_MASK    0x3
+#       define AVIVO_DC_LB_MEMORY_SPLIT_SHIFT   0
+#       define AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF  0
+#       define AVIVO_DC_LB_MEMORY_SPLIT_D1_3Q_D2_1Q    1
+#       define AVIVO_DC_LB_MEMORY_SPLIT_D1_ONLY        2
+#       define AVIVO_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q    3
+#       define AVIVO_DC_LB_MEMORY_SPLIT_SHIFT_MODE (1 << 2)
+#       define AVIVO_DC_LB_DISP1_END_ADR_SHIFT  4
+#       define AVIVO_DC_LB_DISP1_END_ADR_MASK   0x7ff
+
+#define R500_DxMODE_INT_MASK 0x6540
+#define R500_D1MODE_INT_MASK (1<<0)
+#define R500_D2MODE_INT_MASK (1<<8)
+
+#define AVIVO_D1MODE_DATA_FORMAT                0x6528
+#       define AVIVO_D1MODE_INTERLEAVE_EN       (1 << 0)
+#define AVIVO_D1MODE_DESKTOP_HEIGHT             0x652C
+#define AVIVO_D1MODE_VIEWPORT_START             0x6580
+#define AVIVO_D1MODE_VIEWPORT_SIZE              0x6584
+#define AVIVO_D1MODE_EXT_OVERSCAN_LEFT_RIGHT    0x6588
+#define AVIVO_D1MODE_EXT_OVERSCAN_TOP_BOTTOM    0x658c
+
+#define AVIVO_D1SCL_SCALER_ENABLE               0x6590
+#define AVIVO_D1SCL_SCALER_TAP_CONTROL         0x6594
+#define AVIVO_D1SCL_UPDATE                      0x65cc
+#       define AVIVO_D1SCL_UPDATE_LOCK          (1 << 16)
+
+/* second crtc */
+#define AVIVO_D2CRTC_H_TOTAL                                   0x6800
+#define AVIVO_D2CRTC_H_BLANK_START_END                          0x6804
+#define AVIVO_D2CRTC_H_SYNC_A                                   0x6808
+#define AVIVO_D2CRTC_H_SYNC_A_CNTL                              0x680c
+#define AVIVO_D2CRTC_H_SYNC_B                                   0x6810
+#define AVIVO_D2CRTC_H_SYNC_B_CNTL                              0x6814
+
+#define AVIVO_D2CRTC_V_TOTAL                                   0x6820
+#define AVIVO_D2CRTC_V_BLANK_START_END                          0x6824
+#define AVIVO_D2CRTC_V_SYNC_A                                   0x6828
+#define AVIVO_D2CRTC_V_SYNC_A_CNTL                              0x682c
+#define AVIVO_D2CRTC_V_SYNC_B                                   0x6830
+#define AVIVO_D2CRTC_V_SYNC_B_CNTL                              0x6834
+
+#define AVIVO_D2CRTC_CONTROL                                    0x6880
+#define AVIVO_D2CRTC_BLANK_CONTROL                              0x6884
+#define AVIVO_D2CRTC_INTERLACE_CONTROL                          0x6888
+#define AVIVO_D2CRTC_INTERLACE_STATUS                           0x688c
+#define AVIVO_D2CRTC_STEREO_CONTROL                             0x68c4
+
+#define AVIVO_D2GRPH_ENABLE                                     0x6900
+#define AVIVO_D2GRPH_CONTROL                                    0x6904
+#define AVIVO_D2GRPH_LUT_SEL                                    0x6908
+#define AVIVO_D2GRPH_PRIMARY_SURFACE_ADDRESS                    0x6910
+#define AVIVO_D2GRPH_SECONDARY_SURFACE_ADDRESS                  0x6918
+#define AVIVO_D2GRPH_PITCH                                      0x6920
+#define AVIVO_D2GRPH_SURFACE_OFFSET_X                           0x6924
+#define AVIVO_D2GRPH_SURFACE_OFFSET_Y                           0x6928
+#define AVIVO_D2GRPH_X_START                                    0x692c
+#define AVIVO_D2GRPH_Y_START                                    0x6930
+#define AVIVO_D2GRPH_X_END                                      0x6934
+#define AVIVO_D2GRPH_Y_END                                      0x6938
+#define AVIVO_D2GRPH_UPDATE                                     0x6944
+#define AVIVO_D2GRPH_FLIP_CONTROL                               0x6948
+
+#define AVIVO_D2CUR_CONTROL                     0x6c00
+#define AVIVO_D2CUR_SURFACE_ADDRESS             0x6c08
+#define AVIVO_D2CUR_SIZE                        0x6c10
+#define AVIVO_D2CUR_POSITION                    0x6c14
+
+#define AVIVO_D2MODE_VIEWPORT_START             0x6d80
+#define AVIVO_D2MODE_VIEWPORT_SIZE              0x6d84
+#define AVIVO_D2MODE_EXT_OVERSCAN_LEFT_RIGHT    0x6d88
+#define AVIVO_D2MODE_EXT_OVERSCAN_TOP_BOTTOM    0x6d8c
+
+#define AVIVO_D2SCL_SCALER_ENABLE               0x6d90
+#define AVIVO_D2SCL_SCALER_TAP_CONTROL         0x6d94
+
+#define AVIVO_DDIA_BIT_DEPTH_CONTROL                           0x7214
+
+#define AVIVO_DACA_ENABLE                                      0x7800
+#      define AVIVO_DAC_ENABLE                         (1 << 0)
+#define AVIVO_DACA_SOURCE_SELECT                               0x7804
+#       define AVIVO_DAC_SOURCE_CRTC1                   (0 << 0)
+#       define AVIVO_DAC_SOURCE_CRTC2                   (1 << 0)
+#       define AVIVO_DAC_SOURCE_TV                      (2 << 0)
+
+#define AVIVO_DACA_FORCE_OUTPUT_CNTL                           0x783c
+# define AVIVO_DACA_FORCE_OUTPUT_CNTL_FORCE_DATA_EN             (1 << 0)
+# define AVIVO_DACA_FORCE_OUTPUT_CNTL_DATA_SEL_SHIFT            (8)
+# define AVIVO_DACA_FORCE_OUTPUT_CNTL_DATA_SEL_BLUE             (1 << 0)
+# define AVIVO_DACA_FORCE_OUTPUT_CNTL_DATA_SEL_GREEN            (1 << 1)
+# define AVIVO_DACA_FORCE_OUTPUT_CNTL_DATA_SEL_RED              (1 << 2)
+# define AVIVO_DACA_FORCE_OUTPUT_CNTL_DATA_ON_BLANKB_ONLY       (1 << 24)
+#define AVIVO_DACA_POWERDOWN                                   0x7850
+# define AVIVO_DACA_POWERDOWN_POWERDOWN                         (1 << 0)
+# define AVIVO_DACA_POWERDOWN_BLUE                              (1 << 8)
+# define AVIVO_DACA_POWERDOWN_GREEN                             (1 << 16)
+# define AVIVO_DACA_POWERDOWN_RED                               (1 << 24)
+
+#define AVIVO_DACB_ENABLE                                      0x7a00
+#define AVIVO_DACB_SOURCE_SELECT                               0x7a04
+#define AVIVO_DACB_FORCE_OUTPUT_CNTL                           0x7a3c
+# define AVIVO_DACB_FORCE_OUTPUT_CNTL_FORCE_DATA_EN             (1 << 0)
+# define AVIVO_DACB_FORCE_OUTPUT_CNTL_DATA_SEL_SHIFT            (8)
+# define AVIVO_DACB_FORCE_OUTPUT_CNTL_DATA_SEL_BLUE             (1 << 0)
+# define AVIVO_DACB_FORCE_OUTPUT_CNTL_DATA_SEL_GREEN            (1 << 1)
+# define AVIVO_DACB_FORCE_OUTPUT_CNTL_DATA_SEL_RED              (1 << 2)
+# define AVIVO_DACB_FORCE_OUTPUT_CNTL_DATA_ON_BLANKB_ONLY       (1 << 24)
+#define AVIVO_DACB_POWERDOWN                                   0x7a50
+# define AVIVO_DACB_POWERDOWN_POWERDOWN                         (1 << 0)
+# define AVIVO_DACB_POWERDOWN_BLUE                              (1 << 8)
+# define AVIVO_DACB_POWERDOWN_GREEN                             (1 << 16)
+# define AVIVO_DACB_POWERDOWN_RED
+
+#define AVIVO_TMDSA_CNTL                    0x7880
+#   define AVIVO_TMDSA_CNTL_ENABLE               (1 << 0)
+#   define AVIVO_TMDSA_CNTL_HPD_MASK             (1 << 4)
+#   define AVIVO_TMDSA_CNTL_HPD_SELECT           (1 << 8)
+#   define AVIVO_TMDSA_CNTL_SYNC_PHASE           (1 << 12)
+#   define AVIVO_TMDSA_CNTL_PIXEL_ENCODING       (1 << 16)
+#   define AVIVO_TMDSA_CNTL_DUAL_LINK_ENABLE     (1 << 24)
+#   define AVIVO_TMDSA_CNTL_SWAP                 (1 << 28)
+#define AVIVO_TMDSA_SOURCE_SELECT                              0x7884
+/* 78a8 appears to be some kind of (reasonably tolerant) clock?
+ * 78d0 definitely hits the transmitter, definitely clock. */
+/* MYSTERY1 This appears to control dithering? */
+#define AVIVO_TMDSA_BIT_DEPTH_CONTROL          0x7894
+#   define AVIVO_TMDS_BIT_DEPTH_CONTROL_TRUNCATE_EN           (1 << 0)
+#   define AVIVO_TMDS_BIT_DEPTH_CONTROL_TRUNCATE_DEPTH        (1 << 4)
+#   define AVIVO_TMDS_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN     (1 << 8)
+#   define AVIVO_TMDS_BIT_DEPTH_CONTROL_SPATIAL_DITHER_DEPTH  (1 << 12)
+#   define AVIVO_TMDS_BIT_DEPTH_CONTROL_TEMPORAL_DITHER_EN    (1 << 16)
+#   define AVIVO_TMDS_BIT_DEPTH_CONTROL_TEMPORAL_DITHER_DEPTH (1 << 20)
+#   define AVIVO_TMDS_BIT_DEPTH_CONTROL_TEMPORAL_LEVEL        (1 << 24)
+#   define AVIVO_TMDS_BIT_DEPTH_CONTROL_TEMPORAL_DITHER_RESET (1 << 26)
+#define AVIVO_TMDSA_DCBALANCER_CONTROL                  0x78d0
+#   define AVIVO_TMDSA_DCBALANCER_CONTROL_EN                  (1 << 0)
+#   define AVIVO_TMDSA_DCBALANCER_CONTROL_TEST_EN             (1 << 8)
+#   define AVIVO_TMDSA_DCBALANCER_CONTROL_TEST_IN_SHIFT       (16)
+#   define AVIVO_TMDSA_DCBALANCER_CONTROL_FORCE               (1 << 24)
+#define AVIVO_TMDSA_DATA_SYNCHRONIZATION                0x78d8
+#   define AVIVO_TMDSA_DATA_SYNCHRONIZATION_DSYNSEL           (1 << 0)
+#   define AVIVO_TMDSA_DATA_SYNCHRONIZATION_PFREQCHG          (1 << 8)
+#define AVIVO_TMDSA_CLOCK_ENABLE            0x7900
+#define AVIVO_TMDSA_TRANSMITTER_ENABLE              0x7904
+#   define AVIVO_TMDSA_TRANSMITTER_ENABLE_TX0_ENABLE          (1 << 0)
+#   define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKC0EN             (1 << 1)
+#   define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKD00EN            (1 << 2)
+#   define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKD01EN            (1 << 3)
+#   define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKD02EN            (1 << 4)
+#   define AVIVO_TMDSA_TRANSMITTER_ENABLE_TX1_ENABLE          (1 << 8)
+#   define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKD10EN            (1 << 10)
+#   define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKD11EN            (1 << 11)
+#   define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKD12EN            (1 << 12)
+#   define AVIVO_TMDSA_TRANSMITTER_ENABLE_TX_ENABLE_HPD_MASK  (1 << 16)
+#   define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKCEN_HPD_MASK     (1 << 17)
+#   define AVIVO_TMDSA_TRANSMITTER_ENABLE_LNKDEN_HPD_MASK     (1 << 18)
+
+#define AVIVO_TMDSA_TRANSMITTER_CONTROL                                0x7910
+#      define AVIVO_TMDSA_TRANSMITTER_CONTROL_PLL_ENABLE       (1 << 0)
+#      define AVIVO_TMDSA_TRANSMITTER_CONTROL_PLL_RESET        (1 << 1)
+#      define AVIVO_TMDSA_TRANSMITTER_CONTROL_PLL_HPD_MASK_SHIFT       (2)
+#      define AVIVO_TMDSA_TRANSMITTER_CONTROL_IDSCKSEL         (1 << 4)
+#       define AVIVO_TMDSA_TRANSMITTER_CONTROL_BGSLEEP          (1 << 5)
+#      define AVIVO_TMDSA_TRANSMITTER_CONTROL_PLL_PWRUP_SEQ_EN (1 << 6)
+#      define AVIVO_TMDSA_TRANSMITTER_CONTROL_TMCLK            (1 << 8)
+#      define AVIVO_TMDSA_TRANSMITTER_CONTROL_TMCLK_FROM_PADS  (1 << 13)
+#      define AVIVO_TMDSA_TRANSMITTER_CONTROL_TDCLK            (1 << 14)
+#      define AVIVO_TMDSA_TRANSMITTER_CONTROL_TDCLK_FROM_PADS  (1 << 15)
+#       define AVIVO_TMDSA_TRANSMITTER_CONTROL_CLK_PATTERN_SHIFT (16)
+#      define AVIVO_TMDSA_TRANSMITTER_CONTROL_BYPASS_PLL       (1 << 28)
+#       define AVIVO_TMDSA_TRANSMITTER_CONTROL_USE_CLK_DATA     (1 << 29)
+#      define AVIVO_TMDSA_TRANSMITTER_CONTROL_INPUT_TEST_CLK_SEL       (1 << 31)
+
+#define AVIVO_LVTMA_CNTL                                       0x7a80
+#   define AVIVO_LVTMA_CNTL_ENABLE               (1 << 0)
+#   define AVIVO_LVTMA_CNTL_HPD_MASK             (1 << 4)
+#   define AVIVO_LVTMA_CNTL_HPD_SELECT           (1 << 8)
+#   define AVIVO_LVTMA_CNTL_SYNC_PHASE           (1 << 12)
+#   define AVIVO_LVTMA_CNTL_PIXEL_ENCODING       (1 << 16)
+#   define AVIVO_LVTMA_CNTL_DUAL_LINK_ENABLE     (1 << 24)
+#   define AVIVO_LVTMA_CNTL_SWAP                 (1 << 28)
+#define AVIVO_LVTMA_SOURCE_SELECT                               0x7a84
+#define AVIVO_LVTMA_COLOR_FORMAT                                0x7a88
+#define AVIVO_LVTMA_BIT_DEPTH_CONTROL                           0x7a94
+#   define AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_EN           (1 << 0)
+#   define AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_DEPTH        (1 << 4)
+#   define AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN     (1 << 8)
+#   define AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_DEPTH  (1 << 12)
+#   define AVIVO_LVTMA_BIT_DEPTH_CONTROL_TEMPORAL_DITHER_EN    (1 << 16)
+#   define AVIVO_LVTMA_BIT_DEPTH_CONTROL_TEMPORAL_DITHER_DEPTH (1 << 20)
+#   define AVIVO_LVTMA_BIT_DEPTH_CONTROL_TEMPORAL_LEVEL        (1 << 24)
+#   define AVIVO_LVTMA_BIT_DEPTH_CONTROL_TEMPORAL_DITHER_RESET (1 << 26)
+
+
+
+#define AVIVO_LVTMA_DCBALANCER_CONTROL                  0x7ad0
+#   define AVIVO_LVTMA_DCBALANCER_CONTROL_EN                  (1 << 0)
+#   define AVIVO_LVTMA_DCBALANCER_CONTROL_TEST_EN             (1 << 8)
+#   define AVIVO_LVTMA_DCBALANCER_CONTROL_TEST_IN_SHIFT       (16)
+#   define AVIVO_LVTMA_DCBALANCER_CONTROL_FORCE               (1 << 24)
+
+#define AVIVO_LVTMA_DATA_SYNCHRONIZATION                0x78d8
+#   define AVIVO_LVTMA_DATA_SYNCHRONIZATION_DSYNSEL           (1 << 0)
+#   define AVIVO_LVTMA_DATA_SYNCHRONIZATION_PFREQCHG          (1 << 8)
+#define R500_LVTMA_CLOCK_ENABLE                        0x7b00
+#define R600_LVTMA_CLOCK_ENABLE                        0x7b04
+
+#define R500_LVTMA_TRANSMITTER_ENABLE              0x7b04
+#define R600_LVTMA_TRANSMITTER_ENABLE              0x7b08
+#   define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKC0EN             (1 << 1)
+#   define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD00EN            (1 << 2)
+#   define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD01EN            (1 << 3)
+#   define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD02EN            (1 << 4)
+#   define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD03EN            (1 << 5)
+#   define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKC1EN             (1 << 9)
+#   define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD10EN            (1 << 10)
+#   define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD11EN            (1 << 11)
+#   define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKD12EN            (1 << 12)
+#   define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKCEN_HPD_MASK     (1 << 17)
+#   define AVIVO_LVTMA_TRANSMITTER_ENABLE_LNKDEN_HPD_MASK     (1 << 18)
+
+#define R500_LVTMA_TRANSMITTER_CONTROL                         0x7b10
+#define R600_LVTMA_TRANSMITTER_CONTROL                         0x7b14
+#      define AVIVO_LVTMA_TRANSMITTER_CONTROL_PLL_ENABLE         (1 << 0)
+#      define AVIVO_LVTMA_TRANSMITTER_CONTROL_PLL_RESET          (1 << 1)
+#      define AVIVO_LVTMA_TRANSMITTER_CONTROL_PLL_HPD_MASK_SHIFT (2)
+#      define AVIVO_LVTMA_TRANSMITTER_CONTROL_IDSCKSEL           (1 << 4)
+#       define AVIVO_LVTMA_TRANSMITTER_CONTROL_BGSLEEP            (1 << 5)
+#      define AVIVO_LVTMA_TRANSMITTER_CONTROL_PLL_PWRUP_SEQ_EN   (1 << 6)
+#      define AVIVO_LVTMA_TRANSMITTER_CONTROL_TMCLK              (1 << 8)
+#      define AVIVO_LVTMA_TRANSMITTER_CONTROL_TMCLK_FROM_PADS    (1 << 13)
+#      define AVIVO_LVTMA_TRANSMITTER_CONTROL_TDCLK              (1 << 14)
+#      define AVIVO_LVTMA_TRANSMITTER_CONTROL_TDCLK_FROM_PADS    (1 << 15)
+#       define AVIVO_LVTMA_TRANSMITTER_CONTROL_CLK_PATTERN_SHIFT  (16)
+#      define AVIVO_LVTMA_TRANSMITTER_CONTROL_BYPASS_PLL         (1 << 28)
+#       define AVIVO_LVTMA_TRANSMITTER_CONTROL_USE_CLK_DATA       (1 << 29)
+#      define AVIVO_LVTMA_TRANSMITTER_CONTROL_INPUT_TEST_CLK_SEL (1 << 31)
+
+#define R500_LVTMA_PWRSEQ_CNTL                                         0x7af0
+#define R600_LVTMA_PWRSEQ_CNTL                                         0x7af4
+#      define AVIVO_LVTMA_PWRSEQ_EN                                        (1 << 0)
+#      define AVIVO_LVTMA_PWRSEQ_PLL_ENABLE_MASK                           (1 << 2)
+#      define AVIVO_LVTMA_PWRSEQ_PLL_RESET_MASK                            (1 << 3)
+#      define AVIVO_LVTMA_PWRSEQ_TARGET_STATE                              (1 << 4)
+#      define AVIVO_LVTMA_SYNCEN                                           (1 << 8)
+#      define AVIVO_LVTMA_SYNCEN_OVRD                                      (1 << 9)
+#      define AVIVO_LVTMA_SYNCEN_POL                                       (1 << 10)
+#      define AVIVO_LVTMA_DIGON                                            (1 << 16)
+#      define AVIVO_LVTMA_DIGON_OVRD                                       (1 << 17)
+#      define AVIVO_LVTMA_DIGON_POL                                        (1 << 18)
+#      define AVIVO_LVTMA_BLON                                             (1 << 24)
+#      define AVIVO_LVTMA_BLON_OVRD                                        (1 << 25)
+#      define AVIVO_LVTMA_BLON_POL                                         (1 << 26)
+
+#define R500_LVTMA_PWRSEQ_STATE                        0x7af4
+#define R600_LVTMA_PWRSEQ_STATE                        0x7af8
+#       define AVIVO_LVTMA_PWRSEQ_STATE_TARGET_STATE_R          (1 << 0)
+#       define AVIVO_LVTMA_PWRSEQ_STATE_DIGON                   (1 << 1)
+#       define AVIVO_LVTMA_PWRSEQ_STATE_SYNCEN                  (1 << 2)
+#       define AVIVO_LVTMA_PWRSEQ_STATE_BLON                    (1 << 3)
+#       define AVIVO_LVTMA_PWRSEQ_STATE_DONE                    (1 << 4)
+#       define AVIVO_LVTMA_PWRSEQ_STATE_STATUS_SHIFT            (8)
+
+#define AVIVO_LVDS_BACKLIGHT_CNTL                      0x7af8
+#      define AVIVO_LVDS_BACKLIGHT_CNTL_EN                     (1 << 0)
+#      define AVIVO_LVDS_BACKLIGHT_LEVEL_MASK          0x0000ff00
+#      define AVIVO_LVDS_BACKLIGHT_LEVEL_SHIFT         8
+
+#define AVIVO_DVOA_BIT_DEPTH_CONTROL                   0x7988
+
+#define AVIVO_GPIO_0                        0x7e30
+#define AVIVO_GPIO_1                        0x7e40
+#define AVIVO_GPIO_2                        0x7e50
+#define AVIVO_GPIO_3                        0x7e60
+
+#define AVIVO_DC_GPIO_HPD_Y                 0x7e9c
+
+#define AVIVO_I2C_STATUS                                       0x7d30
+#      define AVIVO_I2C_STATUS_DONE                            (1 << 0)
+#      define AVIVO_I2C_STATUS_NACK                            (1 << 1)
+#      define AVIVO_I2C_STATUS_HALT                            (1 << 2)
+#      define AVIVO_I2C_STATUS_GO                              (1 << 3)
+#      define AVIVO_I2C_STATUS_MASK                            0x7
+/* If radeon_mm_i2c is to be believed, this is HALT, NACK, and maybe
+ * DONE? */
+#      define AVIVO_I2C_STATUS_CMD_RESET                       0x7
+#      define AVIVO_I2C_STATUS_CMD_WAIT                        (1 << 3)
+#define AVIVO_I2C_STOP                                         0x7d34
+#define AVIVO_I2C_START_CNTL                           0x7d38
+#      define AVIVO_I2C_START                                          (1 << 8)
+#      define AVIVO_I2C_CONNECTOR0                                     (0 << 16)
+#      define AVIVO_I2C_CONNECTOR1                                     (1 << 16)
+#define R520_I2C_START (1<<0)
+#define R520_I2C_STOP (1<<1)
+#define R520_I2C_RX (1<<2)
+#define R520_I2C_EN (1<<8)
+#define R520_I2C_DDC1 (0<<16)
+#define R520_I2C_DDC2 (1<<16)
+#define R520_I2C_DDC3 (2<<16)
+#define R520_I2C_DDC_MASK (3<<16)
+#define AVIVO_I2C_CONTROL2                                     0x7d3c
+#      define AVIVO_I2C_7D3C_SIZE_SHIFT                        8
+#      define AVIVO_I2C_7D3C_SIZE_MASK                         (0xf << 8)
+#define AVIVO_I2C_CONTROL3                                             0x7d40
+/* Reading is done 4 bytes at a time: read the bottom 8 bits from
+ * 7d44, four times in a row.
+ * Writing is a little more complex.  First write DATA with
+ * 0xnnnnnnzz, then 0xnnnnnnyy, where nnnnnn is some non-deterministic
+ * magic number, zz is, I think, the slave address, and yy is the byte
+ * you want to write. */
+#define AVIVO_I2C_DATA                                         0x7d44
+#define R520_I2C_ADDR_COUNT_MASK (0x7)
+#define R520_I2C_DATA_COUNT_SHIFT (8)
+#define R520_I2C_DATA_COUNT_MASK (0xF00)
+#define AVIVO_I2C_CNTL                                         0x7d50
+#      define AVIVO_I2C_EN                                                     (1 << 0)
+#      define AVIVO_I2C_RESET                                          (1 << 8)
+
+#endif
diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c
new file mode 100644 (file)
index 0000000..570a244
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ *          Jerome Glisse
+ */
+#include "drmP.h"
+#include "radeon_reg.h"
+#include "radeon.h"
+
+/* r520,rv530,rv560,rv570,r580 depends on : */
+void r100_hdp_reset(struct radeon_device *rdev);
+int rv370_pcie_gart_enable(struct radeon_device *rdev);
+void rv370_pcie_gart_disable(struct radeon_device *rdev);
+void r420_pipes_init(struct radeon_device *rdev);
+void rs600_mc_disable_clients(struct radeon_device *rdev);
+void rs600_disable_vga(struct radeon_device *rdev);
+int rv515_debugfs_pipes_info_init(struct radeon_device *rdev);
+int rv515_debugfs_ga_info_init(struct radeon_device *rdev);
+
+/* This files gather functions specifics to:
+ * r520,rv530,rv560,rv570,r580
+ *
+ * Some of these functions might be used by newer ASICs.
+ */
+void r520_gpu_init(struct radeon_device *rdev);
+int r520_mc_wait_for_idle(struct radeon_device *rdev);
+
+
+/*
+ * MC
+ */
+int r520_mc_init(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+       int r;
+
+       if (r100_debugfs_rbbm_init(rdev)) {
+               DRM_ERROR("Failed to register debugfs file for RBBM !\n");
+       }
+       if (rv515_debugfs_pipes_info_init(rdev)) {
+               DRM_ERROR("Failed to register debugfs file for pipes !\n");
+       }
+       if (rv515_debugfs_ga_info_init(rdev)) {
+               DRM_ERROR("Failed to register debugfs file for pipes !\n");
+       }
+
+       r520_gpu_init(rdev);
+       rv370_pcie_gart_disable(rdev);
+
+       /* Setup GPU memory space */
+       rdev->mc.vram_location = 0xFFFFFFFFUL;
+       rdev->mc.gtt_location = 0xFFFFFFFFUL;
+       if (rdev->flags & RADEON_IS_AGP) {
+               r = radeon_agp_init(rdev);
+               if (r) {
+                       printk(KERN_WARNING "[drm] Disabling AGP\n");
+                       rdev->flags &= ~RADEON_IS_AGP;
+                       rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024;
+               } else {
+                       rdev->mc.gtt_location = rdev->mc.agp_base;
+               }
+       }
+       r = radeon_mc_setup(rdev);
+       if (r) {
+               return r;
+       }
+
+       /* Program GPU memory space */
+       rs600_mc_disable_clients(rdev);
+       if (r520_mc_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait MC idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+       /* Write VRAM size in case we are limiting it */
+       WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size);
+       tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1;
+       tmp = REG_SET(R520_MC_FB_TOP, tmp >> 16);
+       tmp |= REG_SET(R520_MC_FB_START, rdev->mc.vram_location >> 16);
+       WREG32_MC(R520_MC_FB_LOCATION, tmp);
+       WREG32(RS690_HDP_FB_LOCATION, rdev->mc.vram_location >> 16);
+       WREG32(0x310, rdev->mc.vram_location);
+       if (rdev->flags & RADEON_IS_AGP) {
+               tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1;
+               tmp = REG_SET(R520_MC_AGP_TOP, tmp >> 16);
+               tmp |= REG_SET(R520_MC_AGP_START, rdev->mc.gtt_location >> 16);
+               WREG32_MC(R520_MC_AGP_LOCATION, tmp);
+               WREG32_MC(R520_MC_AGP_BASE, rdev->mc.agp_base);
+               WREG32_MC(R520_MC_AGP_BASE_2, 0);
+       } else {
+               WREG32_MC(R520_MC_AGP_LOCATION, 0x0FFFFFFF);
+               WREG32_MC(R520_MC_AGP_BASE, 0);
+               WREG32_MC(R520_MC_AGP_BASE_2, 0);
+       }
+       return 0;
+}
+
+void r520_mc_fini(struct radeon_device *rdev)
+{
+       rv370_pcie_gart_disable(rdev);
+       radeon_gart_table_vram_free(rdev);
+       radeon_gart_fini(rdev);
+}
+
+
+/*
+ * Global GPU functions
+ */
+void r520_errata(struct radeon_device *rdev)
+{
+       rdev->pll_errata = 0;
+}
+
+int r520_mc_wait_for_idle(struct radeon_device *rdev)
+{
+       unsigned i;
+       uint32_t tmp;
+
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               /* read MC_STATUS */
+               tmp = RREG32_MC(R520_MC_STATUS);
+               if (tmp & R520_MC_STATUS_IDLE) {
+                       return 0;
+               }
+               DRM_UDELAY(1);
+       }
+       return -1;
+}
+
+void r520_gpu_init(struct radeon_device *rdev)
+{
+       unsigned pipe_select_current, gb_pipe_select, tmp;
+
+       r100_hdp_reset(rdev);
+       rs600_disable_vga(rdev);
+       /*
+        * DST_PIPE_CONFIG              0x170C
+        * GB_TILE_CONFIG               0x4018
+        * GB_FIFO_SIZE                 0x4024
+        * GB_PIPE_SELECT               0x402C
+        * GB_PIPE_SELECT2              0x4124
+        *      Z_PIPE_SHIFT                    0
+        *      Z_PIPE_MASK                     0x000000003
+        * GB_FIFO_SIZE2                0x4128
+        *      SC_SFIFO_SIZE_SHIFT             0
+        *      SC_SFIFO_SIZE_MASK              0x000000003
+        *      SC_MFIFO_SIZE_SHIFT             2
+        *      SC_MFIFO_SIZE_MASK              0x00000000C
+        *      FG_SFIFO_SIZE_SHIFT             4
+        *      FG_SFIFO_SIZE_MASK              0x000000030
+        *      ZB_MFIFO_SIZE_SHIFT             6
+        *      ZB_MFIFO_SIZE_MASK              0x0000000C0
+        * GA_ENHANCE                   0x4274
+        * SU_REG_DEST                  0x42C8
+        */
+       /* workaround for RV530 */
+       if (rdev->family == CHIP_RV530) {
+               WREG32(0x4124, 1);
+               WREG32(0x4128, 0xFF);
+       }
+       r420_pipes_init(rdev);
+       gb_pipe_select = RREG32(0x402C);
+       tmp = RREG32(0x170C);
+       pipe_select_current = (tmp >> 2) & 3;
+       tmp = (1 << pipe_select_current) |
+             (((gb_pipe_select >> 8) & 0xF) << 4);
+       WREG32_PLL(0x000D, tmp);
+       if (r520_mc_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait MC idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+}
+
+
+/*
+ * VRAM info
+ */
+static void r520_vram_get_type(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+
+       rdev->mc.vram_width = 128;
+       rdev->mc.vram_is_ddr = true;
+       tmp = RREG32_MC(R520_MC_CNTL0);
+       switch ((tmp & R520_MEM_NUM_CHANNELS_MASK) >> R520_MEM_NUM_CHANNELS_SHIFT) {
+       case 0:
+               rdev->mc.vram_width = 32;
+               break;
+       case 1:
+               rdev->mc.vram_width = 64;
+               break;
+       case 2:
+               rdev->mc.vram_width = 128;
+               break;
+       case 3:
+               rdev->mc.vram_width = 256;
+               break;
+       default:
+               rdev->mc.vram_width = 128;
+               break;
+       }
+       if (tmp & R520_MC_CHANNEL_SIZE)
+               rdev->mc.vram_width *= 2;
+}
+
+void r520_vram_info(struct radeon_device *rdev)
+{
+       r520_vram_get_type(rdev);
+       rdev->mc.vram_size = RREG32(RADEON_CONFIG_MEMSIZE);
+
+       rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
+       rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
+}
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
new file mode 100644 (file)
index 0000000..c45559f
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ *          Jerome Glisse
+ */
+#include "drmP.h"
+#include "radeon_reg.h"
+#include "radeon.h"
+
+/* r600,rv610,rv630,rv620,rv635,rv670 depends on : */
+void rs600_mc_disable_clients(struct radeon_device *rdev);
+
+/* This files gather functions specifics to:
+ * r600,rv610,rv630,rv620,rv635,rv670
+ *
+ * Some of these functions might be used by newer ASICs.
+ */
+int r600_mc_wait_for_idle(struct radeon_device *rdev);
+void r600_gpu_init(struct radeon_device *rdev);
+
+
+/*
+ * MC
+ */
+int r600_mc_init(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+
+       r600_gpu_init(rdev);
+
+       /* setup the gart before changing location so we can ask to
+        * discard unmapped mc request
+        */
+       /* FIXME: disable out of gart access */
+       tmp = rdev->mc.gtt_location / 4096;
+       tmp = REG_SET(R600_LOGICAL_PAGE_NUMBER, tmp);
+       WREG32(R600_MC_VM_SYSTEM_APERTURE_LOW_ADDR, tmp);
+       tmp = (rdev->mc.gtt_location + rdev->mc.gtt_size) / 4096;
+       tmp = REG_SET(R600_LOGICAL_PAGE_NUMBER, tmp);
+       WREG32(R600_MC_VM_SYSTEM_APERTURE_HIGH_ADDR, tmp);
+
+       rs600_mc_disable_clients(rdev);
+       if (r600_mc_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait MC idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+
+       tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1;
+       tmp = REG_SET(R600_MC_FB_TOP, tmp >> 24);
+       tmp |= REG_SET(R600_MC_FB_BASE, rdev->mc.vram_location >> 24);
+       WREG32(R600_MC_VM_FB_LOCATION, tmp);
+       tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1;
+       tmp = REG_SET(R600_MC_AGP_TOP, tmp >> 22);
+       WREG32(R600_MC_VM_AGP_TOP, tmp);
+       tmp = REG_SET(R600_MC_AGP_BOT, rdev->mc.gtt_location >> 22);
+       WREG32(R600_MC_VM_AGP_BOT, tmp);
+       return 0;
+}
+
+void r600_mc_fini(struct radeon_device *rdev)
+{
+       /* FIXME: implement */
+}
+
+
+/*
+ * Global GPU functions
+ */
+void r600_errata(struct radeon_device *rdev)
+{
+       rdev->pll_errata = 0;
+}
+
+int r600_mc_wait_for_idle(struct radeon_device *rdev)
+{
+       /* FIXME: implement */
+       return 0;
+}
+
+void r600_gpu_init(struct radeon_device *rdev)
+{
+       /* FIXME: implement */
+}
+
+
+/*
+ * VRAM info
+ */
+void r600_vram_get_type(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+       int chansize;
+
+       rdev->mc.vram_width = 128;
+       rdev->mc.vram_is_ddr = true;
+
+       tmp = RREG32(R600_RAMCFG);
+       if (tmp & R600_CHANSIZE_OVERRIDE) {
+               chansize = 16;
+       } else if (tmp & R600_CHANSIZE) {
+               chansize = 64;
+       } else {
+               chansize = 32;
+       }
+       if (rdev->family == CHIP_R600) {
+               rdev->mc.vram_width = 8 * chansize;
+       } else if (rdev->family == CHIP_RV670) {
+               rdev->mc.vram_width = 4 * chansize;
+       } else if ((rdev->family == CHIP_RV610) ||
+                       (rdev->family == CHIP_RV620)) {
+               rdev->mc.vram_width = chansize;
+       } else if ((rdev->family == CHIP_RV630) ||
+                       (rdev->family == CHIP_RV635)) {
+               rdev->mc.vram_width = 2 * chansize;
+       }
+}
+
+void r600_vram_info(struct radeon_device *rdev)
+{
+       r600_vram_get_type(rdev);
+       rdev->mc.vram_size = RREG32(R600_CONFIG_MEMSIZE);
+
+       /* Could aper size report 0 ? */
+       rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
+       rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
+}
+
+/*
+ * Indirect registers accessor
+ */
+uint32_t r600_pciep_rreg(struct radeon_device *rdev, uint32_t reg)
+{
+       uint32_t r;
+
+       WREG32(R600_PCIE_PORT_INDEX, ((reg) & 0xff));
+       (void)RREG32(R600_PCIE_PORT_INDEX);
+       r = RREG32(R600_PCIE_PORT_DATA);
+       return r;
+}
+
+void r600_pciep_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
+{
+       WREG32(R600_PCIE_PORT_INDEX, ((reg) & 0xff));
+       (void)RREG32(R600_PCIE_PORT_INDEX);
+       WREG32(R600_PCIE_PORT_DATA, (v));
+       (void)RREG32(R600_PCIE_PORT_DATA);
+}
diff --git a/drivers/gpu/drm/radeon/r600_reg.h b/drivers/gpu/drm/radeon/r600_reg.h
new file mode 100644 (file)
index 0000000..e2d1f5f
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ *          Jerome Glisse
+ */
+#ifndef __R600_REG_H__
+#define __R600_REG_H__
+
+#define R600_PCIE_PORT_INDEX                0x0038
+#define R600_PCIE_PORT_DATA                 0x003c
+
+#define R600_MC_VM_FB_LOCATION                 0x2180
+#define                R600_MC_FB_BASE_MASK                    0x0000FFFF
+#define                R600_MC_FB_BASE_SHIFT                   0
+#define                R600_MC_FB_TOP_MASK                     0xFFFF0000
+#define                R600_MC_FB_TOP_SHIFT                    16
+#define R600_MC_VM_AGP_TOP                     0x2184
+#define                R600_MC_AGP_TOP_MASK                    0x0003FFFF
+#define                R600_MC_AGP_TOP_SHIFT                   0
+#define R600_MC_VM_AGP_BOT                     0x2188
+#define                R600_MC_AGP_BOT_MASK                    0x0003FFFF
+#define                R600_MC_AGP_BOT_SHIFT                   0
+#define R600_MC_VM_AGP_BASE                    0x218c
+#define R600_MC_VM_SYSTEM_APERTURE_LOW_ADDR    0x2190
+#define                R600_LOGICAL_PAGE_NUMBER_MASK           0x000FFFFF
+#define                R600_LOGICAL_PAGE_NUMBER_SHIFT          0
+#define R600_MC_VM_SYSTEM_APERTURE_HIGH_ADDR   0x2194
+#define R600_MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR        0x2198
+
+#define R700_MC_VM_FB_LOCATION                 0x2024
+#define                R700_MC_FB_BASE_MASK                    0x0000FFFF
+#define                R700_MC_FB_BASE_SHIFT                   0
+#define                R700_MC_FB_TOP_MASK                     0xFFFF0000
+#define                R700_MC_FB_TOP_SHIFT                    16
+#define R700_MC_VM_AGP_TOP                     0x2028
+#define                R700_MC_AGP_TOP_MASK                    0x0003FFFF
+#define                R700_MC_AGP_TOP_SHIFT                   0
+#define R700_MC_VM_AGP_BOT                     0x202c
+#define                R700_MC_AGP_BOT_MASK                    0x0003FFFF
+#define                R700_MC_AGP_BOT_SHIFT                   0
+#define R700_MC_VM_AGP_BASE                    0x2030
+#define R700_MC_VM_SYSTEM_APERTURE_LOW_ADDR    0x2034
+#define                R700_LOGICAL_PAGE_NUMBER_MASK           0x000FFFFF
+#define                R700_LOGICAL_PAGE_NUMBER_SHIFT          0
+#define R700_MC_VM_SYSTEM_APERTURE_HIGH_ADDR   0x2038
+#define R700_MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR        0x203c
+
+#define R600_RAMCFG                                   0x2408
+#       define R600_CHANSIZE                           (1 << 7)
+#       define R600_CHANSIZE_OVERRIDE                  (1 << 10)
+
+
+#define R600_GENERAL_PWRMGT                                        0x618
+#      define R600_OPEN_DRAIN_PADS                                (1 << 11)
+
+#define R600_LOWER_GPIO_ENABLE                                     0x710
+#define R600_CTXSW_VID_LOWER_GPIO_CNTL                             0x718
+#define R600_HIGH_VID_LOWER_GPIO_CNTL                              0x71c
+#define R600_MEDIUM_VID_LOWER_GPIO_CNTL                            0x720
+#define R600_LOW_VID_LOWER_GPIO_CNTL                               0x724
+
+
+
+#define R600_HDP_NONSURFACE_BASE                                0x2c04
+
+#define R600_BUS_CNTL                                           0x5420
+#define R600_CONFIG_CNTL                                        0x5424
+#define R600_CONFIG_MEMSIZE                                     0x5428
+#define R600_CONFIG_F0_BASE                                     0x542C
+#define R600_CONFIG_APER_SIZE                                   0x5430
+
+#define R600_ROM_CNTL                              0x1600
+#       define R600_SCK_OVERWRITE                  (1 << 1)
+#       define R600_SCK_PRESCALE_CRYSTAL_CLK_SHIFT 28
+#       define R600_SCK_PRESCALE_CRYSTAL_CLK_MASK  (0xf << 28)
+
+#define R600_CG_SPLL_FUNC_CNTL                     0x600
+#       define R600_SPLL_BYPASS_EN                 (1 << 3)
+#define R600_CG_SPLL_STATUS                        0x60c
+#       define R600_SPLL_CHG_STATUS                (1 << 1)
+
+#define R600_BIOS_0_SCRATCH               0x1724
+#define R600_BIOS_1_SCRATCH               0x1728
+#define R600_BIOS_2_SCRATCH               0x172c
+#define R600_BIOS_3_SCRATCH               0x1730
+#define R600_BIOS_4_SCRATCH               0x1734
+#define R600_BIOS_5_SCRATCH               0x1738
+#define R600_BIOS_6_SCRATCH               0x173c
+#define R600_BIOS_7_SCRATCH               0x1740
+
+
+#endif
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
new file mode 100644 (file)
index 0000000..c3f24cc
--- /dev/null
@@ -0,0 +1,793 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ *          Jerome Glisse
+ */
+#ifndef __RADEON_H__
+#define __RADEON_H__
+
+#include "radeon_object.h"
+
+/* TODO: Here are things that needs to be done :
+ *     - surface allocator & initializer : (bit like scratch reg) should
+ *       initialize HDP_ stuff on RS600, R600, R700 hw, well anythings
+ *       related to surface
+ *     - WB : write back stuff (do it bit like scratch reg things)
+ *     - Vblank : look at Jesse's rework and what we should do
+ *     - r600/r700: gart & cp
+ *     - cs : clean cs ioctl use bitmap & things like that.
+ *     - power management stuff
+ *     - Barrier in gart code
+ *     - Unmappabled vram ?
+ *     - TESTING, TESTING, TESTING
+ */
+
+#include <asm/atomic.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/kref.h>
+
+#include "radeon_mode.h"
+#include "radeon_reg.h"
+
+
+/*
+ * Modules parameters.
+ */
+extern int radeon_no_wb;
+extern int radeon_modeset;
+extern int radeon_dynclks;
+extern int radeon_r4xx_atom;
+extern int radeon_agpmode;
+extern int radeon_vram_limit;
+extern int radeon_gart_size;
+extern int radeon_benchmarking;
+extern int radeon_connector_table;
+
+/*
+ * Copy from radeon_drv.h so we don't have to include both and have conflicting
+ * symbol;
+ */
+#define RADEON_MAX_USEC_TIMEOUT                100000  /* 100 ms */
+#define RADEON_IB_POOL_SIZE            16
+#define RADEON_DEBUGFS_MAX_NUM_FILES   32
+#define RADEONFB_CONN_LIMIT            4
+
+enum radeon_family {
+       CHIP_R100,
+       CHIP_RV100,
+       CHIP_RS100,
+       CHIP_RV200,
+       CHIP_RS200,
+       CHIP_R200,
+       CHIP_RV250,
+       CHIP_RS300,
+       CHIP_RV280,
+       CHIP_R300,
+       CHIP_R350,
+       CHIP_RV350,
+       CHIP_RV380,
+       CHIP_R420,
+       CHIP_R423,
+       CHIP_RV410,
+       CHIP_RS400,
+       CHIP_RS480,
+       CHIP_RS600,
+       CHIP_RS690,
+       CHIP_RS740,
+       CHIP_RV515,
+       CHIP_R520,
+       CHIP_RV530,
+       CHIP_RV560,
+       CHIP_RV570,
+       CHIP_R580,
+       CHIP_R600,
+       CHIP_RV610,
+       CHIP_RV630,
+       CHIP_RV620,
+       CHIP_RV635,
+       CHIP_RV670,
+       CHIP_RS780,
+       CHIP_RV770,
+       CHIP_RV730,
+       CHIP_RV710,
+       CHIP_LAST,
+};
+
+enum radeon_chip_flags {
+       RADEON_FAMILY_MASK = 0x0000ffffUL,
+       RADEON_FLAGS_MASK = 0xffff0000UL,
+       RADEON_IS_MOBILITY = 0x00010000UL,
+       RADEON_IS_IGP = 0x00020000UL,
+       RADEON_SINGLE_CRTC = 0x00040000UL,
+       RADEON_IS_AGP = 0x00080000UL,
+       RADEON_HAS_HIERZ = 0x00100000UL,
+       RADEON_IS_PCIE = 0x00200000UL,
+       RADEON_NEW_MEMMAP = 0x00400000UL,
+       RADEON_IS_PCI = 0x00800000UL,
+       RADEON_IS_IGPGART = 0x01000000UL,
+};
+
+
+/*
+ * Errata workarounds.
+ */
+enum radeon_pll_errata {
+       CHIP_ERRATA_R300_CG             = 0x00000001,
+       CHIP_ERRATA_PLL_DUMMYREADS      = 0x00000002,
+       CHIP_ERRATA_PLL_DELAY           = 0x00000004
+};
+
+
+struct radeon_device;
+
+
+/*
+ * BIOS.
+ */
+bool radeon_get_bios(struct radeon_device *rdev);
+
+/*
+ * Clocks
+ */
+
+struct radeon_clock {
+       struct radeon_pll p1pll;
+       struct radeon_pll p2pll;
+       struct radeon_pll spll;
+       struct radeon_pll mpll;
+       /* 10 Khz units */
+       uint32_t default_mclk;
+       uint32_t default_sclk;
+};
+
+/*
+ * Fences.
+ */
+struct radeon_fence_driver {
+       uint32_t                        scratch_reg;
+       atomic_t                        seq;
+       uint32_t                        last_seq;
+       unsigned long                   count_timeout;
+       wait_queue_head_t               queue;
+       rwlock_t                        lock;
+       struct list_head                created;
+       struct list_head                emited;
+       struct list_head                signaled;
+};
+
+struct radeon_fence {
+       struct radeon_device            *rdev;
+       struct kref                     kref;
+       struct list_head                list;
+       /* protected by radeon_fence.lock */
+       uint32_t                        seq;
+       unsigned long                   timeout;
+       bool                            emited;
+       bool                            signaled;
+};
+
+int radeon_fence_driver_init(struct radeon_device *rdev);
+void radeon_fence_driver_fini(struct radeon_device *rdev);
+int radeon_fence_create(struct radeon_device *rdev, struct radeon_fence **fence);
+int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence);
+void radeon_fence_process(struct radeon_device *rdev);
+bool radeon_fence_signaled(struct radeon_fence *fence);
+int radeon_fence_wait(struct radeon_fence *fence, bool interruptible);
+int radeon_fence_wait_next(struct radeon_device *rdev);
+int radeon_fence_wait_last(struct radeon_device *rdev);
+struct radeon_fence *radeon_fence_ref(struct radeon_fence *fence);
+void radeon_fence_unref(struct radeon_fence **fence);
+
+
+/*
+ * Radeon buffer.
+ */
+struct radeon_object;
+
+struct radeon_object_list {
+       struct list_head        list;
+       struct radeon_object    *robj;
+       uint64_t                gpu_offset;
+       unsigned                rdomain;
+       unsigned                wdomain;
+};
+
+int radeon_object_init(struct radeon_device *rdev);
+void radeon_object_fini(struct radeon_device *rdev);
+int radeon_object_create(struct radeon_device *rdev,
+                        struct drm_gem_object *gobj,
+                        unsigned long size,
+                        bool kernel,
+                        uint32_t domain,
+                        bool interruptible,
+                        struct radeon_object **robj_ptr);
+int radeon_object_kmap(struct radeon_object *robj, void **ptr);
+void radeon_object_kunmap(struct radeon_object *robj);
+void radeon_object_unref(struct radeon_object **robj);
+int radeon_object_pin(struct radeon_object *robj, uint32_t domain,
+                     uint64_t *gpu_addr);
+void radeon_object_unpin(struct radeon_object *robj);
+int radeon_object_wait(struct radeon_object *robj);
+int radeon_object_evict_vram(struct radeon_device *rdev);
+int radeon_object_mmap(struct radeon_object *robj, uint64_t *offset);
+void radeon_object_force_delete(struct radeon_device *rdev);
+void radeon_object_list_add_object(struct radeon_object_list *lobj,
+                                  struct list_head *head);
+int radeon_object_list_validate(struct list_head *head, void *fence);
+void radeon_object_list_unvalidate(struct list_head *head);
+void radeon_object_list_clean(struct list_head *head);
+int radeon_object_fbdev_mmap(struct radeon_object *robj,
+                            struct vm_area_struct *vma);
+unsigned long radeon_object_size(struct radeon_object *robj);
+
+
+/*
+ * GEM objects.
+ */
+struct radeon_gem {
+       struct list_head        objects;
+};
+
+int radeon_gem_init(struct radeon_device *rdev);
+void radeon_gem_fini(struct radeon_device *rdev);
+int radeon_gem_object_create(struct radeon_device *rdev, int size,
+                            int alignment, int initial_domain,
+                            bool discardable, bool kernel,
+                            bool interruptible,
+                            struct drm_gem_object **obj);
+int radeon_gem_object_pin(struct drm_gem_object *obj, uint32_t pin_domain,
+                         uint64_t *gpu_addr);
+void radeon_gem_object_unpin(struct drm_gem_object *obj);
+
+
+/*
+ * GART structures, functions & helpers
+ */
+struct radeon_mc;
+
+struct radeon_gart_table_ram {
+       volatile uint32_t               *ptr;
+};
+
+struct radeon_gart_table_vram {
+       struct radeon_object            *robj;
+       volatile uint32_t               *ptr;
+};
+
+union radeon_gart_table {
+       struct radeon_gart_table_ram    ram;
+       struct radeon_gart_table_vram   vram;
+};
+
+struct radeon_gart {
+       dma_addr_t                      table_addr;
+       unsigned                        num_gpu_pages;
+       unsigned                        num_cpu_pages;
+       unsigned                        table_size;
+       union radeon_gart_table         table;
+       struct page                     **pages;
+       dma_addr_t                      *pages_addr;
+       bool                            ready;
+};
+
+int radeon_gart_table_ram_alloc(struct radeon_device *rdev);
+void radeon_gart_table_ram_free(struct radeon_device *rdev);
+int radeon_gart_table_vram_alloc(struct radeon_device *rdev);
+void radeon_gart_table_vram_free(struct radeon_device *rdev);
+int radeon_gart_init(struct radeon_device *rdev);
+void radeon_gart_fini(struct radeon_device *rdev);
+void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset,
+                       int pages);
+int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
+                    int pages, struct page **pagelist);
+
+
+/*
+ * GPU MC structures, functions & helpers
+ */
+struct radeon_mc {
+       resource_size_t         aper_size;
+       resource_size_t         aper_base;
+       resource_size_t         agp_base;
+       unsigned                gtt_location;
+       unsigned                gtt_size;
+       unsigned                vram_location;
+       unsigned                vram_size;
+       unsigned                vram_width;
+       int                     vram_mtrr;
+       bool                    vram_is_ddr;
+};
+
+int radeon_mc_setup(struct radeon_device *rdev);
+
+
+/*
+ * GPU scratch registers structures, functions & helpers
+ */
+struct radeon_scratch {
+       unsigned                num_reg;
+       bool                    free[32];
+       uint32_t                reg[32];
+};
+
+int radeon_scratch_get(struct radeon_device *rdev, uint32_t *reg);
+void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg);
+
+
+/*
+ * IRQS.
+ */
+struct radeon_irq {
+       bool            installed;
+       bool            sw_int;
+       /* FIXME: use a define max crtc rather than hardcode it */
+       bool            crtc_vblank_int[2];
+};
+
+int radeon_irq_kms_init(struct radeon_device *rdev);
+void radeon_irq_kms_fini(struct radeon_device *rdev);
+
+
+/*
+ * CP & ring.
+ */
+struct radeon_ib {
+       struct list_head        list;
+       unsigned long           idx;
+       uint64_t                gpu_addr;
+       struct radeon_fence     *fence;
+       volatile uint32_t       *ptr;
+       uint32_t                length_dw;
+};
+
+struct radeon_ib_pool {
+       struct mutex            mutex;
+       struct radeon_object    *robj;
+       struct list_head        scheduled_ibs;
+       struct radeon_ib        ibs[RADEON_IB_POOL_SIZE];
+       bool                    ready;
+       DECLARE_BITMAP(alloc_bm, RADEON_IB_POOL_SIZE);
+};
+
+struct radeon_cp {
+       struct radeon_object    *ring_obj;
+       volatile uint32_t       *ring;
+       unsigned                rptr;
+       unsigned                wptr;
+       unsigned                wptr_old;
+       unsigned                ring_size;
+       unsigned                ring_free_dw;
+       int                     count_dw;
+       uint64_t                gpu_addr;
+       uint32_t                align_mask;
+       uint32_t                ptr_mask;
+       struct mutex            mutex;
+       bool                    ready;
+};
+
+int radeon_ib_get(struct radeon_device *rdev, struct radeon_ib **ib);
+void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib **ib);
+int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib);
+int radeon_ib_pool_init(struct radeon_device *rdev);
+void radeon_ib_pool_fini(struct radeon_device *rdev);
+int radeon_ib_test(struct radeon_device *rdev);
+/* Ring access between begin & end cannot sleep */
+void radeon_ring_free_size(struct radeon_device *rdev);
+int radeon_ring_lock(struct radeon_device *rdev, unsigned ndw);
+void radeon_ring_unlock_commit(struct radeon_device *rdev);
+void radeon_ring_unlock_undo(struct radeon_device *rdev);
+int radeon_ring_test(struct radeon_device *rdev);
+int radeon_ring_init(struct radeon_device *rdev, unsigned ring_size);
+void radeon_ring_fini(struct radeon_device *rdev);
+
+
+/*
+ * CS.
+ */
+struct radeon_cs_reloc {
+       struct drm_gem_object           *gobj;
+       struct radeon_object            *robj;
+       struct radeon_object_list       lobj;
+       uint32_t                        handle;
+       uint32_t                        flags;
+};
+
+struct radeon_cs_chunk {
+       uint32_t                chunk_id;
+       uint32_t                length_dw;
+       uint32_t                *kdata;
+};
+
+struct radeon_cs_parser {
+       struct radeon_device    *rdev;
+       struct drm_file         *filp;
+       /* chunks */
+       unsigned                nchunks;
+       struct radeon_cs_chunk  *chunks;
+       uint64_t                *chunks_array;
+       /* IB */
+       unsigned                idx;
+       /* relocations */
+       unsigned                nrelocs;
+       struct radeon_cs_reloc  *relocs;
+       struct radeon_cs_reloc  **relocs_ptr;
+       struct list_head        validated;
+       /* indices of various chunks */
+       int                     chunk_ib_idx;
+       int                     chunk_relocs_idx;
+       struct radeon_ib        *ib;
+       void                    *track;
+};
+
+struct radeon_cs_packet {
+       unsigned        idx;
+       unsigned        type;
+       unsigned        reg;
+       unsigned        opcode;
+       int             count;
+       unsigned        one_reg_wr;
+};
+
+typedef int (*radeon_packet0_check_t)(struct radeon_cs_parser *p,
+                                     struct radeon_cs_packet *pkt,
+                                     unsigned idx, unsigned reg);
+typedef int (*radeon_packet3_check_t)(struct radeon_cs_parser *p,
+                                     struct radeon_cs_packet *pkt);
+
+
+/*
+ * AGP
+ */
+int radeon_agp_init(struct radeon_device *rdev);
+void radeon_agp_fini(struct radeon_device *rdev);
+
+
+/*
+ * Writeback
+ */
+struct radeon_wb {
+       struct radeon_object    *wb_obj;
+       volatile uint32_t       *wb;
+       uint64_t                gpu_addr;
+};
+
+
+/*
+ * Benchmarking
+ */
+void radeon_benchmark(struct radeon_device *rdev);
+
+
+/*
+ * Debugfs
+ */
+int radeon_debugfs_add_files(struct radeon_device *rdev,
+                            struct drm_info_list *files,
+                            unsigned nfiles);
+int radeon_debugfs_fence_init(struct radeon_device *rdev);
+int r100_debugfs_rbbm_init(struct radeon_device *rdev);
+int r100_debugfs_cp_init(struct radeon_device *rdev);
+
+
+/*
+ * ASIC specific functions.
+ */
+struct radeon_asic {
+       void (*errata)(struct radeon_device *rdev);
+       void (*vram_info)(struct radeon_device *rdev);
+       int (*gpu_reset)(struct radeon_device *rdev);
+       int (*mc_init)(struct radeon_device *rdev);
+       void (*mc_fini)(struct radeon_device *rdev);
+       int (*wb_init)(struct radeon_device *rdev);
+       void (*wb_fini)(struct radeon_device *rdev);
+       int (*gart_enable)(struct radeon_device *rdev);
+       void (*gart_disable)(struct radeon_device *rdev);
+       void (*gart_tlb_flush)(struct radeon_device *rdev);
+       int (*gart_set_page)(struct radeon_device *rdev, int i, uint64_t addr);
+       int (*cp_init)(struct radeon_device *rdev, unsigned ring_size);
+       void (*cp_fini)(struct radeon_device *rdev);
+       void (*cp_disable)(struct radeon_device *rdev);
+       void (*ring_start)(struct radeon_device *rdev);
+       int (*irq_set)(struct radeon_device *rdev);
+       int (*irq_process)(struct radeon_device *rdev);
+       void (*fence_ring_emit)(struct radeon_device *rdev, struct radeon_fence *fence);
+       int (*cs_parse)(struct radeon_cs_parser *p);
+       int (*copy_blit)(struct radeon_device *rdev,
+                        uint64_t src_offset,
+                        uint64_t dst_offset,
+                        unsigned num_pages,
+                        struct radeon_fence *fence);
+       int (*copy_dma)(struct radeon_device *rdev,
+                       uint64_t src_offset,
+                       uint64_t dst_offset,
+                       unsigned num_pages,
+                       struct radeon_fence *fence);
+       int (*copy)(struct radeon_device *rdev,
+                   uint64_t src_offset,
+                   uint64_t dst_offset,
+                   unsigned num_pages,
+                   struct radeon_fence *fence);
+       void (*set_engine_clock)(struct radeon_device *rdev, uint32_t eng_clock);
+       void (*set_memory_clock)(struct radeon_device *rdev, uint32_t mem_clock);
+       void (*set_pcie_lanes)(struct radeon_device *rdev, int lanes);
+       void (*set_clock_gating)(struct radeon_device *rdev, int enable);
+};
+
+
+/*
+ * IOCTL.
+ */
+int radeon_gem_info_ioctl(struct drm_device *dev, void *data,
+                         struct drm_file *filp);
+int radeon_gem_create_ioctl(struct drm_device *dev, void *data,
+                           struct drm_file *filp);
+int radeon_gem_pin_ioctl(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv);
+int radeon_gem_unpin_ioctl(struct drm_device *dev, void *data,
+                          struct drm_file *file_priv);
+int radeon_gem_pwrite_ioctl(struct drm_device *dev, void *data,
+                           struct drm_file *file_priv);
+int radeon_gem_pread_ioctl(struct drm_device *dev, void *data,
+                          struct drm_file *file_priv);
+int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data,
+                               struct drm_file *filp);
+int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data,
+                         struct drm_file *filp);
+int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,
+                         struct drm_file *filp);
+int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
+                             struct drm_file *filp);
+int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp);
+
+
+/*
+ * Core structure, functions and helpers.
+ */
+typedef uint32_t (*radeon_rreg_t)(struct radeon_device*, uint32_t);
+typedef void (*radeon_wreg_t)(struct radeon_device*, uint32_t, uint32_t);
+
+struct radeon_device {
+       struct drm_device               *ddev;
+       struct pci_dev                  *pdev;
+       /* ASIC */
+       enum radeon_family              family;
+       unsigned long                   flags;
+       int                             usec_timeout;
+       enum radeon_pll_errata          pll_errata;
+       int                             num_gb_pipes;
+       int                             disp_priority;
+       /* BIOS */
+       uint8_t                         *bios;
+       bool                            is_atom_bios;
+       uint16_t                        bios_header_start;
+       struct radeon_object            *stollen_vga_memory;
+       struct fb_info                  *fbdev_info;
+       struct radeon_object            *fbdev_robj;
+       struct radeon_framebuffer       *fbdev_rfb;
+       /* Register mmio */
+       unsigned long                   rmmio_base;
+       unsigned long                   rmmio_size;
+       void                            *rmmio;
+       radeon_rreg_t                   mm_rreg;
+       radeon_wreg_t                   mm_wreg;
+       radeon_rreg_t                   mc_rreg;
+       radeon_wreg_t                   mc_wreg;
+       radeon_rreg_t                   pll_rreg;
+       radeon_wreg_t                   pll_wreg;
+       radeon_rreg_t                   pcie_rreg;
+       radeon_wreg_t                   pcie_wreg;
+       radeon_rreg_t                   pciep_rreg;
+       radeon_wreg_t                   pciep_wreg;
+       struct radeon_clock             clock;
+       struct radeon_mc                mc;
+       struct radeon_gart              gart;
+       struct radeon_mode_info         mode_info;
+       struct radeon_scratch           scratch;
+       struct radeon_mman              mman;
+       struct radeon_fence_driver      fence_drv;
+       struct radeon_cp                cp;
+       struct radeon_ib_pool           ib_pool;
+       struct radeon_irq               irq;
+       struct radeon_asic              *asic;
+       struct radeon_gem               gem;
+       struct mutex                    cs_mutex;
+       struct radeon_wb                wb;
+       bool                            gpu_lockup;
+       bool                            shutdown;
+       bool                            suspend;
+};
+
+int radeon_device_init(struct radeon_device *rdev,
+                      struct drm_device *ddev,
+                      struct pci_dev *pdev,
+                      uint32_t flags);
+void radeon_device_fini(struct radeon_device *rdev);
+int radeon_gpu_wait_for_idle(struct radeon_device *rdev);
+
+
+/*
+ * Registers read & write functions.
+ */
+#define RREG8(reg) readb(((void __iomem *)rdev->rmmio) + (reg))
+#define WREG8(reg, v) writeb(v, ((void __iomem *)rdev->rmmio) + (reg))
+#define RREG32(reg) rdev->mm_rreg(rdev, (reg))
+#define WREG32(reg, v) rdev->mm_wreg(rdev, (reg), (v))
+#define REG_SET(FIELD, v) (((v) << FIELD##_SHIFT) & FIELD##_MASK)
+#define REG_GET(FIELD, v) (((v) << FIELD##_SHIFT) & FIELD##_MASK)
+#define RREG32_PLL(reg) rdev->pll_rreg(rdev, (reg))
+#define WREG32_PLL(reg, v) rdev->pll_wreg(rdev, (reg), (v))
+#define RREG32_MC(reg) rdev->mc_rreg(rdev, (reg))
+#define WREG32_MC(reg, v) rdev->mc_wreg(rdev, (reg), (v))
+#define RREG32_PCIE(reg) rdev->pcie_rreg(rdev, (reg))
+#define WREG32_PCIE(reg, v) rdev->pcie_wreg(rdev, (reg), (v))
+#define WREG32_P(reg, val, mask)                               \
+       do {                                                    \
+               uint32_t tmp_ = RREG32(reg);                    \
+               tmp_ &= (mask);                                 \
+               tmp_ |= ((val) & ~(mask));                      \
+               WREG32(reg, tmp_);                              \
+       } while (0)
+#define WREG32_PLL_P(reg, val, mask)                           \
+       do {                                                    \
+               uint32_t tmp_ = RREG32_PLL(reg);                \
+               tmp_ &= (mask);                                 \
+               tmp_ |= ((val) & ~(mask));                      \
+               WREG32_PLL(reg, tmp_);                          \
+       } while (0)
+
+void r100_pll_errata_after_index(struct radeon_device *rdev);
+
+
+/*
+ * ASICs helpers.
+ */
+#define ASIC_IS_RV100(rdev) ((rdev->family == CHIP_RV100) || \
+               (rdev->family == CHIP_RV200) || \
+               (rdev->family == CHIP_RS100) || \
+               (rdev->family == CHIP_RS200) || \
+               (rdev->family == CHIP_RV250) || \
+               (rdev->family == CHIP_RV280) || \
+               (rdev->family == CHIP_RS300))
+#define ASIC_IS_R300(rdev) ((rdev->family == CHIP_R300)  ||    \
+               (rdev->family == CHIP_RV350) ||                 \
+               (rdev->family == CHIP_R350)  ||                 \
+               (rdev->family == CHIP_RV380) ||                 \
+               (rdev->family == CHIP_R420)  ||                 \
+               (rdev->family == CHIP_R423)  ||                 \
+               (rdev->family == CHIP_RV410) ||                 \
+               (rdev->family == CHIP_RS400) ||                 \
+               (rdev->family == CHIP_RS480))
+#define ASIC_IS_AVIVO(rdev) ((rdev->family >= CHIP_RS600))
+#define ASIC_IS_DCE3(rdev) ((rdev->family >= CHIP_RV620))
+#define ASIC_IS_DCE32(rdev) ((rdev->family >= CHIP_RV730))
+
+
+/*
+ * BIOS helpers.
+ */
+#define RBIOS8(i) (rdev->bios[i])
+#define RBIOS16(i) (RBIOS8(i) | (RBIOS8((i)+1) << 8))
+#define RBIOS32(i) ((RBIOS16(i)) | (RBIOS16((i)+2) << 16))
+
+int radeon_combios_init(struct radeon_device *rdev);
+void radeon_combios_fini(struct radeon_device *rdev);
+int radeon_atombios_init(struct radeon_device *rdev);
+void radeon_atombios_fini(struct radeon_device *rdev);
+
+
+/*
+ * RING helpers.
+ */
+#define CP_PACKET0                     0x00000000
+#define                PACKET0_BASE_INDEX_SHIFT        0
+#define                PACKET0_BASE_INDEX_MASK         (0x1ffff << 0)
+#define                PACKET0_COUNT_SHIFT             16
+#define                PACKET0_COUNT_MASK              (0x3fff << 16)
+#define CP_PACKET1                     0x40000000
+#define CP_PACKET2                     0x80000000
+#define                PACKET2_PAD_SHIFT               0
+#define                PACKET2_PAD_MASK                (0x3fffffff << 0)
+#define CP_PACKET3                     0xC0000000
+#define                PACKET3_IT_OPCODE_SHIFT         8
+#define                PACKET3_IT_OPCODE_MASK          (0xff << 8)
+#define                PACKET3_COUNT_SHIFT             16
+#define                PACKET3_COUNT_MASK              (0x3fff << 16)
+/* PACKET3 op code */
+#define                PACKET3_NOP                     0x10
+#define                PACKET3_3D_DRAW_VBUF            0x28
+#define                PACKET3_3D_DRAW_IMMD            0x29
+#define                PACKET3_3D_DRAW_INDX            0x2A
+#define                PACKET3_3D_LOAD_VBPNTR          0x2F
+#define                PACKET3_INDX_BUFFER             0x33
+#define                PACKET3_3D_DRAW_VBUF_2          0x34
+#define                PACKET3_3D_DRAW_IMMD_2          0x35
+#define                PACKET3_3D_DRAW_INDX_2          0x36
+#define                PACKET3_BITBLT_MULTI            0x9B
+
+#define PACKET0(reg, n)        (CP_PACKET0 |                                   \
+                        REG_SET(PACKET0_BASE_INDEX, (reg) >> 2) |      \
+                        REG_SET(PACKET0_COUNT, (n)))
+#define PACKET2(v)     (CP_PACKET2 | REG_SET(PACKET2_PAD, (v)))
+#define PACKET3(op, n) (CP_PACKET3 |                                   \
+                        REG_SET(PACKET3_IT_OPCODE, (op)) |             \
+                        REG_SET(PACKET3_COUNT, (n)))
+
+#define        PACKET_TYPE0    0
+#define        PACKET_TYPE1    1
+#define        PACKET_TYPE2    2
+#define        PACKET_TYPE3    3
+
+#define CP_PACKET_GET_TYPE(h) (((h) >> 30) & 3)
+#define CP_PACKET_GET_COUNT(h) (((h) >> 16) & 0x3FFF)
+#define CP_PACKET0_GET_REG(h) (((h) & 0x1FFF) << 2)
+#define CP_PACKET0_GET_ONE_REG_WR(h) (((h) >> 15) & 1)
+#define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF)
+
+static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v)
+{
+#if DRM_DEBUG_CODE
+       if (rdev->cp.count_dw <= 0) {
+               DRM_ERROR("radeon: writting more dword to ring than expected !\n");
+       }
+#endif
+       rdev->cp.ring[rdev->cp.wptr++] = v;
+       rdev->cp.wptr &= rdev->cp.ptr_mask;
+       rdev->cp.count_dw--;
+       rdev->cp.ring_free_dw--;
+}
+
+
+/*
+ * ASICs macro.
+ */
+#define radeon_cs_parse(p) rdev->asic->cs_parse((p))
+#define radeon_errata(rdev) (rdev)->asic->errata((rdev))
+#define radeon_vram_info(rdev) (rdev)->asic->vram_info((rdev))
+#define radeon_gpu_reset(rdev) (rdev)->asic->gpu_reset((rdev))
+#define radeon_mc_init(rdev) (rdev)->asic->mc_init((rdev))
+#define radeon_mc_fini(rdev) (rdev)->asic->mc_fini((rdev))
+#define radeon_wb_init(rdev) (rdev)->asic->wb_init((rdev))
+#define radeon_wb_fini(rdev) (rdev)->asic->wb_fini((rdev))
+#define radeon_gart_enable(rdev) (rdev)->asic->gart_enable((rdev))
+#define radeon_gart_disable(rdev) (rdev)->asic->gart_disable((rdev))
+#define radeon_gart_tlb_flush(rdev) (rdev)->asic->gart_tlb_flush((rdev))
+#define radeon_gart_set_page(rdev, i, p) (rdev)->asic->gart_set_page((rdev), (i), (p))
+#define radeon_cp_init(rdev,rsize) (rdev)->asic->cp_init((rdev), (rsize))
+#define radeon_cp_fini(rdev) (rdev)->asic->cp_fini((rdev))
+#define radeon_cp_disable(rdev) (rdev)->asic->cp_disable((rdev))
+#define radeon_ring_start(rdev) (rdev)->asic->ring_start((rdev))
+#define radeon_irq_set(rdev) (rdev)->asic->irq_set((rdev))
+#define radeon_irq_process(rdev) (rdev)->asic->irq_process((rdev))
+#define radeon_fence_ring_emit(rdev, fence) (rdev)->asic->fence_ring_emit((rdev), (fence))
+#define radeon_copy_blit(rdev, s, d, np, f) (rdev)->asic->copy_blit((rdev), (s), (d), (np), (f))
+#define radeon_copy_dma(rdev, s, d, np, f) (rdev)->asic->copy_dma((rdev), (s), (d), (np), (f))
+#define radeon_copy(rdev, s, d, np, f) (rdev)->asic->copy((rdev), (s), (d), (np), (f))
+#define radeon_set_engine_clock(rdev, e) (rdev)->asic->set_engine_clock((rdev), (e))
+#define radeon_set_memory_clock(rdev, e) (rdev)->asic->set_engine_clock((rdev), (e))
+#define radeon_set_pcie_lanes(rdev, l) (rdev)->asic->set_pcie_lanes((rdev), (l))
+#define radeon_set_clock_gating(rdev, e) (rdev)->asic->set_clock_gating((rdev), (e))
+
+#endif
diff --git a/drivers/gpu/drm/radeon/radeon_agp.c b/drivers/gpu/drm/radeon/radeon_agp.c
new file mode 100644 (file)
index 0000000..23ea995
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Dave Airlie
+ *    Jerome Glisse <glisse@freedesktop.org>
+ */
+#include "drmP.h"
+#include "drm.h"
+#include "radeon.h"
+#include "radeon_drm.h"
+
+#if __OS_HAS_AGP
+
+struct radeon_agpmode_quirk {
+       u32 hostbridge_vendor;
+       u32 hostbridge_device;
+       u32 chip_vendor;
+       u32 chip_device;
+       u32 subsys_vendor;
+       u32 subsys_device;
+       u32 default_mode;
+};
+
+static struct radeon_agpmode_quirk radeon_agpmode_quirk_list[] = {
+       /* Intel E7505 Memory Controller Hub / RV350 AR [Radeon 9600XT] Needs AGPMode 4 (deb #515326) */
+       { PCI_VENDOR_ID_INTEL, 0x2550, PCI_VENDOR_ID_ATI, 0x4152, 0x1458, 0x4038, 4},
+       /* Intel 82865G/PE/P DRAM Controller/Host-Hub / Mobility 9800 Needs AGPMode 4 (deb #462590) */
+       { PCI_VENDOR_ID_INTEL, 0x2570, PCI_VENDOR_ID_ATI, 0x4a4e, PCI_VENDOR_ID_DELL, 0x5106, 4},
+       /* Intel 82865G/PE/P DRAM Controller/Host-Hub / RV280 [Radeon 9200 SE] Needs AGPMode 4 (lp #300304) */
+       { PCI_VENDOR_ID_INTEL, 0x2570, PCI_VENDOR_ID_ATI, 0x5964,
+               0x148c, 0x2073, 4},
+       /* Intel 82855PM Processor to I/O Controller / Mobility M6 LY Needs AGPMode 1 (deb #467235) */
+       { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4c59,
+               PCI_VENDOR_ID_IBM, 0x052f, 1},
+       /* Intel 82855PM host bridge / Mobility 9600 M10 RV350 Needs AGPMode 1 (lp #195051) */
+       { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4e50,
+               PCI_VENDOR_ID_IBM, 0x0550, 1},
+       /* Intel 82855PM host bridge / Mobility M7 needs AGPMode 1 */
+       { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4c57,
+               PCI_VENDOR_ID_IBM, 0x0530, 1},
+       /* Intel 82855PM host bridge / FireGL Mobility T2 RV350 Needs AGPMode 2 (fdo #20647) */
+       { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4e54,
+               PCI_VENDOR_ID_IBM, 0x054f, 2},
+       /* Intel 82855PM host bridge / Mobility M9+ / VaioPCG-V505DX Needs AGPMode 2 (fdo #17928) */
+       { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x5c61,
+               PCI_VENDOR_ID_SONY, 0x816b, 2},
+       /* Intel 82855PM Processor to I/O Controller / Mobility M9+ Needs AGPMode 8 (phoronix forum) */
+       { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x5c61,
+               PCI_VENDOR_ID_SONY, 0x8195, 8},
+       /* Intel 82830 830 Chipset Host Bridge / Mobility M6 LY Needs AGPMode 2 (fdo #17360)*/
+       { PCI_VENDOR_ID_INTEL, 0x3575, PCI_VENDOR_ID_ATI, 0x4c59,
+               PCI_VENDOR_ID_DELL, 0x00e3, 2},
+       /* Intel 82852/82855 host bridge / Mobility FireGL 9000 R250 Needs AGPMode 1 (lp #296617) */
+       { PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4c66,
+               PCI_VENDOR_ID_DELL, 0x0149, 1},
+       /* Intel 82852/82855 host bridge / Mobility 9600 M10 RV350 Needs AGPMode 1 (deb #467460) */
+       { PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4e50,
+               0x1025, 0x0061, 1},
+       /* Intel 82852/82855 host bridge / Mobility 9600 M10 RV350 Needs AGPMode 1 (lp #203007) */
+       { PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4e50,
+               0x1025, 0x0064, 1},
+       /* Intel 82852/82855 host bridge / Mobility 9600 M10 RV350 Needs AGPMode 1 (lp #141551) */
+       { PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4e50,
+               PCI_VENDOR_ID_ASUSTEK, 0x1942, 1},
+       /* Intel 82852/82855 host bridge / Mobility 9600/9700 Needs AGPMode 1 (deb #510208) */
+       { PCI_VENDOR_ID_INTEL, 0x3580, PCI_VENDOR_ID_ATI, 0x4e50,
+               0x10cf, 0x127f, 1},
+       /* ASRock K7VT4A+ AGP 8x / ATI Radeon 9250 AGP Needs AGPMode 4 (lp #133192) */
+       { 0x1849, 0x3189, PCI_VENDOR_ID_ATI, 0x5960,
+               0x1787, 0x5960, 4},
+       /* VIA K8M800 Host Bridge / RV280 [Radeon 9200 PRO] Needs AGPMode 4 (fdo #12544) */
+       { PCI_VENDOR_ID_VIA, 0x0204, PCI_VENDOR_ID_ATI, 0x5960,
+               0x17af, 0x2020, 4},
+       /* VIA KT880 Host Bridge / RV350 [Radeon 9550] Needs AGPMode 4 (fdo #19981) */
+       { PCI_VENDOR_ID_VIA, 0x0269, PCI_VENDOR_ID_ATI, 0x4153,
+               PCI_VENDOR_ID_ASUSTEK, 0x003c, 4},
+       /* VIA VT8363 Host Bridge / R200 QL [Radeon 8500] Needs AGPMode 2 (lp #141551) */
+       { PCI_VENDOR_ID_VIA, 0x0305, PCI_VENDOR_ID_ATI, 0x514c,
+               PCI_VENDOR_ID_ATI, 0x013a, 2},
+       /* VIA VT82C693A Host Bridge / RV280 [Radeon 9200 PRO] Needs AGPMode 2 (deb #515512) */
+       { PCI_VENDOR_ID_VIA, 0x0691, PCI_VENDOR_ID_ATI, 0x5960,
+               PCI_VENDOR_ID_ASUSTEK, 0x004c, 2},
+       /* VIA VT82C693A Host Bridge / RV280 [Radeon 9200 PRO] Needs AGPMode 2 */
+       { PCI_VENDOR_ID_VIA, 0x0691, PCI_VENDOR_ID_ATI, 0x5960,
+               PCI_VENDOR_ID_ASUSTEK, 0x0054, 2},
+       /* VIA VT8377 Host Bridge / R200 QM [Radeon 9100] Needs AGPMode 4 (deb #461144) */
+       { PCI_VENDOR_ID_VIA, 0x3189, PCI_VENDOR_ID_ATI, 0x514d,
+               0x174b, 0x7149, 4},
+       /* VIA VT8377 Host Bridge / RV280 [Radeon 9200 PRO] Needs AGPMode 4 (lp #312693) */
+       { PCI_VENDOR_ID_VIA, 0x3189, PCI_VENDOR_ID_ATI, 0x5960,
+               0x1462, 0x0380, 4},
+       /* VIA VT8377 Host Bridge / RV280 Needs AGPMode 4 (ati ML) */
+       { PCI_VENDOR_ID_VIA, 0x3189, PCI_VENDOR_ID_ATI, 0x5964,
+               0x148c, 0x2073, 4},
+       /* ATI Host Bridge / RV280 [M9+] Needs AGPMode 1 (phoronix forum) */
+       { PCI_VENDOR_ID_ATI, 0xcbb2, PCI_VENDOR_ID_ATI, 0x5c61,
+               PCI_VENDOR_ID_SONY, 0x8175, 1},
+       /* HP Host Bridge / R300 [FireGL X1] Needs AGPMode 2 (fdo #7770) */
+       { PCI_VENDOR_ID_HP, 0x122e, PCI_VENDOR_ID_ATI, 0x4e47,
+               PCI_VENDOR_ID_ATI, 0x0152, 2},
+       { 0, 0, 0, 0, 0, 0, 0 },
+};
+#endif
+
+int radeon_agp_init(struct radeon_device *rdev)
+{
+#if __OS_HAS_AGP
+       struct radeon_agpmode_quirk *p = radeon_agpmode_quirk_list;
+       struct drm_agp_mode mode;
+       struct drm_agp_info info;
+       uint32_t agp_status;
+       int default_mode;
+       bool is_v3;
+       int ret;
+
+       /* Acquire AGP. */
+       if (!rdev->ddev->agp->acquired) {
+               ret = drm_agp_acquire(rdev->ddev);
+               if (ret) {
+                       DRM_ERROR("Unable to acquire AGP: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       ret = drm_agp_info(rdev->ddev, &info);
+       if (ret) {
+               DRM_ERROR("Unable to get AGP info: %d\n", ret);
+               return ret;
+       }
+       mode.mode = info.mode;
+       agp_status = (RREG32(RADEON_AGP_STATUS) | RADEON_AGPv3_MODE) & mode.mode;
+       is_v3 = !!(agp_status & RADEON_AGPv3_MODE);
+
+       if (is_v3) {
+               default_mode = (agp_status & RADEON_AGPv3_8X_MODE) ? 8 : 4;
+       } else {
+               if (agp_status & RADEON_AGP_4X_MODE) {
+                       default_mode = 4;
+               } else if (agp_status & RADEON_AGP_2X_MODE) {
+                       default_mode = 2;
+               } else {
+                       default_mode = 1;
+               }
+       }
+
+       /* Apply AGPMode Quirks */
+       while (p && p->chip_device != 0) {
+               if (info.id_vendor == p->hostbridge_vendor &&
+                   info.id_device == p->hostbridge_device &&
+                   rdev->pdev->vendor == p->chip_vendor &&
+                   rdev->pdev->device == p->chip_device &&
+                   rdev->pdev->subsystem_vendor == p->subsys_vendor &&
+                   rdev->pdev->subsystem_device == p->subsys_device) {
+                       default_mode = p->default_mode;
+               }
+               ++p;
+       }
+
+       if (radeon_agpmode > 0) {
+               if ((radeon_agpmode < (is_v3 ? 4 : 1)) ||
+                   (radeon_agpmode > (is_v3 ? 8 : 4)) ||
+                   (radeon_agpmode & (radeon_agpmode - 1))) {
+                       DRM_ERROR("Illegal AGP Mode: %d (valid %s), leaving at %d\n",
+                                 radeon_agpmode, is_v3 ? "4, 8" : "1, 2, 4",
+                                 default_mode);
+                       radeon_agpmode = default_mode;
+               } else {
+                       DRM_INFO("AGP mode requested: %d\n", radeon_agpmode);
+               }
+       } else {
+               radeon_agpmode = default_mode;
+       }
+
+       mode.mode &= ~RADEON_AGP_MODE_MASK;
+       if (is_v3) {
+               switch (radeon_agpmode) {
+               case 8:
+                       mode.mode |= RADEON_AGPv3_8X_MODE;
+                       break;
+               case 4:
+               default:
+                       mode.mode |= RADEON_AGPv3_4X_MODE;
+                       break;
+               }
+       } else {
+               switch (radeon_agpmode) {
+               case 4:
+                       mode.mode |= RADEON_AGP_4X_MODE;
+                       break;
+               case 2:
+                       mode.mode |= RADEON_AGP_2X_MODE;
+                       break;
+               case 1:
+               default:
+                       mode.mode |= RADEON_AGP_1X_MODE;
+                       break;
+               }
+       }
+
+       mode.mode &= ~RADEON_AGP_FW_MODE; /* disable fw */
+       ret = drm_agp_enable(rdev->ddev, mode);
+       if (ret) {
+               DRM_ERROR("Unable to enable AGP (mode = 0x%lx)\n", mode.mode);
+               return ret;
+       }
+
+       rdev->mc.agp_base = rdev->ddev->agp->agp_info.aper_base;
+       rdev->mc.gtt_size = rdev->ddev->agp->agp_info.aper_size << 20;
+
+       /* workaround some hw issues */
+       if (rdev->family < CHIP_R200) {
+               WREG32(RADEON_AGP_CNTL, RREG32(RADEON_AGP_CNTL) | 0x000e0000);
+       }
+       return 0;
+#else
+       return 0;
+#endif
+}
+
+void radeon_agp_fini(struct radeon_device *rdev)
+{
+#if __OS_HAS_AGP
+       if (rdev->flags & RADEON_IS_AGP) {
+               if (rdev->ddev->agp && rdev->ddev->agp->acquired) {
+                       drm_agp_release(rdev->ddev);
+               }
+       }
+#endif
+}
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
new file mode 100644 (file)
index 0000000..e57d8a7
--- /dev/null
@@ -0,0 +1,405 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ *          Jerome Glisse
+ */
+#ifndef __RADEON_ASIC_H__
+#define __RADEON_ASIC_H__
+
+/*
+ * common functions
+ */
+void radeon_legacy_set_engine_clock(struct radeon_device *rdev, uint32_t eng_clock);
+void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable);
+
+void radeon_atom_set_engine_clock(struct radeon_device *rdev, uint32_t eng_clock);
+void radeon_atom_set_memory_clock(struct radeon_device *rdev, uint32_t mem_clock);
+void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable);
+
+/*
+ * r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280
+ */
+uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg);
+void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
+void r100_errata(struct radeon_device *rdev);
+void r100_vram_info(struct radeon_device *rdev);
+int r100_gpu_reset(struct radeon_device *rdev);
+int r100_mc_init(struct radeon_device *rdev);
+void r100_mc_fini(struct radeon_device *rdev);
+int r100_wb_init(struct radeon_device *rdev);
+void r100_wb_fini(struct radeon_device *rdev);
+int r100_gart_enable(struct radeon_device *rdev);
+void r100_pci_gart_disable(struct radeon_device *rdev);
+void r100_pci_gart_tlb_flush(struct radeon_device *rdev);
+int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr);
+int r100_cp_init(struct radeon_device *rdev, unsigned ring_size);
+void r100_cp_fini(struct radeon_device *rdev);
+void r100_cp_disable(struct radeon_device *rdev);
+void r100_ring_start(struct radeon_device *rdev);
+int r100_irq_set(struct radeon_device *rdev);
+int r100_irq_process(struct radeon_device *rdev);
+void r100_fence_ring_emit(struct radeon_device *rdev,
+                         struct radeon_fence *fence);
+int r100_cs_parse(struct radeon_cs_parser *p);
+void r100_pll_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
+uint32_t r100_pll_rreg(struct radeon_device *rdev, uint32_t reg);
+int r100_copy_blit(struct radeon_device *rdev,
+                  uint64_t src_offset,
+                  uint64_t dst_offset,
+                  unsigned num_pages,
+                  struct radeon_fence *fence);
+
+static struct radeon_asic r100_asic = {
+       .errata = &r100_errata,
+       .vram_info = &r100_vram_info,
+       .gpu_reset = &r100_gpu_reset,
+       .mc_init = &r100_mc_init,
+       .mc_fini = &r100_mc_fini,
+       .wb_init = &r100_wb_init,
+       .wb_fini = &r100_wb_fini,
+       .gart_enable = &r100_gart_enable,
+       .gart_disable = &r100_pci_gart_disable,
+       .gart_tlb_flush = &r100_pci_gart_tlb_flush,
+       .gart_set_page = &r100_pci_gart_set_page,
+       .cp_init = &r100_cp_init,
+       .cp_fini = &r100_cp_fini,
+       .cp_disable = &r100_cp_disable,
+       .ring_start = &r100_ring_start,
+       .irq_set = &r100_irq_set,
+       .irq_process = &r100_irq_process,
+       .fence_ring_emit = &r100_fence_ring_emit,
+       .cs_parse = &r100_cs_parse,
+       .copy_blit = &r100_copy_blit,
+       .copy_dma = NULL,
+       .copy = &r100_copy_blit,
+       .set_engine_clock = &radeon_legacy_set_engine_clock,
+       .set_memory_clock = NULL,
+       .set_pcie_lanes = NULL,
+       .set_clock_gating = &radeon_legacy_set_clock_gating,
+};
+
+
+/*
+ * r300,r350,rv350,rv380
+ */
+void r300_errata(struct radeon_device *rdev);
+void r300_vram_info(struct radeon_device *rdev);
+int r300_gpu_reset(struct radeon_device *rdev);
+int r300_mc_init(struct radeon_device *rdev);
+void r300_mc_fini(struct radeon_device *rdev);
+void r300_ring_start(struct radeon_device *rdev);
+void r300_fence_ring_emit(struct radeon_device *rdev,
+                         struct radeon_fence *fence);
+int r300_cs_parse(struct radeon_cs_parser *p);
+int r300_gart_enable(struct radeon_device *rdev);
+void rv370_pcie_gart_disable(struct radeon_device *rdev);
+void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev);
+int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr);
+uint32_t rv370_pcie_rreg(struct radeon_device *rdev, uint32_t reg);
+void rv370_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
+void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes);
+int r300_copy_dma(struct radeon_device *rdev,
+                 uint64_t src_offset,
+                 uint64_t dst_offset,
+                 unsigned num_pages,
+                 struct radeon_fence *fence);
+static struct radeon_asic r300_asic = {
+       .errata = &r300_errata,
+       .vram_info = &r300_vram_info,
+       .gpu_reset = &r300_gpu_reset,
+       .mc_init = &r300_mc_init,
+       .mc_fini = &r300_mc_fini,
+       .wb_init = &r100_wb_init,
+       .wb_fini = &r100_wb_fini,
+       .gart_enable = &r300_gart_enable,
+       .gart_disable = &r100_pci_gart_disable,
+       .gart_tlb_flush = &r100_pci_gart_tlb_flush,
+       .gart_set_page = &r100_pci_gart_set_page,
+       .cp_init = &r100_cp_init,
+       .cp_fini = &r100_cp_fini,
+       .cp_disable = &r100_cp_disable,
+       .ring_start = &r300_ring_start,
+       .irq_set = &r100_irq_set,
+       .irq_process = &r100_irq_process,
+       .fence_ring_emit = &r300_fence_ring_emit,
+       .cs_parse = &r300_cs_parse,
+       .copy_blit = &r100_copy_blit,
+       .copy_dma = &r300_copy_dma,
+       .copy = &r100_copy_blit,
+       .set_engine_clock = &radeon_legacy_set_engine_clock,
+       .set_memory_clock = NULL,
+       .set_pcie_lanes = &rv370_set_pcie_lanes,
+       .set_clock_gating = &radeon_legacy_set_clock_gating,
+};
+
+/*
+ * r420,r423,rv410
+ */
+void r420_errata(struct radeon_device *rdev);
+void r420_vram_info(struct radeon_device *rdev);
+int r420_mc_init(struct radeon_device *rdev);
+void r420_mc_fini(struct radeon_device *rdev);
+static struct radeon_asic r420_asic = {
+       .errata = &r420_errata,
+       .vram_info = &r420_vram_info,
+       .gpu_reset = &r300_gpu_reset,
+       .mc_init = &r420_mc_init,
+       .mc_fini = &r420_mc_fini,
+       .wb_init = &r100_wb_init,
+       .wb_fini = &r100_wb_fini,
+       .gart_enable = &r300_gart_enable,
+       .gart_disable = &rv370_pcie_gart_disable,
+       .gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
+       .gart_set_page = &rv370_pcie_gart_set_page,
+       .cp_init = &r100_cp_init,
+       .cp_fini = &r100_cp_fini,
+       .cp_disable = &r100_cp_disable,
+       .ring_start = &r300_ring_start,
+       .irq_set = &r100_irq_set,
+       .irq_process = &r100_irq_process,
+       .fence_ring_emit = &r300_fence_ring_emit,
+       .cs_parse = &r300_cs_parse,
+       .copy_blit = &r100_copy_blit,
+       .copy_dma = &r300_copy_dma,
+       .copy = &r100_copy_blit,
+       .set_engine_clock = &radeon_atom_set_engine_clock,
+       .set_memory_clock = &radeon_atom_set_memory_clock,
+       .set_pcie_lanes = &rv370_set_pcie_lanes,
+       .set_clock_gating = &radeon_atom_set_clock_gating,
+};
+
+
+/*
+ * rs400,rs480
+ */
+void rs400_errata(struct radeon_device *rdev);
+void rs400_vram_info(struct radeon_device *rdev);
+int rs400_mc_init(struct radeon_device *rdev);
+void rs400_mc_fini(struct radeon_device *rdev);
+int rs400_gart_enable(struct radeon_device *rdev);
+void rs400_gart_disable(struct radeon_device *rdev);
+void rs400_gart_tlb_flush(struct radeon_device *rdev);
+int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr);
+uint32_t rs400_mc_rreg(struct radeon_device *rdev, uint32_t reg);
+void rs400_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
+static struct radeon_asic rs400_asic = {
+       .errata = &rs400_errata,
+       .vram_info = &rs400_vram_info,
+       .gpu_reset = &r300_gpu_reset,
+       .mc_init = &rs400_mc_init,
+       .mc_fini = &rs400_mc_fini,
+       .wb_init = &r100_wb_init,
+       .wb_fini = &r100_wb_fini,
+       .gart_enable = &rs400_gart_enable,
+       .gart_disable = &rs400_gart_disable,
+       .gart_tlb_flush = &rs400_gart_tlb_flush,
+       .gart_set_page = &rs400_gart_set_page,
+       .cp_init = &r100_cp_init,
+       .cp_fini = &r100_cp_fini,
+       .cp_disable = &r100_cp_disable,
+       .ring_start = &r300_ring_start,
+       .irq_set = &r100_irq_set,
+       .irq_process = &r100_irq_process,
+       .fence_ring_emit = &r300_fence_ring_emit,
+       .cs_parse = &r300_cs_parse,
+       .copy_blit = &r100_copy_blit,
+       .copy_dma = &r300_copy_dma,
+       .copy = &r100_copy_blit,
+       .set_engine_clock = &radeon_legacy_set_engine_clock,
+       .set_memory_clock = NULL,
+       .set_pcie_lanes = NULL,
+       .set_clock_gating = &radeon_legacy_set_clock_gating,
+};
+
+
+/*
+ * rs600.
+ */
+void rs600_errata(struct radeon_device *rdev);
+void rs600_vram_info(struct radeon_device *rdev);
+int rs600_mc_init(struct radeon_device *rdev);
+void rs600_mc_fini(struct radeon_device *rdev);
+int rs600_irq_set(struct radeon_device *rdev);
+int rs600_gart_enable(struct radeon_device *rdev);
+void rs600_gart_disable(struct radeon_device *rdev);
+void rs600_gart_tlb_flush(struct radeon_device *rdev);
+int rs600_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr);
+uint32_t rs600_mc_rreg(struct radeon_device *rdev, uint32_t reg);
+void rs600_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
+static struct radeon_asic rs600_asic = {
+       .errata = &rs600_errata,
+       .vram_info = &rs600_vram_info,
+       .gpu_reset = &r300_gpu_reset,
+       .mc_init = &rs600_mc_init,
+       .mc_fini = &rs600_mc_fini,
+       .wb_init = &r100_wb_init,
+       .wb_fini = &r100_wb_fini,
+       .gart_enable = &rs600_gart_enable,
+       .gart_disable = &rs600_gart_disable,
+       .gart_tlb_flush = &rs600_gart_tlb_flush,
+       .gart_set_page = &rs600_gart_set_page,
+       .cp_init = &r100_cp_init,
+       .cp_fini = &r100_cp_fini,
+       .cp_disable = &r100_cp_disable,
+       .ring_start = &r300_ring_start,
+       .irq_set = &rs600_irq_set,
+       .irq_process = &r100_irq_process,
+       .fence_ring_emit = &r300_fence_ring_emit,
+       .cs_parse = &r300_cs_parse,
+       .copy_blit = &r100_copy_blit,
+       .copy_dma = &r300_copy_dma,
+       .copy = &r100_copy_blit,
+       .set_engine_clock = &radeon_atom_set_engine_clock,
+       .set_memory_clock = &radeon_atom_set_memory_clock,
+       .set_pcie_lanes = NULL,
+       .set_clock_gating = &radeon_atom_set_clock_gating,
+};
+
+
+/*
+ * rs690,rs740
+ */
+void rs690_errata(struct radeon_device *rdev);
+void rs690_vram_info(struct radeon_device *rdev);
+int rs690_mc_init(struct radeon_device *rdev);
+void rs690_mc_fini(struct radeon_device *rdev);
+uint32_t rs690_mc_rreg(struct radeon_device *rdev, uint32_t reg);
+void rs690_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
+static struct radeon_asic rs690_asic = {
+       .errata = &rs690_errata,
+       .vram_info = &rs690_vram_info,
+       .gpu_reset = &r300_gpu_reset,
+       .mc_init = &rs690_mc_init,
+       .mc_fini = &rs690_mc_fini,
+       .wb_init = &r100_wb_init,
+       .wb_fini = &r100_wb_fini,
+       .gart_enable = &rs400_gart_enable,
+       .gart_disable = &rs400_gart_disable,
+       .gart_tlb_flush = &rs400_gart_tlb_flush,
+       .gart_set_page = &rs400_gart_set_page,
+       .cp_init = &r100_cp_init,
+       .cp_fini = &r100_cp_fini,
+       .cp_disable = &r100_cp_disable,
+       .ring_start = &r300_ring_start,
+       .irq_set = &rs600_irq_set,
+       .irq_process = &r100_irq_process,
+       .fence_ring_emit = &r300_fence_ring_emit,
+       .cs_parse = &r300_cs_parse,
+       .copy_blit = &r100_copy_blit,
+       .copy_dma = &r300_copy_dma,
+       .copy = &r300_copy_dma,
+       .set_engine_clock = &radeon_atom_set_engine_clock,
+       .set_memory_clock = &radeon_atom_set_memory_clock,
+       .set_pcie_lanes = NULL,
+       .set_clock_gating = &radeon_atom_set_clock_gating,
+};
+
+
+/*
+ * rv515
+ */
+void rv515_errata(struct radeon_device *rdev);
+void rv515_vram_info(struct radeon_device *rdev);
+int rv515_gpu_reset(struct radeon_device *rdev);
+int rv515_mc_init(struct radeon_device *rdev);
+void rv515_mc_fini(struct radeon_device *rdev);
+uint32_t rv515_mc_rreg(struct radeon_device *rdev, uint32_t reg);
+void rv515_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
+void rv515_ring_start(struct radeon_device *rdev);
+uint32_t rv515_pcie_rreg(struct radeon_device *rdev, uint32_t reg);
+void rv515_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
+static struct radeon_asic rv515_asic = {
+       .errata = &rv515_errata,
+       .vram_info = &rv515_vram_info,
+       .gpu_reset = &rv515_gpu_reset,
+       .mc_init = &rv515_mc_init,
+       .mc_fini = &rv515_mc_fini,
+       .wb_init = &r100_wb_init,
+       .wb_fini = &r100_wb_fini,
+       .gart_enable = &r300_gart_enable,
+       .gart_disable = &rv370_pcie_gart_disable,
+       .gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
+       .gart_set_page = &rv370_pcie_gart_set_page,
+       .cp_init = &r100_cp_init,
+       .cp_fini = &r100_cp_fini,
+       .cp_disable = &r100_cp_disable,
+       .ring_start = &rv515_ring_start,
+       .irq_set = &r100_irq_set,
+       .irq_process = &r100_irq_process,
+       .fence_ring_emit = &r300_fence_ring_emit,
+       .cs_parse = &r100_cs_parse,
+       .copy_blit = &r100_copy_blit,
+       .copy_dma = &r300_copy_dma,
+       .copy = &r100_copy_blit,
+       .set_engine_clock = &radeon_atom_set_engine_clock,
+       .set_memory_clock = &radeon_atom_set_memory_clock,
+       .set_pcie_lanes = &rv370_set_pcie_lanes,
+       .set_clock_gating = &radeon_atom_set_clock_gating,
+};
+
+
+/*
+ * r520,rv530,rv560,rv570,r580
+ */
+void r520_errata(struct radeon_device *rdev);
+void r520_vram_info(struct radeon_device *rdev);
+int r520_mc_init(struct radeon_device *rdev);
+void r520_mc_fini(struct radeon_device *rdev);
+static struct radeon_asic r520_asic = {
+       .errata = &r520_errata,
+       .vram_info = &r520_vram_info,
+       .gpu_reset = &rv515_gpu_reset,
+       .mc_init = &r520_mc_init,
+       .mc_fini = &r520_mc_fini,
+       .wb_init = &r100_wb_init,
+       .wb_fini = &r100_wb_fini,
+       .gart_enable = &r300_gart_enable,
+       .gart_disable = &rv370_pcie_gart_disable,
+       .gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
+       .gart_set_page = &rv370_pcie_gart_set_page,
+       .cp_init = &r100_cp_init,
+       .cp_fini = &r100_cp_fini,
+       .cp_disable = &r100_cp_disable,
+       .ring_start = &rv515_ring_start,
+       .irq_set = &r100_irq_set,
+       .irq_process = &r100_irq_process,
+       .fence_ring_emit = &r300_fence_ring_emit,
+       .cs_parse = &r100_cs_parse,
+       .copy_blit = &r100_copy_blit,
+       .copy_dma = &r300_copy_dma,
+       .copy = &r100_copy_blit,
+       .set_engine_clock = &radeon_atom_set_engine_clock,
+       .set_memory_clock = &radeon_atom_set_memory_clock,
+       .set_pcie_lanes = &rv370_set_pcie_lanes,
+       .set_clock_gating = &radeon_atom_set_clock_gating,
+};
+
+/*
+ * r600,rv610,rv630,rv620,rv635,rv670,rs780,rv770,rv730,rv710
+ */
+uint32_t r600_pciep_rreg(struct radeon_device *rdev, uint32_t reg);
+void r600_pciep_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
+
+#endif
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
new file mode 100644 (file)
index 0000000..786632d
--- /dev/null
@@ -0,0 +1,1298 @@
+/*
+ * Copyright 2007-8 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ */
+#include "drmP.h"
+#include "radeon_drm.h"
+#include "radeon.h"
+
+#include "atom.h"
+#include "atom-bits.h"
+
+/* from radeon_encoder.c */
+extern uint32_t
+radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device,
+                     uint8_t dac);
+extern void radeon_link_encoder_connector(struct drm_device *dev);
+extern void
+radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id,
+                       uint32_t supported_device);
+
+/* from radeon_connector.c */
+extern void
+radeon_add_atom_connector(struct drm_device *dev,
+                         uint32_t connector_id,
+                         uint32_t supported_device,
+                         int connector_type,
+                         struct radeon_i2c_bus_rec *i2c_bus,
+                         bool linkb, uint32_t igp_lane_info);
+
+/* from radeon_legacy_encoder.c */
+extern void
+radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_id,
+                         uint32_t supported_device);
+
+union atom_supported_devices {
+       struct _ATOM_SUPPORTED_DEVICES_INFO info;
+       struct _ATOM_SUPPORTED_DEVICES_INFO_2 info_2;
+       struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 info_2d1;
+};
+
+static inline struct radeon_i2c_bus_rec radeon_lookup_gpio(struct drm_device
+                                                          *dev, uint8_t id)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       struct atom_context *ctx = rdev->mode_info.atom_context;
+       ATOM_GPIO_I2C_ASSIGMENT gpio;
+       struct radeon_i2c_bus_rec i2c;
+       int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info);
+       struct _ATOM_GPIO_I2C_INFO *i2c_info;
+       uint16_t data_offset;
+
+       memset(&i2c, 0, sizeof(struct radeon_i2c_bus_rec));
+       i2c.valid = false;
+
+       atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset);
+
+       i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset);
+
+       gpio = i2c_info->asGPIO_Info[id];
+
+       i2c.mask_clk_reg = le16_to_cpu(gpio.usClkMaskRegisterIndex) * 4;
+       i2c.mask_data_reg = le16_to_cpu(gpio.usDataMaskRegisterIndex) * 4;
+       i2c.put_clk_reg = le16_to_cpu(gpio.usClkEnRegisterIndex) * 4;
+       i2c.put_data_reg = le16_to_cpu(gpio.usDataEnRegisterIndex) * 4;
+       i2c.get_clk_reg = le16_to_cpu(gpio.usClkY_RegisterIndex) * 4;
+       i2c.get_data_reg = le16_to_cpu(gpio.usDataY_RegisterIndex) * 4;
+       i2c.a_clk_reg = le16_to_cpu(gpio.usClkA_RegisterIndex) * 4;
+       i2c.a_data_reg = le16_to_cpu(gpio.usDataA_RegisterIndex) * 4;
+       i2c.mask_clk_mask = (1 << gpio.ucClkMaskShift);
+       i2c.mask_data_mask = (1 << gpio.ucDataMaskShift);
+       i2c.put_clk_mask = (1 << gpio.ucClkEnShift);
+       i2c.put_data_mask = (1 << gpio.ucDataEnShift);
+       i2c.get_clk_mask = (1 << gpio.ucClkY_Shift);
+       i2c.get_data_mask = (1 << gpio.ucDataY_Shift);
+       i2c.a_clk_mask = (1 << gpio.ucClkA_Shift);
+       i2c.a_data_mask = (1 << gpio.ucDataA_Shift);
+       i2c.valid = true;
+
+       return i2c;
+}
+
+static bool radeon_atom_apply_quirks(struct drm_device *dev,
+                                    uint32_t supported_device,
+                                    int *connector_type,
+                                    struct radeon_i2c_bus_rec *i2c_bus)
+{
+
+       /* Asus M2A-VM HDMI board lists the DVI port as HDMI */
+       if ((dev->pdev->device == 0x791e) &&
+           (dev->pdev->subsystem_vendor == 0x1043) &&
+           (dev->pdev->subsystem_device == 0x826d)) {
+               if ((*connector_type == DRM_MODE_CONNECTOR_HDMIA) &&
+                   (supported_device == ATOM_DEVICE_DFP3_SUPPORT))
+                       *connector_type = DRM_MODE_CONNECTOR_DVID;
+       }
+
+       /* a-bit f-i90hd - ciaranm on #radeonhd - this board has no DVI */
+       if ((dev->pdev->device == 0x7941) &&
+           (dev->pdev->subsystem_vendor == 0x147b) &&
+           (dev->pdev->subsystem_device == 0x2412)) {
+               if (*connector_type == DRM_MODE_CONNECTOR_DVII)
+                       return false;
+       }
+
+       /* Falcon NW laptop lists vga ddc line for LVDS */
+       if ((dev->pdev->device == 0x5653) &&
+           (dev->pdev->subsystem_vendor == 0x1462) &&
+           (dev->pdev->subsystem_device == 0x0291)) {
+               if (*connector_type == DRM_MODE_CONNECTOR_LVDS)
+                       i2c_bus->valid = false;
+       }
+
+       /* Funky macbooks */
+       if ((dev->pdev->device == 0x71C5) &&
+           (dev->pdev->subsystem_vendor == 0x106b) &&
+           (dev->pdev->subsystem_device == 0x0080)) {
+               if ((supported_device == ATOM_DEVICE_CRT1_SUPPORT) ||
+                   (supported_device == ATOM_DEVICE_DFP2_SUPPORT))
+                       return false;
+       }
+
+       /* some BIOSes seem to report DAC on HDMI - they hurt me with their lies */
+       if ((*connector_type == DRM_MODE_CONNECTOR_HDMIA) ||
+           (*connector_type == DRM_MODE_CONNECTOR_HDMIB)) {
+               if (supported_device & (ATOM_DEVICE_CRT_SUPPORT)) {
+                       return false;
+               }
+       }
+
+       /* ASUS HD 3600 XT board lists the DVI port as HDMI */
+       if ((dev->pdev->device == 0x9598) &&
+           (dev->pdev->subsystem_vendor == 0x1043) &&
+           (dev->pdev->subsystem_device == 0x01da)) {
+               if (*connector_type == DRM_MODE_CONNECTOR_HDMIB) {
+                       *connector_type = DRM_MODE_CONNECTOR_DVID;
+               }
+       }
+
+       return true;
+}
+
+const int supported_devices_connector_convert[] = {
+       DRM_MODE_CONNECTOR_Unknown,
+       DRM_MODE_CONNECTOR_VGA,
+       DRM_MODE_CONNECTOR_DVII,
+       DRM_MODE_CONNECTOR_DVID,
+       DRM_MODE_CONNECTOR_DVIA,
+       DRM_MODE_CONNECTOR_SVIDEO,
+       DRM_MODE_CONNECTOR_Composite,
+       DRM_MODE_CONNECTOR_LVDS,
+       DRM_MODE_CONNECTOR_Unknown,
+       DRM_MODE_CONNECTOR_Unknown,
+       DRM_MODE_CONNECTOR_HDMIA,
+       DRM_MODE_CONNECTOR_HDMIB,
+       DRM_MODE_CONNECTOR_Unknown,
+       DRM_MODE_CONNECTOR_Unknown,
+       DRM_MODE_CONNECTOR_9PinDIN,
+       DRM_MODE_CONNECTOR_DisplayPort
+};
+
+const int object_connector_convert[] = {
+       DRM_MODE_CONNECTOR_Unknown,
+       DRM_MODE_CONNECTOR_DVII,
+       DRM_MODE_CONNECTOR_DVII,
+       DRM_MODE_CONNECTOR_DVID,
+       DRM_MODE_CONNECTOR_DVID,
+       DRM_MODE_CONNECTOR_VGA,
+       DRM_MODE_CONNECTOR_Composite,
+       DRM_MODE_CONNECTOR_SVIDEO,
+       DRM_MODE_CONNECTOR_Unknown,
+       DRM_MODE_CONNECTOR_9PinDIN,
+       DRM_MODE_CONNECTOR_Unknown,
+       DRM_MODE_CONNECTOR_HDMIA,
+       DRM_MODE_CONNECTOR_HDMIB,
+       DRM_MODE_CONNECTOR_HDMIB,
+       DRM_MODE_CONNECTOR_LVDS,
+       DRM_MODE_CONNECTOR_9PinDIN,
+       DRM_MODE_CONNECTOR_Unknown,
+       DRM_MODE_CONNECTOR_Unknown,
+       DRM_MODE_CONNECTOR_Unknown,
+       DRM_MODE_CONNECTOR_DisplayPort
+};
+
+bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_mode_info *mode_info = &rdev->mode_info;
+       struct atom_context *ctx = mode_info->atom_context;
+       int index = GetIndexIntoMasterTable(DATA, Object_Header);
+       uint16_t size, data_offset;
+       uint8_t frev, crev, line_mux = 0;
+       ATOM_CONNECTOR_OBJECT_TABLE *con_obj;
+       ATOM_DISPLAY_OBJECT_PATH_TABLE *path_obj;
+       ATOM_OBJECT_HEADER *obj_header;
+       int i, j, path_size, device_support;
+       int connector_type;
+       uint16_t igp_lane_info;
+       bool linkb;
+       struct radeon_i2c_bus_rec ddc_bus;
+
+       atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset);
+
+       if (data_offset == 0)
+               return false;
+
+       if (crev < 2)
+               return false;
+
+       obj_header = (ATOM_OBJECT_HEADER *) (ctx->bios + data_offset);
+       path_obj = (ATOM_DISPLAY_OBJECT_PATH_TABLE *)
+           (ctx->bios + data_offset +
+            le16_to_cpu(obj_header->usDisplayPathTableOffset));
+       con_obj = (ATOM_CONNECTOR_OBJECT_TABLE *)
+           (ctx->bios + data_offset +
+            le16_to_cpu(obj_header->usConnectorObjectTableOffset));
+       device_support = le16_to_cpu(obj_header->usDeviceSupport);
+
+       path_size = 0;
+       for (i = 0; i < path_obj->ucNumOfDispPath; i++) {
+               uint8_t *addr = (uint8_t *) path_obj->asDispPath;
+               ATOM_DISPLAY_OBJECT_PATH *path;
+               addr += path_size;
+               path = (ATOM_DISPLAY_OBJECT_PATH *) addr;
+               path_size += le16_to_cpu(path->usSize);
+               linkb = false;
+
+               if (device_support & le16_to_cpu(path->usDeviceTag)) {
+                       uint8_t con_obj_id, con_obj_num, con_obj_type;
+
+                       con_obj_id =
+                           (le16_to_cpu(path->usConnObjectId) & OBJECT_ID_MASK)
+                           >> OBJECT_ID_SHIFT;
+                       con_obj_num =
+                           (le16_to_cpu(path->usConnObjectId) & ENUM_ID_MASK)
+                           >> ENUM_ID_SHIFT;
+                       con_obj_type =
+                           (le16_to_cpu(path->usConnObjectId) &
+                            OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
+
+                       if ((le16_to_cpu(path->usDeviceTag) ==
+                            ATOM_DEVICE_TV1_SUPPORT)
+                           || (le16_to_cpu(path->usDeviceTag) ==
+                               ATOM_DEVICE_TV2_SUPPORT)
+                           || (le16_to_cpu(path->usDeviceTag) ==
+                               ATOM_DEVICE_CV_SUPPORT))
+                               continue;
+
+                       if ((rdev->family == CHIP_RS780) &&
+                           (con_obj_id ==
+                            CONNECTOR_OBJECT_ID_PCIE_CONNECTOR)) {
+                               uint16_t igp_offset = 0;
+                               ATOM_INTEGRATED_SYSTEM_INFO_V2 *igp_obj;
+
+                               index =
+                                   GetIndexIntoMasterTable(DATA,
+                                                           IntegratedSystemInfo);
+
+                               atom_parse_data_header(ctx, index, &size, &frev,
+                                                      &crev, &igp_offset);
+
+                               if (crev >= 2) {
+                                       igp_obj =
+                                           (ATOM_INTEGRATED_SYSTEM_INFO_V2
+                                            *) (ctx->bios + igp_offset);
+
+                                       if (igp_obj) {
+                                               uint32_t slot_config, ct;
+
+                                               if (con_obj_num == 1)
+                                                       slot_config =
+                                                           igp_obj->
+                                                           ulDDISlot1Config;
+                                               else
+                                                       slot_config =
+                                                           igp_obj->
+                                                           ulDDISlot2Config;
+
+                                               ct = (slot_config >> 16) & 0xff;
+                                               connector_type =
+                                                   object_connector_convert
+                                                   [ct];
+                                               igp_lane_info =
+                                                   slot_config & 0xffff;
+                                       } else
+                                               continue;
+                               } else
+                                       continue;
+                       } else {
+                               igp_lane_info = 0;
+                               connector_type =
+                                   object_connector_convert[con_obj_id];
+                       }
+
+                       if (connector_type == DRM_MODE_CONNECTOR_Unknown)
+                               continue;
+
+                       for (j = 0; j < ((le16_to_cpu(path->usSize) - 8) / 2);
+                            j++) {
+                               uint8_t enc_obj_id, enc_obj_num, enc_obj_type;
+
+                               enc_obj_id =
+                                   (le16_to_cpu(path->usGraphicObjIds[j]) &
+                                    OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
+                               enc_obj_num =
+                                   (le16_to_cpu(path->usGraphicObjIds[j]) &
+                                    ENUM_ID_MASK) >> ENUM_ID_SHIFT;
+                               enc_obj_type =
+                                   (le16_to_cpu(path->usGraphicObjIds[j]) &
+                                    OBJECT_TYPE_MASK) >> OBJECT_TYPE_SHIFT;
+
+                               /* FIXME: add support for router objects */
+                               if (enc_obj_type == GRAPH_OBJECT_TYPE_ENCODER) {
+                                       if (enc_obj_num == 2)
+                                               linkb = true;
+                                       else
+                                               linkb = false;
+
+                                       radeon_add_atom_encoder(dev,
+                                                               enc_obj_id,
+                                                               le16_to_cpu
+                                                               (path->
+                                                                usDeviceTag));
+
+                               }
+                       }
+
+                       /* look up gpio for ddc */
+                       if ((le16_to_cpu(path->usDeviceTag) &
+                            (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT))
+                           == 0) {
+                               for (j = 0; j < con_obj->ucNumberOfObjects; j++) {
+                                       if (le16_to_cpu(path->usConnObjectId) ==
+                                           le16_to_cpu(con_obj->asObjects[j].
+                                                       usObjectID)) {
+                                               ATOM_COMMON_RECORD_HEADER
+                                                   *record =
+                                                   (ATOM_COMMON_RECORD_HEADER
+                                                    *)
+                                                   (ctx->bios + data_offset +
+                                                    le16_to_cpu(con_obj->
+                                                                asObjects[j].
+                                                                usRecordOffset));
+                                               ATOM_I2C_RECORD *i2c_record;
+
+                                               while (record->ucRecordType > 0
+                                                      && record->
+                                                      ucRecordType <=
+                                                      ATOM_MAX_OBJECT_RECORD_NUMBER) {
+                                                       DRM_ERROR
+                                                           ("record type %d\n",
+                                                            record->
+                                                            ucRecordType);
+                                                       switch (record->
+                                                               ucRecordType) {
+                                                       case ATOM_I2C_RECORD_TYPE:
+                                                               i2c_record =
+                                                                   (ATOM_I2C_RECORD
+                                                                    *) record;
+                                                               line_mux =
+                                                                   i2c_record->
+                                                                   sucI2cId.
+                                                                   bfI2C_LineMux;
+                                                               break;
+                                                       }
+                                                       record =
+                                                           (ATOM_COMMON_RECORD_HEADER
+                                                            *) ((char *)record
+                                                                +
+                                                                record->
+                                                                ucRecordSize);
+                                               }
+                                               break;
+                                       }
+                               }
+                       } else
+                               line_mux = 0;
+
+                       if ((le16_to_cpu(path->usDeviceTag) ==
+                            ATOM_DEVICE_TV1_SUPPORT)
+                           || (le16_to_cpu(path->usDeviceTag) ==
+                               ATOM_DEVICE_TV2_SUPPORT)
+                           || (le16_to_cpu(path->usDeviceTag) ==
+                               ATOM_DEVICE_CV_SUPPORT))
+                               ddc_bus.valid = false;
+                       else
+                               ddc_bus = radeon_lookup_gpio(dev, line_mux);
+
+                       radeon_add_atom_connector(dev,
+                                                 le16_to_cpu(path->
+                                                             usConnObjectId),
+                                                 le16_to_cpu(path->
+                                                             usDeviceTag),
+                                                 connector_type, &ddc_bus,
+                                                 linkb, igp_lane_info);
+
+               }
+       }
+
+       radeon_link_encoder_connector(dev);
+
+       return true;
+}
+
+struct bios_connector {
+       bool valid;
+       uint8_t line_mux;
+       uint16_t devices;
+       int connector_type;
+       struct radeon_i2c_bus_rec ddc_bus;
+};
+
+bool radeon_get_atom_connector_info_from_supported_devices_table(struct
+                                                                drm_device
+                                                                *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_mode_info *mode_info = &rdev->mode_info;
+       struct atom_context *ctx = mode_info->atom_context;
+       int index = GetIndexIntoMasterTable(DATA, SupportedDevicesInfo);
+       uint16_t size, data_offset;
+       uint8_t frev, crev;
+       uint16_t device_support;
+       uint8_t dac;
+       union atom_supported_devices *supported_devices;
+       int i, j;
+       struct bios_connector bios_connectors[ATOM_MAX_SUPPORTED_DEVICE];
+
+       atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset);
+
+       supported_devices =
+           (union atom_supported_devices *)(ctx->bios + data_offset);
+
+       device_support = le16_to_cpu(supported_devices->info.usDeviceSupport);
+
+       for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {
+               ATOM_CONNECTOR_INFO_I2C ci =
+                   supported_devices->info.asConnInfo[i];
+
+               bios_connectors[i].valid = false;
+
+               if (!(device_support & (1 << i))) {
+                       continue;
+               }
+
+               if (i == ATOM_DEVICE_CV_INDEX) {
+                       DRM_DEBUG("Skipping Component Video\n");
+                       continue;
+               }
+
+               if (i == ATOM_DEVICE_TV1_INDEX) {
+                       DRM_DEBUG("Skipping TV Out\n");
+                       continue;
+               }
+
+               bios_connectors[i].connector_type =
+                   supported_devices_connector_convert[ci.sucConnectorInfo.
+                                                       sbfAccess.
+                                                       bfConnectorType];
+
+               if (bios_connectors[i].connector_type ==
+                   DRM_MODE_CONNECTOR_Unknown)
+                       continue;
+
+               dac = ci.sucConnectorInfo.sbfAccess.bfAssociatedDAC;
+
+               if ((rdev->family == CHIP_RS690) ||
+                   (rdev->family == CHIP_RS740)) {
+                       if ((i == ATOM_DEVICE_DFP2_INDEX)
+                           && (ci.sucI2cId.sbfAccess.bfI2C_LineMux == 2))
+                               bios_connectors[i].line_mux =
+                                   ci.sucI2cId.sbfAccess.bfI2C_LineMux + 1;
+                       else if ((i == ATOM_DEVICE_DFP3_INDEX)
+                                && (ci.sucI2cId.sbfAccess.bfI2C_LineMux == 1))
+                               bios_connectors[i].line_mux =
+                                   ci.sucI2cId.sbfAccess.bfI2C_LineMux + 1;
+                       else
+                               bios_connectors[i].line_mux =
+                                   ci.sucI2cId.sbfAccess.bfI2C_LineMux;
+               } else
+                       bios_connectors[i].line_mux =
+                           ci.sucI2cId.sbfAccess.bfI2C_LineMux;
+
+               /* give tv unique connector ids */
+               if (i == ATOM_DEVICE_TV1_INDEX) {
+                       bios_connectors[i].ddc_bus.valid = false;
+                       bios_connectors[i].line_mux = 50;
+               } else if (i == ATOM_DEVICE_TV2_INDEX) {
+                       bios_connectors[i].ddc_bus.valid = false;
+                       bios_connectors[i].line_mux = 51;
+               } else if (i == ATOM_DEVICE_CV_INDEX) {
+                       bios_connectors[i].ddc_bus.valid = false;
+                       bios_connectors[i].line_mux = 52;
+               } else
+                       bios_connectors[i].ddc_bus =
+                           radeon_lookup_gpio(dev,
+                                              bios_connectors[i].line_mux);
+
+               /* Always set the connector type to VGA for CRT1/CRT2. if they are
+                * shared with a DVI port, we'll pick up the DVI connector when we
+                * merge the outputs.  Some bioses incorrectly list VGA ports as DVI.
+                */
+               if (i == ATOM_DEVICE_CRT1_INDEX || i == ATOM_DEVICE_CRT2_INDEX)
+                       bios_connectors[i].connector_type =
+                           DRM_MODE_CONNECTOR_VGA;
+
+               if (!radeon_atom_apply_quirks
+                   (dev, (1 << i), &bios_connectors[i].connector_type,
+                    &bios_connectors[i].ddc_bus))
+                       continue;
+
+               bios_connectors[i].valid = true;
+               bios_connectors[i].devices = (1 << i);
+
+               if (ASIC_IS_AVIVO(rdev) || radeon_r4xx_atom)
+                       radeon_add_atom_encoder(dev,
+                                               radeon_get_encoder_id(dev,
+                                                                     (1 << i),
+                                                                     dac),
+                                               (1 << i));
+               else
+                       radeon_add_legacy_encoder(dev,
+                                                 radeon_get_encoder_id(dev,
+                                                                       (1 <<
+                                                                        i),
+                                                                       dac),
+                                                 (1 << i));
+       }
+
+       /* combine shared connectors */
+       for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {
+               if (bios_connectors[i].valid) {
+                       for (j = 0; j < ATOM_MAX_SUPPORTED_DEVICE; j++) {
+                               if (bios_connectors[j].valid && (i != j)) {
+                                       if (bios_connectors[i].line_mux ==
+                                           bios_connectors[j].line_mux) {
+                                               if (((bios_connectors[i].
+                                                     devices &
+                                                     (ATOM_DEVICE_DFP_SUPPORT))
+                                                    && (bios_connectors[j].
+                                                        devices &
+                                                        (ATOM_DEVICE_CRT_SUPPORT)))
+                                                   ||
+                                                   ((bios_connectors[j].
+                                                     devices &
+                                                     (ATOM_DEVICE_DFP_SUPPORT))
+                                                    && (bios_connectors[i].
+                                                        devices &
+                                                        (ATOM_DEVICE_CRT_SUPPORT)))) {
+                                                       bios_connectors[i].
+                                                           devices |=
+                                                           bios_connectors[j].
+                                                           devices;
+                                                       bios_connectors[i].
+                                                           connector_type =
+                                                           DRM_MODE_CONNECTOR_DVII;
+                                                       bios_connectors[j].
+                                                           valid = false;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /* add the connectors */
+       for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) {
+               if (bios_connectors[i].valid)
+                       radeon_add_atom_connector(dev,
+                                                 bios_connectors[i].line_mux,
+                                                 bios_connectors[i].devices,
+                                                 bios_connectors[i].
+                                                 connector_type,
+                                                 &bios_connectors[i].ddc_bus,
+                                                 false, 0);
+       }
+
+       radeon_link_encoder_connector(dev);
+
+       return true;
+}
+
+union firmware_info {
+       ATOM_FIRMWARE_INFO info;
+       ATOM_FIRMWARE_INFO_V1_2 info_12;
+       ATOM_FIRMWARE_INFO_V1_3 info_13;
+       ATOM_FIRMWARE_INFO_V1_4 info_14;
+};
+
+bool radeon_atom_get_clock_info(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_mode_info *mode_info = &rdev->mode_info;
+       int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
+       union firmware_info *firmware_info;
+       uint8_t frev, crev;
+       struct radeon_pll *p1pll = &rdev->clock.p1pll;
+       struct radeon_pll *p2pll = &rdev->clock.p2pll;
+       struct radeon_pll *spll = &rdev->clock.spll;
+       struct radeon_pll *mpll = &rdev->clock.mpll;
+       uint16_t data_offset;
+
+       atom_parse_data_header(mode_info->atom_context, index, NULL, &frev,
+                              &crev, &data_offset);
+
+       firmware_info =
+           (union firmware_info *)(mode_info->atom_context->bios +
+                                   data_offset);
+
+       if (firmware_info) {
+               /* pixel clocks */
+               p1pll->reference_freq =
+                   le16_to_cpu(firmware_info->info.usReferenceClock);
+               p1pll->reference_div = 0;
+
+               p1pll->pll_out_min =
+                   le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Output);
+               p1pll->pll_out_max =
+                   le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output);
+
+               if (p1pll->pll_out_min == 0) {
+                       if (ASIC_IS_AVIVO(rdev))
+                               p1pll->pll_out_min = 64800;
+                       else
+                               p1pll->pll_out_min = 20000;
+               }
+
+               p1pll->pll_in_min =
+                   le16_to_cpu(firmware_info->info.usMinPixelClockPLL_Input);
+               p1pll->pll_in_max =
+                   le16_to_cpu(firmware_info->info.usMaxPixelClockPLL_Input);
+
+               *p2pll = *p1pll;
+
+               /* system clock */
+               spll->reference_freq =
+                   le16_to_cpu(firmware_info->info.usReferenceClock);
+               spll->reference_div = 0;
+
+               spll->pll_out_min =
+                   le16_to_cpu(firmware_info->info.usMinEngineClockPLL_Output);
+               spll->pll_out_max =
+                   le32_to_cpu(firmware_info->info.ulMaxEngineClockPLL_Output);
+
+               /* ??? */
+               if (spll->pll_out_min == 0) {
+                       if (ASIC_IS_AVIVO(rdev))
+                               spll->pll_out_min = 64800;
+                       else
+                               spll->pll_out_min = 20000;
+               }
+
+               spll->pll_in_min =
+                   le16_to_cpu(firmware_info->info.usMinEngineClockPLL_Input);
+               spll->pll_in_max =
+                   le16_to_cpu(firmware_info->info.usMaxEngineClockPLL_Input);
+
+               /* memory clock */
+               mpll->reference_freq =
+                   le16_to_cpu(firmware_info->info.usReferenceClock);
+               mpll->reference_div = 0;
+
+               mpll->pll_out_min =
+                   le16_to_cpu(firmware_info->info.usMinMemoryClockPLL_Output);
+               mpll->pll_out_max =
+                   le32_to_cpu(firmware_info->info.ulMaxMemoryClockPLL_Output);
+
+               /* ??? */
+               if (mpll->pll_out_min == 0) {
+                       if (ASIC_IS_AVIVO(rdev))
+                               mpll->pll_out_min = 64800;
+                       else
+                               mpll->pll_out_min = 20000;
+               }
+
+               mpll->pll_in_min =
+                   le16_to_cpu(firmware_info->info.usMinMemoryClockPLL_Input);
+               mpll->pll_in_max =
+                   le16_to_cpu(firmware_info->info.usMaxMemoryClockPLL_Input);
+
+               rdev->clock.default_sclk =
+                   le32_to_cpu(firmware_info->info.ulDefaultEngineClock);
+               rdev->clock.default_mclk =
+                   le32_to_cpu(firmware_info->info.ulDefaultMemoryClock);
+
+               return true;
+       }
+       return false;
+}
+
+struct radeon_encoder_int_tmds *radeon_atombios_get_tmds_info(struct
+                                                             radeon_encoder
+                                                             *encoder)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_mode_info *mode_info = &rdev->mode_info;
+       int index = GetIndexIntoMasterTable(DATA, TMDS_Info);
+       uint16_t data_offset;
+       struct _ATOM_TMDS_INFO *tmds_info;
+       uint8_t frev, crev;
+       uint16_t maxfreq;
+       int i;
+       struct radeon_encoder_int_tmds *tmds = NULL;
+
+       atom_parse_data_header(mode_info->atom_context, index, NULL, &frev,
+                              &crev, &data_offset);
+
+       tmds_info =
+           (struct _ATOM_TMDS_INFO *)(mode_info->atom_context->bios +
+                                      data_offset);
+
+       if (tmds_info) {
+               tmds =
+                   kzalloc(sizeof(struct radeon_encoder_int_tmds), GFP_KERNEL);
+
+               if (!tmds)
+                       return NULL;
+
+               maxfreq = le16_to_cpu(tmds_info->usMaxFrequency);
+               for (i = 0; i < 4; i++) {
+                       tmds->tmds_pll[i].freq =
+                           le16_to_cpu(tmds_info->asMiscInfo[i].usFrequency);
+                       tmds->tmds_pll[i].value =
+                           tmds_info->asMiscInfo[i].ucPLL_ChargePump & 0x3f;
+                       tmds->tmds_pll[i].value |=
+                           (tmds_info->asMiscInfo[i].
+                            ucPLL_VCO_Gain & 0x3f) << 6;
+                       tmds->tmds_pll[i].value |=
+                           (tmds_info->asMiscInfo[i].
+                            ucPLL_DutyCycle & 0xf) << 12;
+                       tmds->tmds_pll[i].value |=
+                           (tmds_info->asMiscInfo[i].
+                            ucPLL_VoltageSwing & 0xf) << 16;
+
+                       DRM_DEBUG("TMDS PLL From ATOMBIOS %u %x\n",
+                                 tmds->tmds_pll[i].freq,
+                                 tmds->tmds_pll[i].value);
+
+                       if (maxfreq == tmds->tmds_pll[i].freq) {
+                               tmds->tmds_pll[i].freq = 0xffffffff;
+                               break;
+                       }
+               }
+       }
+       return tmds;
+}
+
+union lvds_info {
+       struct _ATOM_LVDS_INFO info;
+       struct _ATOM_LVDS_INFO_V12 info_12;
+};
+
+struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct
+                                                             radeon_encoder
+                                                             *encoder)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_mode_info *mode_info = &rdev->mode_info;
+       int index = GetIndexIntoMasterTable(DATA, LVDS_Info);
+       uint16_t data_offset;
+       union lvds_info *lvds_info;
+       uint8_t frev, crev;
+       struct radeon_encoder_atom_dig *lvds = NULL;
+
+       atom_parse_data_header(mode_info->atom_context, index, NULL, &frev,
+                              &crev, &data_offset);
+
+       lvds_info =
+           (union lvds_info *)(mode_info->atom_context->bios + data_offset);
+
+       if (lvds_info) {
+               lvds =
+                   kzalloc(sizeof(struct radeon_encoder_atom_dig), GFP_KERNEL);
+
+               if (!lvds)
+                       return NULL;
+
+               lvds->native_mode.dotclock =
+                   le16_to_cpu(lvds_info->info.sLCDTiming.usPixClk) * 10;
+               lvds->native_mode.panel_xres =
+                   le16_to_cpu(lvds_info->info.sLCDTiming.usHActive);
+               lvds->native_mode.panel_yres =
+                   le16_to_cpu(lvds_info->info.sLCDTiming.usVActive);
+               lvds->native_mode.hblank =
+                   le16_to_cpu(lvds_info->info.sLCDTiming.usHBlanking_Time);
+               lvds->native_mode.hoverplus =
+                   le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncOffset);
+               lvds->native_mode.hsync_width =
+                   le16_to_cpu(lvds_info->info.sLCDTiming.usHSyncWidth);
+               lvds->native_mode.vblank =
+                   le16_to_cpu(lvds_info->info.sLCDTiming.usVBlanking_Time);
+               lvds->native_mode.voverplus =
+                   le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncOffset);
+               lvds->native_mode.vsync_width =
+                   le16_to_cpu(lvds_info->info.sLCDTiming.usVSyncWidth);
+               lvds->panel_pwr_delay =
+                   le16_to_cpu(lvds_info->info.usOffDelayInMs);
+               lvds->lvds_misc = lvds_info->info.ucLVDS_Misc;
+
+               encoder->native_mode = lvds->native_mode;
+       }
+       return lvds;
+}
+
+struct radeon_encoder_primary_dac *
+radeon_atombios_get_primary_dac_info(struct radeon_encoder *encoder)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_mode_info *mode_info = &rdev->mode_info;
+       int index = GetIndexIntoMasterTable(DATA, CompassionateData);
+       uint16_t data_offset;
+       struct _COMPASSIONATE_DATA *dac_info;
+       uint8_t frev, crev;
+       uint8_t bg, dac;
+       int i;
+       struct radeon_encoder_primary_dac *p_dac = NULL;
+
+       atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset);
+
+       dac_info = (struct _COMPASSIONATE_DATA *)(mode_info->atom_context->bios + data_offset);
+
+       if (dac_info) {
+               p_dac = kzalloc(sizeof(struct radeon_encoder_primary_dac), GFP_KERNEL);
+
+               if (!p_dac)
+                       return NULL;
+
+               bg = dac_info->ucDAC1_BG_Adjustment;
+               dac = dac_info->ucDAC1_DAC_Adjustment;
+               p_dac->ps2_pdac_adj = (bg << 8) | (dac);
+
+       }
+       return p_dac;
+}
+
+struct radeon_encoder_tv_dac *
+radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_mode_info *mode_info = &rdev->mode_info;
+       int index = GetIndexIntoMasterTable(DATA, CompassionateData);
+       uint16_t data_offset;
+       struct _COMPASSIONATE_DATA *dac_info;
+       uint8_t frev, crev;
+       uint8_t bg, dac;
+       int i;
+       struct radeon_encoder_tv_dac *tv_dac = NULL;
+
+       atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset);
+
+       dac_info = (struct _COMPASSIONATE_DATA *)(mode_info->atom_context->bios + data_offset);
+
+       if (dac_info) {
+               tv_dac = kzalloc(sizeof(struct radeon_encoder_tv_dac), GFP_KERNEL);
+
+               if (!tv_dac)
+                       return NULL;
+
+               bg = dac_info->ucDAC2_CRT2_BG_Adjustment;
+               dac = dac_info->ucDAC2_CRT2_DAC_Adjustment;
+               tv_dac->ps2_tvdac_adj = (bg << 16) | (dac << 20);
+
+               bg = dac_info->ucDAC2_PAL_BG_Adjustment;
+               dac = dac_info->ucDAC2_PAL_DAC_Adjustment;
+               tv_dac->pal_tvdac_adj = (bg << 16) | (dac << 20);
+
+               bg = dac_info->ucDAC2_NTSC_BG_Adjustment;
+               dac = dac_info->ucDAC2_NTSC_DAC_Adjustment;
+               tv_dac->ntsc_tvdac_adj = (bg << 16) | (dac << 20);
+
+       }
+       return tv_dac;
+}
+
+void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable)
+{
+       DYNAMIC_CLOCK_GATING_PS_ALLOCATION args;
+       int index = GetIndexIntoMasterTable(COMMAND, DynamicClockGating);
+
+       args.ucEnable = enable;
+
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+void radeon_atom_static_pwrmgt_setup(struct radeon_device *rdev, int enable)
+{
+       ENABLE_ASIC_STATIC_PWR_MGT_PS_ALLOCATION args;
+       int index = GetIndexIntoMasterTable(COMMAND, EnableASIC_StaticPwrMgt);
+
+       args.ucEnable = enable;
+
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+void radeon_atom_set_engine_clock(struct radeon_device *rdev,
+                                 uint32_t eng_clock)
+{
+       SET_ENGINE_CLOCK_PS_ALLOCATION args;
+       int index = GetIndexIntoMasterTable(COMMAND, SetEngineClock);
+
+       args.ulTargetEngineClock = eng_clock;   /* 10 khz */
+
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+void radeon_atom_set_memory_clock(struct radeon_device *rdev,
+                                 uint32_t mem_clock)
+{
+       SET_MEMORY_CLOCK_PS_ALLOCATION args;
+       int index = GetIndexIntoMasterTable(COMMAND, SetMemoryClock);
+
+       if (rdev->flags & RADEON_IS_IGP)
+               return;
+
+       args.ulTargetMemoryClock = mem_clock;   /* 10 khz */
+
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t bios_2_scratch, bios_6_scratch;
+
+       if (rdev->family >= CHIP_R600) {
+               bios_2_scratch = RREG32(R600_BIOS_0_SCRATCH);
+               bios_6_scratch = RREG32(R600_BIOS_6_SCRATCH);
+       } else {
+               bios_2_scratch = RREG32(RADEON_BIOS_0_SCRATCH);
+               bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH);
+       }
+
+       /* let the bios control the backlight */
+       bios_2_scratch &= ~ATOM_S2_VRI_BRIGHT_ENABLE;
+
+       /* tell the bios not to handle mode switching */
+       bios_6_scratch |= (ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH | ATOM_S6_ACC_MODE);
+
+       if (rdev->family >= CHIP_R600) {
+               WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch);
+               WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch);
+       } else {
+               WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch);
+               WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch);
+       }
+
+}
+
+void radeon_atom_output_lock(struct drm_encoder *encoder, bool lock)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t bios_6_scratch;
+
+       if (rdev->family >= CHIP_R600)
+               bios_6_scratch = RREG32(R600_BIOS_6_SCRATCH);
+       else
+               bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH);
+
+       if (lock)
+               bios_6_scratch |= ATOM_S6_CRITICAL_STATE;
+       else
+               bios_6_scratch &= ~ATOM_S6_CRITICAL_STATE;
+
+       if (rdev->family >= CHIP_R600)
+               WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch);
+       else
+               WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch);
+}
+
+/* at some point we may want to break this out into individual functions */
+void
+radeon_atombios_connected_scratch_regs(struct drm_connector *connector,
+                                      struct drm_encoder *encoder,
+                                      bool connected)
+{
+       struct drm_device *dev = connector->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_connector *radeon_connector =
+           to_radeon_connector(connector);
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       uint32_t bios_0_scratch, bios_3_scratch, bios_6_scratch;
+
+       if (rdev->family >= CHIP_R600) {
+               bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH);
+               bios_3_scratch = RREG32(R600_BIOS_3_SCRATCH);
+               bios_6_scratch = RREG32(R600_BIOS_6_SCRATCH);
+       } else {
+               bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH);
+               bios_3_scratch = RREG32(RADEON_BIOS_3_SCRATCH);
+               bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH);
+       }
+
+       if ((radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) &&
+           (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT)) {
+               if (connected) {
+                       DRM_DEBUG("TV1 connected\n");
+                       bios_3_scratch |= ATOM_S3_TV1_ACTIVE;
+                       bios_6_scratch |= ATOM_S6_ACC_REQ_TV1;
+               } else {
+                       DRM_DEBUG("TV1 disconnected\n");
+                       bios_0_scratch &= ~ATOM_S0_TV1_MASK;
+                       bios_3_scratch &= ~ATOM_S3_TV1_ACTIVE;
+                       bios_6_scratch &= ~ATOM_S6_ACC_REQ_TV1;
+               }
+       }
+       if ((radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) &&
+           (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT)) {
+               if (connected) {
+                       DRM_DEBUG("CV connected\n");
+                       bios_3_scratch |= ATOM_S3_CV_ACTIVE;
+                       bios_6_scratch |= ATOM_S6_ACC_REQ_CV;
+               } else {
+                       DRM_DEBUG("CV disconnected\n");
+                       bios_0_scratch &= ~ATOM_S0_CV_MASK;
+                       bios_3_scratch &= ~ATOM_S3_CV_ACTIVE;
+                       bios_6_scratch &= ~ATOM_S6_ACC_REQ_CV;
+               }
+       }
+       if ((radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) &&
+           (radeon_connector->devices & ATOM_DEVICE_LCD1_SUPPORT)) {
+               if (connected) {
+                       DRM_DEBUG("LCD1 connected\n");
+                       bios_0_scratch |= ATOM_S0_LCD1;
+                       bios_3_scratch |= ATOM_S3_LCD1_ACTIVE;
+                       bios_6_scratch |= ATOM_S6_ACC_REQ_LCD1;
+               } else {
+                       DRM_DEBUG("LCD1 disconnected\n");
+                       bios_0_scratch &= ~ATOM_S0_LCD1;
+                       bios_3_scratch &= ~ATOM_S3_LCD1_ACTIVE;
+                       bios_6_scratch &= ~ATOM_S6_ACC_REQ_LCD1;
+               }
+       }
+       if ((radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) &&
+           (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT)) {
+               if (connected) {
+                       DRM_DEBUG("CRT1 connected\n");
+                       bios_0_scratch |= ATOM_S0_CRT1_COLOR;
+                       bios_3_scratch |= ATOM_S3_CRT1_ACTIVE;
+                       bios_6_scratch |= ATOM_S6_ACC_REQ_CRT1;
+               } else {
+                       DRM_DEBUG("CRT1 disconnected\n");
+                       bios_0_scratch &= ~ATOM_S0_CRT1_MASK;
+                       bios_3_scratch &= ~ATOM_S3_CRT1_ACTIVE;
+                       bios_6_scratch &= ~ATOM_S6_ACC_REQ_CRT1;
+               }
+       }
+       if ((radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) &&
+           (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT)) {
+               if (connected) {
+                       DRM_DEBUG("CRT2 connected\n");
+                       bios_0_scratch |= ATOM_S0_CRT2_COLOR;
+                       bios_3_scratch |= ATOM_S3_CRT2_ACTIVE;
+                       bios_6_scratch |= ATOM_S6_ACC_REQ_CRT2;
+               } else {
+                       DRM_DEBUG("CRT2 disconnected\n");
+                       bios_0_scratch &= ~ATOM_S0_CRT2_MASK;
+                       bios_3_scratch &= ~ATOM_S3_CRT2_ACTIVE;
+                       bios_6_scratch &= ~ATOM_S6_ACC_REQ_CRT2;
+               }
+       }
+       if ((radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) &&
+           (radeon_connector->devices & ATOM_DEVICE_DFP1_SUPPORT)) {
+               if (connected) {
+                       DRM_DEBUG("DFP1 connected\n");
+                       bios_0_scratch |= ATOM_S0_DFP1;
+                       bios_3_scratch |= ATOM_S3_DFP1_ACTIVE;
+                       bios_6_scratch |= ATOM_S6_ACC_REQ_DFP1;
+               } else {
+                       DRM_DEBUG("DFP1 disconnected\n");
+                       bios_0_scratch &= ~ATOM_S0_DFP1;
+                       bios_3_scratch &= ~ATOM_S3_DFP1_ACTIVE;
+                       bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP1;
+               }
+       }
+       if ((radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) &&
+           (radeon_connector->devices & ATOM_DEVICE_DFP2_SUPPORT)) {
+               if (connected) {
+                       DRM_DEBUG("DFP2 connected\n");
+                       bios_0_scratch |= ATOM_S0_DFP2;
+                       bios_3_scratch |= ATOM_S3_DFP2_ACTIVE;
+                       bios_6_scratch |= ATOM_S6_ACC_REQ_DFP2;
+               } else {
+                       DRM_DEBUG("DFP2 disconnected\n");
+                       bios_0_scratch &= ~ATOM_S0_DFP2;
+                       bios_3_scratch &= ~ATOM_S3_DFP2_ACTIVE;
+                       bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP2;
+               }
+       }
+       if ((radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) &&
+           (radeon_connector->devices & ATOM_DEVICE_DFP3_SUPPORT)) {
+               if (connected) {
+                       DRM_DEBUG("DFP3 connected\n");
+                       bios_0_scratch |= ATOM_S0_DFP3;
+                       bios_3_scratch |= ATOM_S3_DFP3_ACTIVE;
+                       bios_6_scratch |= ATOM_S6_ACC_REQ_DFP3;
+               } else {
+                       DRM_DEBUG("DFP3 disconnected\n");
+                       bios_0_scratch &= ~ATOM_S0_DFP3;
+                       bios_3_scratch &= ~ATOM_S3_DFP3_ACTIVE;
+                       bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP3;
+               }
+       }
+       if ((radeon_encoder->devices & ATOM_DEVICE_DFP4_SUPPORT) &&
+           (radeon_connector->devices & ATOM_DEVICE_DFP4_SUPPORT)) {
+               if (connected) {
+                       DRM_DEBUG("DFP4 connected\n");
+                       bios_0_scratch |= ATOM_S0_DFP4;
+                       bios_3_scratch |= ATOM_S3_DFP4_ACTIVE;
+                       bios_6_scratch |= ATOM_S6_ACC_REQ_DFP4;
+               } else {
+                       DRM_DEBUG("DFP4 disconnected\n");
+                       bios_0_scratch &= ~ATOM_S0_DFP4;
+                       bios_3_scratch &= ~ATOM_S3_DFP4_ACTIVE;
+                       bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP4;
+               }
+       }
+       if ((radeon_encoder->devices & ATOM_DEVICE_DFP5_SUPPORT) &&
+           (radeon_connector->devices & ATOM_DEVICE_DFP5_SUPPORT)) {
+               if (connected) {
+                       DRM_DEBUG("DFP5 connected\n");
+                       bios_0_scratch |= ATOM_S0_DFP5;
+                       bios_3_scratch |= ATOM_S3_DFP5_ACTIVE;
+                       bios_6_scratch |= ATOM_S6_ACC_REQ_DFP5;
+               } else {
+                       DRM_DEBUG("DFP5 disconnected\n");
+                       bios_0_scratch &= ~ATOM_S0_DFP5;
+                       bios_3_scratch &= ~ATOM_S3_DFP5_ACTIVE;
+                       bios_6_scratch &= ~ATOM_S6_ACC_REQ_DFP5;
+               }
+       }
+
+       if (rdev->family >= CHIP_R600) {
+               WREG32(R600_BIOS_0_SCRATCH, bios_0_scratch);
+               WREG32(R600_BIOS_3_SCRATCH, bios_3_scratch);
+               WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch);
+       } else {
+               WREG32(RADEON_BIOS_0_SCRATCH, bios_0_scratch);
+               WREG32(RADEON_BIOS_3_SCRATCH, bios_3_scratch);
+               WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch);
+       }
+}
+
+void
+radeon_atombios_encoder_crtc_scratch_regs(struct drm_encoder *encoder, int crtc)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       uint32_t bios_3_scratch;
+
+       if (rdev->family >= CHIP_R600)
+               bios_3_scratch = RREG32(R600_BIOS_3_SCRATCH);
+       else
+               bios_3_scratch = RREG32(RADEON_BIOS_3_SCRATCH);
+
+       if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) {
+               bios_3_scratch &= ~ATOM_S3_TV1_CRTC_ACTIVE;
+               bios_3_scratch |= (crtc << 18);
+       }
+       if (radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) {
+               bios_3_scratch &= ~ATOM_S3_CV_CRTC_ACTIVE;
+               bios_3_scratch |= (crtc << 24);
+       }
+       if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) {
+               bios_3_scratch &= ~ATOM_S3_CRT1_CRTC_ACTIVE;
+               bios_3_scratch |= (crtc << 16);
+       }
+       if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) {
+               bios_3_scratch &= ~ATOM_S3_CRT2_CRTC_ACTIVE;
+               bios_3_scratch |= (crtc << 20);
+       }
+       if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) {
+               bios_3_scratch &= ~ATOM_S3_LCD1_CRTC_ACTIVE;
+               bios_3_scratch |= (crtc << 17);
+       }
+       if (radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) {
+               bios_3_scratch &= ~ATOM_S3_DFP1_CRTC_ACTIVE;
+               bios_3_scratch |= (crtc << 19);
+       }
+       if (radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) {
+               bios_3_scratch &= ~ATOM_S3_DFP2_CRTC_ACTIVE;
+               bios_3_scratch |= (crtc << 23);
+       }
+       if (radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) {
+               bios_3_scratch &= ~ATOM_S3_DFP3_CRTC_ACTIVE;
+               bios_3_scratch |= (crtc << 25);
+       }
+
+       if (rdev->family >= CHIP_R600)
+               WREG32(R600_BIOS_3_SCRATCH, bios_3_scratch);
+       else
+               WREG32(RADEON_BIOS_3_SCRATCH, bios_3_scratch);
+}
+
+void
+radeon_atombios_encoder_dpms_scratch_regs(struct drm_encoder *encoder, bool on)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       uint32_t bios_2_scratch;
+
+       if (rdev->family >= CHIP_R600)
+               bios_2_scratch = RREG32(R600_BIOS_2_SCRATCH);
+       else
+               bios_2_scratch = RREG32(RADEON_BIOS_2_SCRATCH);
+
+       if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) {
+               if (on)
+                       bios_2_scratch &= ~ATOM_S2_TV1_DPMS_STATE;
+               else
+                       bios_2_scratch |= ATOM_S2_TV1_DPMS_STATE;
+       }
+       if (radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) {
+               if (on)
+                       bios_2_scratch &= ~ATOM_S2_CV_DPMS_STATE;
+               else
+                       bios_2_scratch |= ATOM_S2_CV_DPMS_STATE;
+       }
+       if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) {
+               if (on)
+                       bios_2_scratch &= ~ATOM_S2_CRT1_DPMS_STATE;
+               else
+                       bios_2_scratch |= ATOM_S2_CRT1_DPMS_STATE;
+       }
+       if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) {
+               if (on)
+                       bios_2_scratch &= ~ATOM_S2_CRT2_DPMS_STATE;
+               else
+                       bios_2_scratch |= ATOM_S2_CRT2_DPMS_STATE;
+       }
+       if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) {
+               if (on)
+                       bios_2_scratch &= ~ATOM_S2_LCD1_DPMS_STATE;
+               else
+                       bios_2_scratch |= ATOM_S2_LCD1_DPMS_STATE;
+       }
+       if (radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) {
+               if (on)
+                       bios_2_scratch &= ~ATOM_S2_DFP1_DPMS_STATE;
+               else
+                       bios_2_scratch |= ATOM_S2_DFP1_DPMS_STATE;
+       }
+       if (radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) {
+               if (on)
+                       bios_2_scratch &= ~ATOM_S2_DFP2_DPMS_STATE;
+               else
+                       bios_2_scratch |= ATOM_S2_DFP2_DPMS_STATE;
+       }
+       if (radeon_encoder->devices & ATOM_DEVICE_DFP3_SUPPORT) {
+               if (on)
+                       bios_2_scratch &= ~ATOM_S2_DFP3_DPMS_STATE;
+               else
+                       bios_2_scratch |= ATOM_S2_DFP3_DPMS_STATE;
+       }
+       if (radeon_encoder->devices & ATOM_DEVICE_DFP4_SUPPORT) {
+               if (on)
+                       bios_2_scratch &= ~ATOM_S2_DFP4_DPMS_STATE;
+               else
+                       bios_2_scratch |= ATOM_S2_DFP4_DPMS_STATE;
+       }
+       if (radeon_encoder->devices & ATOM_DEVICE_DFP5_SUPPORT) {
+               if (on)
+                       bios_2_scratch &= ~ATOM_S2_DFP5_DPMS_STATE;
+               else
+                       bios_2_scratch |= ATOM_S2_DFP5_DPMS_STATE;
+       }
+
+       if (rdev->family >= CHIP_R600)
+               WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch);
+       else
+               WREG32(RADEON_BIOS_2_SCRATCH, bios_2_scratch);
+}
diff --git a/drivers/gpu/drm/radeon/radeon_benchmark.c b/drivers/gpu/drm/radeon/radeon_benchmark.c
new file mode 100644 (file)
index 0000000..c44403a
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Jerome Glisse
+ */
+#include <drm/drmP.h>
+#include <drm/radeon_drm.h>
+#include "radeon_reg.h"
+#include "radeon.h"
+
+void radeon_benchmark_move(struct radeon_device *rdev, unsigned bsize,
+                          unsigned sdomain, unsigned ddomain)
+{
+       struct radeon_object *dobj = NULL;
+       struct radeon_object *sobj = NULL;
+       struct radeon_fence *fence = NULL;
+       uint64_t saddr, daddr;
+       unsigned long start_jiffies;
+       unsigned long end_jiffies;
+       unsigned long time;
+       unsigned i, n, size;
+       int r;
+
+       size = bsize;
+       n = 1024;
+       r = radeon_object_create(rdev, NULL, size, true, sdomain, false, &sobj);
+       if (r) {
+               goto out_cleanup;
+       }
+       r = radeon_object_pin(sobj, sdomain, &saddr);
+       if (r) {
+               goto out_cleanup;
+       }
+       r = radeon_object_create(rdev, NULL, size, true, ddomain, false, &dobj);
+       if (r) {
+               goto out_cleanup;
+       }
+       r = radeon_object_pin(dobj, ddomain, &daddr);
+       if (r) {
+               goto out_cleanup;
+       }
+       start_jiffies = jiffies;
+       for (i = 0; i < n; i++) {
+               r = radeon_fence_create(rdev, &fence);
+               if (r) {
+                       goto out_cleanup;
+               }
+               r = radeon_copy_dma(rdev, saddr, daddr, size >> 14, fence);
+               if (r) {
+                       goto out_cleanup;
+               }
+               r = radeon_fence_wait(fence, false);
+               if (r) {
+                       goto out_cleanup;
+               }
+               radeon_fence_unref(&fence);
+       }
+       end_jiffies = jiffies;
+       time = end_jiffies - start_jiffies;
+       time = jiffies_to_msecs(time);
+       if (time > 0) {
+               i = ((n * size) >> 10) / time;
+               printk(KERN_INFO "radeon: dma %u bo moves of %ukb from %d to %d"
+                      " in %lums (%ukb/ms %ukb/s %uM/s)\n", n, size >> 10,
+                      sdomain, ddomain, time, i, i * 1000, (i * 1000) / 1024);
+       }
+       start_jiffies = jiffies;
+       for (i = 0; i < n; i++) {
+               r = radeon_fence_create(rdev, &fence);
+               if (r) {
+                       goto out_cleanup;
+               }
+               r = radeon_copy_blit(rdev, saddr, daddr, size >> 14, fence);
+               if (r) {
+                       goto out_cleanup;
+               }
+               r = radeon_fence_wait(fence, false);
+               if (r) {
+                       goto out_cleanup;
+               }
+               radeon_fence_unref(&fence);
+       }
+       end_jiffies = jiffies;
+       time = end_jiffies - start_jiffies;
+       time = jiffies_to_msecs(time);
+       if (time > 0) {
+               i = ((n * size) >> 10) / time;
+               printk(KERN_INFO "radeon: blit %u bo moves of %ukb from %d to %d"
+                      " in %lums (%ukb/ms %ukb/s %uM/s)\n", n, size >> 10,
+                      sdomain, ddomain, time, i, i * 1000, (i * 1000) / 1024);
+       }
+out_cleanup:
+       if (sobj) {
+               radeon_object_unpin(sobj);
+               radeon_object_unref(&sobj);
+       }
+       if (dobj) {
+               radeon_object_unpin(dobj);
+               radeon_object_unref(&dobj);
+       }
+       if (fence) {
+               radeon_fence_unref(&fence);
+       }
+       if (r) {
+               printk(KERN_WARNING "Error while benchmarking BO move.\n");
+       }
+}
+
+void radeon_benchmark(struct radeon_device *rdev)
+{
+       radeon_benchmark_move(rdev, 1024*1024, RADEON_GEM_DOMAIN_GTT,
+                             RADEON_GEM_DOMAIN_VRAM);
+       radeon_benchmark_move(rdev, 1024*1024, RADEON_GEM_DOMAIN_VRAM,
+                             RADEON_GEM_DOMAIN_GTT);
+}
diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c
new file mode 100644 (file)
index 0000000..96e37a6
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ *          Jerome Glisse
+ */
+#include "drmP.h"
+#include "radeon_reg.h"
+#include "radeon.h"
+#include "atom.h"
+
+/*
+ * BIOS.
+ */
+static bool radeon_read_bios(struct radeon_device *rdev)
+{
+       uint8_t __iomem *bios;
+       size_t size;
+
+       rdev->bios = NULL;
+       bios = pci_map_rom(rdev->pdev, &size);
+       if (!bios) {
+               return false;
+       }
+
+       if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
+               pci_unmap_rom(rdev->pdev, bios);
+               return false;
+       }
+       rdev->bios = kmalloc(size, GFP_KERNEL);
+       if (rdev->bios == NULL) {
+               pci_unmap_rom(rdev->pdev, bios);
+               return false;
+       }
+       memcpy(rdev->bios, bios, size);
+       pci_unmap_rom(rdev->pdev, bios);
+       return true;
+}
+
+static bool r700_read_disabled_bios(struct radeon_device *rdev)
+{
+       uint32_t viph_control;
+       uint32_t bus_cntl;
+       uint32_t d1vga_control;
+       uint32_t d2vga_control;
+       uint32_t vga_render_control;
+       uint32_t rom_cntl;
+       uint32_t cg_spll_func_cntl = 0;
+       uint32_t cg_spll_status;
+       bool r;
+
+       viph_control = RREG32(RADEON_VIPH_CONTROL);
+       bus_cntl = RREG32(RADEON_BUS_CNTL);
+       d1vga_control = RREG32(AVIVO_D1VGA_CONTROL);
+       d2vga_control = RREG32(AVIVO_D2VGA_CONTROL);
+       vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL);
+       rom_cntl = RREG32(R600_ROM_CNTL);
+
+       /* disable VIP */
+       WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
+       /* enable the rom */
+       WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM));
+       /* Disable VGA mode */
+       WREG32(AVIVO_D1VGA_CONTROL,
+              (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
+               AVIVO_DVGA_CONTROL_TIMING_SELECT)));
+       WREG32(AVIVO_D2VGA_CONTROL,
+              (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
+               AVIVO_DVGA_CONTROL_TIMING_SELECT)));
+       WREG32(AVIVO_VGA_RENDER_CONTROL,
+              (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK));
+
+       if (rdev->family == CHIP_RV730) {
+               cg_spll_func_cntl = RREG32(R600_CG_SPLL_FUNC_CNTL);
+
+               /* enable bypass mode */
+               WREG32(R600_CG_SPLL_FUNC_CNTL, (cg_spll_func_cntl |
+                                               R600_SPLL_BYPASS_EN));
+
+               /* wait for SPLL_CHG_STATUS to change to 1 */
+               cg_spll_status = 0;
+               while (!(cg_spll_status & R600_SPLL_CHG_STATUS))
+                       cg_spll_status = RREG32(R600_CG_SPLL_STATUS);
+
+               WREG32(R600_ROM_CNTL, (rom_cntl & ~R600_SCK_OVERWRITE));
+       } else
+               WREG32(R600_ROM_CNTL, (rom_cntl | R600_SCK_OVERWRITE));
+
+       r = radeon_read_bios(rdev);
+
+       /* restore regs */
+       if (rdev->family == CHIP_RV730) {
+               WREG32(R600_CG_SPLL_FUNC_CNTL, cg_spll_func_cntl);
+
+               /* wait for SPLL_CHG_STATUS to change to 1 */
+               cg_spll_status = 0;
+               while (!(cg_spll_status & R600_SPLL_CHG_STATUS))
+                       cg_spll_status = RREG32(R600_CG_SPLL_STATUS);
+       }
+       WREG32(RADEON_VIPH_CONTROL, viph_control);
+       WREG32(RADEON_BUS_CNTL, bus_cntl);
+       WREG32(AVIVO_D1VGA_CONTROL, d1vga_control);
+       WREG32(AVIVO_D2VGA_CONTROL, d2vga_control);
+       WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
+       WREG32(R600_ROM_CNTL, rom_cntl);
+       return r;
+}
+
+static bool r600_read_disabled_bios(struct radeon_device *rdev)
+{
+       uint32_t viph_control;
+       uint32_t bus_cntl;
+       uint32_t d1vga_control;
+       uint32_t d2vga_control;
+       uint32_t vga_render_control;
+       uint32_t rom_cntl;
+       uint32_t general_pwrmgt;
+       uint32_t low_vid_lower_gpio_cntl;
+       uint32_t medium_vid_lower_gpio_cntl;
+       uint32_t high_vid_lower_gpio_cntl;
+       uint32_t ctxsw_vid_lower_gpio_cntl;
+       uint32_t lower_gpio_enable;
+       bool r;
+
+       viph_control = RREG32(RADEON_VIPH_CONTROL);
+       bus_cntl = RREG32(RADEON_BUS_CNTL);
+       d1vga_control = RREG32(AVIVO_D1VGA_CONTROL);
+       d2vga_control = RREG32(AVIVO_D2VGA_CONTROL);
+       vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL);
+       rom_cntl = RREG32(R600_ROM_CNTL);
+       general_pwrmgt = RREG32(R600_GENERAL_PWRMGT);
+       low_vid_lower_gpio_cntl = RREG32(R600_LOW_VID_LOWER_GPIO_CNTL);
+       medium_vid_lower_gpio_cntl = RREG32(R600_MEDIUM_VID_LOWER_GPIO_CNTL);
+       high_vid_lower_gpio_cntl = RREG32(R600_HIGH_VID_LOWER_GPIO_CNTL);
+       ctxsw_vid_lower_gpio_cntl = RREG32(R600_CTXSW_VID_LOWER_GPIO_CNTL);
+       lower_gpio_enable = RREG32(R600_LOWER_GPIO_ENABLE);
+
+       /* disable VIP */
+       WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
+       /* enable the rom */
+       WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM));
+       /* Disable VGA mode */
+       WREG32(AVIVO_D1VGA_CONTROL,
+              (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
+               AVIVO_DVGA_CONTROL_TIMING_SELECT)));
+       WREG32(AVIVO_D2VGA_CONTROL,
+              (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
+               AVIVO_DVGA_CONTROL_TIMING_SELECT)));
+       WREG32(AVIVO_VGA_RENDER_CONTROL,
+              (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK));
+
+       WREG32(R600_ROM_CNTL,
+              ((rom_cntl & ~R600_SCK_PRESCALE_CRYSTAL_CLK_MASK) |
+               (1 << R600_SCK_PRESCALE_CRYSTAL_CLK_SHIFT) |
+               R600_SCK_OVERWRITE));
+
+       WREG32(R600_GENERAL_PWRMGT, (general_pwrmgt & ~R600_OPEN_DRAIN_PADS));
+       WREG32(R600_LOW_VID_LOWER_GPIO_CNTL,
+              (low_vid_lower_gpio_cntl & ~0x400));
+       WREG32(R600_MEDIUM_VID_LOWER_GPIO_CNTL,
+              (medium_vid_lower_gpio_cntl & ~0x400));
+       WREG32(R600_HIGH_VID_LOWER_GPIO_CNTL,
+              (high_vid_lower_gpio_cntl & ~0x400));
+       WREG32(R600_CTXSW_VID_LOWER_GPIO_CNTL,
+              (ctxsw_vid_lower_gpio_cntl & ~0x400));
+       WREG32(R600_LOWER_GPIO_ENABLE, (lower_gpio_enable | 0x400));
+
+       r = radeon_read_bios(rdev);
+
+       /* restore regs */
+       WREG32(RADEON_VIPH_CONTROL, viph_control);
+       WREG32(RADEON_BUS_CNTL, bus_cntl);
+       WREG32(AVIVO_D1VGA_CONTROL, d1vga_control);
+       WREG32(AVIVO_D2VGA_CONTROL, d2vga_control);
+       WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
+       WREG32(R600_ROM_CNTL, rom_cntl);
+       WREG32(R600_GENERAL_PWRMGT, general_pwrmgt);
+       WREG32(R600_LOW_VID_LOWER_GPIO_CNTL, low_vid_lower_gpio_cntl);
+       WREG32(R600_MEDIUM_VID_LOWER_GPIO_CNTL, medium_vid_lower_gpio_cntl);
+       WREG32(R600_HIGH_VID_LOWER_GPIO_CNTL, high_vid_lower_gpio_cntl);
+       WREG32(R600_CTXSW_VID_LOWER_GPIO_CNTL, ctxsw_vid_lower_gpio_cntl);
+       WREG32(R600_LOWER_GPIO_ENABLE, lower_gpio_enable);
+       return r;
+}
+
+static bool avivo_read_disabled_bios(struct radeon_device *rdev)
+{
+       uint32_t seprom_cntl1;
+       uint32_t viph_control;
+       uint32_t bus_cntl;
+       uint32_t d1vga_control;
+       uint32_t d2vga_control;
+       uint32_t vga_render_control;
+       uint32_t gpiopad_a;
+       uint32_t gpiopad_en;
+       uint32_t gpiopad_mask;
+       bool r;
+
+       seprom_cntl1 = RREG32(RADEON_SEPROM_CNTL1);
+       viph_control = RREG32(RADEON_VIPH_CONTROL);
+       bus_cntl = RREG32(RADEON_BUS_CNTL);
+       d1vga_control = RREG32(AVIVO_D1VGA_CONTROL);
+       d2vga_control = RREG32(AVIVO_D2VGA_CONTROL);
+       vga_render_control = RREG32(AVIVO_VGA_RENDER_CONTROL);
+       gpiopad_a = RREG32(RADEON_GPIOPAD_A);
+       gpiopad_en = RREG32(RADEON_GPIOPAD_EN);
+       gpiopad_mask = RREG32(RADEON_GPIOPAD_MASK);
+
+       WREG32(RADEON_SEPROM_CNTL1,
+              ((seprom_cntl1 & ~RADEON_SCK_PRESCALE_MASK) |
+               (0xc << RADEON_SCK_PRESCALE_SHIFT)));
+       WREG32(RADEON_GPIOPAD_A, 0);
+       WREG32(RADEON_GPIOPAD_EN, 0);
+       WREG32(RADEON_GPIOPAD_MASK, 0);
+
+       /* disable VIP */
+       WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
+
+       /* enable the rom */
+       WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM));
+
+       /* Disable VGA mode */
+       WREG32(AVIVO_D1VGA_CONTROL,
+              (d1vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
+               AVIVO_DVGA_CONTROL_TIMING_SELECT)));
+       WREG32(AVIVO_D2VGA_CONTROL,
+              (d2vga_control & ~(AVIVO_DVGA_CONTROL_MODE_ENABLE |
+               AVIVO_DVGA_CONTROL_TIMING_SELECT)));
+       WREG32(AVIVO_VGA_RENDER_CONTROL,
+              (vga_render_control & ~AVIVO_VGA_VSTATUS_CNTL_MASK));
+
+       r = radeon_read_bios(rdev);
+
+       /* restore regs */
+       WREG32(RADEON_SEPROM_CNTL1, seprom_cntl1);
+       WREG32(RADEON_VIPH_CONTROL, viph_control);
+       WREG32(RADEON_BUS_CNTL, bus_cntl);
+       WREG32(AVIVO_D1VGA_CONTROL, d1vga_control);
+       WREG32(AVIVO_D2VGA_CONTROL, d2vga_control);
+       WREG32(AVIVO_VGA_RENDER_CONTROL, vga_render_control);
+       WREG32(RADEON_GPIOPAD_A, gpiopad_a);
+       WREG32(RADEON_GPIOPAD_EN, gpiopad_en);
+       WREG32(RADEON_GPIOPAD_MASK, gpiopad_mask);
+       return r;
+}
+
+static bool legacy_read_disabled_bios(struct radeon_device *rdev)
+{
+       uint32_t seprom_cntl1;
+       uint32_t viph_control;
+       uint32_t bus_cntl;
+       uint32_t crtc_gen_cntl;
+       uint32_t crtc2_gen_cntl;
+       uint32_t crtc_ext_cntl;
+       uint32_t fp2_gen_cntl;
+       bool r;
+
+       seprom_cntl1 = RREG32(RADEON_SEPROM_CNTL1);
+       viph_control = RREG32(RADEON_VIPH_CONTROL);
+       bus_cntl = RREG32(RADEON_BUS_CNTL);
+       crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL);
+       crtc2_gen_cntl = 0;
+       crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL);
+       fp2_gen_cntl = 0;
+
+       if (rdev->ddev->pci_device == PCI_DEVICE_ID_ATI_RADEON_QY) {
+               fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
+       }
+
+       if (!(rdev->flags & RADEON_SINGLE_CRTC)) {
+               crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL);
+       }
+
+       WREG32(RADEON_SEPROM_CNTL1,
+              ((seprom_cntl1 & ~RADEON_SCK_PRESCALE_MASK) |
+               (0xc << RADEON_SCK_PRESCALE_SHIFT)));
+
+       /* disable VIP */
+       WREG32(RADEON_VIPH_CONTROL, (viph_control & ~RADEON_VIPH_EN));
+
+       /* enable the rom */
+       WREG32(RADEON_BUS_CNTL, (bus_cntl & ~RADEON_BUS_BIOS_DIS_ROM));
+
+       /* Turn off mem requests and CRTC for both controllers */
+       WREG32(RADEON_CRTC_GEN_CNTL,
+              ((crtc_gen_cntl & ~RADEON_CRTC_EN) |
+               (RADEON_CRTC_DISP_REQ_EN_B |
+                RADEON_CRTC_EXT_DISP_EN)));
+       if (!(rdev->flags & RADEON_SINGLE_CRTC)) {
+               WREG32(RADEON_CRTC2_GEN_CNTL,
+                      ((crtc2_gen_cntl & ~RADEON_CRTC2_EN) |
+                       RADEON_CRTC2_DISP_REQ_EN_B));
+       }
+       /* Turn off CRTC */
+       WREG32(RADEON_CRTC_EXT_CNTL,
+              ((crtc_ext_cntl & ~RADEON_CRTC_CRT_ON) |
+               (RADEON_CRTC_SYNC_TRISTAT |
+                RADEON_CRTC_DISPLAY_DIS)));
+
+       if (rdev->ddev->pci_device == PCI_DEVICE_ID_ATI_RADEON_QY) {
+               WREG32(RADEON_FP2_GEN_CNTL, (fp2_gen_cntl & ~RADEON_FP2_ON));
+       }
+
+       r = radeon_read_bios(rdev);
+
+       /* restore regs */
+       WREG32(RADEON_SEPROM_CNTL1, seprom_cntl1);
+       WREG32(RADEON_VIPH_CONTROL, viph_control);
+       WREG32(RADEON_BUS_CNTL, bus_cntl);
+       WREG32(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl);
+       if (!(rdev->flags & RADEON_SINGLE_CRTC)) {
+               WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
+       }
+       WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl);
+       if (rdev->ddev->pci_device == PCI_DEVICE_ID_ATI_RADEON_QY) {
+               WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl);
+       }
+       return r;
+}
+
+static bool radeon_read_disabled_bios(struct radeon_device *rdev)
+{
+       if (rdev->family >= CHIP_RV770)
+               return r700_read_disabled_bios(rdev);
+       else if (rdev->family >= CHIP_R600)
+               return r600_read_disabled_bios(rdev);
+       else if (rdev->family >= CHIP_RS600)
+               return avivo_read_disabled_bios(rdev);
+       else
+               return legacy_read_disabled_bios(rdev);
+}
+
+bool radeon_get_bios(struct radeon_device *rdev)
+{
+       bool r;
+       uint16_t tmp;
+
+       r = radeon_read_bios(rdev);
+       if (r == false) {
+               r = radeon_read_disabled_bios(rdev);
+       }
+       if (r == false || rdev->bios == NULL) {
+               DRM_ERROR("Unable to locate a BIOS ROM\n");
+               rdev->bios = NULL;
+               return false;
+       }
+       if (rdev->bios[0] != 0x55 || rdev->bios[1] != 0xaa) {
+               goto free_bios;
+       }
+
+       rdev->bios_header_start = RBIOS16(0x48);
+       if (!rdev->bios_header_start) {
+               goto free_bios;
+       }
+       tmp = rdev->bios_header_start + 4;
+       if (!memcmp(rdev->bios + tmp, "ATOM", 4) ||
+           !memcmp(rdev->bios + tmp, "MOTA", 4)) {
+               rdev->is_atom_bios = true;
+       } else {
+               rdev->is_atom_bios = false;
+       }
+
+       DRM_DEBUG("%sBIOS detected\n", rdev->is_atom_bios ? "ATOM" : "COM");
+       return true;
+free_bios:
+       kfree(rdev->bios);
+       rdev->bios = NULL;
+       return false;
+}
diff --git a/drivers/gpu/drm/radeon/radeon_clocks.c b/drivers/gpu/drm/radeon/radeon_clocks.c
new file mode 100644 (file)
index 0000000..a37cbce
--- /dev/null
@@ -0,0 +1,833 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ *          Jerome Glisse
+ */
+#include "drmP.h"
+#include "radeon_drm.h"
+#include "radeon_reg.h"
+#include "radeon.h"
+#include "atom.h"
+
+/* 10 khz */
+static uint32_t radeon_legacy_get_engine_clock(struct radeon_device *rdev)
+{
+       struct radeon_pll *spll = &rdev->clock.spll;
+       uint32_t fb_div, ref_div, post_div, sclk;
+
+       fb_div = RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV);
+       fb_div = (fb_div >> RADEON_SPLL_FB_DIV_SHIFT) & RADEON_SPLL_FB_DIV_MASK;
+       fb_div <<= 1;
+       fb_div *= spll->reference_freq;
+
+       ref_div =
+           RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV) & RADEON_M_SPLL_REF_DIV_MASK;
+       sclk = fb_div / ref_div;
+
+       post_div = RREG32_PLL(RADEON_SCLK_CNTL) & RADEON_SCLK_SRC_SEL_MASK;
+       if (post_div == 2)
+               sclk >>= 1;
+       else if (post_div == 3)
+               sclk >>= 2;
+       else if (post_div == 4)
+               sclk >>= 4;
+
+       return sclk;
+}
+
+/* 10 khz */
+static uint32_t radeon_legacy_get_memory_clock(struct radeon_device *rdev)
+{
+       struct radeon_pll *mpll = &rdev->clock.mpll;
+       uint32_t fb_div, ref_div, post_div, mclk;
+
+       fb_div = RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV);
+       fb_div = (fb_div >> RADEON_MPLL_FB_DIV_SHIFT) & RADEON_MPLL_FB_DIV_MASK;
+       fb_div <<= 1;
+       fb_div *= mpll->reference_freq;
+
+       ref_div =
+           RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV) & RADEON_M_SPLL_REF_DIV_MASK;
+       mclk = fb_div / ref_div;
+
+       post_div = RREG32_PLL(RADEON_MCLK_CNTL) & 0x7;
+       if (post_div == 2)
+               mclk >>= 1;
+       else if (post_div == 3)
+               mclk >>= 2;
+       else if (post_div == 4)
+               mclk >>= 4;
+
+       return mclk;
+}
+
+void radeon_get_clock_info(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_pll *p1pll = &rdev->clock.p1pll;
+       struct radeon_pll *p2pll = &rdev->clock.p2pll;
+       struct radeon_pll *spll = &rdev->clock.spll;
+       struct radeon_pll *mpll = &rdev->clock.mpll;
+       int ret;
+
+       if (rdev->is_atom_bios)
+               ret = radeon_atom_get_clock_info(dev);
+       else
+               ret = radeon_combios_get_clock_info(dev);
+
+       if (ret) {
+               if (p1pll->reference_div < 2)
+                       p1pll->reference_div = 12;
+               if (p2pll->reference_div < 2)
+                       p2pll->reference_div = 12;
+               if (spll->reference_div < 2)
+                       spll->reference_div =
+                           RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV) &
+                           RADEON_M_SPLL_REF_DIV_MASK;
+               if (mpll->reference_div < 2)
+                       mpll->reference_div = spll->reference_div;
+       } else {
+               if (ASIC_IS_AVIVO(rdev)) {
+                       /* TODO FALLBACK */
+               } else {
+                       DRM_INFO("Using generic clock info\n");
+
+                       if (rdev->flags & RADEON_IS_IGP) {
+                               p1pll->reference_freq = 1432;
+                               p2pll->reference_freq = 1432;
+                               spll->reference_freq = 1432;
+                               mpll->reference_freq = 1432;
+                       } else {
+                               p1pll->reference_freq = 2700;
+                               p2pll->reference_freq = 2700;
+                               spll->reference_freq = 2700;
+                               mpll->reference_freq = 2700;
+                       }
+                       p1pll->reference_div =
+                           RREG32_PLL(RADEON_PPLL_REF_DIV) & 0x3ff;
+                       if (p1pll->reference_div < 2)
+                               p1pll->reference_div = 12;
+                       p2pll->reference_div = p1pll->reference_div;
+
+                       if (rdev->family >= CHIP_R420) {
+                               p1pll->pll_in_min = 100;
+                               p1pll->pll_in_max = 1350;
+                               p1pll->pll_out_min = 20000;
+                               p1pll->pll_out_max = 50000;
+                               p2pll->pll_in_min = 100;
+                               p2pll->pll_in_max = 1350;
+                               p2pll->pll_out_min = 20000;
+                               p2pll->pll_out_max = 50000;
+                       } else {
+                               p1pll->pll_in_min = 40;
+                               p1pll->pll_in_max = 500;
+                               p1pll->pll_out_min = 12500;
+                               p1pll->pll_out_max = 35000;
+                               p2pll->pll_in_min = 40;
+                               p2pll->pll_in_max = 500;
+                               p2pll->pll_out_min = 12500;
+                               p2pll->pll_out_max = 35000;
+                       }
+
+                       spll->reference_div =
+                           RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV) &
+                           RADEON_M_SPLL_REF_DIV_MASK;
+                       mpll->reference_div = spll->reference_div;
+                       rdev->clock.default_sclk =
+                           radeon_legacy_get_engine_clock(rdev);
+                       rdev->clock.default_mclk =
+                           radeon_legacy_get_memory_clock(rdev);
+               }
+       }
+
+       /* pixel clocks */
+       if (ASIC_IS_AVIVO(rdev)) {
+               p1pll->min_post_div = 2;
+               p1pll->max_post_div = 0x7f;
+               p1pll->min_frac_feedback_div = 0;
+               p1pll->max_frac_feedback_div = 9;
+               p2pll->min_post_div = 2;
+               p2pll->max_post_div = 0x7f;
+               p2pll->min_frac_feedback_div = 0;
+               p2pll->max_frac_feedback_div = 9;
+       } else {
+               p1pll->min_post_div = 1;
+               p1pll->max_post_div = 16;
+               p1pll->min_frac_feedback_div = 0;
+               p1pll->max_frac_feedback_div = 0;
+               p2pll->min_post_div = 1;
+               p2pll->max_post_div = 12;
+               p2pll->min_frac_feedback_div = 0;
+               p2pll->max_frac_feedback_div = 0;
+       }
+
+       p1pll->min_ref_div = 2;
+       p1pll->max_ref_div = 0x3ff;
+       p1pll->min_feedback_div = 4;
+       p1pll->max_feedback_div = 0x7ff;
+       p1pll->best_vco = 0;
+
+       p2pll->min_ref_div = 2;
+       p2pll->max_ref_div = 0x3ff;
+       p2pll->min_feedback_div = 4;
+       p2pll->max_feedback_div = 0x7ff;
+       p2pll->best_vco = 0;
+
+       /* system clock */
+       spll->min_post_div = 1;
+       spll->max_post_div = 1;
+       spll->min_ref_div = 2;
+       spll->max_ref_div = 0xff;
+       spll->min_feedback_div = 4;
+       spll->max_feedback_div = 0xff;
+       spll->best_vco = 0;
+
+       /* memory clock */
+       mpll->min_post_div = 1;
+       mpll->max_post_div = 1;
+       mpll->min_ref_div = 2;
+       mpll->max_ref_div = 0xff;
+       mpll->min_feedback_div = 4;
+       mpll->max_feedback_div = 0xff;
+       mpll->best_vco = 0;
+
+}
+
+/* 10 khz */
+static uint32_t calc_eng_mem_clock(struct radeon_device *rdev,
+                                  uint32_t req_clock,
+                                  int *fb_div, int *post_div)
+{
+       struct radeon_pll *spll = &rdev->clock.spll;
+       int ref_div = spll->reference_div;
+
+       if (!ref_div)
+               ref_div =
+                   RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV) &
+                   RADEON_M_SPLL_REF_DIV_MASK;
+
+       if (req_clock < 15000) {
+               *post_div = 8;
+               req_clock *= 8;
+       } else if (req_clock < 30000) {
+               *post_div = 4;
+               req_clock *= 4;
+       } else if (req_clock < 60000) {
+               *post_div = 2;
+               req_clock *= 2;
+       } else
+               *post_div = 1;
+
+       req_clock *= ref_div;
+       req_clock += spll->reference_freq;
+       req_clock /= (2 * spll->reference_freq);
+
+       *fb_div = req_clock & 0xff;
+
+       req_clock = (req_clock & 0xffff) << 1;
+       req_clock *= spll->reference_freq;
+       req_clock /= ref_div;
+       req_clock /= *post_div;
+
+       return req_clock;
+}
+
+/* 10 khz */
+void radeon_legacy_set_engine_clock(struct radeon_device *rdev,
+                                   uint32_t eng_clock)
+{
+       uint32_t tmp;
+       int fb_div, post_div;
+
+       /* XXX: wait for idle */
+
+       eng_clock = calc_eng_mem_clock(rdev, eng_clock, &fb_div, &post_div);
+
+       tmp = RREG32_PLL(RADEON_CLK_PIN_CNTL);
+       tmp &= ~RADEON_DONT_USE_XTALIN;
+       WREG32_PLL(RADEON_CLK_PIN_CNTL, tmp);
+
+       tmp = RREG32_PLL(RADEON_SCLK_CNTL);
+       tmp &= ~RADEON_SCLK_SRC_SEL_MASK;
+       WREG32_PLL(RADEON_SCLK_CNTL, tmp);
+
+       udelay(10);
+
+       tmp = RREG32_PLL(RADEON_SPLL_CNTL);
+       tmp |= RADEON_SPLL_SLEEP;
+       WREG32_PLL(RADEON_SPLL_CNTL, tmp);
+
+       udelay(2);
+
+       tmp = RREG32_PLL(RADEON_SPLL_CNTL);
+       tmp |= RADEON_SPLL_RESET;
+       WREG32_PLL(RADEON_SPLL_CNTL, tmp);
+
+       udelay(200);
+
+       tmp = RREG32_PLL(RADEON_M_SPLL_REF_FB_DIV);
+       tmp &= ~(RADEON_SPLL_FB_DIV_MASK << RADEON_SPLL_FB_DIV_SHIFT);
+       tmp |= (fb_div & RADEON_SPLL_FB_DIV_MASK) << RADEON_SPLL_FB_DIV_SHIFT;
+       WREG32_PLL(RADEON_M_SPLL_REF_FB_DIV, tmp);
+
+       /* XXX: verify on different asics */
+       tmp = RREG32_PLL(RADEON_SPLL_CNTL);
+       tmp &= ~RADEON_SPLL_PVG_MASK;
+       if ((eng_clock * post_div) >= 90000)
+               tmp |= (0x7 << RADEON_SPLL_PVG_SHIFT);
+       else
+               tmp |= (0x4 << RADEON_SPLL_PVG_SHIFT);
+       WREG32_PLL(RADEON_SPLL_CNTL, tmp);
+
+       tmp = RREG32_PLL(RADEON_SPLL_CNTL);
+       tmp &= ~RADEON_SPLL_SLEEP;
+       WREG32_PLL(RADEON_SPLL_CNTL, tmp);
+
+       udelay(2);
+
+       tmp = RREG32_PLL(RADEON_SPLL_CNTL);
+       tmp &= ~RADEON_SPLL_RESET;
+       WREG32_PLL(RADEON_SPLL_CNTL, tmp);
+
+       udelay(200);
+
+       tmp = RREG32_PLL(RADEON_SCLK_CNTL);
+       tmp &= ~RADEON_SCLK_SRC_SEL_MASK;
+       switch (post_div) {
+       case 1:
+       default:
+               tmp |= 1;
+               break;
+       case 2:
+               tmp |= 2;
+               break;
+       case 4:
+               tmp |= 3;
+               break;
+       case 8:
+               tmp |= 4;
+               break;
+       }
+       WREG32_PLL(RADEON_SCLK_CNTL, tmp);
+
+       udelay(20);
+
+       tmp = RREG32_PLL(RADEON_CLK_PIN_CNTL);
+       tmp |= RADEON_DONT_USE_XTALIN;
+       WREG32_PLL(RADEON_CLK_PIN_CNTL, tmp);
+
+       udelay(10);
+}
+
+void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable)
+{
+       uint32_t tmp;
+
+       if (enable) {
+               if (rdev->flags & RADEON_SINGLE_CRTC) {
+                       tmp = RREG32_PLL(RADEON_SCLK_CNTL);
+                       if ((RREG32(RADEON_CONFIG_CNTL) &
+                            RADEON_CFG_ATI_REV_ID_MASK) >
+                           RADEON_CFG_ATI_REV_A13) {
+                               tmp &=
+                                   ~(RADEON_SCLK_FORCE_CP |
+                                     RADEON_SCLK_FORCE_RB);
+                       }
+                       tmp &=
+                           ~(RADEON_SCLK_FORCE_HDP | RADEON_SCLK_FORCE_DISP1 |
+                             RADEON_SCLK_FORCE_TOP | RADEON_SCLK_FORCE_SE |
+                             RADEON_SCLK_FORCE_IDCT | RADEON_SCLK_FORCE_RE |
+                             RADEON_SCLK_FORCE_PB | RADEON_SCLK_FORCE_TAM |
+                             RADEON_SCLK_FORCE_TDM);
+                       WREG32_PLL(RADEON_SCLK_CNTL, tmp);
+               } else if (ASIC_IS_R300(rdev)) {
+                       if ((rdev->family == CHIP_RS400) ||
+                           (rdev->family == CHIP_RS480)) {
+                               tmp = RREG32_PLL(RADEON_SCLK_CNTL);
+                               tmp &=
+                                   ~(RADEON_SCLK_FORCE_DISP2 |
+                                     RADEON_SCLK_FORCE_CP |
+                                     RADEON_SCLK_FORCE_HDP |
+                                     RADEON_SCLK_FORCE_DISP1 |
+                                     RADEON_SCLK_FORCE_TOP |
+                                     RADEON_SCLK_FORCE_E2 | R300_SCLK_FORCE_VAP
+                                     | RADEON_SCLK_FORCE_IDCT |
+                                     RADEON_SCLK_FORCE_VIP | R300_SCLK_FORCE_SR
+                                     | R300_SCLK_FORCE_PX | R300_SCLK_FORCE_TX
+                                     | R300_SCLK_FORCE_US |
+                                     RADEON_SCLK_FORCE_TV_SCLK |
+                                     R300_SCLK_FORCE_SU |
+                                     RADEON_SCLK_FORCE_OV0);
+                               tmp |= RADEON_DYN_STOP_LAT_MASK;
+                               tmp |=
+                                   RADEON_SCLK_FORCE_TOP |
+                                   RADEON_SCLK_FORCE_VIP;
+                               WREG32_PLL(RADEON_SCLK_CNTL, tmp);
+
+                               tmp = RREG32_PLL(RADEON_SCLK_MORE_CNTL);
+                               tmp &= ~RADEON_SCLK_MORE_FORCEON;
+                               tmp |= RADEON_SCLK_MORE_MAX_DYN_STOP_LAT;
+                               WREG32_PLL(RADEON_SCLK_MORE_CNTL, tmp);
+
+                               tmp = RREG32_PLL(RADEON_VCLK_ECP_CNTL);
+                               tmp |= (RADEON_PIXCLK_ALWAYS_ONb |
+                                       RADEON_PIXCLK_DAC_ALWAYS_ONb);
+                               WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp);
+
+                               tmp = RREG32_PLL(RADEON_PIXCLKS_CNTL);
+                               tmp |= (RADEON_PIX2CLK_ALWAYS_ONb |
+                                       RADEON_PIX2CLK_DAC_ALWAYS_ONb |
+                                       RADEON_DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb |
+                                       R300_DVOCLK_ALWAYS_ONb |
+                                       RADEON_PIXCLK_BLEND_ALWAYS_ONb |
+                                       RADEON_PIXCLK_GV_ALWAYS_ONb |
+                                       R300_PIXCLK_DVO_ALWAYS_ONb |
+                                       RADEON_PIXCLK_LVDS_ALWAYS_ONb |
+                                       RADEON_PIXCLK_TMDS_ALWAYS_ONb |
+                                       R300_PIXCLK_TRANS_ALWAYS_ONb |
+                                       R300_PIXCLK_TVO_ALWAYS_ONb |
+                                       R300_P2G2CLK_ALWAYS_ONb |
+                                       R300_P2G2CLK_ALWAYS_ONb);
+                               WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp);
+                       } else if (rdev->family >= CHIP_RV350) {
+                               tmp = RREG32_PLL(R300_SCLK_CNTL2);
+                               tmp &= ~(R300_SCLK_FORCE_TCL |
+                                        R300_SCLK_FORCE_GA |
+                                        R300_SCLK_FORCE_CBA);
+                               tmp |= (R300_SCLK_TCL_MAX_DYN_STOP_LAT |
+                                       R300_SCLK_GA_MAX_DYN_STOP_LAT |
+                                       R300_SCLK_CBA_MAX_DYN_STOP_LAT);
+                               WREG32_PLL(R300_SCLK_CNTL2, tmp);
+
+                               tmp = RREG32_PLL(RADEON_SCLK_CNTL);
+                               tmp &=
+                                   ~(RADEON_SCLK_FORCE_DISP2 |
+                                     RADEON_SCLK_FORCE_CP |
+                                     RADEON_SCLK_FORCE_HDP |
+                                     RADEON_SCLK_FORCE_DISP1 |
+                                     RADEON_SCLK_FORCE_TOP |
+                                     RADEON_SCLK_FORCE_E2 | R300_SCLK_FORCE_VAP
+                                     | RADEON_SCLK_FORCE_IDCT |
+                                     RADEON_SCLK_FORCE_VIP | R300_SCLK_FORCE_SR
+                                     | R300_SCLK_FORCE_PX | R300_SCLK_FORCE_TX
+                                     | R300_SCLK_FORCE_US |
+                                     RADEON_SCLK_FORCE_TV_SCLK |
+                                     R300_SCLK_FORCE_SU |
+                                     RADEON_SCLK_FORCE_OV0);
+                               tmp |= RADEON_DYN_STOP_LAT_MASK;
+                               WREG32_PLL(RADEON_SCLK_CNTL, tmp);
+
+                               tmp = RREG32_PLL(RADEON_SCLK_MORE_CNTL);
+                               tmp &= ~RADEON_SCLK_MORE_FORCEON;
+                               tmp |= RADEON_SCLK_MORE_MAX_DYN_STOP_LAT;
+                               WREG32_PLL(RADEON_SCLK_MORE_CNTL, tmp);
+
+                               tmp = RREG32_PLL(RADEON_VCLK_ECP_CNTL);
+                               tmp |= (RADEON_PIXCLK_ALWAYS_ONb |
+                                       RADEON_PIXCLK_DAC_ALWAYS_ONb);
+                               WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp);
+
+                               tmp = RREG32_PLL(RADEON_PIXCLKS_CNTL);
+                               tmp |= (RADEON_PIX2CLK_ALWAYS_ONb |
+                                       RADEON_PIX2CLK_DAC_ALWAYS_ONb |
+                                       RADEON_DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb |
+                                       R300_DVOCLK_ALWAYS_ONb |
+                                       RADEON_PIXCLK_BLEND_ALWAYS_ONb |
+                                       RADEON_PIXCLK_GV_ALWAYS_ONb |
+                                       R300_PIXCLK_DVO_ALWAYS_ONb |
+                                       RADEON_PIXCLK_LVDS_ALWAYS_ONb |
+                                       RADEON_PIXCLK_TMDS_ALWAYS_ONb |
+                                       R300_PIXCLK_TRANS_ALWAYS_ONb |
+                                       R300_PIXCLK_TVO_ALWAYS_ONb |
+                                       R300_P2G2CLK_ALWAYS_ONb |
+                                       R300_P2G2CLK_ALWAYS_ONb);
+                               WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp);
+
+                               tmp = RREG32_PLL(RADEON_MCLK_MISC);
+                               tmp |= (RADEON_MC_MCLK_DYN_ENABLE |
+                                       RADEON_IO_MCLK_DYN_ENABLE);
+                               WREG32_PLL(RADEON_MCLK_MISC, tmp);
+
+                               tmp = RREG32_PLL(RADEON_MCLK_CNTL);
+                               tmp |= (RADEON_FORCEON_MCLKA |
+                                       RADEON_FORCEON_MCLKB);
+
+                               tmp &= ~(RADEON_FORCEON_YCLKA |
+                                        RADEON_FORCEON_YCLKB |
+                                        RADEON_FORCEON_MC);
+
+                               /* Some releases of vbios have set DISABLE_MC_MCLKA
+                                  and DISABLE_MC_MCLKB bits in the vbios table.  Setting these
+                                  bits will cause H/W hang when reading video memory with dynamic clocking
+                                  enabled. */
+                               if ((tmp & R300_DISABLE_MC_MCLKA) &&
+                                   (tmp & R300_DISABLE_MC_MCLKB)) {
+                                       /* If both bits are set, then check the active channels */
+                                       tmp = RREG32_PLL(RADEON_MCLK_CNTL);
+                                       if (rdev->mc.vram_width == 64) {
+                                               if (RREG32(RADEON_MEM_CNTL) &
+                                                   R300_MEM_USE_CD_CH_ONLY)
+                                                       tmp &=
+                                                           ~R300_DISABLE_MC_MCLKB;
+                                               else
+                                                       tmp &=
+                                                           ~R300_DISABLE_MC_MCLKA;
+                                       } else {
+                                               tmp &= ~(R300_DISABLE_MC_MCLKA |
+                                                        R300_DISABLE_MC_MCLKB);
+                                       }
+                               }
+
+                               WREG32_PLL(RADEON_MCLK_CNTL, tmp);
+                       } else {
+                               tmp = RREG32_PLL(RADEON_SCLK_CNTL);
+                               tmp &= ~(R300_SCLK_FORCE_VAP);
+                               tmp |= RADEON_SCLK_FORCE_CP;
+                               WREG32_PLL(RADEON_SCLK_CNTL, tmp);
+                               udelay(15000);
+
+                               tmp = RREG32_PLL(R300_SCLK_CNTL2);
+                               tmp &= ~(R300_SCLK_FORCE_TCL |
+                                        R300_SCLK_FORCE_GA |
+                                        R300_SCLK_FORCE_CBA);
+                               WREG32_PLL(R300_SCLK_CNTL2, tmp);
+                       }
+               } else {
+                       tmp = RREG32_PLL(RADEON_CLK_PWRMGT_CNTL);
+
+                       tmp &= ~(RADEON_ACTIVE_HILO_LAT_MASK |
+                                RADEON_DISP_DYN_STOP_LAT_MASK |
+                                RADEON_DYN_STOP_MODE_MASK);
+
+                       tmp |= (RADEON_ENGIN_DYNCLK_MODE |
+                               (0x01 << RADEON_ACTIVE_HILO_LAT_SHIFT));
+                       WREG32_PLL(RADEON_CLK_PWRMGT_CNTL, tmp);
+                       udelay(15000);
+
+                       tmp = RREG32_PLL(RADEON_CLK_PIN_CNTL);
+                       tmp |= RADEON_SCLK_DYN_START_CNTL;
+                       WREG32_PLL(RADEON_CLK_PIN_CNTL, tmp);
+                       udelay(15000);
+
+                       /* When DRI is enabled, setting DYN_STOP_LAT to zero can cause some R200
+                          to lockup randomly, leave them as set by BIOS.
+                        */
+                       tmp = RREG32_PLL(RADEON_SCLK_CNTL);
+                       /*tmp &= RADEON_SCLK_SRC_SEL_MASK; */
+                       tmp &= ~RADEON_SCLK_FORCEON_MASK;
+
+                       /*RAGE_6::A11 A12 A12N1 A13, RV250::A11 A12, R300 */
+                       if (((rdev->family == CHIP_RV250) &&
+                            ((RREG32(RADEON_CONFIG_CNTL) &
+                              RADEON_CFG_ATI_REV_ID_MASK) <
+                             RADEON_CFG_ATI_REV_A13))
+                           || ((rdev->family == CHIP_RV100)
+                               &&
+                               ((RREG32(RADEON_CONFIG_CNTL) &
+                                 RADEON_CFG_ATI_REV_ID_MASK) <=
+                                RADEON_CFG_ATI_REV_A13))) {
+                               tmp |= RADEON_SCLK_FORCE_CP;
+                               tmp |= RADEON_SCLK_FORCE_VIP;
+                       }
+
+                       WREG32_PLL(RADEON_SCLK_CNTL, tmp);
+
+                       if ((rdev->family == CHIP_RV200) ||
+                           (rdev->family == CHIP_RV250) ||
+                           (rdev->family == CHIP_RV280)) {
+                               tmp = RREG32_PLL(RADEON_SCLK_MORE_CNTL);
+                               tmp &= ~RADEON_SCLK_MORE_FORCEON;
+
+                               /* RV200::A11 A12 RV250::A11 A12 */
+                               if (((rdev->family == CHIP_RV200) ||
+                                    (rdev->family == CHIP_RV250)) &&
+                                   ((RREG32(RADEON_CONFIG_CNTL) &
+                                     RADEON_CFG_ATI_REV_ID_MASK) <
+                                    RADEON_CFG_ATI_REV_A13)) {
+                                       tmp |= RADEON_SCLK_MORE_FORCEON;
+                               }
+                               WREG32_PLL(RADEON_SCLK_MORE_CNTL, tmp);
+                               udelay(15000);
+                       }
+
+                       /* RV200::A11 A12, RV250::A11 A12 */
+                       if (((rdev->family == CHIP_RV200) ||
+                            (rdev->family == CHIP_RV250)) &&
+                           ((RREG32(RADEON_CONFIG_CNTL) &
+                             RADEON_CFG_ATI_REV_ID_MASK) <
+                            RADEON_CFG_ATI_REV_A13)) {
+                               tmp = RREG32_PLL(RADEON_PLL_PWRMGT_CNTL);
+                               tmp |= RADEON_TCL_BYPASS_DISABLE;
+                               WREG32_PLL(RADEON_PLL_PWRMGT_CNTL, tmp);
+                       }
+                       udelay(15000);
+
+                       /*enable dynamic mode for display clocks (PIXCLK and PIX2CLK) */
+                       tmp = RREG32_PLL(RADEON_PIXCLKS_CNTL);
+                       tmp |= (RADEON_PIX2CLK_ALWAYS_ONb |
+                               RADEON_PIX2CLK_DAC_ALWAYS_ONb |
+                               RADEON_PIXCLK_BLEND_ALWAYS_ONb |
+                               RADEON_PIXCLK_GV_ALWAYS_ONb |
+                               RADEON_PIXCLK_DIG_TMDS_ALWAYS_ONb |
+                               RADEON_PIXCLK_LVDS_ALWAYS_ONb |
+                               RADEON_PIXCLK_TMDS_ALWAYS_ONb);
+
+                       WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp);
+                       udelay(15000);
+
+                       tmp = RREG32_PLL(RADEON_VCLK_ECP_CNTL);
+                       tmp |= (RADEON_PIXCLK_ALWAYS_ONb |
+                               RADEON_PIXCLK_DAC_ALWAYS_ONb);
+
+                       WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp);
+                       udelay(15000);
+               }
+       } else {
+               /* Turn everything OFF (ForceON to everything) */
+               if (rdev->flags & RADEON_SINGLE_CRTC) {
+                       tmp = RREG32_PLL(RADEON_SCLK_CNTL);
+                       tmp |= (RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_HDP |
+                               RADEON_SCLK_FORCE_DISP1 | RADEON_SCLK_FORCE_TOP
+                               | RADEON_SCLK_FORCE_E2 | RADEON_SCLK_FORCE_SE |
+                               RADEON_SCLK_FORCE_IDCT | RADEON_SCLK_FORCE_VIP |
+                               RADEON_SCLK_FORCE_RE | RADEON_SCLK_FORCE_PB |
+                               RADEON_SCLK_FORCE_TAM | RADEON_SCLK_FORCE_TDM |
+                               RADEON_SCLK_FORCE_RB);
+                       WREG32_PLL(RADEON_SCLK_CNTL, tmp);
+               } else if ((rdev->family == CHIP_RS400) ||
+                          (rdev->family == CHIP_RS480)) {
+                       tmp = RREG32_PLL(RADEON_SCLK_CNTL);
+                       tmp |= (RADEON_SCLK_FORCE_DISP2 | RADEON_SCLK_FORCE_CP |
+                               RADEON_SCLK_FORCE_HDP | RADEON_SCLK_FORCE_DISP1
+                               | RADEON_SCLK_FORCE_TOP | RADEON_SCLK_FORCE_E2 |
+                               R300_SCLK_FORCE_VAP | RADEON_SCLK_FORCE_IDCT |
+                               RADEON_SCLK_FORCE_VIP | R300_SCLK_FORCE_SR |
+                               R300_SCLK_FORCE_PX | R300_SCLK_FORCE_TX |
+                               R300_SCLK_FORCE_US | RADEON_SCLK_FORCE_TV_SCLK |
+                               R300_SCLK_FORCE_SU | RADEON_SCLK_FORCE_OV0);
+                       WREG32_PLL(RADEON_SCLK_CNTL, tmp);
+
+                       tmp = RREG32_PLL(RADEON_SCLK_MORE_CNTL);
+                       tmp |= RADEON_SCLK_MORE_FORCEON;
+                       WREG32_PLL(RADEON_SCLK_MORE_CNTL, tmp);
+
+                       tmp = RREG32_PLL(RADEON_VCLK_ECP_CNTL);
+                       tmp &= ~(RADEON_PIXCLK_ALWAYS_ONb |
+                                RADEON_PIXCLK_DAC_ALWAYS_ONb |
+                                R300_DISP_DAC_PIXCLK_DAC_BLANK_OFF);
+                       WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp);
+
+                       tmp = RREG32_PLL(RADEON_PIXCLKS_CNTL);
+                       tmp &= ~(RADEON_PIX2CLK_ALWAYS_ONb |
+                                RADEON_PIX2CLK_DAC_ALWAYS_ONb |
+                                RADEON_DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb |
+                                R300_DVOCLK_ALWAYS_ONb |
+                                RADEON_PIXCLK_BLEND_ALWAYS_ONb |
+                                RADEON_PIXCLK_GV_ALWAYS_ONb |
+                                R300_PIXCLK_DVO_ALWAYS_ONb |
+                                RADEON_PIXCLK_LVDS_ALWAYS_ONb |
+                                RADEON_PIXCLK_TMDS_ALWAYS_ONb |
+                                R300_PIXCLK_TRANS_ALWAYS_ONb |
+                                R300_PIXCLK_TVO_ALWAYS_ONb |
+                                R300_P2G2CLK_ALWAYS_ONb |
+                                R300_P2G2CLK_ALWAYS_ONb |
+                                R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF);
+                       WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp);
+               } else if (rdev->family >= CHIP_RV350) {
+                       /* for RV350/M10, no delays are required. */
+                       tmp = RREG32_PLL(R300_SCLK_CNTL2);
+                       tmp |= (R300_SCLK_FORCE_TCL |
+                               R300_SCLK_FORCE_GA | R300_SCLK_FORCE_CBA);
+                       WREG32_PLL(R300_SCLK_CNTL2, tmp);
+
+                       tmp = RREG32_PLL(RADEON_SCLK_CNTL);
+                       tmp |= (RADEON_SCLK_FORCE_DISP2 | RADEON_SCLK_FORCE_CP |
+                               RADEON_SCLK_FORCE_HDP | RADEON_SCLK_FORCE_DISP1
+                               | RADEON_SCLK_FORCE_TOP | RADEON_SCLK_FORCE_E2 |
+                               R300_SCLK_FORCE_VAP | RADEON_SCLK_FORCE_IDCT |
+                               RADEON_SCLK_FORCE_VIP | R300_SCLK_FORCE_SR |
+                               R300_SCLK_FORCE_PX | R300_SCLK_FORCE_TX |
+                               R300_SCLK_FORCE_US | RADEON_SCLK_FORCE_TV_SCLK |
+                               R300_SCLK_FORCE_SU | RADEON_SCLK_FORCE_OV0);
+                       WREG32_PLL(RADEON_SCLK_CNTL, tmp);
+
+                       tmp = RREG32_PLL(RADEON_SCLK_MORE_CNTL);
+                       tmp |= RADEON_SCLK_MORE_FORCEON;
+                       WREG32_PLL(RADEON_SCLK_MORE_CNTL, tmp);
+
+                       tmp = RREG32_PLL(RADEON_MCLK_CNTL);
+                       tmp |= (RADEON_FORCEON_MCLKA |
+                               RADEON_FORCEON_MCLKB |
+                               RADEON_FORCEON_YCLKA |
+                               RADEON_FORCEON_YCLKB | RADEON_FORCEON_MC);
+                       WREG32_PLL(RADEON_MCLK_CNTL, tmp);
+
+                       tmp = RREG32_PLL(RADEON_VCLK_ECP_CNTL);
+                       tmp &= ~(RADEON_PIXCLK_ALWAYS_ONb |
+                                RADEON_PIXCLK_DAC_ALWAYS_ONb |
+                                R300_DISP_DAC_PIXCLK_DAC_BLANK_OFF);
+                       WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp);
+
+                       tmp = RREG32_PLL(RADEON_PIXCLKS_CNTL);
+                       tmp &= ~(RADEON_PIX2CLK_ALWAYS_ONb |
+                                RADEON_PIX2CLK_DAC_ALWAYS_ONb |
+                                RADEON_DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb |
+                                R300_DVOCLK_ALWAYS_ONb |
+                                RADEON_PIXCLK_BLEND_ALWAYS_ONb |
+                                RADEON_PIXCLK_GV_ALWAYS_ONb |
+                                R300_PIXCLK_DVO_ALWAYS_ONb |
+                                RADEON_PIXCLK_LVDS_ALWAYS_ONb |
+                                RADEON_PIXCLK_TMDS_ALWAYS_ONb |
+                                R300_PIXCLK_TRANS_ALWAYS_ONb |
+                                R300_PIXCLK_TVO_ALWAYS_ONb |
+                                R300_P2G2CLK_ALWAYS_ONb |
+                                R300_P2G2CLK_ALWAYS_ONb |
+                                R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF);
+                       WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp);
+               } else {
+                       tmp = RREG32_PLL(RADEON_SCLK_CNTL);
+                       tmp |= (RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_E2);
+                       tmp |= RADEON_SCLK_FORCE_SE;
+
+                       if (rdev->flags & RADEON_SINGLE_CRTC) {
+                               tmp |= (RADEON_SCLK_FORCE_RB |
+                                       RADEON_SCLK_FORCE_TDM |
+                                       RADEON_SCLK_FORCE_TAM |
+                                       RADEON_SCLK_FORCE_PB |
+                                       RADEON_SCLK_FORCE_RE |
+                                       RADEON_SCLK_FORCE_VIP |
+                                       RADEON_SCLK_FORCE_IDCT |
+                                       RADEON_SCLK_FORCE_TOP |
+                                       RADEON_SCLK_FORCE_DISP1 |
+                                       RADEON_SCLK_FORCE_DISP2 |
+                                       RADEON_SCLK_FORCE_HDP);
+                       } else if ((rdev->family == CHIP_R300) ||
+                                  (rdev->family == CHIP_R350)) {
+                               tmp |= (RADEON_SCLK_FORCE_HDP |
+                                       RADEON_SCLK_FORCE_DISP1 |
+                                       RADEON_SCLK_FORCE_DISP2 |
+                                       RADEON_SCLK_FORCE_TOP |
+                                       RADEON_SCLK_FORCE_IDCT |
+                                       RADEON_SCLK_FORCE_VIP);
+                       }
+                       WREG32_PLL(RADEON_SCLK_CNTL, tmp);
+
+                       udelay(16000);
+
+                       if ((rdev->family == CHIP_R300) ||
+                           (rdev->family == CHIP_R350)) {
+                               tmp = RREG32_PLL(R300_SCLK_CNTL2);
+                               tmp |= (R300_SCLK_FORCE_TCL |
+                                       R300_SCLK_FORCE_GA |
+                                       R300_SCLK_FORCE_CBA);
+                               WREG32_PLL(R300_SCLK_CNTL2, tmp);
+                               udelay(16000);
+                       }
+
+                       if (rdev->flags & RADEON_IS_IGP) {
+                               tmp = RREG32_PLL(RADEON_MCLK_CNTL);
+                               tmp &= ~(RADEON_FORCEON_MCLKA |
+                                        RADEON_FORCEON_YCLKA);
+                               WREG32_PLL(RADEON_MCLK_CNTL, tmp);
+                               udelay(16000);
+                       }
+
+                       if ((rdev->family == CHIP_RV200) ||
+                           (rdev->family == CHIP_RV250) ||
+                           (rdev->family == CHIP_RV280)) {
+                               tmp = RREG32_PLL(RADEON_SCLK_MORE_CNTL);
+                               tmp |= RADEON_SCLK_MORE_FORCEON;
+                               WREG32_PLL(RADEON_SCLK_MORE_CNTL, tmp);
+                               udelay(16000);
+                       }
+
+                       tmp = RREG32_PLL(RADEON_PIXCLKS_CNTL);
+                       tmp &= ~(RADEON_PIX2CLK_ALWAYS_ONb |
+                                RADEON_PIX2CLK_DAC_ALWAYS_ONb |
+                                RADEON_PIXCLK_BLEND_ALWAYS_ONb |
+                                RADEON_PIXCLK_GV_ALWAYS_ONb |
+                                RADEON_PIXCLK_DIG_TMDS_ALWAYS_ONb |
+                                RADEON_PIXCLK_LVDS_ALWAYS_ONb |
+                                RADEON_PIXCLK_TMDS_ALWAYS_ONb);
+
+                       WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp);
+                       udelay(16000);
+
+                       tmp = RREG32_PLL(RADEON_VCLK_ECP_CNTL);
+                       tmp &= ~(RADEON_PIXCLK_ALWAYS_ONb |
+                                RADEON_PIXCLK_DAC_ALWAYS_ONb);
+                       WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp);
+               }
+       }
+}
+
+static void radeon_apply_clock_quirks(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+
+       /* XXX make sure engine is idle */
+
+       if (rdev->family < CHIP_RS600) {
+               tmp = RREG32_PLL(RADEON_SCLK_CNTL);
+               if (ASIC_IS_R300(rdev) || ASIC_IS_RV100(rdev))
+                       tmp |= RADEON_SCLK_FORCE_CP | RADEON_SCLK_FORCE_VIP;
+               if ((rdev->family == CHIP_RV250)
+                   || (rdev->family == CHIP_RV280))
+                       tmp |=
+                           RADEON_SCLK_FORCE_DISP1 | RADEON_SCLK_FORCE_DISP2;
+               if ((rdev->family == CHIP_RV350)
+                   || (rdev->family == CHIP_RV380))
+                       tmp |= R300_SCLK_FORCE_VAP;
+               if (rdev->family == CHIP_R420)
+                       tmp |= R300_SCLK_FORCE_PX | R300_SCLK_FORCE_TX;
+               WREG32_PLL(RADEON_SCLK_CNTL, tmp);
+       } else if (rdev->family < CHIP_R600) {
+               tmp = RREG32_PLL(AVIVO_CP_DYN_CNTL);
+               tmp |= AVIVO_CP_FORCEON;
+               WREG32_PLL(AVIVO_CP_DYN_CNTL, tmp);
+
+               tmp = RREG32_PLL(AVIVO_E2_DYN_CNTL);
+               tmp |= AVIVO_E2_FORCEON;
+               WREG32_PLL(AVIVO_E2_DYN_CNTL, tmp);
+
+               tmp = RREG32_PLL(AVIVO_IDCT_DYN_CNTL);
+               tmp |= AVIVO_IDCT_FORCEON;
+               WREG32_PLL(AVIVO_IDCT_DYN_CNTL, tmp);
+       }
+}
+
+int radeon_static_clocks_init(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+
+       /* XXX make sure engine is idle */
+
+       if (radeon_dynclks != -1) {
+               if (radeon_dynclks)
+                       radeon_set_clock_gating(rdev, 1);
+       }
+       radeon_apply_clock_quirks(rdev);
+       return 0;
+}
diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c
new file mode 100644 (file)
index 0000000..06e8038
--- /dev/null
@@ -0,0 +1,2481 @@
+/*
+ * Copyright 2004 ATI Technologies Inc., Markham, Ontario
+ * Copyright 2007-8 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ */
+#include "drmP.h"
+#include "radeon_drm.h"
+#include "radeon.h"
+#include "atom.h"
+
+#ifdef CONFIG_PPC_PMAC
+/* not sure which of these are needed */
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#endif /* CONFIG_PPC_PMAC */
+
+/* from radeon_encoder.c */
+extern uint32_t
+radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device,
+                     uint8_t dac);
+extern void radeon_link_encoder_connector(struct drm_device *dev);
+
+/* from radeon_connector.c */
+extern void
+radeon_add_legacy_connector(struct drm_device *dev,
+                           uint32_t connector_id,
+                           uint32_t supported_device,
+                           int connector_type,
+                           struct radeon_i2c_bus_rec *i2c_bus);
+
+/* from radeon_legacy_encoder.c */
+extern void
+radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_id,
+                         uint32_t supported_device);
+
+/* old legacy ATI BIOS routines */
+
+/* COMBIOS table offsets */
+enum radeon_combios_table_offset {
+       /* absolute offset tables */
+       COMBIOS_ASIC_INIT_1_TABLE,
+       COMBIOS_BIOS_SUPPORT_TABLE,
+       COMBIOS_DAC_PROGRAMMING_TABLE,
+       COMBIOS_MAX_COLOR_DEPTH_TABLE,
+       COMBIOS_CRTC_INFO_TABLE,
+       COMBIOS_PLL_INFO_TABLE,
+       COMBIOS_TV_INFO_TABLE,
+       COMBIOS_DFP_INFO_TABLE,
+       COMBIOS_HW_CONFIG_INFO_TABLE,
+       COMBIOS_MULTIMEDIA_INFO_TABLE,
+       COMBIOS_TV_STD_PATCH_TABLE,
+       COMBIOS_LCD_INFO_TABLE,
+       COMBIOS_MOBILE_INFO_TABLE,
+       COMBIOS_PLL_INIT_TABLE,
+       COMBIOS_MEM_CONFIG_TABLE,
+       COMBIOS_SAVE_MASK_TABLE,
+       COMBIOS_HARDCODED_EDID_TABLE,
+       COMBIOS_ASIC_INIT_2_TABLE,
+       COMBIOS_CONNECTOR_INFO_TABLE,
+       COMBIOS_DYN_CLK_1_TABLE,
+       COMBIOS_RESERVED_MEM_TABLE,
+       COMBIOS_EXT_TMDS_INFO_TABLE,
+       COMBIOS_MEM_CLK_INFO_TABLE,
+       COMBIOS_EXT_DAC_INFO_TABLE,
+       COMBIOS_MISC_INFO_TABLE,
+       COMBIOS_CRT_INFO_TABLE,
+       COMBIOS_INTEGRATED_SYSTEM_INFO_TABLE,
+       COMBIOS_COMPONENT_VIDEO_INFO_TABLE,
+       COMBIOS_FAN_SPEED_INFO_TABLE,
+       COMBIOS_OVERDRIVE_INFO_TABLE,
+       COMBIOS_OEM_INFO_TABLE,
+       COMBIOS_DYN_CLK_2_TABLE,
+       COMBIOS_POWER_CONNECTOR_INFO_TABLE,
+       COMBIOS_I2C_INFO_TABLE,
+       /* relative offset tables */
+       COMBIOS_ASIC_INIT_3_TABLE,      /* offset from misc info */
+       COMBIOS_ASIC_INIT_4_TABLE,      /* offset from misc info */
+       COMBIOS_DETECTED_MEM_TABLE,     /* offset from misc info */
+       COMBIOS_ASIC_INIT_5_TABLE,      /* offset from misc info */
+       COMBIOS_RAM_RESET_TABLE,        /* offset from mem config */
+       COMBIOS_POWERPLAY_INFO_TABLE,   /* offset from mobile info */
+       COMBIOS_GPIO_INFO_TABLE,        /* offset from mobile info */
+       COMBIOS_LCD_DDC_INFO_TABLE,     /* offset from mobile info */
+       COMBIOS_TMDS_POWER_TABLE,       /* offset from mobile info */
+       COMBIOS_TMDS_POWER_ON_TABLE,    /* offset from tmds power */
+       COMBIOS_TMDS_POWER_OFF_TABLE,   /* offset from tmds power */
+};
+
+enum radeon_combios_ddc {
+       DDC_NONE_DETECTED,
+       DDC_MONID,
+       DDC_DVI,
+       DDC_VGA,
+       DDC_CRT2,
+       DDC_LCD,
+       DDC_GPIO,
+};
+
+enum radeon_combios_connector {
+       CONNECTOR_NONE_LEGACY,
+       CONNECTOR_PROPRIETARY_LEGACY,
+       CONNECTOR_CRT_LEGACY,
+       CONNECTOR_DVI_I_LEGACY,
+       CONNECTOR_DVI_D_LEGACY,
+       CONNECTOR_CTV_LEGACY,
+       CONNECTOR_STV_LEGACY,
+       CONNECTOR_UNSUPPORTED_LEGACY
+};
+
+const int legacy_connector_convert[] = {
+       DRM_MODE_CONNECTOR_Unknown,
+       DRM_MODE_CONNECTOR_DVID,
+       DRM_MODE_CONNECTOR_VGA,
+       DRM_MODE_CONNECTOR_DVII,
+       DRM_MODE_CONNECTOR_DVID,
+       DRM_MODE_CONNECTOR_Composite,
+       DRM_MODE_CONNECTOR_SVIDEO,
+       DRM_MODE_CONNECTOR_Unknown,
+};
+
+static uint16_t combios_get_table_offset(struct drm_device *dev,
+                                        enum radeon_combios_table_offset table)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       int rev;
+       uint16_t offset = 0, check_offset;
+
+       switch (table) {
+               /* absolute offset tables */
+       case COMBIOS_ASIC_INIT_1_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0xc);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_BIOS_SUPPORT_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x14);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_DAC_PROGRAMMING_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x2a);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_MAX_COLOR_DEPTH_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x2c);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_CRTC_INFO_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x2e);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_PLL_INFO_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x30);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_TV_INFO_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x32);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_DFP_INFO_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x34);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_HW_CONFIG_INFO_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x36);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_MULTIMEDIA_INFO_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x38);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_TV_STD_PATCH_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x3e);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_LCD_INFO_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x40);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_MOBILE_INFO_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x42);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_PLL_INIT_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x46);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_MEM_CONFIG_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x48);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_SAVE_MASK_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x4a);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_HARDCODED_EDID_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x4c);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_ASIC_INIT_2_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x4e);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_CONNECTOR_INFO_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x50);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_DYN_CLK_1_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x52);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_RESERVED_MEM_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x54);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_EXT_TMDS_INFO_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x58);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_MEM_CLK_INFO_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x5a);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_EXT_DAC_INFO_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x5c);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_MISC_INFO_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x5e);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_CRT_INFO_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x60);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_INTEGRATED_SYSTEM_INFO_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x62);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_COMPONENT_VIDEO_INFO_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x64);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_FAN_SPEED_INFO_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x66);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_OVERDRIVE_INFO_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x68);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_OEM_INFO_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x6a);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_DYN_CLK_2_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x6c);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_POWER_CONNECTOR_INFO_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x6e);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+       case COMBIOS_I2C_INFO_TABLE:
+               check_offset = RBIOS16(rdev->bios_header_start + 0x70);
+               if (check_offset)
+                       offset = check_offset;
+               break;
+               /* relative offset tables */
+       case COMBIOS_ASIC_INIT_3_TABLE: /* offset from misc info */
+               check_offset =
+                   combios_get_table_offset(dev, COMBIOS_MISC_INFO_TABLE);
+               if (check_offset) {
+                       rev = RBIOS8(check_offset);
+                       if (rev > 0) {
+                               check_offset = RBIOS16(check_offset + 0x3);
+                               if (check_offset)
+                                       offset = check_offset;
+                       }
+               }
+               break;
+       case COMBIOS_ASIC_INIT_4_TABLE: /* offset from misc info */
+               check_offset =
+                   combios_get_table_offset(dev, COMBIOS_MISC_INFO_TABLE);
+               if (check_offset) {
+                       rev = RBIOS8(check_offset);
+                       if (rev > 0) {
+                               check_offset = RBIOS16(check_offset + 0x5);
+                               if (check_offset)
+                                       offset = check_offset;
+                       }
+               }
+               break;
+       case COMBIOS_DETECTED_MEM_TABLE:        /* offset from misc info */
+               check_offset =
+                   combios_get_table_offset(dev, COMBIOS_MISC_INFO_TABLE);
+               if (check_offset) {
+                       rev = RBIOS8(check_offset);
+                       if (rev > 0) {
+                               check_offset = RBIOS16(check_offset + 0x7);
+                               if (check_offset)
+                                       offset = check_offset;
+                       }
+               }
+               break;
+       case COMBIOS_ASIC_INIT_5_TABLE: /* offset from misc info */
+               check_offset =
+                   combios_get_table_offset(dev, COMBIOS_MISC_INFO_TABLE);
+               if (check_offset) {
+                       rev = RBIOS8(check_offset);
+                       if (rev == 2) {
+                               check_offset = RBIOS16(check_offset + 0x9);
+                               if (check_offset)
+                                       offset = check_offset;
+                       }
+               }
+               break;
+       case COMBIOS_RAM_RESET_TABLE:   /* offset from mem config */
+               check_offset =
+                   combios_get_table_offset(dev, COMBIOS_MEM_CONFIG_TABLE);
+               if (check_offset) {
+                       while (RBIOS8(check_offset++));
+                       check_offset += 2;
+                       if (check_offset)
+                               offset = check_offset;
+               }
+               break;
+       case COMBIOS_POWERPLAY_INFO_TABLE:      /* offset from mobile info */
+               check_offset =
+                   combios_get_table_offset(dev, COMBIOS_MOBILE_INFO_TABLE);
+               if (check_offset) {
+                       check_offset = RBIOS16(check_offset + 0x11);
+                       if (check_offset)
+                               offset = check_offset;
+               }
+               break;
+       case COMBIOS_GPIO_INFO_TABLE:   /* offset from mobile info */
+               check_offset =
+                   combios_get_table_offset(dev, COMBIOS_MOBILE_INFO_TABLE);
+               if (check_offset) {
+                       check_offset = RBIOS16(check_offset + 0x13);
+                       if (check_offset)
+                               offset = check_offset;
+               }
+               break;
+       case COMBIOS_LCD_DDC_INFO_TABLE:        /* offset from mobile info */
+               check_offset =
+                   combios_get_table_offset(dev, COMBIOS_MOBILE_INFO_TABLE);
+               if (check_offset) {
+                       check_offset = RBIOS16(check_offset + 0x15);
+                       if (check_offset)
+                               offset = check_offset;
+               }
+               break;
+       case COMBIOS_TMDS_POWER_TABLE:  /* offset from mobile info */
+               check_offset =
+                   combios_get_table_offset(dev, COMBIOS_MOBILE_INFO_TABLE);
+               if (check_offset) {
+                       check_offset = RBIOS16(check_offset + 0x17);
+                       if (check_offset)
+                               offset = check_offset;
+               }
+               break;
+       case COMBIOS_TMDS_POWER_ON_TABLE:       /* offset from tmds power */
+               check_offset =
+                   combios_get_table_offset(dev, COMBIOS_TMDS_POWER_TABLE);
+               if (check_offset) {
+                       check_offset = RBIOS16(check_offset + 0x2);
+                       if (check_offset)
+                               offset = check_offset;
+               }
+               break;
+       case COMBIOS_TMDS_POWER_OFF_TABLE:      /* offset from tmds power */
+               check_offset =
+                   combios_get_table_offset(dev, COMBIOS_TMDS_POWER_TABLE);
+               if (check_offset) {
+                       check_offset = RBIOS16(check_offset + 0x4);
+                       if (check_offset)
+                               offset = check_offset;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return offset;
+
+}
+
+struct radeon_i2c_bus_rec combios_setup_i2c_bus(int ddc_line)
+{
+       struct radeon_i2c_bus_rec i2c;
+
+       i2c.mask_clk_mask = RADEON_GPIO_EN_1;
+       i2c.mask_data_mask = RADEON_GPIO_EN_0;
+       i2c.a_clk_mask = RADEON_GPIO_A_1;
+       i2c.a_data_mask = RADEON_GPIO_A_0;
+       i2c.put_clk_mask = RADEON_GPIO_EN_1;
+       i2c.put_data_mask = RADEON_GPIO_EN_0;
+       i2c.get_clk_mask = RADEON_GPIO_Y_1;
+       i2c.get_data_mask = RADEON_GPIO_Y_0;
+       if ((ddc_line == RADEON_LCD_GPIO_MASK) ||
+           (ddc_line == RADEON_MDGPIO_EN_REG)) {
+               i2c.mask_clk_reg = ddc_line;
+               i2c.mask_data_reg = ddc_line;
+               i2c.a_clk_reg = ddc_line;
+               i2c.a_data_reg = ddc_line;
+               i2c.put_clk_reg = ddc_line;
+               i2c.put_data_reg = ddc_line;
+               i2c.get_clk_reg = ddc_line + 4;
+               i2c.get_data_reg = ddc_line + 4;
+       } else {
+               i2c.mask_clk_reg = ddc_line;
+               i2c.mask_data_reg = ddc_line;
+               i2c.a_clk_reg = ddc_line;
+               i2c.a_data_reg = ddc_line;
+               i2c.put_clk_reg = ddc_line;
+               i2c.put_data_reg = ddc_line;
+               i2c.get_clk_reg = ddc_line;
+               i2c.get_data_reg = ddc_line;
+       }
+
+       if (ddc_line)
+               i2c.valid = true;
+       else
+               i2c.valid = false;
+
+       return i2c;
+}
+
+bool radeon_combios_get_clock_info(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       uint16_t pll_info;
+       struct radeon_pll *p1pll = &rdev->clock.p1pll;
+       struct radeon_pll *p2pll = &rdev->clock.p2pll;
+       struct radeon_pll *spll = &rdev->clock.spll;
+       struct radeon_pll *mpll = &rdev->clock.mpll;
+       int8_t rev;
+       uint16_t sclk, mclk;
+
+       if (rdev->bios == NULL)
+               return NULL;
+
+       pll_info = combios_get_table_offset(dev, COMBIOS_PLL_INFO_TABLE);
+       if (pll_info) {
+               rev = RBIOS8(pll_info);
+
+               /* pixel clocks */
+               p1pll->reference_freq = RBIOS16(pll_info + 0xe);
+               p1pll->reference_div = RBIOS16(pll_info + 0x10);
+               p1pll->pll_out_min = RBIOS32(pll_info + 0x12);
+               p1pll->pll_out_max = RBIOS32(pll_info + 0x16);
+
+               if (rev > 9) {
+                       p1pll->pll_in_min = RBIOS32(pll_info + 0x36);
+                       p1pll->pll_in_max = RBIOS32(pll_info + 0x3a);
+               } else {
+                       p1pll->pll_in_min = 40;
+                       p1pll->pll_in_max = 500;
+               }
+               *p2pll = *p1pll;
+
+               /* system clock */
+               spll->reference_freq = RBIOS16(pll_info + 0x1a);
+               spll->reference_div = RBIOS16(pll_info + 0x1c);
+               spll->pll_out_min = RBIOS32(pll_info + 0x1e);
+               spll->pll_out_max = RBIOS32(pll_info + 0x22);
+
+               if (rev > 10) {
+                       spll->pll_in_min = RBIOS32(pll_info + 0x48);
+                       spll->pll_in_max = RBIOS32(pll_info + 0x4c);
+               } else {
+                       /* ??? */
+                       spll->pll_in_min = 40;
+                       spll->pll_in_max = 500;
+               }
+
+               /* memory clock */
+               mpll->reference_freq = RBIOS16(pll_info + 0x26);
+               mpll->reference_div = RBIOS16(pll_info + 0x28);
+               mpll->pll_out_min = RBIOS32(pll_info + 0x2a);
+               mpll->pll_out_max = RBIOS32(pll_info + 0x2e);
+
+               if (rev > 10) {
+                       mpll->pll_in_min = RBIOS32(pll_info + 0x5a);
+                       mpll->pll_in_max = RBIOS32(pll_info + 0x5e);
+               } else {
+                       /* ??? */
+                       mpll->pll_in_min = 40;
+                       mpll->pll_in_max = 500;
+               }
+
+               /* default sclk/mclk */
+               sclk = RBIOS16(pll_info + 0xa);
+               mclk = RBIOS16(pll_info + 0x8);
+               if (sclk == 0)
+                       sclk = 200 * 100;
+               if (mclk == 0)
+                       mclk = 200 * 100;
+
+               rdev->clock.default_sclk = sclk;
+               rdev->clock.default_mclk = mclk;
+
+               return true;
+       }
+       return false;
+}
+
+struct radeon_encoder_primary_dac *radeon_combios_get_primary_dac_info(struct
+                                                                      radeon_encoder
+                                                                      *encoder)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint16_t dac_info;
+       uint8_t rev, bg, dac;
+       struct radeon_encoder_primary_dac *p_dac = NULL;
+
+       if (rdev->bios == NULL)
+               return NULL;
+
+       /* check CRT table */
+       dac_info = combios_get_table_offset(dev, COMBIOS_CRT_INFO_TABLE);
+       if (dac_info) {
+               p_dac =
+                   kzalloc(sizeof(struct radeon_encoder_primary_dac),
+                           GFP_KERNEL);
+
+               if (!p_dac)
+                       return NULL;
+
+               rev = RBIOS8(dac_info) & 0x3;
+               if (rev < 2) {
+                       bg = RBIOS8(dac_info + 0x2) & 0xf;
+                       dac = (RBIOS8(dac_info + 0x2) >> 4) & 0xf;
+                       p_dac->ps2_pdac_adj = (bg << 8) | (dac);
+               } else {
+                       bg = RBIOS8(dac_info + 0x2) & 0xf;
+                       dac = RBIOS8(dac_info + 0x3) & 0xf;
+                       p_dac->ps2_pdac_adj = (bg << 8) | (dac);
+               }
+
+       }
+
+       return p_dac;
+}
+
+static enum radeon_tv_std
+radeon_combios_get_tv_info(struct radeon_encoder *encoder)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint16_t tv_info;
+       enum radeon_tv_std tv_std = TV_STD_NTSC;
+
+       tv_info = combios_get_table_offset(dev, COMBIOS_TV_INFO_TABLE);
+       if (tv_info) {
+               if (RBIOS8(tv_info + 6) == 'T') {
+                       switch (RBIOS8(tv_info + 7) & 0xf) {
+                       case 1:
+                               tv_std = TV_STD_NTSC;
+                               DRM_INFO("Default TV standard: NTSC\n");
+                               break;
+                       case 2:
+                               tv_std = TV_STD_PAL;
+                               DRM_INFO("Default TV standard: PAL\n");
+                               break;
+                       case 3:
+                               tv_std = TV_STD_PAL_M;
+                               DRM_INFO("Default TV standard: PAL-M\n");
+                               break;
+                       case 4:
+                               tv_std = TV_STD_PAL_60;
+                               DRM_INFO("Default TV standard: PAL-60\n");
+                               break;
+                       case 5:
+                               tv_std = TV_STD_NTSC_J;
+                               DRM_INFO("Default TV standard: NTSC-J\n");
+                               break;
+                       case 6:
+                               tv_std = TV_STD_SCART_PAL;
+                               DRM_INFO("Default TV standard: SCART-PAL\n");
+                               break;
+                       default:
+                               tv_std = TV_STD_NTSC;
+                               DRM_INFO
+                                   ("Unknown TV standard; defaulting to NTSC\n");
+                               break;
+                       }
+
+                       switch ((RBIOS8(tv_info + 9) >> 2) & 0x3) {
+                       case 0:
+                               DRM_INFO("29.498928713 MHz TV ref clk\n");
+                               break;
+                       case 1:
+                               DRM_INFO("28.636360000 MHz TV ref clk\n");
+                               break;
+                       case 2:
+                               DRM_INFO("14.318180000 MHz TV ref clk\n");
+                               break;
+                       case 3:
+                               DRM_INFO("27.000000000 MHz TV ref clk\n");
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
+       return tv_std;
+}
+
+static const uint32_t default_tvdac_adj[CHIP_LAST] = {
+       0x00000000,             /* r100  */
+       0x00280000,             /* rv100 */
+       0x00000000,             /* rs100 */
+       0x00880000,             /* rv200 */
+       0x00000000,             /* rs200 */
+       0x00000000,             /* r200  */
+       0x00770000,             /* rv250 */
+       0x00290000,             /* rs300 */
+       0x00560000,             /* rv280 */
+       0x00780000,             /* r300  */
+       0x00770000,             /* r350  */
+       0x00780000,             /* rv350 */
+       0x00780000,             /* rv380 */
+       0x01080000,             /* r420  */
+       0x01080000,             /* r423  */
+       0x01080000,             /* rv410 */
+       0x00780000,             /* rs400 */
+       0x00780000,             /* rs480 */
+};
+
+static struct radeon_encoder_tv_dac
+    *radeon_legacy_get_tv_dac_info_from_table(struct radeon_device *rdev)
+{
+       struct radeon_encoder_tv_dac *tv_dac = NULL;
+
+       tv_dac = kzalloc(sizeof(struct radeon_encoder_tv_dac), GFP_KERNEL);
+
+       if (!tv_dac)
+               return NULL;
+
+       tv_dac->ps2_tvdac_adj = default_tvdac_adj[rdev->family];
+       if ((rdev->flags & RADEON_IS_MOBILITY) && (rdev->family == CHIP_RV250))
+               tv_dac->ps2_tvdac_adj = 0x00880000;
+       tv_dac->pal_tvdac_adj = tv_dac->ps2_tvdac_adj;
+       tv_dac->ntsc_tvdac_adj = tv_dac->ps2_tvdac_adj;
+
+       return tv_dac;
+}
+
+struct radeon_encoder_tv_dac *radeon_combios_get_tv_dac_info(struct
+                                                            radeon_encoder
+                                                            *encoder)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint16_t dac_info;
+       uint8_t rev, bg, dac;
+       struct radeon_encoder_tv_dac *tv_dac = NULL;
+
+       if (rdev->bios == NULL)
+               return radeon_legacy_get_tv_dac_info_from_table(rdev);
+
+       /* first check TV table */
+       dac_info = combios_get_table_offset(dev, COMBIOS_TV_INFO_TABLE);
+       if (dac_info) {
+               tv_dac =
+                   kzalloc(sizeof(struct radeon_encoder_tv_dac), GFP_KERNEL);
+
+               if (!tv_dac)
+                       return NULL;
+
+               rev = RBIOS8(dac_info + 0x3);
+               if (rev > 4) {
+                       bg = RBIOS8(dac_info + 0xc) & 0xf;
+                       dac = RBIOS8(dac_info + 0xd) & 0xf;
+                       tv_dac->ps2_tvdac_adj = (bg << 16) | (dac << 20);
+
+                       bg = RBIOS8(dac_info + 0xe) & 0xf;
+                       dac = RBIOS8(dac_info + 0xf) & 0xf;
+                       tv_dac->pal_tvdac_adj = (bg << 16) | (dac << 20);
+
+                       bg = RBIOS8(dac_info + 0x10) & 0xf;
+                       dac = RBIOS8(dac_info + 0x11) & 0xf;
+                       tv_dac->ntsc_tvdac_adj = (bg << 16) | (dac << 20);
+               } else if (rev > 1) {
+                       bg = RBIOS8(dac_info + 0xc) & 0xf;
+                       dac = (RBIOS8(dac_info + 0xc) >> 4) & 0xf;
+                       tv_dac->ps2_tvdac_adj = (bg << 16) | (dac << 20);
+
+                       bg = RBIOS8(dac_info + 0xd) & 0xf;
+                       dac = (RBIOS8(dac_info + 0xd) >> 4) & 0xf;
+                       tv_dac->pal_tvdac_adj = (bg << 16) | (dac << 20);
+
+                       bg = RBIOS8(dac_info + 0xe) & 0xf;
+                       dac = (RBIOS8(dac_info + 0xe) >> 4) & 0xf;
+                       tv_dac->ntsc_tvdac_adj = (bg << 16) | (dac << 20);
+               }
+
+               tv_dac->tv_std = radeon_combios_get_tv_info(encoder);
+
+       } else {
+               /* then check CRT table */
+               dac_info =
+                   combios_get_table_offset(dev, COMBIOS_CRT_INFO_TABLE);
+               if (dac_info) {
+                       tv_dac =
+                           kzalloc(sizeof(struct radeon_encoder_tv_dac),
+                                   GFP_KERNEL);
+
+                       if (!tv_dac)
+                               return NULL;
+
+                       rev = RBIOS8(dac_info) & 0x3;
+                       if (rev < 2) {
+                               bg = RBIOS8(dac_info + 0x3) & 0xf;
+                               dac = (RBIOS8(dac_info + 0x3) >> 4) & 0xf;
+                               tv_dac->ps2_tvdac_adj =
+                                   (bg << 16) | (dac << 20);
+                               tv_dac->pal_tvdac_adj = tv_dac->ps2_tvdac_adj;
+                               tv_dac->ntsc_tvdac_adj = tv_dac->ps2_tvdac_adj;
+                       } else {
+                               bg = RBIOS8(dac_info + 0x4) & 0xf;
+                               dac = RBIOS8(dac_info + 0x5) & 0xf;
+                               tv_dac->ps2_tvdac_adj =
+                                   (bg << 16) | (dac << 20);
+                               tv_dac->pal_tvdac_adj = tv_dac->ps2_tvdac_adj;
+                               tv_dac->ntsc_tvdac_adj = tv_dac->ps2_tvdac_adj;
+                       }
+               } else {
+                       DRM_INFO("No TV DAC info found in BIOS\n");
+                       return radeon_legacy_get_tv_dac_info_from_table(rdev);
+               }
+       }
+
+       return tv_dac;
+}
+
+static struct radeon_encoder_lvds *radeon_legacy_get_lvds_info_from_regs(struct
+                                                                        radeon_device
+                                                                        *rdev)
+{
+       struct radeon_encoder_lvds *lvds = NULL;
+       uint32_t fp_vert_stretch, fp_horz_stretch;
+       uint32_t ppll_div_sel, ppll_val;
+
+       lvds = kzalloc(sizeof(struct radeon_encoder_lvds), GFP_KERNEL);
+
+       if (!lvds)
+               return NULL;
+
+       fp_vert_stretch = RREG32(RADEON_FP_VERT_STRETCH);
+       fp_horz_stretch = RREG32(RADEON_FP_HORZ_STRETCH);
+
+       if (fp_vert_stretch & RADEON_VERT_STRETCH_ENABLE)
+               lvds->native_mode.panel_yres =
+                   ((fp_vert_stretch & RADEON_VERT_PANEL_SIZE) >>
+                    RADEON_VERT_PANEL_SHIFT) + 1;
+       else
+               lvds->native_mode.panel_yres =
+                   (RREG32(RADEON_CRTC_V_TOTAL_DISP) >> 16) + 1;
+
+       if (fp_horz_stretch & RADEON_HORZ_STRETCH_ENABLE)
+               lvds->native_mode.panel_xres =
+                   (((fp_horz_stretch & RADEON_HORZ_PANEL_SIZE) >>
+                     RADEON_HORZ_PANEL_SHIFT) + 1) * 8;
+       else
+               lvds->native_mode.panel_xres =
+                   ((RREG32(RADEON_CRTC_H_TOTAL_DISP) >> 16) + 1) * 8;
+
+       if ((lvds->native_mode.panel_xres < 640) ||
+           (lvds->native_mode.panel_yres < 480)) {
+               lvds->native_mode.panel_xres = 640;
+               lvds->native_mode.panel_yres = 480;
+       }
+
+       ppll_div_sel = RREG8(RADEON_CLOCK_CNTL_INDEX + 1) & 0x3;
+       ppll_val = RREG32_PLL(RADEON_PPLL_DIV_0 + ppll_div_sel);
+       if ((ppll_val & 0x000707ff) == 0x1bb)
+               lvds->use_bios_dividers = false;
+       else {
+               lvds->panel_ref_divider =
+                   RREG32_PLL(RADEON_PPLL_REF_DIV) & 0x3ff;
+               lvds->panel_post_divider = (ppll_val >> 16) & 0x7;
+               lvds->panel_fb_divider = ppll_val & 0x7ff;
+
+               if ((lvds->panel_ref_divider != 0) &&
+                   (lvds->panel_fb_divider > 3))
+                       lvds->use_bios_dividers = true;
+       }
+       lvds->panel_vcc_delay = 200;
+
+       DRM_INFO("Panel info derived from registers\n");
+       DRM_INFO("Panel Size %dx%d\n", lvds->native_mode.panel_xres,
+                lvds->native_mode.panel_yres);
+
+       return lvds;
+}
+
+struct radeon_encoder_lvds *radeon_combios_get_lvds_info(struct radeon_encoder
+                                                        *encoder)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint16_t lcd_info;
+       uint32_t panel_setup;
+       char stmp[30];
+       int tmp, i;
+       struct radeon_encoder_lvds *lvds = NULL;
+
+       if (rdev->bios == NULL)
+               return radeon_legacy_get_lvds_info_from_regs(rdev);
+
+       lcd_info = combios_get_table_offset(dev, COMBIOS_LCD_INFO_TABLE);
+
+       if (lcd_info) {
+               lvds = kzalloc(sizeof(struct radeon_encoder_lvds), GFP_KERNEL);
+
+               if (!lvds)
+                       return NULL;
+
+               for (i = 0; i < 24; i++)
+                       stmp[i] = RBIOS8(lcd_info + i + 1);
+               stmp[24] = 0;
+
+               DRM_INFO("Panel ID String: %s\n", stmp);
+
+               lvds->native_mode.panel_xres = RBIOS16(lcd_info + 0x19);
+               lvds->native_mode.panel_yres = RBIOS16(lcd_info + 0x1b);
+
+               DRM_INFO("Panel Size %dx%d\n", lvds->native_mode.panel_xres,
+                        lvds->native_mode.panel_yres);
+
+               lvds->panel_vcc_delay = RBIOS16(lcd_info + 0x2c);
+               if (lvds->panel_vcc_delay > 2000 || lvds->panel_vcc_delay < 0)
+                       lvds->panel_vcc_delay = 2000;
+
+               lvds->panel_pwr_delay = RBIOS8(lcd_info + 0x24);
+               lvds->panel_digon_delay = RBIOS16(lcd_info + 0x38) & 0xf;
+               lvds->panel_blon_delay = (RBIOS16(lcd_info + 0x38) >> 4) & 0xf;
+
+               lvds->panel_ref_divider = RBIOS16(lcd_info + 0x2e);
+               lvds->panel_post_divider = RBIOS8(lcd_info + 0x30);
+               lvds->panel_fb_divider = RBIOS16(lcd_info + 0x31);
+               if ((lvds->panel_ref_divider != 0) &&
+                   (lvds->panel_fb_divider > 3))
+                       lvds->use_bios_dividers = true;
+
+               panel_setup = RBIOS32(lcd_info + 0x39);
+               lvds->lvds_gen_cntl = 0xff00;
+               if (panel_setup & 0x1)
+                       lvds->lvds_gen_cntl |= RADEON_LVDS_PANEL_FORMAT;
+
+               if ((panel_setup >> 4) & 0x1)
+                       lvds->lvds_gen_cntl |= RADEON_LVDS_PANEL_TYPE;
+
+               switch ((panel_setup >> 8) & 0x7) {
+               case 0:
+                       lvds->lvds_gen_cntl |= RADEON_LVDS_NO_FM;
+                       break;
+               case 1:
+                       lvds->lvds_gen_cntl |= RADEON_LVDS_2_GREY;
+                       break;
+               case 2:
+                       lvds->lvds_gen_cntl |= RADEON_LVDS_4_GREY;
+                       break;
+               default:
+                       break;
+               }
+
+               if ((panel_setup >> 16) & 0x1)
+                       lvds->lvds_gen_cntl |= RADEON_LVDS_FP_POL_LOW;
+
+               if ((panel_setup >> 17) & 0x1)
+                       lvds->lvds_gen_cntl |= RADEON_LVDS_LP_POL_LOW;
+
+               if ((panel_setup >> 18) & 0x1)
+                       lvds->lvds_gen_cntl |= RADEON_LVDS_DTM_POL_LOW;
+
+               if ((panel_setup >> 23) & 0x1)
+                       lvds->lvds_gen_cntl |= RADEON_LVDS_BL_CLK_SEL;
+
+               lvds->lvds_gen_cntl |= (panel_setup & 0xf0000000);
+
+               for (i = 0; i < 32; i++) {
+                       tmp = RBIOS16(lcd_info + 64 + i * 2);
+                       if (tmp == 0)
+                               break;
+
+                       if ((RBIOS16(tmp) == lvds->native_mode.panel_xres) &&
+                           (RBIOS16(tmp + 2) ==
+                            lvds->native_mode.panel_yres)) {
+                               lvds->native_mode.hblank =
+                                   (RBIOS16(tmp + 17) - RBIOS16(tmp + 19)) * 8;
+                               lvds->native_mode.hoverplus =
+                                   (RBIOS16(tmp + 21) - RBIOS16(tmp + 19) -
+                                    1) * 8;
+                               lvds->native_mode.hsync_width =
+                                   RBIOS8(tmp + 23) * 8;
+
+                               lvds->native_mode.vblank = (RBIOS16(tmp + 24) -
+                                                           RBIOS16(tmp + 26));
+                               lvds->native_mode.voverplus =
+                                   ((RBIOS16(tmp + 28) & 0x7ff) -
+                                    RBIOS16(tmp + 26));
+                               lvds->native_mode.vsync_width =
+                                   ((RBIOS16(tmp + 28) & 0xf800) >> 11);
+                               lvds->native_mode.dotclock =
+                                   RBIOS16(tmp + 9) * 10;
+                               lvds->native_mode.flags = 0;
+                       }
+               }
+               encoder->native_mode = lvds->native_mode;
+       } else {
+               DRM_INFO("No panel info found in BIOS\n");
+               return radeon_legacy_get_lvds_info_from_regs(rdev);
+       }
+       return lvds;
+}
+
+static const struct radeon_tmds_pll default_tmds_pll[CHIP_LAST][4] = {
+       {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}},  /* CHIP_R100  */
+       {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}},  /* CHIP_RV100 */
+       {{0, 0}, {0, 0}, {0, 0}, {0, 0}},       /* CHIP_RS100 */
+       {{15000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}},  /* CHIP_RV200 */
+       {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}},  /* CHIP_RS200 */
+       {{15000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}},  /* CHIP_R200  */
+       {{15500, 0x81b}, {0xffffffff, 0x83f}, {0, 0}, {0, 0}},  /* CHIP_RV250 */
+       {{0, 0}, {0, 0}, {0, 0}, {0, 0}},       /* CHIP_RS300 */
+       {{13000, 0x400f4}, {15000, 0x400f7}, {0xffffffff, 0x40111}, {0, 0}},    /* CHIP_RV280 */
+       {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}},        /* CHIP_R300  */
+       {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}},        /* CHIP_R350  */
+       {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}},      /* CHIP_RV350 */
+       {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}},      /* CHIP_RV380 */
+       {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}},        /* CHIP_R420  */
+       {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}},        /* CHIP_R423  */
+       {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}},        /* CHIP_RV410 */
+       {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}},      /* CHIP_RS400 */
+       {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}},      /* CHIP_RS480 */
+};
+
+static struct radeon_encoder_int_tmds
+    *radeon_legacy_get_tmds_info_from_table(struct radeon_device *rdev)
+{
+       int i;
+       struct radeon_encoder_int_tmds *tmds = NULL;
+
+       tmds = kzalloc(sizeof(struct radeon_encoder_int_tmds), GFP_KERNEL);
+
+       if (!tmds)
+               return NULL;
+
+       for (i = 0; i < 4; i++) {
+               tmds->tmds_pll[i].value =
+                   default_tmds_pll[rdev->family][i].value;
+               tmds->tmds_pll[i].freq = default_tmds_pll[rdev->family][i].freq;
+       }
+
+       return tmds;
+}
+
+struct radeon_encoder_int_tmds *radeon_combios_get_tmds_info(struct
+                                                            radeon_encoder
+                                                            *encoder)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint16_t tmds_info;
+       int i, n;
+       uint8_t ver;
+       struct radeon_encoder_int_tmds *tmds = NULL;
+
+       if (rdev->bios == NULL)
+               return radeon_legacy_get_tmds_info_from_table(rdev);
+
+       tmds_info = combios_get_table_offset(dev, COMBIOS_DFP_INFO_TABLE);
+
+       if (tmds_info) {
+               tmds =
+                   kzalloc(sizeof(struct radeon_encoder_int_tmds), GFP_KERNEL);
+
+               if (!tmds)
+                       return NULL;
+
+               ver = RBIOS8(tmds_info);
+               DRM_INFO("DFP table revision: %d\n", ver);
+               if (ver == 3) {
+                       n = RBIOS8(tmds_info + 5) + 1;
+                       if (n > 4)
+                               n = 4;
+                       for (i = 0; i < n; i++) {
+                               tmds->tmds_pll[i].value =
+                                   RBIOS32(tmds_info + i * 10 + 0x08);
+                               tmds->tmds_pll[i].freq =
+                                   RBIOS16(tmds_info + i * 10 + 0x10);
+                               DRM_DEBUG("TMDS PLL From COMBIOS %u %x\n",
+                                         tmds->tmds_pll[i].freq,
+                                         tmds->tmds_pll[i].value);
+                       }
+               } else if (ver == 4) {
+                       int stride = 0;
+                       n = RBIOS8(tmds_info + 5) + 1;
+                       if (n > 4)
+                               n = 4;
+                       for (i = 0; i < n; i++) {
+                               tmds->tmds_pll[i].value =
+                                   RBIOS32(tmds_info + stride + 0x08);
+                               tmds->tmds_pll[i].freq =
+                                   RBIOS16(tmds_info + stride + 0x10);
+                               if (i == 0)
+                                       stride += 10;
+                               else
+                                       stride += 6;
+                               DRM_DEBUG("TMDS PLL From COMBIOS %u %x\n",
+                                         tmds->tmds_pll[i].freq,
+                                         tmds->tmds_pll[i].value);
+                       }
+               }
+       } else
+               DRM_INFO("No TMDS info found in BIOS\n");
+       return tmds;
+}
+
+void radeon_combios_get_ext_tmds_info(struct radeon_encoder *encoder)
+{
+       struct drm_device *dev = encoder->base.dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint16_t ext_tmds_info;
+       uint8_t ver;
+
+       if (rdev->bios == NULL)
+               return;
+
+       ext_tmds_info =
+           combios_get_table_offset(dev, COMBIOS_EXT_TMDS_INFO_TABLE);
+       if (ext_tmds_info) {
+               ver = RBIOS8(ext_tmds_info);
+               DRM_INFO("External TMDS Table revision: %d\n", ver);
+               // TODO
+       }
+}
+
+bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_i2c_bus_rec ddc_i2c;
+
+       rdev->mode_info.connector_table = radeon_connector_table;
+       if (rdev->mode_info.connector_table == CT_NONE) {
+#ifdef CONFIG_PPC_PMAC
+               if (machine_is_compatible("PowerBook3,3")) {
+                       /* powerbook with VGA */
+                       rdev->mode_info.connector_table = CT_POWERBOOK_VGA;
+               } else if (machine_is_compatible("PowerBook3,4") ||
+                          machine_is_compatible("PowerBook3,5")) {
+                       /* powerbook with internal tmds */
+                       rdev->mode_info.connector_table = CT_POWERBOOK_INTERNAL;
+               } else if (machine_is_compatible("PowerBook5,1") ||
+                          machine_is_compatible("PowerBook5,2") ||
+                          machine_is_compatible("PowerBook5,3") ||
+                          machine_is_compatible("PowerBook5,4") ||
+                          machine_is_compatible("PowerBook5,5")) {
+                       /* powerbook with external single link tmds (sil164) */
+                       rdev->mode_info.connector_table = CT_POWERBOOK_EXTERNAL;
+               } else if (machine_is_compatible("PowerBook5,6")) {
+                       /* powerbook with external dual or single link tmds */
+                       rdev->mode_info.connector_table = CT_POWERBOOK_EXTERNAL;
+               } else if (machine_is_compatible("PowerBook5,7") ||
+                          machine_is_compatible("PowerBook5,8") ||
+                          machine_is_compatible("PowerBook5,9")) {
+                       /* PowerBook6,2 ? */
+                       /* powerbook with external dual link tmds (sil1178?) */
+                       rdev->mode_info.connector_table = CT_POWERBOOK_EXTERNAL;
+               } else if (machine_is_compatible("PowerBook4,1") ||
+                          machine_is_compatible("PowerBook4,2") ||
+                          machine_is_compatible("PowerBook4,3") ||
+                          machine_is_compatible("PowerBook6,3") ||
+                          machine_is_compatible("PowerBook6,5") ||
+                          machine_is_compatible("PowerBook6,7")) {
+                       /* ibook */
+                       rdev->mode_info.connector_table = CT_IBOOK;
+               } else if (machine_is_compatible("PowerMac4,4")) {
+                       /* emac */
+                       rdev->mode_info.connector_table = CT_EMAC;
+               } else if (machine_is_compatible("PowerMac10,1")) {
+                       /* mini with internal tmds */
+                       rdev->mode_info.connector_table = CT_MINI_INTERNAL;
+               } else if (machine_is_compatible("PowerMac10,2")) {
+                       /* mini with external tmds */
+                       rdev->mode_info.connector_table = CT_MINI_EXTERNAL;
+               } else if (machine_is_compatible("PowerMac12,1")) {
+                       /* PowerMac8,1 ? */
+                       /* imac g5 isight */
+                       rdev->mode_info.connector_table = CT_IMAC_G5_ISIGHT;
+               } else
+#endif /* CONFIG_PPC_PMAC */
+                       rdev->mode_info.connector_table = CT_GENERIC;
+       }
+
+       switch (rdev->mode_info.connector_table) {
+       case CT_GENERIC:
+               DRM_INFO("Connector Table: %d (generic)\n",
+                        rdev->mode_info.connector_table);
+               /* these are the most common settings */
+               if (rdev->flags & RADEON_SINGLE_CRTC) {
+                       /* VGA - primary dac */
+                       ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
+                       radeon_add_legacy_encoder(dev,
+                                                 radeon_get_encoder_id(dev,
+                                                                       ATOM_DEVICE_CRT1_SUPPORT,
+                                                                       1),
+                                                 ATOM_DEVICE_CRT1_SUPPORT);
+                       radeon_add_legacy_connector(dev, 0,
+                                                   ATOM_DEVICE_CRT1_SUPPORT,
+                                                   DRM_MODE_CONNECTOR_VGA,
+                                                   &ddc_i2c);
+               } else if (rdev->flags & RADEON_IS_MOBILITY) {
+                       /* LVDS */
+                       ddc_i2c = combios_setup_i2c_bus(RADEON_LCD_GPIO_MASK);
+                       radeon_add_legacy_encoder(dev,
+                                                 radeon_get_encoder_id(dev,
+                                                                       ATOM_DEVICE_LCD1_SUPPORT,
+                                                                       0),
+                                                 ATOM_DEVICE_LCD1_SUPPORT);
+                       radeon_add_legacy_connector(dev, 0,
+                                                   ATOM_DEVICE_LCD1_SUPPORT,
+                                                   DRM_MODE_CONNECTOR_LVDS,
+                                                   &ddc_i2c);
+
+                       /* VGA - primary dac */
+                       ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
+                       radeon_add_legacy_encoder(dev,
+                                                 radeon_get_encoder_id(dev,
+                                                                       ATOM_DEVICE_CRT1_SUPPORT,
+                                                                       1),
+                                                 ATOM_DEVICE_CRT1_SUPPORT);
+                       radeon_add_legacy_connector(dev, 1,
+                                                   ATOM_DEVICE_CRT1_SUPPORT,
+                                                   DRM_MODE_CONNECTOR_VGA,
+                                                   &ddc_i2c);
+               } else {
+                       /* DVI-I - tv dac, int tmds */
+                       ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
+                       radeon_add_legacy_encoder(dev,
+                                                 radeon_get_encoder_id(dev,
+                                                                       ATOM_DEVICE_DFP1_SUPPORT,
+                                                                       0),
+                                                 ATOM_DEVICE_DFP1_SUPPORT);
+                       radeon_add_legacy_encoder(dev,
+                                                 radeon_get_encoder_id(dev,
+                                                                       ATOM_DEVICE_CRT2_SUPPORT,
+                                                                       2),
+                                                 ATOM_DEVICE_CRT2_SUPPORT);
+                       radeon_add_legacy_connector(dev, 0,
+                                                   ATOM_DEVICE_DFP1_SUPPORT |
+                                                   ATOM_DEVICE_CRT2_SUPPORT,
+                                                   DRM_MODE_CONNECTOR_DVII,
+                                                   &ddc_i2c);
+
+                       /* VGA - primary dac */
+                       ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
+                       radeon_add_legacy_encoder(dev,
+                                                 radeon_get_encoder_id(dev,
+                                                                       ATOM_DEVICE_CRT1_SUPPORT,
+                                                                       1),
+                                                 ATOM_DEVICE_CRT1_SUPPORT);
+                       radeon_add_legacy_connector(dev, 1,
+                                                   ATOM_DEVICE_CRT1_SUPPORT,
+                                                   DRM_MODE_CONNECTOR_VGA,
+                                                   &ddc_i2c);
+               }
+
+               if (rdev->family != CHIP_R100 && rdev->family != CHIP_R200) {
+                       /* TV - tv dac */
+                       radeon_add_legacy_encoder(dev,
+                                                 radeon_get_encoder_id(dev,
+                                                                       ATOM_DEVICE_TV1_SUPPORT,
+                                                                       2),
+                                                 ATOM_DEVICE_TV1_SUPPORT);
+                       radeon_add_legacy_connector(dev, 2,
+                                                   ATOM_DEVICE_TV1_SUPPORT,
+                                                   DRM_MODE_CONNECTOR_SVIDEO,
+                                                   &ddc_i2c);
+               }
+               break;
+       case CT_IBOOK:
+               DRM_INFO("Connector Table: %d (ibook)\n",
+                        rdev->mode_info.connector_table);
+               /* LVDS */
+               ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_LCD1_SUPPORT,
+                                                               0),
+                                         ATOM_DEVICE_LCD1_SUPPORT);
+               radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_LCD1_SUPPORT,
+                                           DRM_MODE_CONNECTOR_LVDS, &ddc_i2c);
+               /* VGA - TV DAC */
+               ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_CRT2_SUPPORT,
+                                                               2),
+                                         ATOM_DEVICE_CRT2_SUPPORT);
+               radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_CRT2_SUPPORT,
+                                           DRM_MODE_CONNECTOR_VGA, &ddc_i2c);
+               /* TV - TV DAC */
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_TV1_SUPPORT,
+                                                               2),
+                                         ATOM_DEVICE_TV1_SUPPORT);
+               radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT,
+                                           DRM_MODE_CONNECTOR_SVIDEO,
+                                           &ddc_i2c);
+               break;
+       case CT_POWERBOOK_EXTERNAL:
+               DRM_INFO("Connector Table: %d (powerbook external tmds)\n",
+                        rdev->mode_info.connector_table);
+               /* LVDS */
+               ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_LCD1_SUPPORT,
+                                                               0),
+                                         ATOM_DEVICE_LCD1_SUPPORT);
+               radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_LCD1_SUPPORT,
+                                           DRM_MODE_CONNECTOR_LVDS, &ddc_i2c);
+               /* DVI-I - primary dac, ext tmds */
+               ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_DFP2_SUPPORT,
+                                                               0),
+                                         ATOM_DEVICE_DFP2_SUPPORT);
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_CRT1_SUPPORT,
+                                                               1),
+                                         ATOM_DEVICE_CRT1_SUPPORT);
+               radeon_add_legacy_connector(dev, 1,
+                                           ATOM_DEVICE_DFP2_SUPPORT |
+                                           ATOM_DEVICE_CRT1_SUPPORT,
+                                           DRM_MODE_CONNECTOR_DVII, &ddc_i2c);
+               /* TV - TV DAC */
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_TV1_SUPPORT,
+                                                               2),
+                                         ATOM_DEVICE_TV1_SUPPORT);
+               radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT,
+                                           DRM_MODE_CONNECTOR_SVIDEO,
+                                           &ddc_i2c);
+               break;
+       case CT_POWERBOOK_INTERNAL:
+               DRM_INFO("Connector Table: %d (powerbook internal tmds)\n",
+                        rdev->mode_info.connector_table);
+               /* LVDS */
+               ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_LCD1_SUPPORT,
+                                                               0),
+                                         ATOM_DEVICE_LCD1_SUPPORT);
+               radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_LCD1_SUPPORT,
+                                           DRM_MODE_CONNECTOR_LVDS, &ddc_i2c);
+               /* DVI-I - primary dac, int tmds */
+               ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_DFP1_SUPPORT,
+                                                               0),
+                                         ATOM_DEVICE_DFP1_SUPPORT);
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_CRT1_SUPPORT,
+                                                               1),
+                                         ATOM_DEVICE_CRT1_SUPPORT);
+               radeon_add_legacy_connector(dev, 1,
+                                           ATOM_DEVICE_DFP1_SUPPORT |
+                                           ATOM_DEVICE_CRT1_SUPPORT,
+                                           DRM_MODE_CONNECTOR_DVII, &ddc_i2c);
+               /* TV - TV DAC */
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_TV1_SUPPORT,
+                                                               2),
+                                         ATOM_DEVICE_TV1_SUPPORT);
+               radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT,
+                                           DRM_MODE_CONNECTOR_SVIDEO,
+                                           &ddc_i2c);
+               break;
+       case CT_POWERBOOK_VGA:
+               DRM_INFO("Connector Table: %d (powerbook vga)\n",
+                        rdev->mode_info.connector_table);
+               /* LVDS */
+               ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_LCD1_SUPPORT,
+                                                               0),
+                                         ATOM_DEVICE_LCD1_SUPPORT);
+               radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_LCD1_SUPPORT,
+                                           DRM_MODE_CONNECTOR_LVDS, &ddc_i2c);
+               /* VGA - primary dac */
+               ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_CRT1_SUPPORT,
+                                                               1),
+                                         ATOM_DEVICE_CRT1_SUPPORT);
+               radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_CRT1_SUPPORT,
+                                           DRM_MODE_CONNECTOR_VGA, &ddc_i2c);
+               /* TV - TV DAC */
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_TV1_SUPPORT,
+                                                               2),
+                                         ATOM_DEVICE_TV1_SUPPORT);
+               radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT,
+                                           DRM_MODE_CONNECTOR_SVIDEO,
+                                           &ddc_i2c);
+               break;
+       case CT_MINI_EXTERNAL:
+               DRM_INFO("Connector Table: %d (mini external tmds)\n",
+                        rdev->mode_info.connector_table);
+               /* DVI-I - tv dac, ext tmds */
+               ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_CRT2_DDC);
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_DFP2_SUPPORT,
+                                                               0),
+                                         ATOM_DEVICE_DFP2_SUPPORT);
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_CRT2_SUPPORT,
+                                                               2),
+                                         ATOM_DEVICE_CRT2_SUPPORT);
+               radeon_add_legacy_connector(dev, 0,
+                                           ATOM_DEVICE_DFP2_SUPPORT |
+                                           ATOM_DEVICE_CRT2_SUPPORT,
+                                           DRM_MODE_CONNECTOR_DVII, &ddc_i2c);
+               /* TV - TV DAC */
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_TV1_SUPPORT,
+                                                               2),
+                                         ATOM_DEVICE_TV1_SUPPORT);
+               radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_TV1_SUPPORT,
+                                           DRM_MODE_CONNECTOR_SVIDEO,
+                                           &ddc_i2c);
+               break;
+       case CT_MINI_INTERNAL:
+               DRM_INFO("Connector Table: %d (mini internal tmds)\n",
+                        rdev->mode_info.connector_table);
+               /* DVI-I - tv dac, int tmds */
+               ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_CRT2_DDC);
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_DFP1_SUPPORT,
+                                                               0),
+                                         ATOM_DEVICE_DFP1_SUPPORT);
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_CRT2_SUPPORT,
+                                                               2),
+                                         ATOM_DEVICE_CRT2_SUPPORT);
+               radeon_add_legacy_connector(dev, 0,
+                                           ATOM_DEVICE_DFP1_SUPPORT |
+                                           ATOM_DEVICE_CRT2_SUPPORT,
+                                           DRM_MODE_CONNECTOR_DVII, &ddc_i2c);
+               /* TV - TV DAC */
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_TV1_SUPPORT,
+                                                               2),
+                                         ATOM_DEVICE_TV1_SUPPORT);
+               radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_TV1_SUPPORT,
+                                           DRM_MODE_CONNECTOR_SVIDEO,
+                                           &ddc_i2c);
+               break;
+       case CT_IMAC_G5_ISIGHT:
+               DRM_INFO("Connector Table: %d (imac g5 isight)\n",
+                        rdev->mode_info.connector_table);
+               /* DVI-D - int tmds */
+               ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_MONID);
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_DFP1_SUPPORT,
+                                                               0),
+                                         ATOM_DEVICE_DFP1_SUPPORT);
+               radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_DFP1_SUPPORT,
+                                           DRM_MODE_CONNECTOR_DVID, &ddc_i2c);
+               /* VGA - tv dac */
+               ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_CRT2_SUPPORT,
+                                                               2),
+                                         ATOM_DEVICE_CRT2_SUPPORT);
+               radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_CRT2_SUPPORT,
+                                           DRM_MODE_CONNECTOR_VGA, &ddc_i2c);
+               /* TV - TV DAC */
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_TV1_SUPPORT,
+                                                               2),
+                                         ATOM_DEVICE_TV1_SUPPORT);
+               radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT,
+                                           DRM_MODE_CONNECTOR_SVIDEO,
+                                           &ddc_i2c);
+               break;
+       case CT_EMAC:
+               DRM_INFO("Connector Table: %d (emac)\n",
+                        rdev->mode_info.connector_table);
+               /* VGA - primary dac */
+               ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_CRT1_SUPPORT,
+                                                               1),
+                                         ATOM_DEVICE_CRT1_SUPPORT);
+               radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_CRT1_SUPPORT,
+                                           DRM_MODE_CONNECTOR_VGA, &ddc_i2c);
+               /* VGA - tv dac */
+               ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_CRT2_DDC);
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_CRT2_SUPPORT,
+                                                               2),
+                                         ATOM_DEVICE_CRT2_SUPPORT);
+               radeon_add_legacy_connector(dev, 1, ATOM_DEVICE_CRT2_SUPPORT,
+                                           DRM_MODE_CONNECTOR_VGA, &ddc_i2c);
+               /* TV - TV DAC */
+               radeon_add_legacy_encoder(dev,
+                                         radeon_get_encoder_id(dev,
+                                                               ATOM_DEVICE_TV1_SUPPORT,
+                                                               2),
+                                         ATOM_DEVICE_TV1_SUPPORT);
+               radeon_add_legacy_connector(dev, 2, ATOM_DEVICE_TV1_SUPPORT,
+                                           DRM_MODE_CONNECTOR_SVIDEO,
+                                           &ddc_i2c);
+               break;
+       default:
+               DRM_INFO("Connector table: %d (invalid)\n",
+                        rdev->mode_info.connector_table);
+               return false;
+       }
+
+       radeon_link_encoder_connector(dev);
+
+       return true;
+}
+
+static bool radeon_apply_legacy_quirks(struct drm_device *dev,
+                                      int bios_index,
+                                      enum radeon_combios_connector
+                                      *legacy_connector,
+                                      struct radeon_i2c_bus_rec *ddc_i2c)
+{
+       struct radeon_device *rdev = dev->dev_private;
+
+       /* XPRESS DDC quirks */
+       if ((rdev->family == CHIP_RS400 ||
+            rdev->family == CHIP_RS480) &&
+           ddc_i2c->mask_clk_reg == RADEON_GPIO_CRT2_DDC)
+               *ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_MONID);
+       else if ((rdev->family == CHIP_RS400 ||
+                 rdev->family == CHIP_RS480) &&
+                ddc_i2c->mask_clk_reg == RADEON_GPIO_MONID) {
+               ddc_i2c->valid = true;
+               ddc_i2c->mask_clk_mask = (0x20 << 8);
+               ddc_i2c->mask_data_mask = 0x80;
+               ddc_i2c->a_clk_mask = (0x20 << 8);
+               ddc_i2c->a_data_mask = 0x80;
+               ddc_i2c->put_clk_mask = (0x20 << 8);
+               ddc_i2c->put_data_mask = 0x80;
+               ddc_i2c->get_clk_mask = (0x20 << 8);
+               ddc_i2c->get_data_mask = 0x80;
+               ddc_i2c->mask_clk_reg = RADEON_GPIOPAD_MASK;
+               ddc_i2c->mask_data_reg = RADEON_GPIOPAD_MASK;
+               ddc_i2c->a_clk_reg = RADEON_GPIOPAD_A;
+               ddc_i2c->a_data_reg = RADEON_GPIOPAD_A;
+               ddc_i2c->put_clk_reg = RADEON_GPIOPAD_EN;
+               ddc_i2c->put_data_reg = RADEON_GPIOPAD_EN;
+               ddc_i2c->get_clk_reg = RADEON_LCD_GPIO_Y_REG;
+               ddc_i2c->get_data_reg = RADEON_LCD_GPIO_Y_REG;
+       }
+
+       /* Certain IBM chipset RN50s have a BIOS reporting two VGAs,
+          one with VGA DDC and one with CRT2 DDC. - kill the CRT2 DDC one */
+       if (dev->pdev->device == 0x515e &&
+           dev->pdev->subsystem_vendor == 0x1014) {
+               if (*legacy_connector == CONNECTOR_CRT_LEGACY &&
+                   ddc_i2c->mask_clk_reg == RADEON_GPIO_CRT2_DDC)
+                       return false;
+       }
+
+       /* Some RV100 cards with 2 VGA ports show up with DVI+VGA */
+       if (dev->pdev->device == 0x5159 &&
+           dev->pdev->subsystem_vendor == 0x1002 &&
+           dev->pdev->subsystem_device == 0x013a) {
+               if (*legacy_connector == CONNECTOR_DVI_I_LEGACY)
+                       *legacy_connector = CONNECTOR_CRT_LEGACY;
+
+       }
+
+       /* X300 card with extra non-existent DVI port */
+       if (dev->pdev->device == 0x5B60 &&
+           dev->pdev->subsystem_vendor == 0x17af &&
+           dev->pdev->subsystem_device == 0x201e && bios_index == 2) {
+               if (*legacy_connector == CONNECTOR_DVI_I_LEGACY)
+                       return false;
+       }
+
+       return true;
+}
+
+bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t conn_info, entry, devices;
+       uint16_t tmp;
+       enum radeon_combios_ddc ddc_type;
+       enum radeon_combios_connector connector;
+       int i = 0;
+       struct radeon_i2c_bus_rec ddc_i2c;
+
+       if (rdev->bios == NULL)
+               return false;
+
+       conn_info = combios_get_table_offset(dev, COMBIOS_CONNECTOR_INFO_TABLE);
+       if (conn_info) {
+               for (i = 0; i < 4; i++) {
+                       entry = conn_info + 2 + i * 2;
+
+                       if (!RBIOS16(entry))
+                               break;
+
+                       tmp = RBIOS16(entry);
+
+                       connector = (tmp >> 12) & 0xf;
+
+                       ddc_type = (tmp >> 8) & 0xf;
+                       switch (ddc_type) {
+                       case DDC_MONID:
+                               ddc_i2c =
+                                   combios_setup_i2c_bus(RADEON_GPIO_MONID);
+                               break;
+                       case DDC_DVI:
+                               ddc_i2c =
+                                   combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
+                               break;
+                       case DDC_VGA:
+                               ddc_i2c =
+                                   combios_setup_i2c_bus(RADEON_GPIO_VGA_DDC);
+                               break;
+                       case DDC_CRT2:
+                               ddc_i2c =
+                                   combios_setup_i2c_bus(RADEON_GPIO_CRT2_DDC);
+                               break;
+                       default:
+                               break;
+                       }
+
+                       radeon_apply_legacy_quirks(dev, i, &connector,
+                                                  &ddc_i2c);
+
+                       switch (connector) {
+                       case CONNECTOR_PROPRIETARY_LEGACY:
+                               if ((tmp >> 4) & 0x1)
+                                       devices = ATOM_DEVICE_DFP2_SUPPORT;
+                               else
+                                       devices = ATOM_DEVICE_DFP1_SUPPORT;
+                               radeon_add_legacy_encoder(dev,
+                                                         radeon_get_encoder_id
+                                                         (dev, devices, 0),
+                                                         devices);
+                               radeon_add_legacy_connector(dev, i, devices,
+                                                           legacy_connector_convert
+                                                           [connector],
+                                                           &ddc_i2c);
+                               break;
+                       case CONNECTOR_CRT_LEGACY:
+                               if (tmp & 0x1) {
+                                       devices = ATOM_DEVICE_CRT2_SUPPORT;
+                                       radeon_add_legacy_encoder(dev,
+                                                                 radeon_get_encoder_id
+                                                                 (dev,
+                                                                  ATOM_DEVICE_CRT2_SUPPORT,
+                                                                  2),
+                                                                 ATOM_DEVICE_CRT2_SUPPORT);
+                               } else {
+                                       devices = ATOM_DEVICE_CRT1_SUPPORT;
+                                       radeon_add_legacy_encoder(dev,
+                                                                 radeon_get_encoder_id
+                                                                 (dev,
+                                                                  ATOM_DEVICE_CRT1_SUPPORT,
+                                                                  1),
+                                                                 ATOM_DEVICE_CRT1_SUPPORT);
+                               }
+                               radeon_add_legacy_connector(dev,
+                                                           i,
+                                                           devices,
+                                                           legacy_connector_convert
+                                                           [connector],
+                                                           &ddc_i2c);
+                               break;
+                       case CONNECTOR_DVI_I_LEGACY:
+                               devices = 0;
+                               if (tmp & 0x1) {
+                                       devices |= ATOM_DEVICE_CRT2_SUPPORT;
+                                       radeon_add_legacy_encoder(dev,
+                                                                 radeon_get_encoder_id
+                                                                 (dev,
+                                                                  ATOM_DEVICE_CRT2_SUPPORT,
+                                                                  2),
+                                                                 ATOM_DEVICE_CRT2_SUPPORT);
+                               } else {
+                                       devices |= ATOM_DEVICE_CRT1_SUPPORT;
+                                       radeon_add_legacy_encoder(dev,
+                                                                 radeon_get_encoder_id
+                                                                 (dev,
+                                                                  ATOM_DEVICE_CRT1_SUPPORT,
+                                                                  1),
+                                                                 ATOM_DEVICE_CRT1_SUPPORT);
+                               }
+                               if ((tmp >> 4) & 0x1) {
+                                       devices |= ATOM_DEVICE_DFP2_SUPPORT;
+                                       radeon_add_legacy_encoder(dev,
+                                                                 radeon_get_encoder_id
+                                                                 (dev,
+                                                                  ATOM_DEVICE_DFP2_SUPPORT,
+                                                                  0),
+                                                                 ATOM_DEVICE_DFP2_SUPPORT);
+                               } else {
+                                       devices |= ATOM_DEVICE_DFP1_SUPPORT;
+                                       radeon_add_legacy_encoder(dev,
+                                                                 radeon_get_encoder_id
+                                                                 (dev,
+                                                                  ATOM_DEVICE_DFP1_SUPPORT,
+                                                                  0),
+                                                                 ATOM_DEVICE_DFP1_SUPPORT);
+                               }
+                               radeon_add_legacy_connector(dev,
+                                                           i,
+                                                           devices,
+                                                           legacy_connector_convert
+                                                           [connector],
+                                                           &ddc_i2c);
+                               break;
+                       case CONNECTOR_DVI_D_LEGACY:
+                               if ((tmp >> 4) & 0x1)
+                                       devices = ATOM_DEVICE_DFP2_SUPPORT;
+                               else
+                                       devices = ATOM_DEVICE_DFP1_SUPPORT;
+                               radeon_add_legacy_encoder(dev,
+                                                         radeon_get_encoder_id
+                                                         (dev, devices, 0),
+                                                         devices);
+                               radeon_add_legacy_connector(dev, i, devices,
+                                                           legacy_connector_convert
+                                                           [connector],
+                                                           &ddc_i2c);
+                               break;
+                       case CONNECTOR_CTV_LEGACY:
+                       case CONNECTOR_STV_LEGACY:
+                               radeon_add_legacy_encoder(dev,
+                                                         radeon_get_encoder_id
+                                                         (dev,
+                                                          ATOM_DEVICE_TV1_SUPPORT,
+                                                          2),
+                                                         ATOM_DEVICE_TV1_SUPPORT);
+                               radeon_add_legacy_connector(dev, i,
+                                                           ATOM_DEVICE_TV1_SUPPORT,
+                                                           legacy_connector_convert
+                                                           [connector],
+                                                           &ddc_i2c);
+                               break;
+                       default:
+                               DRM_ERROR("Unknown connector type: %d\n",
+                                         connector);
+                               continue;
+                       }
+
+               }
+       } else {
+               uint16_t tmds_info =
+                   combios_get_table_offset(dev, COMBIOS_DFP_INFO_TABLE);
+               if (tmds_info) {
+                       DRM_DEBUG("Found DFP table, assuming DVI connector\n");
+
+                       radeon_add_legacy_encoder(dev,
+                                                 radeon_get_encoder_id(dev,
+                                                                       ATOM_DEVICE_CRT1_SUPPORT,
+                                                                       1),
+                                                 ATOM_DEVICE_CRT1_SUPPORT);
+                       radeon_add_legacy_encoder(dev,
+                                                 radeon_get_encoder_id(dev,
+                                                                       ATOM_DEVICE_DFP1_SUPPORT,
+                                                                       0),
+                                                 ATOM_DEVICE_DFP1_SUPPORT);
+
+                       ddc_i2c = combios_setup_i2c_bus(RADEON_GPIO_DVI_DDC);
+                       radeon_add_legacy_connector(dev,
+                                                   0,
+                                                   ATOM_DEVICE_CRT1_SUPPORT |
+                                                   ATOM_DEVICE_DFP1_SUPPORT,
+                                                   DRM_MODE_CONNECTOR_DVII,
+                                                   &ddc_i2c);
+               } else {
+                       DRM_DEBUG("No connector info found\n");
+                       return false;
+               }
+       }
+
+       if (rdev->flags & RADEON_IS_MOBILITY || rdev->flags & RADEON_IS_IGP) {
+               uint16_t lcd_info =
+                   combios_get_table_offset(dev, COMBIOS_LCD_INFO_TABLE);
+               if (lcd_info) {
+                       uint16_t lcd_ddc_info =
+                           combios_get_table_offset(dev,
+                                                    COMBIOS_LCD_DDC_INFO_TABLE);
+
+                       radeon_add_legacy_encoder(dev,
+                                                 radeon_get_encoder_id(dev,
+                                                                       ATOM_DEVICE_LCD1_SUPPORT,
+                                                                       0),
+                                                 ATOM_DEVICE_LCD1_SUPPORT);
+
+                       if (lcd_ddc_info) {
+                               ddc_type = RBIOS8(lcd_ddc_info + 2);
+                               switch (ddc_type) {
+                               case DDC_MONID:
+                                       ddc_i2c =
+                                           combios_setup_i2c_bus
+                                           (RADEON_GPIO_MONID);
+                                       break;
+                               case DDC_DVI:
+                                       ddc_i2c =
+                                           combios_setup_i2c_bus
+                                           (RADEON_GPIO_DVI_DDC);
+                                       break;
+                               case DDC_VGA:
+                                       ddc_i2c =
+                                           combios_setup_i2c_bus
+                                           (RADEON_GPIO_VGA_DDC);
+                                       break;
+                               case DDC_CRT2:
+                                       ddc_i2c =
+                                           combios_setup_i2c_bus
+                                           (RADEON_GPIO_CRT2_DDC);
+                                       break;
+                               case DDC_LCD:
+                                       ddc_i2c =
+                                           combios_setup_i2c_bus
+                                           (RADEON_LCD_GPIO_MASK);
+                                       ddc_i2c.mask_clk_mask =
+                                           RBIOS32(lcd_ddc_info + 3);
+                                       ddc_i2c.mask_data_mask =
+                                           RBIOS32(lcd_ddc_info + 7);
+                                       ddc_i2c.a_clk_mask =
+                                           RBIOS32(lcd_ddc_info + 3);
+                                       ddc_i2c.a_data_mask =
+                                           RBIOS32(lcd_ddc_info + 7);
+                                       ddc_i2c.put_clk_mask =
+                                           RBIOS32(lcd_ddc_info + 3);
+                                       ddc_i2c.put_data_mask =
+                                           RBIOS32(lcd_ddc_info + 7);
+                                       ddc_i2c.get_clk_mask =
+                                           RBIOS32(lcd_ddc_info + 3);
+                                       ddc_i2c.get_data_mask =
+                                           RBIOS32(lcd_ddc_info + 7);
+                                       break;
+                               case DDC_GPIO:
+                                       ddc_i2c =
+                                           combios_setup_i2c_bus
+                                           (RADEON_MDGPIO_EN_REG);
+                                       ddc_i2c.mask_clk_mask =
+                                           RBIOS32(lcd_ddc_info + 3);
+                                       ddc_i2c.mask_data_mask =
+                                           RBIOS32(lcd_ddc_info + 7);
+                                       ddc_i2c.a_clk_mask =
+                                           RBIOS32(lcd_ddc_info + 3);
+                                       ddc_i2c.a_data_mask =
+                                           RBIOS32(lcd_ddc_info + 7);
+                                       ddc_i2c.put_clk_mask =
+                                           RBIOS32(lcd_ddc_info + 3);
+                                       ddc_i2c.put_data_mask =
+                                           RBIOS32(lcd_ddc_info + 7);
+                                       ddc_i2c.get_clk_mask =
+                                           RBIOS32(lcd_ddc_info + 3);
+                                       ddc_i2c.get_data_mask =
+                                           RBIOS32(lcd_ddc_info + 7);
+                                       break;
+                               default:
+                                       ddc_i2c.valid = false;
+                                       break;
+                               }
+                               DRM_DEBUG("LCD DDC Info Table found!\n");
+                       } else
+                               ddc_i2c.valid = false;
+
+                       radeon_add_legacy_connector(dev,
+                                                   5,
+                                                   ATOM_DEVICE_LCD1_SUPPORT,
+                                                   DRM_MODE_CONNECTOR_LVDS,
+                                                   &ddc_i2c);
+               }
+       }
+
+       /* check TV table */
+       if (rdev->family != CHIP_R100 && rdev->family != CHIP_R200) {
+               uint32_t tv_info =
+                   combios_get_table_offset(dev, COMBIOS_TV_INFO_TABLE);
+               if (tv_info) {
+                       if (RBIOS8(tv_info + 6) == 'T') {
+                               radeon_add_legacy_encoder(dev,
+                                                         radeon_get_encoder_id
+                                                         (dev,
+                                                          ATOM_DEVICE_TV1_SUPPORT,
+                                                          2),
+                                                         ATOM_DEVICE_TV1_SUPPORT);
+                               radeon_add_legacy_connector(dev, 6,
+                                                           ATOM_DEVICE_TV1_SUPPORT,
+                                                           DRM_MODE_CONNECTOR_SVIDEO,
+                                                           &ddc_i2c);
+                       }
+               }
+       }
+
+       radeon_link_encoder_connector(dev);
+
+       return true;
+}
+
+static void combios_parse_mmio_table(struct drm_device *dev, uint16_t offset)
+{
+       struct radeon_device *rdev = dev->dev_private;
+
+       if (offset) {
+               while (RBIOS16(offset)) {
+                       uint16_t cmd = ((RBIOS16(offset) & 0xe000) >> 13);
+                       uint32_t addr = (RBIOS16(offset) & 0x1fff);
+                       uint32_t val, and_mask, or_mask;
+                       uint32_t tmp;
+
+                       offset += 2;
+                       switch (cmd) {
+                       case 0:
+                               val = RBIOS32(offset);
+                               offset += 4;
+                               WREG32(addr, val);
+                               break;
+                       case 1:
+                               val = RBIOS32(offset);
+                               offset += 4;
+                               WREG32(addr, val);
+                               break;
+                       case 2:
+                               and_mask = RBIOS32(offset);
+                               offset += 4;
+                               or_mask = RBIOS32(offset);
+                               offset += 4;
+                               tmp = RREG32(addr);
+                               tmp &= and_mask;
+                               tmp |= or_mask;
+                               WREG32(addr, tmp);
+                               break;
+                       case 3:
+                               and_mask = RBIOS32(offset);
+                               offset += 4;
+                               or_mask = RBIOS32(offset);
+                               offset += 4;
+                               tmp = RREG32(addr);
+                               tmp &= and_mask;
+                               tmp |= or_mask;
+                               WREG32(addr, tmp);
+                               break;
+                       case 4:
+                               val = RBIOS16(offset);
+                               offset += 2;
+                               udelay(val);
+                               break;
+                       case 5:
+                               val = RBIOS16(offset);
+                               offset += 2;
+                               switch (addr) {
+                               case 8:
+                                       while (val--) {
+                                               if (!
+                                                   (RREG32_PLL
+                                                    (RADEON_CLK_PWRMGT_CNTL) &
+                                                    RADEON_MC_BUSY))
+                                                       break;
+                                       }
+                                       break;
+                               case 9:
+                                       while (val--) {
+                                               if ((RREG32(RADEON_MC_STATUS) &
+                                                    RADEON_MC_IDLE))
+                                                       break;
+                                       }
+                                       break;
+                               default:
+                                       break;
+                               }
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
+}
+
+static void combios_parse_pll_table(struct drm_device *dev, uint16_t offset)
+{
+       struct radeon_device *rdev = dev->dev_private;
+
+       if (offset) {
+               while (RBIOS8(offset)) {
+                       uint8_t cmd = ((RBIOS8(offset) & 0xc0) >> 6);
+                       uint8_t addr = (RBIOS8(offset) & 0x3f);
+                       uint32_t val, shift, tmp;
+                       uint32_t and_mask, or_mask;
+
+                       offset++;
+                       switch (cmd) {
+                       case 0:
+                               val = RBIOS32(offset);
+                               offset += 4;
+                               WREG32_PLL(addr, val);
+                               break;
+                       case 1:
+                               shift = RBIOS8(offset) * 8;
+                               offset++;
+                               and_mask = RBIOS8(offset) << shift;
+                               and_mask |= ~(0xff << shift);
+                               offset++;
+                               or_mask = RBIOS8(offset) << shift;
+                               offset++;
+                               tmp = RREG32_PLL(addr);
+                               tmp &= and_mask;
+                               tmp |= or_mask;
+                               WREG32_PLL(addr, tmp);
+                               break;
+                       case 2:
+                       case 3:
+                               tmp = 1000;
+                               switch (addr) {
+                               case 1:
+                                       udelay(150);
+                                       break;
+                               case 2:
+                                       udelay(1000);
+                                       break;
+                               case 3:
+                                       while (tmp--) {
+                                               if (!
+                                                   (RREG32_PLL
+                                                    (RADEON_CLK_PWRMGT_CNTL) &
+                                                    RADEON_MC_BUSY))
+                                                       break;
+                                       }
+                                       break;
+                               case 4:
+                                       while (tmp--) {
+                                               if (RREG32_PLL
+                                                   (RADEON_CLK_PWRMGT_CNTL) &
+                                                   RADEON_DLL_READY)
+                                                       break;
+                                       }
+                                       break;
+                               case 5:
+                                       tmp =
+                                           RREG32_PLL(RADEON_CLK_PWRMGT_CNTL);
+                                       if (tmp & RADEON_CG_NO1_DEBUG_0) {
+#if 0
+                                               uint32_t mclk_cntl =
+                                                   RREG32_PLL
+                                                   (RADEON_MCLK_CNTL);
+                                               mclk_cntl &= 0xffff0000;
+                                               /*mclk_cntl |= 0x00001111;*//* ??? */
+                                               WREG32_PLL(RADEON_MCLK_CNTL,
+                                                          mclk_cntl);
+                                               udelay(10000);
+#endif
+                                               WREG32_PLL
+                                                   (RADEON_CLK_PWRMGT_CNTL,
+                                                    tmp &
+                                                    ~RADEON_CG_NO1_DEBUG_0);
+                                               udelay(10000);
+                                       }
+                                       break;
+                               default:
+                                       break;
+                               }
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
+}
+
+static void combios_parse_ram_reset_table(struct drm_device *dev,
+                                         uint16_t offset)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t tmp;
+
+       if (offset) {
+               uint8_t val = RBIOS8(offset);
+               while (val != 0xff) {
+                       offset++;
+
+                       if (val == 0x0f) {
+                               uint32_t channel_complete_mask;
+
+                               if (ASIC_IS_R300(rdev))
+                                       channel_complete_mask =
+                                           R300_MEM_PWRUP_COMPLETE;
+                               else
+                                       channel_complete_mask =
+                                           RADEON_MEM_PWRUP_COMPLETE;
+                               tmp = 20000;
+                               while (tmp--) {
+                                       if ((RREG32(RADEON_MEM_STR_CNTL) &
+                                            channel_complete_mask) ==
+                                           channel_complete_mask)
+                                               break;
+                               }
+                       } else {
+                               uint32_t or_mask = RBIOS16(offset);
+                               offset += 2;
+
+                               tmp = RREG32(RADEON_MEM_SDRAM_MODE_REG);
+                               tmp &= RADEON_SDRAM_MODE_MASK;
+                               tmp |= or_mask;
+                               WREG32(RADEON_MEM_SDRAM_MODE_REG, tmp);
+
+                               or_mask = val << 24;
+                               tmp = RREG32(RADEON_MEM_SDRAM_MODE_REG);
+                               tmp &= RADEON_B3MEM_RESET_MASK;
+                               tmp |= or_mask;
+                               WREG32(RADEON_MEM_SDRAM_MODE_REG, tmp);
+                       }
+                       val = RBIOS8(offset);
+               }
+       }
+}
+
+static uint32_t combios_detect_ram(struct drm_device *dev, int ram,
+                                  int mem_addr_mapping)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t mem_cntl;
+       uint32_t mem_size;
+       uint32_t addr = 0;
+
+       mem_cntl = RREG32(RADEON_MEM_CNTL);
+       if (mem_cntl & RV100_HALF_MODE)
+               ram /= 2;
+       mem_size = ram;
+       mem_cntl &= ~(0xff << 8);
+       mem_cntl |= (mem_addr_mapping & 0xff) << 8;
+       WREG32(RADEON_MEM_CNTL, mem_cntl);
+       RREG32(RADEON_MEM_CNTL);
+
+       /* sdram reset ? */
+
+       /* something like this????  */
+       while (ram--) {
+               addr = ram * 1024 * 1024;
+               /* write to each page */
+               WREG32(RADEON_MM_INDEX, (addr) | RADEON_MM_APER);
+               WREG32(RADEON_MM_DATA, 0xdeadbeef);
+               /* read back and verify */
+               WREG32(RADEON_MM_INDEX, (addr) | RADEON_MM_APER);
+               if (RREG32(RADEON_MM_DATA) != 0xdeadbeef)
+                       return 0;
+       }
+
+       return mem_size;
+}
+
+static void combios_write_ram_size(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       uint8_t rev;
+       uint16_t offset;
+       uint32_t mem_size = 0;
+       uint32_t mem_cntl = 0;
+
+       /* should do something smarter here I guess... */
+       if (rdev->flags & RADEON_IS_IGP)
+               return;
+
+       /* first check detected mem table */
+       offset = combios_get_table_offset(dev, COMBIOS_DETECTED_MEM_TABLE);
+       if (offset) {
+               rev = RBIOS8(offset);
+               if (rev < 3) {
+                       mem_cntl = RBIOS32(offset + 1);
+                       mem_size = RBIOS16(offset + 5);
+                       if (((rdev->flags & RADEON_FAMILY_MASK) < CHIP_R200) &&
+                           ((dev->pdev->device != 0x515e)
+                            && (dev->pdev->device != 0x5969)))
+                               WREG32(RADEON_MEM_CNTL, mem_cntl);
+               }
+       }
+
+       if (!mem_size) {
+               offset =
+                   combios_get_table_offset(dev, COMBIOS_MEM_CONFIG_TABLE);
+               if (offset) {
+                       rev = RBIOS8(offset - 1);
+                       if (rev < 1) {
+                               if (((rdev->flags & RADEON_FAMILY_MASK) <
+                                    CHIP_R200)
+                                   && ((dev->pdev->device != 0x515e)
+                                       && (dev->pdev->device != 0x5969))) {
+                                       int ram = 0;
+                                       int mem_addr_mapping = 0;
+
+                                       while (RBIOS8(offset)) {
+                                               ram = RBIOS8(offset);
+                                               mem_addr_mapping =
+                                                   RBIOS8(offset + 1);
+                                               if (mem_addr_mapping != 0x25)
+                                                       ram *= 2;
+                                               mem_size =
+                                                   combios_detect_ram(dev, ram,
+                                                                      mem_addr_mapping);
+                                               if (mem_size)
+                                                       break;
+                                               offset += 2;
+                                       }
+                               } else
+                                       mem_size = RBIOS8(offset);
+                       } else {
+                               mem_size = RBIOS8(offset);
+                               mem_size *= 2;  /* convert to MB */
+                       }
+               }
+       }
+
+       mem_size *= (1024 * 1024);      /* convert to bytes */
+       WREG32(RADEON_CONFIG_MEMSIZE, mem_size);
+}
+
+void radeon_combios_dyn_clk_setup(struct drm_device *dev, int enable)
+{
+       uint16_t dyn_clk_info =
+           combios_get_table_offset(dev, COMBIOS_DYN_CLK_1_TABLE);
+
+       if (dyn_clk_info)
+               combios_parse_pll_table(dev, dyn_clk_info);
+}
+
+void radeon_combios_asic_init(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       uint16_t table;
+
+       /* port hardcoded mac stuff from radeonfb */
+       if (rdev->bios == NULL)
+               return;
+
+       /* ASIC INIT 1 */
+       table = combios_get_table_offset(dev, COMBIOS_ASIC_INIT_1_TABLE);
+       if (table)
+               combios_parse_mmio_table(dev, table);
+
+       /* PLL INIT */
+       table = combios_get_table_offset(dev, COMBIOS_PLL_INIT_TABLE);
+       if (table)
+               combios_parse_pll_table(dev, table);
+
+       /* ASIC INIT 2 */
+       table = combios_get_table_offset(dev, COMBIOS_ASIC_INIT_2_TABLE);
+       if (table)
+               combios_parse_mmio_table(dev, table);
+
+       if (!(rdev->flags & RADEON_IS_IGP)) {
+               /* ASIC INIT 4 */
+               table =
+                   combios_get_table_offset(dev, COMBIOS_ASIC_INIT_4_TABLE);
+               if (table)
+                       combios_parse_mmio_table(dev, table);
+
+               /* RAM RESET */
+               table = combios_get_table_offset(dev, COMBIOS_RAM_RESET_TABLE);
+               if (table)
+                       combios_parse_ram_reset_table(dev, table);
+
+               /* ASIC INIT 3 */
+               table =
+                   combios_get_table_offset(dev, COMBIOS_ASIC_INIT_3_TABLE);
+               if (table)
+                       combios_parse_mmio_table(dev, table);
+
+               /* write CONFIG_MEMSIZE */
+               combios_write_ram_size(dev);
+       }
+
+       /* DYN CLK 1 */
+       table = combios_get_table_offset(dev, COMBIOS_DYN_CLK_1_TABLE);
+       if (table)
+               combios_parse_pll_table(dev, table);
+
+}
+
+void radeon_combios_initialize_bios_scratch_regs(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t bios_0_scratch, bios_6_scratch, bios_7_scratch;
+
+       bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH);
+       bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH);
+       bios_7_scratch = RREG32(RADEON_BIOS_7_SCRATCH);
+
+       /* let the bios control the backlight */
+       bios_0_scratch &= ~RADEON_DRIVER_BRIGHTNESS_EN;
+
+       /* tell the bios not to handle mode switching */
+       bios_6_scratch |= (RADEON_DISPLAY_SWITCHING_DIS |
+                          RADEON_ACC_MODE_CHANGE);
+
+       /* tell the bios a driver is loaded */
+       bios_7_scratch |= RADEON_DRV_LOADED;
+
+       WREG32(RADEON_BIOS_0_SCRATCH, bios_0_scratch);
+       WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch);
+       WREG32(RADEON_BIOS_7_SCRATCH, bios_7_scratch);
+}
+
+void radeon_combios_output_lock(struct drm_encoder *encoder, bool lock)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t bios_6_scratch;
+
+       bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH);
+
+       if (lock)
+               bios_6_scratch |= RADEON_DRIVER_CRITICAL;
+       else
+               bios_6_scratch &= ~RADEON_DRIVER_CRITICAL;
+
+       WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch);
+}
+
+void
+radeon_combios_connected_scratch_regs(struct drm_connector *connector,
+                                     struct drm_encoder *encoder,
+                                     bool connected)
+{
+       struct drm_device *dev = connector->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_connector *radeon_connector =
+           to_radeon_connector(connector);
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       uint32_t bios_4_scratch = RREG32(RADEON_BIOS_4_SCRATCH);
+       uint32_t bios_5_scratch = RREG32(RADEON_BIOS_5_SCRATCH);
+
+       if ((radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) &&
+           (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT)) {
+               if (connected) {
+                       DRM_DEBUG("TV1 connected\n");
+                       /* fix me */
+                       bios_4_scratch |= RADEON_TV1_ATTACHED_SVIDEO;
+                       /*save->bios_4_scratch |= RADEON_TV1_ATTACHED_COMP; */
+                       bios_5_scratch |= RADEON_TV1_ON;
+                       bios_5_scratch |= RADEON_ACC_REQ_TV1;
+               } else {
+                       DRM_DEBUG("TV1 disconnected\n");
+                       bios_4_scratch &= ~RADEON_TV1_ATTACHED_MASK;
+                       bios_5_scratch &= ~RADEON_TV1_ON;
+                       bios_5_scratch &= ~RADEON_ACC_REQ_TV1;
+               }
+       }
+       if ((radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) &&
+           (radeon_connector->devices & ATOM_DEVICE_LCD1_SUPPORT)) {
+               if (connected) {
+                       DRM_DEBUG("LCD1 connected\n");
+                       bios_4_scratch |= RADEON_LCD1_ATTACHED;
+                       bios_5_scratch |= RADEON_LCD1_ON;
+                       bios_5_scratch |= RADEON_ACC_REQ_LCD1;
+               } else {
+                       DRM_DEBUG("LCD1 disconnected\n");
+                       bios_4_scratch &= ~RADEON_LCD1_ATTACHED;
+                       bios_5_scratch &= ~RADEON_LCD1_ON;
+                       bios_5_scratch &= ~RADEON_ACC_REQ_LCD1;
+               }
+       }
+       if ((radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) &&
+           (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT)) {
+               if (connected) {
+                       DRM_DEBUG("CRT1 connected\n");
+                       bios_4_scratch |= RADEON_CRT1_ATTACHED_COLOR;
+                       bios_5_scratch |= RADEON_CRT1_ON;
+                       bios_5_scratch |= RADEON_ACC_REQ_CRT1;
+               } else {
+                       DRM_DEBUG("CRT1 disconnected\n");
+                       bios_4_scratch &= ~RADEON_CRT1_ATTACHED_MASK;
+                       bios_5_scratch &= ~RADEON_CRT1_ON;
+                       bios_5_scratch &= ~RADEON_ACC_REQ_CRT1;
+               }
+       }
+       if ((radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) &&
+           (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT)) {
+               if (connected) {
+                       DRM_DEBUG("CRT2 connected\n");
+                       bios_4_scratch |= RADEON_CRT2_ATTACHED_COLOR;
+                       bios_5_scratch |= RADEON_CRT2_ON;
+                       bios_5_scratch |= RADEON_ACC_REQ_CRT2;
+               } else {
+                       DRM_DEBUG("CRT2 disconnected\n");
+                       bios_4_scratch &= ~RADEON_CRT2_ATTACHED_MASK;
+                       bios_5_scratch &= ~RADEON_CRT2_ON;
+                       bios_5_scratch &= ~RADEON_ACC_REQ_CRT2;
+               }
+       }
+       if ((radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) &&
+           (radeon_connector->devices & ATOM_DEVICE_DFP1_SUPPORT)) {
+               if (connected) {
+                       DRM_DEBUG("DFP1 connected\n");
+                       bios_4_scratch |= RADEON_DFP1_ATTACHED;
+                       bios_5_scratch |= RADEON_DFP1_ON;
+                       bios_5_scratch |= RADEON_ACC_REQ_DFP1;
+               } else {
+                       DRM_DEBUG("DFP1 disconnected\n");
+                       bios_4_scratch &= ~RADEON_DFP1_ATTACHED;
+                       bios_5_scratch &= ~RADEON_DFP1_ON;
+                       bios_5_scratch &= ~RADEON_ACC_REQ_DFP1;
+               }
+       }
+       if ((radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) &&
+           (radeon_connector->devices & ATOM_DEVICE_DFP2_SUPPORT)) {
+               if (connected) {
+                       DRM_DEBUG("DFP2 connected\n");
+                       bios_4_scratch |= RADEON_DFP2_ATTACHED;
+                       bios_5_scratch |= RADEON_DFP2_ON;
+                       bios_5_scratch |= RADEON_ACC_REQ_DFP2;
+               } else {
+                       DRM_DEBUG("DFP2 disconnected\n");
+                       bios_4_scratch &= ~RADEON_DFP2_ATTACHED;
+                       bios_5_scratch &= ~RADEON_DFP2_ON;
+                       bios_5_scratch &= ~RADEON_ACC_REQ_DFP2;
+               }
+       }
+       WREG32(RADEON_BIOS_4_SCRATCH, bios_4_scratch);
+       WREG32(RADEON_BIOS_5_SCRATCH, bios_5_scratch);
+}
+
+void
+radeon_combios_encoder_crtc_scratch_regs(struct drm_encoder *encoder, int crtc)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       uint32_t bios_5_scratch = RREG32(RADEON_BIOS_5_SCRATCH);
+
+       if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) {
+               bios_5_scratch &= ~RADEON_TV1_CRTC_MASK;
+               bios_5_scratch |= (crtc << RADEON_TV1_CRTC_SHIFT);
+       }
+       if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) {
+               bios_5_scratch &= ~RADEON_CRT1_CRTC_MASK;
+               bios_5_scratch |= (crtc << RADEON_CRT1_CRTC_SHIFT);
+       }
+       if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) {
+               bios_5_scratch &= ~RADEON_CRT2_CRTC_MASK;
+               bios_5_scratch |= (crtc << RADEON_CRT2_CRTC_SHIFT);
+       }
+       if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) {
+               bios_5_scratch &= ~RADEON_LCD1_CRTC_MASK;
+               bios_5_scratch |= (crtc << RADEON_LCD1_CRTC_SHIFT);
+       }
+       if (radeon_encoder->devices & ATOM_DEVICE_DFP1_SUPPORT) {
+               bios_5_scratch &= ~RADEON_DFP1_CRTC_MASK;
+               bios_5_scratch |= (crtc << RADEON_DFP1_CRTC_SHIFT);
+       }
+       if (radeon_encoder->devices & ATOM_DEVICE_DFP2_SUPPORT) {
+               bios_5_scratch &= ~RADEON_DFP2_CRTC_MASK;
+               bios_5_scratch |= (crtc << RADEON_DFP2_CRTC_SHIFT);
+       }
+       WREG32(RADEON_BIOS_5_SCRATCH, bios_5_scratch);
+}
+
+void
+radeon_combios_encoder_dpms_scratch_regs(struct drm_encoder *encoder, bool on)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       uint32_t bios_6_scratch = RREG32(RADEON_BIOS_6_SCRATCH);
+
+       if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) {
+               if (on)
+                       bios_6_scratch |= RADEON_TV_DPMS_ON;
+               else
+                       bios_6_scratch &= ~RADEON_TV_DPMS_ON;
+       }
+       if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) {
+               if (on)
+                       bios_6_scratch |= RADEON_CRT_DPMS_ON;
+               else
+                       bios_6_scratch &= ~RADEON_CRT_DPMS_ON;
+       }
+       if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+               if (on)
+                       bios_6_scratch |= RADEON_LCD_DPMS_ON;
+               else
+                       bios_6_scratch &= ~RADEON_LCD_DPMS_ON;
+       }
+       if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
+               if (on)
+                       bios_6_scratch |= RADEON_DFP_DPMS_ON;
+               else
+                       bios_6_scratch &= ~RADEON_DFP_DPMS_ON;
+       }
+       WREG32(RADEON_BIOS_6_SCRATCH, bios_6_scratch);
+}
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
new file mode 100644 (file)
index 0000000..70ede6a
--- /dev/null
@@ -0,0 +1,603 @@
+/*
+ * Copyright 2007-8 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ */
+#include "drmP.h"
+#include "drm_edid.h"
+#include "drm_crtc_helper.h"
+#include "radeon_drm.h"
+#include "radeon.h"
+
+extern void
+radeon_combios_connected_scratch_regs(struct drm_connector *connector,
+                                     struct drm_encoder *encoder,
+                                     bool connected);
+extern void
+radeon_atombios_connected_scratch_regs(struct drm_connector *connector,
+                                      struct drm_encoder *encoder,
+                                      bool connected);
+
+static void
+radeon_connector_update_scratch_regs(struct drm_connector *connector, enum drm_connector_status status)
+{
+       struct drm_device *dev = connector->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct drm_encoder *best_encoder = NULL;
+       struct drm_encoder *encoder = NULL;
+       struct drm_connector_helper_funcs *connector_funcs = connector->helper_private;
+       struct drm_mode_object *obj;
+       bool connected;
+       int i;
+
+       best_encoder = connector_funcs->best_encoder(connector);
+
+       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+               if (connector->encoder_ids[i] == 0)
+                       break;
+
+               obj = drm_mode_object_find(connector->dev,
+                                          connector->encoder_ids[i],
+                                          DRM_MODE_OBJECT_ENCODER);
+               if (!obj)
+                       continue;
+
+               encoder = obj_to_encoder(obj);
+
+               if ((encoder == best_encoder) && (status == connector_status_connected))
+                       connected = true;
+               else
+                       connected = false;
+
+               if (rdev->is_atom_bios)
+                       radeon_atombios_connected_scratch_regs(connector, encoder, connected);
+               else
+                       radeon_combios_connected_scratch_regs(connector, encoder, connected);
+
+       }
+}
+
+struct drm_encoder *radeon_best_single_encoder(struct drm_connector *connector)
+{
+       int enc_id = connector->encoder_ids[0];
+       struct drm_mode_object *obj;
+       struct drm_encoder *encoder;
+
+       /* pick the encoder ids */
+       if (enc_id) {
+               obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER);
+               if (!obj)
+                       return NULL;
+               encoder = obj_to_encoder(obj);
+               return encoder;
+       }
+       return NULL;
+}
+
+static struct drm_display_mode *radeon_fp_native_mode(struct drm_encoder *encoder)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct drm_display_mode *mode = NULL;
+       struct radeon_native_mode *native_mode = &radeon_encoder->native_mode;
+
+       if (native_mode->panel_xres != 0 &&
+           native_mode->panel_yres != 0 &&
+           native_mode->dotclock != 0) {
+               mode = drm_mode_create(dev);
+
+               mode->hdisplay = native_mode->panel_xres;
+               mode->vdisplay = native_mode->panel_yres;
+
+               mode->htotal = mode->hdisplay + native_mode->hblank;
+               mode->hsync_start = mode->hdisplay + native_mode->hoverplus;
+               mode->hsync_end = mode->hsync_start + native_mode->hsync_width;
+               mode->vtotal = mode->vdisplay + native_mode->vblank;
+               mode->vsync_start = mode->vdisplay + native_mode->voverplus;
+               mode->vsync_end = mode->vsync_start + native_mode->vsync_width;
+               mode->clock = native_mode->dotclock;
+               mode->flags = 0;
+
+               mode->type = DRM_MODE_TYPE_PREFERRED | DRM_MODE_TYPE_DRIVER;
+               drm_mode_set_name(mode);
+
+               DRM_DEBUG("Adding native panel mode %s\n", mode->name);
+       }
+       return mode;
+}
+
+int radeon_connector_set_property(struct drm_connector *connector, struct drm_property *property,
+                                 uint64_t val)
+{
+       return 0;
+}
+
+
+static int radeon_lvds_get_modes(struct drm_connector *connector)
+{
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       struct drm_encoder *encoder;
+       int ret = 0;
+       struct drm_display_mode *mode;
+
+       if (radeon_connector->ddc_bus) {
+               ret = radeon_ddc_get_modes(radeon_connector);
+               if (ret > 0) {
+                       return ret;
+               }
+       }
+
+       encoder = radeon_best_single_encoder(connector);
+       if (!encoder)
+               return 0;
+
+       /* we have no EDID modes */
+       mode = radeon_fp_native_mode(encoder);
+       if (mode) {
+               ret = 1;
+               drm_mode_probed_add(connector, mode);
+       }
+       return ret;
+}
+
+static int radeon_lvds_mode_valid(struct drm_connector *connector,
+                                 struct drm_display_mode *mode)
+{
+       return MODE_OK;
+}
+
+static enum drm_connector_status radeon_lvds_detect(struct drm_connector *connector)
+{
+       enum drm_connector_status ret = connector_status_connected;
+       /* check acpi lid status ??? */
+       radeon_connector_update_scratch_regs(connector, ret);
+       return ret;
+}
+
+static void radeon_connector_destroy(struct drm_connector *connector)
+{
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+
+       if (radeon_connector->ddc_bus)
+               radeon_i2c_destroy(radeon_connector->ddc_bus);
+       kfree(radeon_connector->con_priv);
+       drm_sysfs_connector_remove(connector);
+       drm_connector_cleanup(connector);
+       kfree(connector);
+}
+
+struct drm_connector_helper_funcs radeon_lvds_connector_helper_funcs = {
+       .get_modes = radeon_lvds_get_modes,
+       .mode_valid = radeon_lvds_mode_valid,
+       .best_encoder = radeon_best_single_encoder,
+};
+
+struct drm_connector_funcs radeon_lvds_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .detect = radeon_lvds_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .destroy = radeon_connector_destroy,
+       .set_property = radeon_connector_set_property,
+};
+
+static int radeon_vga_get_modes(struct drm_connector *connector)
+{
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       int ret;
+
+       ret = radeon_ddc_get_modes(radeon_connector);
+
+       return ret;
+}
+
+static int radeon_vga_mode_valid(struct drm_connector *connector,
+                                 struct drm_display_mode *mode)
+{
+
+       return MODE_OK;
+}
+
+static enum drm_connector_status radeon_vga_detect(struct drm_connector *connector)
+{
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       struct drm_encoder *encoder;
+       struct drm_encoder_helper_funcs *encoder_funcs;
+       bool dret;
+       enum drm_connector_status ret = connector_status_disconnected;
+
+       radeon_i2c_do_lock(radeon_connector, 1);
+       dret = radeon_ddc_probe(radeon_connector);
+       radeon_i2c_do_lock(radeon_connector, 0);
+       if (dret)
+               ret = connector_status_connected;
+       else {
+               /* if EDID fails to a load detect */
+               encoder = radeon_best_single_encoder(connector);
+               if (!encoder)
+                       ret = connector_status_disconnected;
+               else {
+                       encoder_funcs = encoder->helper_private;
+                       ret = encoder_funcs->detect(encoder, connector);
+               }
+       }
+
+       radeon_connector_update_scratch_regs(connector, ret);
+       return ret;
+}
+
+struct drm_connector_helper_funcs radeon_vga_connector_helper_funcs = {
+       .get_modes = radeon_vga_get_modes,
+       .mode_valid = radeon_vga_mode_valid,
+       .best_encoder = radeon_best_single_encoder,
+};
+
+struct drm_connector_funcs radeon_vga_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .detect = radeon_vga_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .destroy = radeon_connector_destroy,
+       .set_property = radeon_connector_set_property,
+};
+
+static int radeon_dvi_get_modes(struct drm_connector *connector)
+{
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       int ret;
+
+       ret = radeon_ddc_get_modes(radeon_connector);
+       /* reset scratch regs here since radeon_dvi_detect doesn't check digital bit */
+       radeon_connector_update_scratch_regs(connector, connector_status_connected);
+       return ret;
+}
+
+static enum drm_connector_status radeon_dvi_detect(struct drm_connector *connector)
+{
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       struct drm_encoder *encoder;
+       struct drm_encoder_helper_funcs *encoder_funcs;
+       struct drm_mode_object *obj;
+       int i;
+       enum drm_connector_status ret = connector_status_disconnected;
+       bool dret;
+
+       radeon_i2c_do_lock(radeon_connector, 1);
+       dret = radeon_ddc_probe(radeon_connector);
+       radeon_i2c_do_lock(radeon_connector, 0);
+       if (dret)
+               ret = connector_status_connected;
+       else {
+               for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+                       if (connector->encoder_ids[i] == 0)
+                               break;
+
+                       obj = drm_mode_object_find(connector->dev,
+                                                  connector->encoder_ids[i],
+                                                  DRM_MODE_OBJECT_ENCODER);
+                       if (!obj)
+                               continue;
+
+                       encoder = obj_to_encoder(obj);
+
+                       encoder_funcs = encoder->helper_private;
+                       if (encoder_funcs->detect) {
+                               ret = encoder_funcs->detect(encoder, connector);
+                               if (ret == connector_status_connected) {
+                                       radeon_connector->use_digital = 0;
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       /* updated in get modes as well since we need to know if it's analog or digital */
+       radeon_connector_update_scratch_regs(connector, ret);
+       return ret;
+}
+
+/* okay need to be smart in here about which encoder to pick */
+struct drm_encoder *radeon_dvi_encoder(struct drm_connector *connector)
+{
+       int enc_id = connector->encoder_ids[0];
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       struct drm_mode_object *obj;
+       struct drm_encoder *encoder;
+       int i;
+       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+               if (connector->encoder_ids[i] == 0)
+                       break;
+
+               obj = drm_mode_object_find(connector->dev, connector->encoder_ids[i], DRM_MODE_OBJECT_ENCODER);
+               if (!obj)
+                       continue;
+
+               encoder = obj_to_encoder(obj);
+
+               if (radeon_connector->use_digital) {
+                       if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)
+                               return encoder;
+               } else {
+                       if (encoder->encoder_type == DRM_MODE_ENCODER_DAC ||
+                           encoder->encoder_type == DRM_MODE_ENCODER_TVDAC)
+                               return encoder;
+               }
+       }
+
+       /* see if we have a default encoder  TODO */
+
+       /* then check use digitial */
+       /* pick the first one */
+       if (enc_id) {
+               obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER);
+               if (!obj)
+                       return NULL;
+               encoder = obj_to_encoder(obj);
+               return encoder;
+       }
+       return NULL;
+}
+
+struct drm_connector_helper_funcs radeon_dvi_connector_helper_funcs = {
+       .get_modes = radeon_dvi_get_modes,
+       .mode_valid = radeon_vga_mode_valid,
+       .best_encoder = radeon_dvi_encoder,
+};
+
+struct drm_connector_funcs radeon_dvi_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .detect = radeon_dvi_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .set_property = radeon_connector_set_property,
+       .destroy = radeon_connector_destroy,
+};
+
+void
+radeon_add_atom_connector(struct drm_device *dev,
+                         uint32_t connector_id,
+                         uint32_t supported_device,
+                         int connector_type,
+                         struct radeon_i2c_bus_rec *i2c_bus,
+                         bool linkb,
+                         uint32_t igp_lane_info)
+{
+       struct drm_connector *connector;
+       struct radeon_connector *radeon_connector;
+       struct radeon_connector_atom_dig *radeon_dig_connector;
+       uint32_t subpixel_order = SubPixelNone;
+
+       /* fixme - tv/cv/din */
+       if ((connector_type == DRM_MODE_CONNECTOR_Unknown) ||
+           (connector_type == DRM_MODE_CONNECTOR_SVIDEO) ||
+           (connector_type == DRM_MODE_CONNECTOR_Composite) ||
+           (connector_type == DRM_MODE_CONNECTOR_9PinDIN))
+               return;
+
+       /* see if we already added it */
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               radeon_connector = to_radeon_connector(connector);
+               if (radeon_connector->connector_id == connector_id) {
+                       radeon_connector->devices |= supported_device;
+                       return;
+               }
+       }
+
+       radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL);
+       if (!radeon_connector)
+               return;
+
+       connector = &radeon_connector->base;
+
+       radeon_connector->connector_id = connector_id;
+       radeon_connector->devices = supported_device;
+       switch (connector_type) {
+       case DRM_MODE_CONNECTOR_VGA:
+               drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
+               drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
+               if (i2c_bus->valid) {
+                       radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA");
+                       if (!radeon_connector->ddc_bus)
+                               goto failed;
+               }
+               break;
+       case DRM_MODE_CONNECTOR_DVIA:
+               drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
+               drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
+               if (i2c_bus->valid) {
+                       radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
+                       if (!radeon_connector->ddc_bus)
+                               goto failed;
+               }
+               break;
+       case DRM_MODE_CONNECTOR_DVII:
+       case DRM_MODE_CONNECTOR_DVID:
+               radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
+               if (!radeon_dig_connector)
+                       goto failed;
+               radeon_dig_connector->linkb = linkb;
+               radeon_dig_connector->igp_lane_info = igp_lane_info;
+               radeon_connector->con_priv = radeon_dig_connector;
+               drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
+               drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
+               if (i2c_bus->valid) {
+                       radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
+                       if (!radeon_connector->ddc_bus)
+                               goto failed;
+               }
+               subpixel_order = SubPixelHorizontalRGB;
+               break;
+       case DRM_MODE_CONNECTOR_HDMIA:
+       case DRM_MODE_CONNECTOR_HDMIB:
+               radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
+               if (!radeon_dig_connector)
+                       goto failed;
+               radeon_dig_connector->linkb = linkb;
+               radeon_dig_connector->igp_lane_info = igp_lane_info;
+               radeon_connector->con_priv = radeon_dig_connector;
+               drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
+               drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
+               if (i2c_bus->valid) {
+                       radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "HDMI");
+                       if (!radeon_connector->ddc_bus)
+                               goto failed;
+               }
+               subpixel_order = SubPixelHorizontalRGB;
+               break;
+       case DRM_MODE_CONNECTOR_DisplayPort:
+               radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
+               if (!radeon_dig_connector)
+                       goto failed;
+               radeon_dig_connector->linkb = linkb;
+               radeon_dig_connector->igp_lane_info = igp_lane_info;
+               radeon_connector->con_priv = radeon_dig_connector;
+               drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
+               drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
+               if (i2c_bus->valid) {
+                       radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DP");
+                       if (!radeon_connector->ddc_bus)
+                               goto failed;
+               }
+               subpixel_order = SubPixelHorizontalRGB;
+               break;
+       case DRM_MODE_CONNECTOR_SVIDEO:
+       case DRM_MODE_CONNECTOR_Composite:
+       case DRM_MODE_CONNECTOR_9PinDIN:
+               break;
+       case DRM_MODE_CONNECTOR_LVDS:
+               radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
+               if (!radeon_dig_connector)
+                       goto failed;
+               radeon_dig_connector->linkb = linkb;
+               radeon_dig_connector->igp_lane_info = igp_lane_info;
+               radeon_connector->con_priv = radeon_dig_connector;
+               drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
+               drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
+               if (i2c_bus->valid) {
+                       radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS");
+                       if (!radeon_connector->ddc_bus)
+                               goto failed;
+               }
+               subpixel_order = SubPixelHorizontalRGB;
+               break;
+       }
+
+       connector->display_info.subpixel_order = subpixel_order;
+       drm_sysfs_connector_add(connector);
+       return;
+
+failed:
+       if (radeon_connector->ddc_bus)
+               radeon_i2c_destroy(radeon_connector->ddc_bus);
+       drm_connector_cleanup(connector);
+       kfree(connector);
+}
+
+void
+radeon_add_legacy_connector(struct drm_device *dev,
+                           uint32_t connector_id,
+                           uint32_t supported_device,
+                           int connector_type,
+                           struct radeon_i2c_bus_rec *i2c_bus)
+{
+       struct drm_connector *connector;
+       struct radeon_connector *radeon_connector;
+       uint32_t subpixel_order = SubPixelNone;
+
+       /* fixme - tv/cv/din */
+       if ((connector_type == DRM_MODE_CONNECTOR_Unknown) ||
+           (connector_type == DRM_MODE_CONNECTOR_SVIDEO) ||
+           (connector_type == DRM_MODE_CONNECTOR_Composite) ||
+           (connector_type == DRM_MODE_CONNECTOR_9PinDIN))
+               return;
+
+       /* see if we already added it */
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               radeon_connector = to_radeon_connector(connector);
+               if (radeon_connector->connector_id == connector_id) {
+                       radeon_connector->devices |= supported_device;
+                       return;
+               }
+       }
+
+       radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL);
+       if (!radeon_connector)
+               return;
+
+       connector = &radeon_connector->base;
+
+       radeon_connector->connector_id = connector_id;
+       radeon_connector->devices = supported_device;
+       switch (connector_type) {
+       case DRM_MODE_CONNECTOR_VGA:
+               drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
+               drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
+               if (i2c_bus->valid) {
+                       radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA");
+                       if (!radeon_connector->ddc_bus)
+                               goto failed;
+               }
+               break;
+       case DRM_MODE_CONNECTOR_DVIA:
+               drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
+               drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
+               if (i2c_bus->valid) {
+                       radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
+                       if (!radeon_connector->ddc_bus)
+                               goto failed;
+               }
+               break;
+       case DRM_MODE_CONNECTOR_DVII:
+       case DRM_MODE_CONNECTOR_DVID:
+               drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
+               drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
+               if (i2c_bus->valid) {
+                       radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
+                       if (!radeon_connector->ddc_bus)
+                               goto failed;
+               }
+               subpixel_order = SubPixelHorizontalRGB;
+               break;
+       case DRM_MODE_CONNECTOR_SVIDEO:
+       case DRM_MODE_CONNECTOR_Composite:
+       case DRM_MODE_CONNECTOR_9PinDIN:
+               break;
+       case DRM_MODE_CONNECTOR_LVDS:
+               drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
+               drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
+               if (i2c_bus->valid) {
+                       radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS");
+                       if (!radeon_connector->ddc_bus)
+                               goto failed;
+               }
+               subpixel_order = SubPixelHorizontalRGB;
+               break;
+       }
+
+       connector->display_info.subpixel_order = subpixel_order;
+       drm_sysfs_connector_add(connector);
+       return;
+
+failed:
+       if (radeon_connector->ddc_bus)
+               radeon_i2c_destroy(radeon_connector->ddc_bus);
+       drm_connector_cleanup(connector);
+       kfree(connector);
+}
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c
new file mode 100644 (file)
index 0000000..b843f9b
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2008 Jerome Glisse.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Jerome Glisse <glisse@freedesktop.org>
+ */
+#include "drmP.h"
+#include "radeon_drm.h"
+#include "radeon_reg.h"
+#include "radeon.h"
+
+void r100_cs_dump_packet(struct radeon_cs_parser *p,
+                        struct radeon_cs_packet *pkt);
+
+int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
+{
+       struct drm_device *ddev = p->rdev->ddev;
+       struct radeon_cs_chunk *chunk;
+       unsigned i, j;
+       bool duplicate;
+
+       if (p->chunk_relocs_idx == -1) {
+               return 0;
+       }
+       chunk = &p->chunks[p->chunk_relocs_idx];
+       /* FIXME: we assume that each relocs use 4 dwords */
+       p->nrelocs = chunk->length_dw / 4;
+       p->relocs_ptr = kcalloc(p->nrelocs, sizeof(void *), GFP_KERNEL);
+       if (p->relocs_ptr == NULL) {
+               return -ENOMEM;
+       }
+       p->relocs = kcalloc(p->nrelocs, sizeof(struct radeon_cs_reloc), GFP_KERNEL);
+       if (p->relocs == NULL) {
+               return -ENOMEM;
+       }
+       for (i = 0; i < p->nrelocs; i++) {
+               struct drm_radeon_cs_reloc *r;
+
+               duplicate = false;
+               r = (struct drm_radeon_cs_reloc *)&chunk->kdata[i*4];
+               for (j = 0; j < p->nrelocs; j++) {
+                       if (r->handle == p->relocs[j].handle) {
+                               p->relocs_ptr[i] = &p->relocs[j];
+                               duplicate = true;
+                               break;
+                       }
+               }
+               if (!duplicate) {
+                       p->relocs[i].gobj = drm_gem_object_lookup(ddev,
+                                                                 p->filp,
+                                                                 r->handle);
+                       if (p->relocs[i].gobj == NULL) {
+                               DRM_ERROR("gem object lookup failed 0x%x\n",
+                                         r->handle);
+                               return -EINVAL;
+                       }
+                       p->relocs_ptr[i] = &p->relocs[i];
+                       p->relocs[i].robj = p->relocs[i].gobj->driver_private;
+                       p->relocs[i].lobj.robj = p->relocs[i].robj;
+                       p->relocs[i].lobj.rdomain = r->read_domains;
+                       p->relocs[i].lobj.wdomain = r->write_domain;
+                       p->relocs[i].handle = r->handle;
+                       p->relocs[i].flags = r->flags;
+                       INIT_LIST_HEAD(&p->relocs[i].lobj.list);
+                       radeon_object_list_add_object(&p->relocs[i].lobj,
+                                                     &p->validated);
+               }
+       }
+       return radeon_object_list_validate(&p->validated, p->ib->fence);
+}
+
+int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
+{
+       struct drm_radeon_cs *cs = data;
+       uint64_t *chunk_array_ptr;
+       unsigned size, i;
+
+       if (!cs->num_chunks) {
+               return 0;
+       }
+       /* get chunks */
+       INIT_LIST_HEAD(&p->validated);
+       p->idx = 0;
+       p->chunk_ib_idx = -1;
+       p->chunk_relocs_idx = -1;
+       p->chunks_array = kcalloc(cs->num_chunks, sizeof(uint64_t), GFP_KERNEL);
+       if (p->chunks_array == NULL) {
+               return -ENOMEM;
+       }
+       chunk_array_ptr = (uint64_t *)(unsigned long)(cs->chunks);
+       if (DRM_COPY_FROM_USER(p->chunks_array, chunk_array_ptr,
+                              sizeof(uint64_t)*cs->num_chunks)) {
+               return -EFAULT;
+       }
+       p->nchunks = cs->num_chunks;
+       p->chunks = kcalloc(p->nchunks, sizeof(struct radeon_cs_chunk), GFP_KERNEL);
+       if (p->chunks == NULL) {
+               return -ENOMEM;
+       }
+       for (i = 0; i < p->nchunks; i++) {
+               struct drm_radeon_cs_chunk __user **chunk_ptr = NULL;
+               struct drm_radeon_cs_chunk user_chunk;
+               uint32_t __user *cdata;
+
+               chunk_ptr = (void __user*)(unsigned long)p->chunks_array[i];
+               if (DRM_COPY_FROM_USER(&user_chunk, chunk_ptr,
+                                      sizeof(struct drm_radeon_cs_chunk))) {
+                       return -EFAULT;
+               }
+               p->chunks[i].chunk_id = user_chunk.chunk_id;
+               if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_RELOCS) {
+                       p->chunk_relocs_idx = i;
+               }
+               if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_IB) {
+                       p->chunk_ib_idx = i;
+               }
+               p->chunks[i].length_dw = user_chunk.length_dw;
+               cdata = (uint32_t *)(unsigned long)user_chunk.chunk_data;
+
+               p->chunks[i].kdata = NULL;
+               size = p->chunks[i].length_dw * sizeof(uint32_t);
+               p->chunks[i].kdata = kzalloc(size, GFP_KERNEL);
+               if (p->chunks[i].kdata == NULL) {
+                       return -ENOMEM;
+               }
+               if (DRM_COPY_FROM_USER(p->chunks[i].kdata, cdata, size)) {
+                       return -EFAULT;
+               }
+       }
+       if (p->chunks[p->chunk_ib_idx].length_dw > (16 * 1024)) {
+               DRM_ERROR("cs IB too big: %d\n",
+                         p->chunks[p->chunk_ib_idx].length_dw);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/**
+ * cs_parser_fini() - clean parser states
+ * @parser:    parser structure holding parsing context.
+ * @error:     error number
+ *
+ * If error is set than unvalidate buffer, otherwise just free memory
+ * used by parsing context.
+ **/
+static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error)
+{
+       unsigned i;
+
+       if (error) {
+               radeon_object_list_unvalidate(&parser->validated);
+       } else {
+               radeon_object_list_clean(&parser->validated);
+       }
+       for (i = 0; i < parser->nrelocs; i++) {
+               if (parser->relocs[i].gobj) {
+                       mutex_lock(&parser->rdev->ddev->struct_mutex);
+                       drm_gem_object_unreference(parser->relocs[i].gobj);
+                       mutex_unlock(&parser->rdev->ddev->struct_mutex);
+               }
+       }
+       kfree(parser->relocs);
+       kfree(parser->relocs_ptr);
+       for (i = 0; i < parser->nchunks; i++) {
+               kfree(parser->chunks[i].kdata);
+       }
+       kfree(parser->chunks);
+       kfree(parser->chunks_array);
+       radeon_ib_free(parser->rdev, &parser->ib);
+}
+
+int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_cs_parser parser;
+       struct radeon_cs_chunk *ib_chunk;
+       int r;
+
+       mutex_lock(&rdev->cs_mutex);
+       if (rdev->gpu_lockup) {
+               mutex_unlock(&rdev->cs_mutex);
+               return -EINVAL;
+       }
+       /* initialize parser */
+       memset(&parser, 0, sizeof(struct radeon_cs_parser));
+       parser.filp = filp;
+       parser.rdev = rdev;
+       r = radeon_cs_parser_init(&parser, data);
+       if (r) {
+               DRM_ERROR("Failed to initialize parser !\n");
+               radeon_cs_parser_fini(&parser, r);
+               mutex_unlock(&rdev->cs_mutex);
+               return r;
+       }
+       r =  radeon_ib_get(rdev, &parser.ib);
+       if (r) {
+               DRM_ERROR("Failed to get ib !\n");
+               radeon_cs_parser_fini(&parser, r);
+               mutex_unlock(&rdev->cs_mutex);
+               return r;
+       }
+       r = radeon_cs_parser_relocs(&parser);
+       if (r) {
+               DRM_ERROR("Failed to parse relocation !\n");
+               radeon_cs_parser_fini(&parser, r);
+               mutex_unlock(&rdev->cs_mutex);
+               return r;
+       }
+       /* Copy the packet into the IB, the parser will read from the
+        * input memory (cached) and write to the IB (which can be
+        * uncached). */
+       ib_chunk = &parser.chunks[parser.chunk_ib_idx];
+       parser.ib->length_dw = ib_chunk->length_dw;
+       memcpy((void *)parser.ib->ptr, ib_chunk->kdata, ib_chunk->length_dw*4);
+       r = radeon_cs_parse(&parser);
+       if (r) {
+               DRM_ERROR("Invalid command stream !\n");
+               radeon_cs_parser_fini(&parser, r);
+               mutex_unlock(&rdev->cs_mutex);
+               return r;
+       }
+       r = radeon_ib_schedule(rdev, parser.ib);
+       if (r) {
+               DRM_ERROR("Faild to schedule IB !\n");
+       }
+       radeon_cs_parser_fini(&parser, r);
+       mutex_unlock(&rdev->cs_mutex);
+       return r;
+}
diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c
new file mode 100644 (file)
index 0000000..5232441
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2007-8 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ */
+#include "drmP.h"
+#include "radeon_drm.h"
+#include "radeon.h"
+
+#define CURSOR_WIDTH 64
+#define CURSOR_HEIGHT 64
+
+static void radeon_lock_cursor(struct drm_crtc *crtc, bool lock)
+{
+       struct radeon_device *rdev = crtc->dev->dev_private;
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       uint32_t cur_lock;
+
+       if (ASIC_IS_AVIVO(rdev)) {
+               cur_lock = RREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset);
+               if (lock)
+                       cur_lock |= AVIVO_D1CURSOR_UPDATE_LOCK;
+               else
+                       cur_lock &= ~AVIVO_D1CURSOR_UPDATE_LOCK;
+               WREG32(AVIVO_D1CUR_UPDATE + radeon_crtc->crtc_offset, cur_lock);
+       } else {
+               cur_lock = RREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset);
+               if (lock)
+                       cur_lock |= RADEON_CUR_LOCK;
+               else
+                       cur_lock &= ~RADEON_CUR_LOCK;
+               WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, cur_lock);
+       }
+}
+
+static void radeon_hide_cursor(struct drm_crtc *crtc)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct radeon_device *rdev = crtc->dev->dev_private;
+
+       if (ASIC_IS_AVIVO(rdev)) {
+               WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);
+               WREG32(RADEON_MM_DATA, (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
+       } else {
+               switch (radeon_crtc->crtc_id) {
+               case 0:
+                       WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL);
+                       break;
+               case 1:
+                       WREG32(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL);
+                       break;
+               default:
+                       return;
+               }
+               WREG32_P(RADEON_MM_DATA, 0, ~RADEON_CRTC_CUR_EN);
+       }
+}
+
+static void radeon_show_cursor(struct drm_crtc *crtc)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct radeon_device *rdev = crtc->dev->dev_private;
+
+       if (ASIC_IS_AVIVO(rdev)) {
+               WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);
+               WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN |
+                            (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
+       } else {
+               switch (radeon_crtc->crtc_id) {
+               case 0:
+                       WREG32(RADEON_MM_INDEX, RADEON_CRTC_GEN_CNTL);
+                       break;
+               case 1:
+                       WREG32(RADEON_MM_INDEX, RADEON_CRTC2_GEN_CNTL);
+                       break;
+               default:
+                       return;
+               }
+
+               WREG32_P(RADEON_MM_DATA, (RADEON_CRTC_CUR_EN |
+                                         (RADEON_CRTC_CUR_MODE_24BPP << RADEON_CRTC_CUR_MODE_SHIFT)),
+                        ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_CUR_MODE_MASK));
+       }
+}
+
+static void radeon_set_cursor(struct drm_crtc *crtc, struct drm_gem_object *obj,
+                             uint32_t gpu_addr)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct radeon_device *rdev = crtc->dev->dev_private;
+
+       if (ASIC_IS_AVIVO(rdev))
+               WREG32(AVIVO_D1CUR_SURFACE_ADDRESS + radeon_crtc->crtc_offset, gpu_addr);
+       else
+               /* offset is from DISP(2)_BASE_ADDRESS */
+               WREG32(RADEON_CUR_OFFSET + radeon_crtc->crtc_offset, gpu_addr);
+}
+
+int radeon_crtc_cursor_set(struct drm_crtc *crtc,
+                          struct drm_file *file_priv,
+                          uint32_t handle,
+                          uint32_t width,
+                          uint32_t height)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct drm_gem_object *obj;
+       uint64_t gpu_addr;
+       int ret;
+
+       if (!handle) {
+               /* turn off cursor */
+               radeon_hide_cursor(crtc);
+               obj = NULL;
+               goto unpin;
+       }
+
+       if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) {
+               DRM_ERROR("bad cursor width or height %d x %d\n", width, height);
+               return -EINVAL;
+       }
+
+       radeon_crtc->cursor_width = width;
+       radeon_crtc->cursor_height = height;
+
+       obj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
+       if (!obj) {
+               DRM_ERROR("Cannot find cursor object %x for crtc %d\n", handle, radeon_crtc->crtc_id);
+               return -EINVAL;
+       }
+
+       ret = radeon_gem_object_pin(obj, RADEON_GEM_DOMAIN_VRAM, &gpu_addr);
+       if (ret)
+               goto fail;
+
+       radeon_lock_cursor(crtc, true);
+       /* XXX only 27 bit offset for legacy cursor */
+       radeon_set_cursor(crtc, obj, gpu_addr);
+       radeon_show_cursor(crtc);
+       radeon_lock_cursor(crtc, false);
+
+unpin:
+       if (radeon_crtc->cursor_bo) {
+               radeon_gem_object_unpin(radeon_crtc->cursor_bo);
+               mutex_lock(&crtc->dev->struct_mutex);
+               drm_gem_object_unreference(radeon_crtc->cursor_bo);
+               mutex_unlock(&crtc->dev->struct_mutex);
+       }
+
+       radeon_crtc->cursor_bo = obj;
+       return 0;
+fail:
+       mutex_lock(&crtc->dev->struct_mutex);
+       drm_gem_object_unreference(obj);
+       mutex_unlock(&crtc->dev->struct_mutex);
+
+       return 0;
+}
+
+int radeon_crtc_cursor_move(struct drm_crtc *crtc,
+                           int x, int y)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct radeon_device *rdev = crtc->dev->dev_private;
+       int xorigin = 0, yorigin = 0;
+
+       if (x < 0)
+               xorigin = -x + 1;
+       if (y < 0)
+               yorigin = -y + 1;
+       if (xorigin >= CURSOR_WIDTH)
+               xorigin = CURSOR_WIDTH - 1;
+       if (yorigin >= CURSOR_HEIGHT)
+               yorigin = CURSOR_HEIGHT - 1;
+
+       radeon_lock_cursor(crtc, true);
+       if (ASIC_IS_AVIVO(rdev)) {
+               int w = radeon_crtc->cursor_width;
+               int i = 0;
+               struct drm_crtc *crtc_p;
+
+               /* avivo cursor are offset into the total surface */
+               x += crtc->x;
+               y += crtc->y;
+               DRM_DEBUG("x %d y %d c->x %d c->y %d\n", x, y, crtc->x, crtc->y);
+
+               /* avivo cursor image can't end on 128 pixel boundry or
+                * go past the end of the frame if both crtcs are enabled
+                */
+               list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) {
+                       if (crtc_p->enabled)
+                               i++;
+               }
+               if (i > 1) {
+                       int cursor_end, frame_end;
+
+                       cursor_end = x - xorigin + w;
+                       frame_end = crtc->x + crtc->mode.crtc_hdisplay;
+                       if (cursor_end >= frame_end) {
+                               w = w - (cursor_end - frame_end);
+                               if (!(frame_end & 0x7f))
+                                       w--;
+                       } else {
+                               if (!(cursor_end & 0x7f))
+                                       w--;
+                       }
+                       if (w <= 0)
+                               w = 1;
+               }
+
+               WREG32(AVIVO_D1CUR_POSITION + radeon_crtc->crtc_offset,
+                            ((xorigin ? 0 : x) << 16) |
+                            (yorigin ? 0 : y));
+               WREG32(AVIVO_D1CUR_HOT_SPOT + radeon_crtc->crtc_offset, (xorigin << 16) | yorigin);
+               WREG32(AVIVO_D1CUR_SIZE + radeon_crtc->crtc_offset,
+                      ((w - 1) << 16) | (radeon_crtc->cursor_height - 1));
+       } else {
+               if (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)
+                       y *= 2;
+
+               WREG32(RADEON_CUR_HORZ_VERT_OFF + radeon_crtc->crtc_offset,
+                      (RADEON_CUR_LOCK
+                       | (xorigin << 16)
+                       | yorigin));
+               WREG32(RADEON_CUR_HORZ_VERT_POSN + radeon_crtc->crtc_offset,
+                      (RADEON_CUR_LOCK
+                       | ((xorigin ? 0 : x) << 16)
+                       | (yorigin ? 0 : y)));
+       }
+       radeon_lock_cursor(crtc, false);
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
new file mode 100644 (file)
index 0000000..5fd2b63
--- /dev/null
@@ -0,0 +1,813 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ *          Jerome Glisse
+ */
+#include <linux/console.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/radeon_drm.h>
+#include "radeon_reg.h"
+#include "radeon.h"
+#include "radeon_asic.h"
+#include "atom.h"
+
+/*
+ * GPU scratch registers helpers function.
+ */
+static void radeon_scratch_init(struct radeon_device *rdev)
+{
+       int i;
+
+       /* FIXME: check this out */
+       if (rdev->family < CHIP_R300) {
+               rdev->scratch.num_reg = 5;
+       } else {
+               rdev->scratch.num_reg = 7;
+       }
+       for (i = 0; i < rdev->scratch.num_reg; i++) {
+               rdev->scratch.free[i] = true;
+               rdev->scratch.reg[i] = RADEON_SCRATCH_REG0 + (i * 4);
+       }
+}
+
+int radeon_scratch_get(struct radeon_device *rdev, uint32_t *reg)
+{
+       int i;
+
+       for (i = 0; i < rdev->scratch.num_reg; i++) {
+               if (rdev->scratch.free[i]) {
+                       rdev->scratch.free[i] = false;
+                       *reg = rdev->scratch.reg[i];
+                       return 0;
+               }
+       }
+       return -EINVAL;
+}
+
+void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg)
+{
+       int i;
+
+       for (i = 0; i < rdev->scratch.num_reg; i++) {
+               if (rdev->scratch.reg[i] == reg) {
+                       rdev->scratch.free[i] = true;
+                       return;
+               }
+       }
+}
+
+/*
+ * MC common functions
+ */
+int radeon_mc_setup(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+
+       /* Some chips have an "issue" with the memory controller, the
+        * location must be aligned to the size. We just align it down,
+        * too bad if we walk over the top of system memory, we don't
+        * use DMA without a remapped anyway.
+        * Affected chips are rv280, all r3xx, and all r4xx, but not IGP
+        */
+       /* FGLRX seems to setup like this, VRAM a 0, then GART.
+        */
+       /*
+        * Note: from R6xx the address space is 40bits but here we only
+        * use 32bits (still have to see a card which would exhaust 4G
+        * address space).
+        */
+       if (rdev->mc.vram_location != 0xFFFFFFFFUL) {
+               /* vram location was already setup try to put gtt after
+                * if it fits */
+               tmp = rdev->mc.vram_location + rdev->mc.vram_size;
+               tmp = (tmp + rdev->mc.gtt_size - 1) & ~(rdev->mc.gtt_size - 1);
+               if ((0xFFFFFFFFUL - tmp) >= rdev->mc.gtt_size) {
+                       rdev->mc.gtt_location = tmp;
+               } else {
+                       if (rdev->mc.gtt_size >= rdev->mc.vram_location) {
+                               printk(KERN_ERR "[drm] GTT too big to fit "
+                                      "before or after vram location.\n");
+                               return -EINVAL;
+                       }
+                       rdev->mc.gtt_location = 0;
+               }
+       } else if (rdev->mc.gtt_location != 0xFFFFFFFFUL) {
+               /* gtt location was already setup try to put vram before
+                * if it fits */
+               if (rdev->mc.vram_size < rdev->mc.gtt_location) {
+                       rdev->mc.vram_location = 0;
+               } else {
+                       tmp = rdev->mc.gtt_location + rdev->mc.gtt_size;
+                       tmp += (rdev->mc.vram_size - 1);
+                       tmp &= ~(rdev->mc.vram_size - 1);
+                       if ((0xFFFFFFFFUL - tmp) >= rdev->mc.vram_size) {
+                               rdev->mc.vram_location = tmp;
+                       } else {
+                               printk(KERN_ERR "[drm] vram too big to fit "
+                                      "before or after GTT location.\n");
+                               return -EINVAL;
+                       }
+               }
+       } else {
+               rdev->mc.vram_location = 0;
+               rdev->mc.gtt_location = rdev->mc.vram_size;
+       }
+       DRM_INFO("radeon: VRAM %uM\n", rdev->mc.vram_size >> 20);
+       DRM_INFO("radeon: VRAM from 0x%08X to 0x%08X\n",
+                rdev->mc.vram_location,
+                rdev->mc.vram_location + rdev->mc.vram_size - 1);
+       DRM_INFO("radeon: GTT %uM\n", rdev->mc.gtt_size >> 20);
+       DRM_INFO("radeon: GTT from 0x%08X to 0x%08X\n",
+                rdev->mc.gtt_location,
+                rdev->mc.gtt_location + rdev->mc.gtt_size - 1);
+       return 0;
+}
+
+
+/*
+ * GPU helpers function.
+ */
+static bool radeon_card_posted(struct radeon_device *rdev)
+{
+       uint32_t reg;
+
+       /* first check CRTCs */
+       if (ASIC_IS_AVIVO(rdev)) {
+               reg = RREG32(AVIVO_D1CRTC_CONTROL) |
+                     RREG32(AVIVO_D2CRTC_CONTROL);
+               if (reg & AVIVO_CRTC_EN) {
+                       return true;
+               }
+       } else {
+               reg = RREG32(RADEON_CRTC_GEN_CNTL) |
+                     RREG32(RADEON_CRTC2_GEN_CNTL);
+               if (reg & RADEON_CRTC_EN) {
+                       return true;
+               }
+       }
+
+       /* then check MEM_SIZE, in case the crtcs are off */
+       if (rdev->family >= CHIP_R600)
+               reg = RREG32(R600_CONFIG_MEMSIZE);
+       else
+               reg = RREG32(RADEON_CONFIG_MEMSIZE);
+
+       if (reg)
+               return true;
+
+       return false;
+
+}
+
+
+/*
+ * Registers accessors functions.
+ */
+uint32_t radeon_invalid_rreg(struct radeon_device *rdev, uint32_t reg)
+{
+       DRM_ERROR("Invalid callback to read register 0x%04X\n", reg);
+       BUG_ON(1);
+       return 0;
+}
+
+void radeon_invalid_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
+{
+       DRM_ERROR("Invalid callback to write register 0x%04X with 0x%08X\n",
+                 reg, v);
+       BUG_ON(1);
+}
+
+void radeon_register_accessor_init(struct radeon_device *rdev)
+{
+       rdev->mm_rreg = &r100_mm_rreg;
+       rdev->mm_wreg = &r100_mm_wreg;
+       rdev->mc_rreg = &radeon_invalid_rreg;
+       rdev->mc_wreg = &radeon_invalid_wreg;
+       rdev->pll_rreg = &radeon_invalid_rreg;
+       rdev->pll_wreg = &radeon_invalid_wreg;
+       rdev->pcie_rreg = &radeon_invalid_rreg;
+       rdev->pcie_wreg = &radeon_invalid_wreg;
+       rdev->pciep_rreg = &radeon_invalid_rreg;
+       rdev->pciep_wreg = &radeon_invalid_wreg;
+
+       /* Don't change order as we are overridding accessor. */
+       if (rdev->family < CHIP_RV515) {
+               rdev->pcie_rreg = &rv370_pcie_rreg;
+               rdev->pcie_wreg = &rv370_pcie_wreg;
+       }
+       if (rdev->family >= CHIP_RV515) {
+               rdev->pcie_rreg = &rv515_pcie_rreg;
+               rdev->pcie_wreg = &rv515_pcie_wreg;
+       }
+       /* FIXME: not sure here */
+       if (rdev->family <= CHIP_R580) {
+               rdev->pll_rreg = &r100_pll_rreg;
+               rdev->pll_wreg = &r100_pll_wreg;
+       }
+       if (rdev->family >= CHIP_RV515) {
+               rdev->mc_rreg = &rv515_mc_rreg;
+               rdev->mc_wreg = &rv515_mc_wreg;
+       }
+       if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480) {
+               rdev->mc_rreg = &rs400_mc_rreg;
+               rdev->mc_wreg = &rs400_mc_wreg;
+       }
+       if (rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) {
+               rdev->mc_rreg = &rs690_mc_rreg;
+               rdev->mc_wreg = &rs690_mc_wreg;
+       }
+       if (rdev->family == CHIP_RS600) {
+               rdev->mc_rreg = &rs600_mc_rreg;
+               rdev->mc_wreg = &rs600_mc_wreg;
+       }
+       if (rdev->family >= CHIP_R600) {
+               rdev->pciep_rreg = &r600_pciep_rreg;
+               rdev->pciep_wreg = &r600_pciep_wreg;
+       }
+}
+
+
+/*
+ * ASIC
+ */
+int radeon_asic_init(struct radeon_device *rdev)
+{
+       radeon_register_accessor_init(rdev);
+       switch (rdev->family) {
+       case CHIP_R100:
+       case CHIP_RV100:
+       case CHIP_RS100:
+       case CHIP_RV200:
+       case CHIP_RS200:
+       case CHIP_R200:
+       case CHIP_RV250:
+       case CHIP_RS300:
+       case CHIP_RV280:
+               rdev->asic = &r100_asic;
+               break;
+       case CHIP_R300:
+       case CHIP_R350:
+       case CHIP_RV350:
+       case CHIP_RV380:
+               rdev->asic = &r300_asic;
+               break;
+       case CHIP_R420:
+       case CHIP_R423:
+       case CHIP_RV410:
+               rdev->asic = &r420_asic;
+               break;
+       case CHIP_RS400:
+       case CHIP_RS480:
+               rdev->asic = &rs400_asic;
+               break;
+       case CHIP_RS600:
+               rdev->asic = &rs600_asic;
+               break;
+       case CHIP_RS690:
+       case CHIP_RS740:
+               rdev->asic = &rs690_asic;
+               break;
+       case CHIP_RV515:
+               rdev->asic = &rv515_asic;
+               break;
+       case CHIP_R520:
+       case CHIP_RV530:
+       case CHIP_RV560:
+       case CHIP_RV570:
+       case CHIP_R580:
+               rdev->asic = &r520_asic;
+               break;
+       case CHIP_R600:
+       case CHIP_RV610:
+       case CHIP_RV630:
+       case CHIP_RV620:
+       case CHIP_RV635:
+       case CHIP_RV670:
+       case CHIP_RS780:
+       case CHIP_RV770:
+       case CHIP_RV730:
+       case CHIP_RV710:
+       default:
+               /* FIXME: not supported yet */
+               return -EINVAL;
+       }
+       return 0;
+}
+
+
+/*
+ * Wrapper around modesetting bits.
+ */
+int radeon_clocks_init(struct radeon_device *rdev)
+{
+       int r;
+
+       radeon_get_clock_info(rdev->ddev);
+       r = radeon_static_clocks_init(rdev->ddev);
+       if (r) {
+               return r;
+       }
+       DRM_INFO("Clocks initialized !\n");
+       return 0;
+}
+
+void radeon_clocks_fini(struct radeon_device *rdev)
+{
+}
+
+/* ATOM accessor methods */
+static uint32_t cail_pll_read(struct card_info *info, uint32_t reg)
+{
+       struct radeon_device *rdev = info->dev->dev_private;
+       uint32_t r;
+
+       r = rdev->pll_rreg(rdev, reg);
+       return r;
+}
+
+static void cail_pll_write(struct card_info *info, uint32_t reg, uint32_t val)
+{
+       struct radeon_device *rdev = info->dev->dev_private;
+
+       rdev->pll_wreg(rdev, reg, val);
+}
+
+static uint32_t cail_mc_read(struct card_info *info, uint32_t reg)
+{
+       struct radeon_device *rdev = info->dev->dev_private;
+       uint32_t r;
+
+       r = rdev->mc_rreg(rdev, reg);
+       return r;
+}
+
+static void cail_mc_write(struct card_info *info, uint32_t reg, uint32_t val)
+{
+       struct radeon_device *rdev = info->dev->dev_private;
+
+       rdev->mc_wreg(rdev, reg, val);
+}
+
+static void cail_reg_write(struct card_info *info, uint32_t reg, uint32_t val)
+{
+       struct radeon_device *rdev = info->dev->dev_private;
+
+       WREG32(reg*4, val);
+}
+
+static uint32_t cail_reg_read(struct card_info *info, uint32_t reg)
+{
+       struct radeon_device *rdev = info->dev->dev_private;
+       uint32_t r;
+
+       r = RREG32(reg*4);
+       return r;
+}
+
+static struct card_info atom_card_info = {
+       .dev = NULL,
+       .reg_read = cail_reg_read,
+       .reg_write = cail_reg_write,
+       .mc_read = cail_mc_read,
+       .mc_write = cail_mc_write,
+       .pll_read = cail_pll_read,
+       .pll_write = cail_pll_write,
+};
+
+int radeon_atombios_init(struct radeon_device *rdev)
+{
+       atom_card_info.dev = rdev->ddev;
+       rdev->mode_info.atom_context = atom_parse(&atom_card_info, rdev->bios);
+       radeon_atom_initialize_bios_scratch_regs(rdev->ddev);
+       return 0;
+}
+
+void radeon_atombios_fini(struct radeon_device *rdev)
+{
+       kfree(rdev->mode_info.atom_context);
+}
+
+int radeon_combios_init(struct radeon_device *rdev)
+{
+       radeon_combios_initialize_bios_scratch_regs(rdev->ddev);
+       return 0;
+}
+
+void radeon_combios_fini(struct radeon_device *rdev)
+{
+}
+
+int radeon_modeset_init(struct radeon_device *rdev);
+void radeon_modeset_fini(struct radeon_device *rdev);
+
+
+/*
+ * Radeon device.
+ */
+int radeon_device_init(struct radeon_device *rdev,
+                      struct drm_device *ddev,
+                      struct pci_dev *pdev,
+                      uint32_t flags)
+{
+       int r, ret;
+
+       DRM_INFO("radeon: Initializing kernel modesetting.\n");
+       rdev->shutdown = false;
+       rdev->ddev = ddev;
+       rdev->pdev = pdev;
+       rdev->flags = flags;
+       rdev->family = flags & RADEON_FAMILY_MASK;
+       rdev->is_atom_bios = false;
+       rdev->usec_timeout = RADEON_MAX_USEC_TIMEOUT;
+       rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024;
+       rdev->gpu_lockup = false;
+       /* mutex initialization are all done here so we
+        * can recall function without having locking issues */
+       mutex_init(&rdev->cs_mutex);
+       mutex_init(&rdev->ib_pool.mutex);
+       mutex_init(&rdev->cp.mutex);
+       rwlock_init(&rdev->fence_drv.lock);
+
+       if (radeon_agpmode == -1) {
+               rdev->flags &= ~RADEON_IS_AGP;
+               if (rdev->family > CHIP_RV515 ||
+                   rdev->family == CHIP_RV380 ||
+                   rdev->family == CHIP_RV410 ||
+                   rdev->family == CHIP_R423) {
+                       DRM_INFO("Forcing AGP to PCIE mode\n");
+                       rdev->flags |= RADEON_IS_PCIE;
+               } else {
+                       DRM_INFO("Forcing AGP to PCI mode\n");
+                       rdev->flags |= RADEON_IS_PCI;
+               }
+       }
+
+       /* Set asic functions */
+       r = radeon_asic_init(rdev);
+       if (r) {
+               return r;
+       }
+
+       /* Report DMA addressing limitation */
+       r = pci_set_dma_mask(rdev->pdev, DMA_BIT_MASK(32));
+       if (r) {
+               printk(KERN_WARNING "radeon: No suitable DMA available.\n");
+       }
+
+       /* Registers mapping */
+       /* TODO: block userspace mapping of io register */
+       rdev->rmmio_base = drm_get_resource_start(rdev->ddev, 2);
+       rdev->rmmio_size = drm_get_resource_len(rdev->ddev, 2);
+       rdev->rmmio = ioremap(rdev->rmmio_base, rdev->rmmio_size);
+       if (rdev->rmmio == NULL) {
+               return -ENOMEM;
+       }
+       DRM_INFO("register mmio base: 0x%08X\n", (uint32_t)rdev->rmmio_base);
+       DRM_INFO("register mmio size: %u\n", (unsigned)rdev->rmmio_size);
+
+       /* Setup errata flags */
+       radeon_errata(rdev);
+       /* Initialize scratch registers */
+       radeon_scratch_init(rdev);
+
+       /* TODO: disable VGA need to use VGA request */
+       /* BIOS*/
+       if (!radeon_get_bios(rdev)) {
+               if (ASIC_IS_AVIVO(rdev))
+                       return -EINVAL;
+       }
+       if (rdev->is_atom_bios) {
+               r = radeon_atombios_init(rdev);
+               if (r) {
+                       return r;
+               }
+       } else {
+               r = radeon_combios_init(rdev);
+               if (r) {
+                       return r;
+               }
+       }
+       /* Reset gpu before posting otherwise ATOM will enter infinite loop */
+       if (radeon_gpu_reset(rdev)) {
+               /* FIXME: what do we want to do here ? */
+       }
+       /* check if cards are posted or not */
+       if (!radeon_card_posted(rdev) && rdev->bios) {
+               DRM_INFO("GPU not posted. posting now...\n");
+               if (rdev->is_atom_bios) {
+                       atom_asic_init(rdev->mode_info.atom_context);
+               } else {
+                       radeon_combios_asic_init(rdev->ddev);
+               }
+       }
+       /* Get vram informations */
+       radeon_vram_info(rdev);
+       /* Device is severly broken if aper size > vram size.
+        * for RN50/M6/M7 - Novell bug 204882 ?
+        */
+       if (rdev->mc.vram_size < rdev->mc.aper_size) {
+               rdev->mc.aper_size = rdev->mc.vram_size;
+       }
+       /* Add an MTRR for the VRAM */
+       rdev->mc.vram_mtrr = mtrr_add(rdev->mc.aper_base, rdev->mc.aper_size,
+                                     MTRR_TYPE_WRCOMB, 1);
+       DRM_INFO("Detected VRAM RAM=%uM, BAR=%uM\n",
+                rdev->mc.vram_size >> 20,
+                (unsigned)rdev->mc.aper_size >> 20);
+       DRM_INFO("RAM width %dbits %cDR\n",
+                rdev->mc.vram_width, rdev->mc.vram_is_ddr ? 'D' : 'S');
+       /* Initialize clocks */
+       r = radeon_clocks_init(rdev);
+       if (r) {
+               return r;
+       }
+       /* Initialize memory controller (also test AGP) */
+       r = radeon_mc_init(rdev);
+       if (r) {
+               return r;
+       }
+       /* Fence driver */
+       r = radeon_fence_driver_init(rdev);
+       if (r) {
+               return r;
+       }
+       r = radeon_irq_kms_init(rdev);
+       if (r) {
+               return r;
+       }
+       /* Memory manager */
+       r = radeon_object_init(rdev);
+       if (r) {
+               return r;
+       }
+       /* Initialize GART (initialize after TTM so we can allocate
+        * memory through TTM but finalize after TTM) */
+       r = radeon_gart_enable(rdev);
+       if (!r) {
+               r = radeon_gem_init(rdev);
+       }
+
+       /* 1M ring buffer */
+       if (!r) {
+               r = radeon_cp_init(rdev, 1024 * 1024);
+       }
+       if (!r) {
+               r = radeon_wb_init(rdev);
+               if (r) {
+                       DRM_ERROR("radeon: failled initializing WB (%d).\n", r);
+                       return r;
+               }
+       }
+       if (!r) {
+               r = radeon_ib_pool_init(rdev);
+               if (r) {
+                       DRM_ERROR("radeon: failled initializing IB pool (%d).\n", r);
+                       return r;
+               }
+       }
+       if (!r) {
+               r = radeon_ib_test(rdev);
+               if (r) {
+                       DRM_ERROR("radeon: failled testing IB (%d).\n", r);
+                       return r;
+               }
+       }
+       ret = r;
+       r = radeon_modeset_init(rdev);
+       if (r) {
+               return r;
+       }
+       if (rdev->fbdev_rfb && rdev->fbdev_rfb->obj) {
+               rdev->fbdev_robj = rdev->fbdev_rfb->obj->driver_private;
+       }
+       if (!ret) {
+               DRM_INFO("radeon: kernel modesetting successfully initialized.\n");
+       }
+       if (radeon_benchmarking) {
+               radeon_benchmark(rdev);
+       }
+       return ret;
+}
+
+void radeon_device_fini(struct radeon_device *rdev)
+{
+       if (rdev == NULL || rdev->rmmio == NULL) {
+               return;
+       }
+       DRM_INFO("radeon: finishing device.\n");
+       rdev->shutdown = true;
+       /* Order matter so becarefull if you rearrange anythings */
+       radeon_modeset_fini(rdev);
+       radeon_ib_pool_fini(rdev);
+       radeon_cp_fini(rdev);
+       radeon_wb_fini(rdev);
+       radeon_gem_fini(rdev);
+       radeon_object_fini(rdev);
+       /* mc_fini must be after object_fini */
+       radeon_mc_fini(rdev);
+#if __OS_HAS_AGP
+       radeon_agp_fini(rdev);
+#endif
+       radeon_irq_kms_fini(rdev);
+       radeon_fence_driver_fini(rdev);
+       radeon_clocks_fini(rdev);
+       if (rdev->is_atom_bios) {
+               radeon_atombios_fini(rdev);
+       } else {
+               radeon_combios_fini(rdev);
+       }
+       kfree(rdev->bios);
+       rdev->bios = NULL;
+       iounmap(rdev->rmmio);
+       rdev->rmmio = NULL;
+}
+
+
+/*
+ * Suspend & resume.
+ */
+int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       struct drm_crtc *crtc;
+
+       if (dev == NULL || rdev == NULL) {
+               return -ENODEV;
+       }
+       if (state.event == PM_EVENT_PRETHAW) {
+               return 0;
+       }
+       /* unpin the front buffers */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->fb);
+               struct radeon_object *robj;
+
+               if (rfb == NULL || rfb->obj == NULL) {
+                       continue;
+               }
+               robj = rfb->obj->driver_private;
+               if (robj != rdev->fbdev_robj) {
+                       radeon_object_unpin(robj);
+               }
+       }
+       /* evict vram memory */
+       radeon_object_evict_vram(rdev);
+       /* wait for gpu to finish processing current batch */
+       radeon_fence_wait_last(rdev);
+
+       radeon_cp_disable(rdev);
+       radeon_gart_disable(rdev);
+
+       /* evict remaining vram memory */
+       radeon_object_evict_vram(rdev);
+
+       rdev->irq.sw_int = false;
+       radeon_irq_set(rdev);
+
+       pci_save_state(dev->pdev);
+       if (state.event == PM_EVENT_SUSPEND) {
+               /* Shut down the device */
+               pci_disable_device(dev->pdev);
+               pci_set_power_state(dev->pdev, PCI_D3hot);
+       }
+       acquire_console_sem();
+       fb_set_suspend(rdev->fbdev_info, 1);
+       release_console_sem();
+       return 0;
+}
+
+int radeon_resume_kms(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       int r;
+
+       acquire_console_sem();
+       pci_set_power_state(dev->pdev, PCI_D0);
+       pci_restore_state(dev->pdev);
+       if (pci_enable_device(dev->pdev)) {
+               release_console_sem();
+               return -1;
+       }
+       pci_set_master(dev->pdev);
+       /* Reset gpu before posting otherwise ATOM will enter infinite loop */
+       if (radeon_gpu_reset(rdev)) {
+               /* FIXME: what do we want to do here ? */
+       }
+       /* post card */
+       if (rdev->is_atom_bios) {
+               atom_asic_init(rdev->mode_info.atom_context);
+       } else {
+               radeon_combios_asic_init(rdev->ddev);
+       }
+       /* Initialize clocks */
+       r = radeon_clocks_init(rdev);
+       if (r) {
+               release_console_sem();
+               return r;
+       }
+       /* Enable IRQ */
+       rdev->irq.sw_int = true;
+       radeon_irq_set(rdev);
+       /* Initialize GPU Memory Controller */
+       r = radeon_mc_init(rdev);
+       if (r) {
+               goto out;
+       }
+       r = radeon_gart_enable(rdev);
+       if (r) {
+               goto out;
+       }
+       r = radeon_cp_init(rdev, rdev->cp.ring_size);
+       if (r) {
+               goto out;
+       }
+out:
+       fb_set_suspend(rdev->fbdev_info, 0);
+       release_console_sem();
+
+       /* blat the mode back in */
+       drm_helper_resume_force_mode(dev);
+       return 0;
+}
+
+
+/*
+ * Debugfs
+ */
+struct radeon_debugfs {
+       struct drm_info_list    *files;
+       unsigned                num_files;
+};
+static struct radeon_debugfs _radeon_debugfs[RADEON_DEBUGFS_MAX_NUM_FILES];
+static unsigned _radeon_debugfs_count = 0;
+
+int radeon_debugfs_add_files(struct radeon_device *rdev,
+                            struct drm_info_list *files,
+                            unsigned nfiles)
+{
+       unsigned i;
+
+       for (i = 0; i < _radeon_debugfs_count; i++) {
+               if (_radeon_debugfs[i].files == files) {
+                       /* Already registered */
+                       return 0;
+               }
+       }
+       if ((_radeon_debugfs_count + nfiles) > RADEON_DEBUGFS_MAX_NUM_FILES) {
+               DRM_ERROR("Reached maximum number of debugfs files.\n");
+               DRM_ERROR("Report so we increase RADEON_DEBUGFS_MAX_NUM_FILES.\n");
+               return -EINVAL;
+       }
+       _radeon_debugfs[_radeon_debugfs_count].files = files;
+       _radeon_debugfs[_radeon_debugfs_count].num_files = nfiles;
+       _radeon_debugfs_count++;
+#if defined(CONFIG_DEBUG_FS)
+       drm_debugfs_create_files(files, nfiles,
+                                rdev->ddev->control->debugfs_root,
+                                rdev->ddev->control);
+       drm_debugfs_create_files(files, nfiles,
+                                rdev->ddev->primary->debugfs_root,
+                                rdev->ddev->primary);
+#endif
+       return 0;
+}
+
+#if defined(CONFIG_DEBUG_FS)
+int radeon_debugfs_init(struct drm_minor *minor)
+{
+       return 0;
+}
+
+void radeon_debugfs_cleanup(struct drm_minor *minor)
+{
+       unsigned i;
+
+       for (i = 0; i < _radeon_debugfs_count; i++) {
+               drm_debugfs_remove_files(_radeon_debugfs[i].files,
+                                        _radeon_debugfs[i].num_files, minor);
+       }
+}
+#endif
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
new file mode 100644 (file)
index 0000000..5452bb9
--- /dev/null
@@ -0,0 +1,692 @@
+/*
+ * Copyright 2007-8 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ */
+#include "drmP.h"
+#include "radeon_drm.h"
+#include "radeon.h"
+
+#include "atom.h"
+#include <asm/div64.h>
+
+#include "drm_crtc_helper.h"
+#include "drm_edid.h"
+
+static int radeon_ddc_dump(struct drm_connector *connector);
+
+static void avivo_crtc_load_lut(struct drm_crtc *crtc)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       int i;
+
+       DRM_DEBUG("%d\n", radeon_crtc->crtc_id);
+       WREG32(AVIVO_DC_LUTA_CONTROL + radeon_crtc->crtc_offset, 0);
+
+       WREG32(AVIVO_DC_LUTA_BLACK_OFFSET_BLUE + radeon_crtc->crtc_offset, 0);
+       WREG32(AVIVO_DC_LUTA_BLACK_OFFSET_GREEN + radeon_crtc->crtc_offset, 0);
+       WREG32(AVIVO_DC_LUTA_BLACK_OFFSET_RED + radeon_crtc->crtc_offset, 0);
+
+       WREG32(AVIVO_DC_LUTA_WHITE_OFFSET_BLUE + radeon_crtc->crtc_offset, 0xffff);
+       WREG32(AVIVO_DC_LUTA_WHITE_OFFSET_GREEN + radeon_crtc->crtc_offset, 0xffff);
+       WREG32(AVIVO_DC_LUTA_WHITE_OFFSET_RED + radeon_crtc->crtc_offset, 0xffff);
+
+       WREG32(AVIVO_DC_LUT_RW_SELECT, radeon_crtc->crtc_id);
+       WREG32(AVIVO_DC_LUT_RW_MODE, 0);
+       WREG32(AVIVO_DC_LUT_WRITE_EN_MASK, 0x0000003f);
+
+       WREG8(AVIVO_DC_LUT_RW_INDEX, 0);
+       for (i = 0; i < 256; i++) {
+               WREG32(AVIVO_DC_LUT_30_COLOR,
+                            (radeon_crtc->lut_r[i] << 20) |
+                            (radeon_crtc->lut_g[i] << 10) |
+                            (radeon_crtc->lut_b[i] << 0));
+       }
+
+       WREG32(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, radeon_crtc->crtc_id);
+}
+
+static void legacy_crtc_load_lut(struct drm_crtc *crtc)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       int i;
+       uint32_t dac2_cntl;
+
+       dac2_cntl = RREG32(RADEON_DAC_CNTL2);
+       if (radeon_crtc->crtc_id == 0)
+               dac2_cntl &= (uint32_t)~RADEON_DAC2_PALETTE_ACC_CTL;
+       else
+               dac2_cntl |= RADEON_DAC2_PALETTE_ACC_CTL;
+       WREG32(RADEON_DAC_CNTL2, dac2_cntl);
+
+       WREG8(RADEON_PALETTE_INDEX, 0);
+       for (i = 0; i < 256; i++) {
+               WREG32(RADEON_PALETTE_30_DATA,
+                            (radeon_crtc->lut_r[i] << 20) |
+                            (radeon_crtc->lut_g[i] << 10) |
+                            (radeon_crtc->lut_b[i] << 0));
+       }
+}
+
+void radeon_crtc_load_lut(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
+
+       if (!crtc->enabled)
+               return;
+
+       if (ASIC_IS_AVIVO(rdev))
+               avivo_crtc_load_lut(crtc);
+       else
+               legacy_crtc_load_lut(crtc);
+}
+
+/** Sets the color ramps on behalf of RandR */
+void radeon_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
+                             u16 blue, int regno)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+
+       if (regno == 0)
+               DRM_DEBUG("gamma set %d\n", radeon_crtc->crtc_id);
+       radeon_crtc->lut_r[regno] = red >> 6;
+       radeon_crtc->lut_g[regno] = green >> 6;
+       radeon_crtc->lut_b[regno] = blue >> 6;
+}
+
+static void radeon_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
+                                 u16 *blue, uint32_t size)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       int i, j;
+
+       if (size != 256) {
+               return;
+       }
+       if (crtc->fb == NULL) {
+               return;
+       }
+
+       if (crtc->fb->depth == 16) {
+               for (i = 0; i < 64; i++) {
+                       if (i <= 31) {
+                               for (j = 0; j < 8; j++) {
+                                       radeon_crtc->lut_r[i * 8 + j] = red[i] >> 6;
+                                       radeon_crtc->lut_b[i * 8 + j] = blue[i] >> 6;
+                               }
+                       }
+                       for (j = 0; j < 4; j++)
+                               radeon_crtc->lut_g[i * 4 + j] = green[i] >> 6;
+               }
+       } else {
+               for (i = 0; i < 256; i++) {
+                       radeon_crtc->lut_r[i] = red[i] >> 6;
+                       radeon_crtc->lut_g[i] = green[i] >> 6;
+                       radeon_crtc->lut_b[i] = blue[i] >> 6;
+               }
+       }
+
+       radeon_crtc_load_lut(crtc);
+}
+
+static void radeon_crtc_destroy(struct drm_crtc *crtc)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+
+       if (radeon_crtc->mode_set.mode) {
+               drm_mode_destroy(crtc->dev, radeon_crtc->mode_set.mode);
+       }
+       drm_crtc_cleanup(crtc);
+       kfree(radeon_crtc);
+}
+
+static const struct drm_crtc_funcs radeon_crtc_funcs = {
+       .cursor_set = radeon_crtc_cursor_set,
+       .cursor_move = radeon_crtc_cursor_move,
+       .gamma_set = radeon_crtc_gamma_set,
+       .set_config = drm_crtc_helper_set_config,
+       .destroy = radeon_crtc_destroy,
+};
+
+static void radeon_crtc_init(struct drm_device *dev, int index)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_crtc *radeon_crtc;
+       int i;
+
+       radeon_crtc = kzalloc(sizeof(struct radeon_crtc) + (RADEONFB_CONN_LIMIT * sizeof(struct drm_connector *)), GFP_KERNEL);
+       if (radeon_crtc == NULL)
+               return;
+
+       drm_crtc_init(dev, &radeon_crtc->base, &radeon_crtc_funcs);
+
+       drm_mode_crtc_set_gamma_size(&radeon_crtc->base, 256);
+       radeon_crtc->crtc_id = index;
+
+       radeon_crtc->mode_set.crtc = &radeon_crtc->base;
+       radeon_crtc->mode_set.connectors = (struct drm_connector **)(radeon_crtc + 1);
+       radeon_crtc->mode_set.num_connectors = 0;
+
+       for (i = 0; i < 256; i++) {
+               radeon_crtc->lut_r[i] = i << 2;
+               radeon_crtc->lut_g[i] = i << 2;
+               radeon_crtc->lut_b[i] = i << 2;
+       }
+
+       if (rdev->is_atom_bios && (ASIC_IS_AVIVO(rdev) || radeon_r4xx_atom))
+               radeon_atombios_init_crtc(dev, radeon_crtc);
+       else
+               radeon_legacy_init_crtc(dev, radeon_crtc);
+}
+
+static const char *encoder_names[34] = {
+       "NONE",
+       "INTERNAL_LVDS",
+       "INTERNAL_TMDS1",
+       "INTERNAL_TMDS2",
+       "INTERNAL_DAC1",
+       "INTERNAL_DAC2",
+       "INTERNAL_SDVOA",
+       "INTERNAL_SDVOB",
+       "SI170B",
+       "CH7303",
+       "CH7301",
+       "INTERNAL_DVO1",
+       "EXTERNAL_SDVOA",
+       "EXTERNAL_SDVOB",
+       "TITFP513",
+       "INTERNAL_LVTM1",
+       "VT1623",
+       "HDMI_SI1930",
+       "HDMI_INTERNAL",
+       "INTERNAL_KLDSCP_TMDS1",
+       "INTERNAL_KLDSCP_DVO1",
+       "INTERNAL_KLDSCP_DAC1",
+       "INTERNAL_KLDSCP_DAC2",
+       "SI178",
+       "MVPU_FPGA",
+       "INTERNAL_DDI",
+       "VT1625",
+       "HDMI_SI1932",
+       "DP_AN9801",
+       "DP_DP501",
+       "INTERNAL_UNIPHY",
+       "INTERNAL_KLDSCP_LVTMA",
+       "INTERNAL_UNIPHY1",
+       "INTERNAL_UNIPHY2",
+};
+
+static const char *connector_names[13] = {
+       "Unknown",
+       "VGA",
+       "DVI-I",
+       "DVI-D",
+       "DVI-A",
+       "Composite",
+       "S-video",
+       "LVDS",
+       "Component",
+       "DIN",
+       "DisplayPort",
+       "HDMI-A",
+       "HDMI-B",
+};
+
+static void radeon_print_display_setup(struct drm_device *dev)
+{
+       struct drm_connector *connector;
+       struct radeon_connector *radeon_connector;
+       struct drm_encoder *encoder;
+       struct radeon_encoder *radeon_encoder;
+       uint32_t devices;
+       int i = 0;
+
+       DRM_INFO("Radeon Display Connectors\n");
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               radeon_connector = to_radeon_connector(connector);
+               DRM_INFO("Connector %d:\n", i);
+               DRM_INFO("  %s\n", connector_names[connector->connector_type]);
+               if (radeon_connector->ddc_bus)
+                       DRM_INFO("  DDC: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+                                radeon_connector->ddc_bus->rec.mask_clk_reg,
+                                radeon_connector->ddc_bus->rec.mask_data_reg,
+                                radeon_connector->ddc_bus->rec.a_clk_reg,
+                                radeon_connector->ddc_bus->rec.a_data_reg,
+                                radeon_connector->ddc_bus->rec.put_clk_reg,
+                                radeon_connector->ddc_bus->rec.put_data_reg,
+                                radeon_connector->ddc_bus->rec.get_clk_reg,
+                                radeon_connector->ddc_bus->rec.get_data_reg);
+               DRM_INFO("  Encoders:\n");
+               list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+                       radeon_encoder = to_radeon_encoder(encoder);
+                       devices = radeon_encoder->devices & radeon_connector->devices;
+                       if (devices) {
+                               if (devices & ATOM_DEVICE_CRT1_SUPPORT)
+                                       DRM_INFO("    CRT1: %s\n", encoder_names[radeon_encoder->encoder_id]);
+                               if (devices & ATOM_DEVICE_CRT2_SUPPORT)
+                                       DRM_INFO("    CRT2: %s\n", encoder_names[radeon_encoder->encoder_id]);
+                               if (devices & ATOM_DEVICE_LCD1_SUPPORT)
+                                       DRM_INFO("    LCD1: %s\n", encoder_names[radeon_encoder->encoder_id]);
+                               if (devices & ATOM_DEVICE_DFP1_SUPPORT)
+                                       DRM_INFO("    DFP1: %s\n", encoder_names[radeon_encoder->encoder_id]);
+                               if (devices & ATOM_DEVICE_DFP2_SUPPORT)
+                                       DRM_INFO("    DFP2: %s\n", encoder_names[radeon_encoder->encoder_id]);
+                               if (devices & ATOM_DEVICE_DFP3_SUPPORT)
+                                       DRM_INFO("    DFP3: %s\n", encoder_names[radeon_encoder->encoder_id]);
+                               if (devices & ATOM_DEVICE_DFP4_SUPPORT)
+                                       DRM_INFO("    DFP4: %s\n", encoder_names[radeon_encoder->encoder_id]);
+                               if (devices & ATOM_DEVICE_DFP5_SUPPORT)
+                                       DRM_INFO("    DFP5: %s\n", encoder_names[radeon_encoder->encoder_id]);
+                               if (devices & ATOM_DEVICE_TV1_SUPPORT)
+                                       DRM_INFO("    TV1: %s\n", encoder_names[radeon_encoder->encoder_id]);
+                               if (devices & ATOM_DEVICE_CV_SUPPORT)
+                                       DRM_INFO("    CV: %s\n", encoder_names[radeon_encoder->encoder_id]);
+                       }
+               }
+               i++;
+       }
+}
+
+bool radeon_setup_enc_conn(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       struct drm_connector *drm_connector;
+       bool ret = false;
+
+       if (rdev->bios) {
+               if (rdev->is_atom_bios) {
+                       if (rdev->family >= CHIP_R600)
+                               ret = radeon_get_atom_connector_info_from_object_table(dev);
+                       else
+                               ret = radeon_get_atom_connector_info_from_supported_devices_table(dev);
+               } else
+                       ret = radeon_get_legacy_connector_info_from_bios(dev);
+       } else {
+               if (!ASIC_IS_AVIVO(rdev))
+                       ret = radeon_get_legacy_connector_info_from_table(dev);
+       }
+       if (ret) {
+               radeon_print_display_setup(dev);
+               list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head)
+                       radeon_ddc_dump(drm_connector);
+       }
+
+       return ret;
+}
+
+int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
+{
+       struct edid *edid;
+       int ret = 0;
+
+       if (!radeon_connector->ddc_bus)
+               return -1;
+       radeon_i2c_do_lock(radeon_connector, 1);
+       edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
+       radeon_i2c_do_lock(radeon_connector, 0);
+       if (edid) {
+               /* update digital bits here */
+               if (edid->digital)
+                       radeon_connector->use_digital = 1;
+               else
+                       radeon_connector->use_digital = 0;
+               drm_mode_connector_update_edid_property(&radeon_connector->base, edid);
+               ret = drm_add_edid_modes(&radeon_connector->base, edid);
+               kfree(edid);
+               return ret;
+       }
+       drm_mode_connector_update_edid_property(&radeon_connector->base, NULL);
+       return -1;
+}
+
+static int radeon_ddc_dump(struct drm_connector *connector)
+{
+       struct edid *edid;
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       int ret = 0;
+
+       if (!radeon_connector->ddc_bus)
+               return -1;
+       radeon_i2c_do_lock(radeon_connector, 1);
+       edid = drm_get_edid(connector, &radeon_connector->ddc_bus->adapter);
+       radeon_i2c_do_lock(radeon_connector, 0);
+       if (edid) {
+               kfree(edid);
+       }
+       return ret;
+}
+
+static inline uint32_t radeon_div(uint64_t n, uint32_t d)
+{
+       uint64_t mod;
+
+       n += d / 2;
+
+       mod = do_div(n, d);
+       return n;
+}
+
+void radeon_compute_pll(struct radeon_pll *pll,
+                       uint64_t freq,
+                       uint32_t *dot_clock_p,
+                       uint32_t *fb_div_p,
+                       uint32_t *frac_fb_div_p,
+                       uint32_t *ref_div_p,
+                       uint32_t *post_div_p,
+                       int flags)
+{
+       uint32_t min_ref_div = pll->min_ref_div;
+       uint32_t max_ref_div = pll->max_ref_div;
+       uint32_t min_fractional_feed_div = 0;
+       uint32_t max_fractional_feed_div = 0;
+       uint32_t best_vco = pll->best_vco;
+       uint32_t best_post_div = 1;
+       uint32_t best_ref_div = 1;
+       uint32_t best_feedback_div = 1;
+       uint32_t best_frac_feedback_div = 0;
+       uint32_t best_freq = -1;
+       uint32_t best_error = 0xffffffff;
+       uint32_t best_vco_diff = 1;
+       uint32_t post_div;
+
+       DRM_DEBUG("PLL freq %llu %u %u\n", freq, pll->min_ref_div, pll->max_ref_div);
+       freq = freq * 1000;
+
+       if (flags & RADEON_PLL_USE_REF_DIV)
+               min_ref_div = max_ref_div = pll->reference_div;
+       else {
+               while (min_ref_div < max_ref_div-1) {
+                       uint32_t mid = (min_ref_div + max_ref_div) / 2;
+                       uint32_t pll_in = pll->reference_freq / mid;
+                       if (pll_in < pll->pll_in_min)
+                               max_ref_div = mid;
+                       else if (pll_in > pll->pll_in_max)
+                               min_ref_div = mid;
+                       else
+                               break;
+               }
+       }
+
+       if (flags & RADEON_PLL_USE_FRAC_FB_DIV) {
+               min_fractional_feed_div = pll->min_frac_feedback_div;
+               max_fractional_feed_div = pll->max_frac_feedback_div;
+       }
+
+       for (post_div = pll->min_post_div; post_div <= pll->max_post_div; ++post_div) {
+               uint32_t ref_div;
+
+               if ((flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1))
+                       continue;
+
+               /* legacy radeons only have a few post_divs */
+               if (flags & RADEON_PLL_LEGACY) {
+                       if ((post_div == 5) ||
+                           (post_div == 7) ||
+                           (post_div == 9) ||
+                           (post_div == 10) ||
+                           (post_div == 11) ||
+                           (post_div == 13) ||
+                           (post_div == 14) ||
+                           (post_div == 15))
+                               continue;
+               }
+
+               for (ref_div = min_ref_div; ref_div <= max_ref_div; ++ref_div) {
+                       uint32_t feedback_div, current_freq = 0, error, vco_diff;
+                       uint32_t pll_in = pll->reference_freq / ref_div;
+                       uint32_t min_feed_div = pll->min_feedback_div;
+                       uint32_t max_feed_div = pll->max_feedback_div + 1;
+
+                       if (pll_in < pll->pll_in_min || pll_in > pll->pll_in_max)
+                               continue;
+
+                       while (min_feed_div < max_feed_div) {
+                               uint32_t vco;
+                               uint32_t min_frac_feed_div = min_fractional_feed_div;
+                               uint32_t max_frac_feed_div = max_fractional_feed_div + 1;
+                               uint32_t frac_feedback_div;
+                               uint64_t tmp;
+
+                               feedback_div = (min_feed_div + max_feed_div) / 2;
+
+                               tmp = (uint64_t)pll->reference_freq * feedback_div;
+                               vco = radeon_div(tmp, ref_div);
+
+                               if (vco < pll->pll_out_min) {
+                                       min_feed_div = feedback_div + 1;
+                                       continue;
+                               } else if (vco > pll->pll_out_max) {
+                                       max_feed_div = feedback_div;
+                                       continue;
+                               }
+
+                               while (min_frac_feed_div < max_frac_feed_div) {
+                                       frac_feedback_div = (min_frac_feed_div + max_frac_feed_div) / 2;
+                                       tmp = (uint64_t)pll->reference_freq * 10000 * feedback_div;
+                                       tmp += (uint64_t)pll->reference_freq * 1000 * frac_feedback_div;
+                                       current_freq = radeon_div(tmp, ref_div * post_div);
+
+                                       error = abs(current_freq - freq);
+                                       vco_diff = abs(vco - best_vco);
+
+                                       if ((best_vco == 0 && error < best_error) ||
+                                           (best_vco != 0 &&
+                                            (error < best_error - 100 ||
+                                             (abs(error - best_error) < 100 && vco_diff < best_vco_diff)))) {
+                                               best_post_div = post_div;
+                                               best_ref_div = ref_div;
+                                               best_feedback_div = feedback_div;
+                                               best_frac_feedback_div = frac_feedback_div;
+                                               best_freq = current_freq;
+                                               best_error = error;
+                                               best_vco_diff = vco_diff;
+                                       } else if (current_freq == freq) {
+                                               if (best_freq == -1) {
+                                                       best_post_div = post_div;
+                                                       best_ref_div = ref_div;
+                                                       best_feedback_div = feedback_div;
+                                                       best_frac_feedback_div = frac_feedback_div;
+                                                       best_freq = current_freq;
+                                                       best_error = error;
+                                                       best_vco_diff = vco_diff;
+                                               } else if (((flags & RADEON_PLL_PREFER_LOW_REF_DIV) && (ref_div < best_ref_div)) ||
+                                                          ((flags & RADEON_PLL_PREFER_HIGH_REF_DIV) && (ref_div > best_ref_div)) ||
+                                                          ((flags & RADEON_PLL_PREFER_LOW_FB_DIV) && (feedback_div < best_feedback_div)) ||
+                                                          ((flags & RADEON_PLL_PREFER_HIGH_FB_DIV) && (feedback_div > best_feedback_div)) ||
+                                                          ((flags & RADEON_PLL_PREFER_LOW_POST_DIV) && (post_div < best_post_div)) ||
+                                                          ((flags & RADEON_PLL_PREFER_HIGH_POST_DIV) && (post_div > best_post_div))) {
+                                                       best_post_div = post_div;
+                                                       best_ref_div = ref_div;
+                                                       best_feedback_div = feedback_div;
+                                                       best_frac_feedback_div = frac_feedback_div;
+                                                       best_freq = current_freq;
+                                                       best_error = error;
+                                                       best_vco_diff = vco_diff;
+                                               }
+                                       }
+                                       if (current_freq < freq)
+                                               min_frac_feed_div = frac_feedback_div + 1;
+                                       else
+                                               max_frac_feed_div = frac_feedback_div;
+                               }
+                               if (current_freq < freq)
+                                       min_feed_div = feedback_div + 1;
+                               else
+                                       max_feed_div = feedback_div;
+                       }
+               }
+       }
+
+       *dot_clock_p = best_freq / 10000;
+       *fb_div_p = best_feedback_div;
+       *frac_fb_div_p = best_frac_feedback_div;
+       *ref_div_p = best_ref_div;
+       *post_div_p = best_post_div;
+}
+
+static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb)
+{
+       struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb);
+       struct drm_device *dev = fb->dev;
+
+       if (fb->fbdev)
+               radeonfb_remove(dev, fb);
+
+       if (radeon_fb->obj) {
+               radeon_gem_object_unpin(radeon_fb->obj);
+               mutex_lock(&dev->struct_mutex);
+               drm_gem_object_unreference(radeon_fb->obj);
+               mutex_unlock(&dev->struct_mutex);
+       }
+       drm_framebuffer_cleanup(fb);
+       kfree(radeon_fb);
+}
+
+static int radeon_user_framebuffer_create_handle(struct drm_framebuffer *fb,
+                                                 struct drm_file *file_priv,
+                                                 unsigned int *handle)
+{
+       struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb);
+
+       return drm_gem_handle_create(file_priv, radeon_fb->obj, handle);
+}
+
+static const struct drm_framebuffer_funcs radeon_fb_funcs = {
+       .destroy = radeon_user_framebuffer_destroy,
+       .create_handle = radeon_user_framebuffer_create_handle,
+};
+
+struct drm_framebuffer *
+radeon_framebuffer_create(struct drm_device *dev,
+                         struct drm_mode_fb_cmd *mode_cmd,
+                         struct drm_gem_object *obj)
+{
+       struct radeon_framebuffer *radeon_fb;
+
+       radeon_fb = kzalloc(sizeof(*radeon_fb), GFP_KERNEL);
+       if (radeon_fb == NULL) {
+               return NULL;
+       }
+       drm_framebuffer_init(dev, &radeon_fb->base, &radeon_fb_funcs);
+       drm_helper_mode_fill_fb_struct(&radeon_fb->base, mode_cmd);
+       radeon_fb->obj = obj;
+       return &radeon_fb->base;
+}
+
+static struct drm_framebuffer *
+radeon_user_framebuffer_create(struct drm_device *dev,
+                              struct drm_file *file_priv,
+                              struct drm_mode_fb_cmd *mode_cmd)
+{
+       struct drm_gem_object *obj;
+
+       obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle);
+
+       return radeon_framebuffer_create(dev, mode_cmd, obj);
+}
+
+static const struct drm_mode_config_funcs radeon_mode_funcs = {
+       .fb_create = radeon_user_framebuffer_create,
+       .fb_changed = radeonfb_probe,
+};
+
+int radeon_modeset_init(struct radeon_device *rdev)
+{
+       int num_crtc = 2, i;
+       int ret;
+
+       drm_mode_config_init(rdev->ddev);
+       rdev->mode_info.mode_config_initialized = true;
+
+       rdev->ddev->mode_config.funcs = (void *)&radeon_mode_funcs;
+
+       if (ASIC_IS_AVIVO(rdev)) {
+               rdev->ddev->mode_config.max_width = 8192;
+               rdev->ddev->mode_config.max_height = 8192;
+       } else {
+               rdev->ddev->mode_config.max_width = 4096;
+               rdev->ddev->mode_config.max_height = 4096;
+       }
+
+       rdev->ddev->mode_config.fb_base = rdev->mc.aper_base;
+
+       /* allocate crtcs - TODO single crtc */
+       for (i = 0; i < num_crtc; i++) {
+               radeon_crtc_init(rdev->ddev, i);
+       }
+
+       /* okay we should have all the bios connectors */
+       ret = radeon_setup_enc_conn(rdev->ddev);
+       if (!ret) {
+               return ret;
+       }
+       drm_helper_initial_config(rdev->ddev);
+       return 0;
+}
+
+void radeon_modeset_fini(struct radeon_device *rdev)
+{
+       if (rdev->mode_info.mode_config_initialized) {
+               drm_mode_config_cleanup(rdev->ddev);
+               rdev->mode_info.mode_config_initialized = false;
+       }
+}
+
+void radeon_init_disp_bandwidth(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       struct drm_display_mode *modes[2];
+       int pixel_bytes[2];
+       struct drm_crtc *crtc;
+
+       pixel_bytes[0] = pixel_bytes[1] = 0;
+       modes[0] = modes[1] = NULL;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+
+               if (crtc->enabled && crtc->fb) {
+                       modes[radeon_crtc->crtc_id] = &crtc->mode;
+                       pixel_bytes[radeon_crtc->crtc_id] = crtc->fb->bits_per_pixel / 8;
+               }
+       }
+
+       if (ASIC_IS_AVIVO(rdev)) {
+               radeon_init_disp_bw_avivo(dev,
+                                         modes[0],
+                                         pixel_bytes[0],
+                                         modes[1],
+                                         pixel_bytes[1]);
+       } else {
+               radeon_init_disp_bw_legacy(dev,
+                                          modes[0],
+                                          pixel_bytes[0],
+                                          modes[1],
+                                          pixel_bytes[1]);
+       }
+}
index 13a60f4d42275f772c81a360d0c2d60fd83f8c17..c815a2cbf7b3ed328259ec9f4e855ccb3967ec39 100644 (file)
 #include "radeon_drv.h"
 
 #include "drm_pciids.h"
+#include <linux/console.h>
+
+
+#if defined(CONFIG_DRM_RADEON_KMS)
+/*
+ * KMS wrapper.
+ */
+#define KMS_DRIVER_MAJOR       2
+#define KMS_DRIVER_MINOR       0
+#define KMS_DRIVER_PATCHLEVEL  0
+int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
+int radeon_driver_unload_kms(struct drm_device *dev);
+int radeon_driver_firstopen_kms(struct drm_device *dev);
+void radeon_driver_lastclose_kms(struct drm_device *dev);
+int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv);
+void radeon_driver_postclose_kms(struct drm_device *dev,
+                                struct drm_file *file_priv);
+void radeon_driver_preclose_kms(struct drm_device *dev,
+                               struct drm_file *file_priv);
+int radeon_suspend_kms(struct drm_device *dev, pm_message_t state);
+int radeon_resume_kms(struct drm_device *dev);
+u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc);
+int radeon_enable_vblank_kms(struct drm_device *dev, int crtc);
+void radeon_disable_vblank_kms(struct drm_device *dev, int crtc);
+void radeon_driver_irq_preinstall_kms(struct drm_device *dev);
+int radeon_driver_irq_postinstall_kms(struct drm_device *dev);
+void radeon_driver_irq_uninstall_kms(struct drm_device *dev);
+irqreturn_t radeon_driver_irq_handler_kms(DRM_IRQ_ARGS);
+int radeon_master_create_kms(struct drm_device *dev, struct drm_master *master);
+void radeon_master_destroy_kms(struct drm_device *dev,
+                              struct drm_master *master);
+int radeon_dma_ioctl_kms(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv);
+int radeon_gem_object_init(struct drm_gem_object *obj);
+void radeon_gem_object_free(struct drm_gem_object *obj);
+extern struct drm_ioctl_desc radeon_ioctls_kms[];
+extern int radeon_max_kms_ioctl;
+int radeon_mmap(struct file *filp, struct vm_area_struct *vma);
+#if defined(CONFIG_DEBUG_FS)
+int radeon_debugfs_init(struct drm_minor *minor);
+void radeon_debugfs_cleanup(struct drm_minor *minor);
+#endif
+#endif
+
 
 int radeon_no_wb;
+#if defined(CONFIG_DRM_RADEON_KMS)
+int radeon_modeset = -1;
+int radeon_dynclks = -1;
+int radeon_r4xx_atom = 0;
+int radeon_agpmode = 0;
+int radeon_vram_limit = 0;
+int radeon_gart_size = 512; /* default gart size */
+int radeon_benchmarking = 0;
+int radeon_connector_table = 0;
+#endif
 
 MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
 module_param_named(no_wb, radeon_no_wb, int, 0444);
 
+#if defined(CONFIG_DRM_RADEON_KMS)
+MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
+module_param_named(modeset, radeon_modeset, int, 0400);
+
+MODULE_PARM_DESC(dynclks, "Disable/Enable dynamic clocks");
+module_param_named(dynclks, radeon_dynclks, int, 0444);
+
+MODULE_PARM_DESC(r4xx_atom, "Enable ATOMBIOS modesetting for R4xx");
+module_param_named(r4xx_atom, radeon_r4xx_atom, int, 0444);
+
+MODULE_PARM_DESC(vramlimit, "Restrict VRAM for testing");
+module_param_named(vramlimit, radeon_vram_limit, int, 0600);
+
+MODULE_PARM_DESC(agpmode, "AGP Mode (-1 == PCI)");
+module_param_named(agpmode, radeon_agpmode, int, 0444);
+
+MODULE_PARM_DESC(gartsize, "Size of PCIE/IGP gart to setup in megabytes (32,64, etc)\n");
+module_param_named(gartsize, radeon_gart_size, int, 0600);
+
+MODULE_PARM_DESC(benchmark, "Run benchmark");
+module_param_named(benchmark, radeon_benchmarking, int, 0444);
+
+MODULE_PARM_DESC(connector_table, "Force connector table");
+module_param_named(connector_table, radeon_connector_table, int, 0444);
+#endif
+
 static int radeon_suspend(struct drm_device *dev, pm_message_t state)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -73,7 +153,11 @@ static struct pci_device_id pciidlist[] = {
        radeon_PCI_IDS
 };
 
-static struct drm_driver driver = {
+#if defined(CONFIG_DRM_RADEON_KMS)
+MODULE_DEVICE_TABLE(pci, pciidlist);
+#endif
+
+static struct drm_driver driver_old = {
        .driver_features =
            DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
            DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED,
@@ -127,18 +211,141 @@ static struct drm_driver driver = {
        .patchlevel = DRIVER_PATCHLEVEL,
 };
 
+#if defined(CONFIG_DRM_RADEON_KMS)
+static struct drm_driver kms_driver;
+
+static int __devinit
+radeon_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       return drm_get_dev(pdev, ent, &kms_driver);
+}
+
+static void
+radeon_pci_remove(struct pci_dev *pdev)
+{
+       struct drm_device *dev = pci_get_drvdata(pdev);
+
+       drm_put_dev(dev);
+}
+
+static int
+radeon_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct drm_device *dev = pci_get_drvdata(pdev);
+       return radeon_suspend_kms(dev, state);
+}
+
+static int
+radeon_pci_resume(struct pci_dev *pdev)
+{
+       struct drm_device *dev = pci_get_drvdata(pdev);
+       return radeon_resume_kms(dev);
+}
+
+static struct drm_driver kms_driver = {
+       .driver_features =
+           DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
+           DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED | DRIVER_GEM,
+       .dev_priv_size = 0,
+       .load = radeon_driver_load_kms,
+       .firstopen = radeon_driver_firstopen_kms,
+       .open = radeon_driver_open_kms,
+       .preclose = radeon_driver_preclose_kms,
+       .postclose = radeon_driver_postclose_kms,
+       .lastclose = radeon_driver_lastclose_kms,
+       .unload = radeon_driver_unload_kms,
+       .suspend = radeon_suspend_kms,
+       .resume = radeon_resume_kms,
+       .get_vblank_counter = radeon_get_vblank_counter_kms,
+       .enable_vblank = radeon_enable_vblank_kms,
+       .disable_vblank = radeon_disable_vblank_kms,
+       .master_create = radeon_master_create_kms,
+       .master_destroy = radeon_master_destroy_kms,
+#if defined(CONFIG_DEBUG_FS)
+       .debugfs_init = radeon_debugfs_init,
+       .debugfs_cleanup = radeon_debugfs_cleanup,
+#endif
+       .irq_preinstall = radeon_driver_irq_preinstall_kms,
+       .irq_postinstall = radeon_driver_irq_postinstall_kms,
+       .irq_uninstall = radeon_driver_irq_uninstall_kms,
+       .irq_handler = radeon_driver_irq_handler_kms,
+       .reclaim_buffers = drm_core_reclaim_buffers,
+       .get_map_ofs = drm_core_get_map_ofs,
+       .get_reg_ofs = drm_core_get_reg_ofs,
+       .ioctls = radeon_ioctls_kms,
+       .gem_init_object = radeon_gem_object_init,
+       .gem_free_object = radeon_gem_object_free,
+       .dma_ioctl = radeon_dma_ioctl_kms,
+       .fops = {
+                .owner = THIS_MODULE,
+                .open = drm_open,
+                .release = drm_release,
+                .ioctl = drm_ioctl,
+                .mmap = radeon_mmap,
+                .poll = drm_poll,
+                .fasync = drm_fasync,
+#ifdef CONFIG_COMPAT
+                .compat_ioctl = NULL,
+#endif
+       },
+
+       .pci_driver = {
+                .name = DRIVER_NAME,
+                .id_table = pciidlist,
+                .probe = radeon_pci_probe,
+                .remove = radeon_pci_remove,
+                .suspend = radeon_pci_suspend,
+                .resume = radeon_pci_resume,
+       },
+
+       .name = DRIVER_NAME,
+       .desc = DRIVER_DESC,
+       .date = DRIVER_DATE,
+       .major = KMS_DRIVER_MAJOR,
+       .minor = KMS_DRIVER_MINOR,
+       .patchlevel = KMS_DRIVER_PATCHLEVEL,
+};
+#endif
+
+static struct drm_driver *driver;
+
 static int __init radeon_init(void)
 {
-       driver.num_ioctls = radeon_max_ioctl;
-       return drm_init(&driver);
+       driver = &driver_old;
+       driver->num_ioctls = radeon_max_ioctl;
+#if defined(CONFIG_DRM_RADEON_KMS) && defined(CONFIG_X86)
+       /* if enabled by default */
+       if (radeon_modeset == -1) {
+               DRM_INFO("radeon default to kernel modesetting.\n");
+               radeon_modeset = 1;
+       }
+       if (radeon_modeset == 1) {
+               DRM_INFO("radeon kernel modesetting enabled.\n");
+               driver = &kms_driver;
+               driver->driver_features |= DRIVER_MODESET;
+               driver->num_ioctls = radeon_max_kms_ioctl;
+       }
+
+       /* if the vga console setting is enabled still
+        * let modprobe override it */
+#ifdef CONFIG_VGA_CONSOLE
+       if (vgacon_text_force() && radeon_modeset == -1) {
+               DRM_INFO("VGACON disable radeon kernel modesetting.\n");
+               driver = &driver_old;
+               driver->driver_features &= ~DRIVER_MODESET;
+               radeon_modeset = 0;
+       }
+#endif
+#endif
+       return drm_init(driver);
 }
 
 static void __exit radeon_exit(void)
 {
-       drm_exit(&driver);
+       drm_exit(driver);
 }
 
-module_init(radeon_init);
+late_initcall(radeon_init);
 module_exit(radeon_exit);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c
new file mode 100644 (file)
index 0000000..c8ef0d1
--- /dev/null
@@ -0,0 +1,1708 @@
+/*
+ * Copyright 2007-8 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ */
+#include "drmP.h"
+#include "drm_crtc_helper.h"
+#include "radeon_drm.h"
+#include "radeon.h"
+#include "atom.h"
+
+extern int atom_debug;
+
+uint32_t
+radeon_get_encoder_id(struct drm_device *dev, uint32_t supported_device, uint8_t dac)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t ret = 0;
+
+       switch (supported_device) {
+       case ATOM_DEVICE_CRT1_SUPPORT:
+       case ATOM_DEVICE_TV1_SUPPORT:
+       case ATOM_DEVICE_TV2_SUPPORT:
+       case ATOM_DEVICE_CRT2_SUPPORT:
+       case ATOM_DEVICE_CV_SUPPORT:
+               switch (dac) {
+               case 1: /* dac a */
+                       if ((rdev->family == CHIP_RS300) ||
+                           (rdev->family == CHIP_RS400) ||
+                           (rdev->family == CHIP_RS480))
+                               ret = ENCODER_OBJECT_ID_INTERNAL_DAC2;
+                       else if (ASIC_IS_AVIVO(rdev))
+                               ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1;
+                       else
+                               ret = ENCODER_OBJECT_ID_INTERNAL_DAC1;
+                       break;
+               case 2: /* dac b */
+                       if (ASIC_IS_AVIVO(rdev))
+                               ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2;
+                       else {
+                               /*if (rdev->family == CHIP_R200)
+                                 ret = ENCODER_OBJECT_ID_INTERNAL_DVO1;
+                                 else*/
+                               ret = ENCODER_OBJECT_ID_INTERNAL_DAC2;
+                       }
+                       break;
+               case 3: /* external dac */
+                       if (ASIC_IS_AVIVO(rdev))
+                               ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1;
+                       else
+                               ret = ENCODER_OBJECT_ID_INTERNAL_DVO1;
+                       break;
+               }
+               break;
+       case ATOM_DEVICE_LCD1_SUPPORT:
+               if (ASIC_IS_AVIVO(rdev))
+                       ret = ENCODER_OBJECT_ID_INTERNAL_LVTM1;
+               else
+                       ret = ENCODER_OBJECT_ID_INTERNAL_LVDS;
+               break;
+       case ATOM_DEVICE_DFP1_SUPPORT:
+               if ((rdev->family == CHIP_RS300) ||
+                   (rdev->family == CHIP_RS400) ||
+                   (rdev->family == CHIP_RS480))
+                       ret = ENCODER_OBJECT_ID_INTERNAL_DVO1;
+               else if (ASIC_IS_AVIVO(rdev))
+                       ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1;
+               else
+                       ret = ENCODER_OBJECT_ID_INTERNAL_TMDS1;
+               break;
+       case ATOM_DEVICE_LCD2_SUPPORT:
+       case ATOM_DEVICE_DFP2_SUPPORT:
+               if ((rdev->family == CHIP_RS600) ||
+                   (rdev->family == CHIP_RS690) ||
+                   (rdev->family == CHIP_RS740))
+                       ret = ENCODER_OBJECT_ID_INTERNAL_DDI;
+               else if (ASIC_IS_AVIVO(rdev))
+                       ret = ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1;
+               else
+                       ret = ENCODER_OBJECT_ID_INTERNAL_DVO1;
+               break;
+       case ATOM_DEVICE_DFP3_SUPPORT:
+               ret = ENCODER_OBJECT_ID_INTERNAL_LVTM1;
+               break;
+       }
+
+       return ret;
+}
+
+void
+radeon_link_encoder_connector(struct drm_device *dev)
+{
+       struct drm_connector *connector;
+       struct radeon_connector *radeon_connector;
+       struct drm_encoder *encoder;
+       struct radeon_encoder *radeon_encoder;
+
+       /* walk the list and link encoders to connectors */
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               radeon_connector = to_radeon_connector(connector);
+               list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+                       radeon_encoder = to_radeon_encoder(encoder);
+                       if (radeon_encoder->devices & radeon_connector->devices)
+                               drm_mode_connector_attach_encoder(connector, encoder);
+               }
+       }
+}
+
+static struct drm_connector *
+radeon_get_connector_for_encoder(struct drm_encoder *encoder)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct drm_connector *connector;
+       struct radeon_connector *radeon_connector;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               radeon_connector = to_radeon_connector(connector);
+               if (radeon_encoder->devices & radeon_connector->devices)
+                       return connector;
+       }
+       return NULL;
+}
+
+/* used for both atom and legacy */
+void radeon_rmx_mode_fixup(struct drm_encoder *encoder,
+                          struct drm_display_mode *mode,
+                          struct drm_display_mode *adjusted_mode)
+{
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_native_mode *native_mode = &radeon_encoder->native_mode;
+
+       if (mode->hdisplay < native_mode->panel_xres ||
+           mode->vdisplay < native_mode->panel_yres) {
+               radeon_encoder->flags |= RADEON_USE_RMX;
+               if (ASIC_IS_AVIVO(rdev)) {
+                       adjusted_mode->hdisplay = native_mode->panel_xres;
+                       adjusted_mode->vdisplay = native_mode->panel_yres;
+                       adjusted_mode->htotal = native_mode->panel_xres + native_mode->hblank;
+                       adjusted_mode->hsync_start = native_mode->panel_xres + native_mode->hoverplus;
+                       adjusted_mode->hsync_end = adjusted_mode->hsync_start + native_mode->hsync_width;
+                       adjusted_mode->vtotal = native_mode->panel_yres + native_mode->vblank;
+                       adjusted_mode->vsync_start = native_mode->panel_yres + native_mode->voverplus;
+                       adjusted_mode->vsync_end = adjusted_mode->vsync_start + native_mode->vsync_width;
+                       /* update crtc values */
+                       drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
+                       /* adjust crtc values */
+                       adjusted_mode->crtc_hdisplay = native_mode->panel_xres;
+                       adjusted_mode->crtc_vdisplay = native_mode->panel_yres;
+                       adjusted_mode->crtc_htotal = adjusted_mode->crtc_hdisplay + native_mode->hblank;
+                       adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hdisplay + native_mode->hoverplus;
+                       adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + native_mode->hsync_width;
+                       adjusted_mode->crtc_vtotal = adjusted_mode->crtc_vdisplay + native_mode->vblank;
+                       adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + native_mode->voverplus;
+                       adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + native_mode->vsync_width;
+               } else {
+                       adjusted_mode->htotal = native_mode->panel_xres + native_mode->hblank;
+                       adjusted_mode->hsync_start = native_mode->panel_xres + native_mode->hoverplus;
+                       adjusted_mode->hsync_end = adjusted_mode->hsync_start + native_mode->hsync_width;
+                       adjusted_mode->vtotal = native_mode->panel_yres + native_mode->vblank;
+                       adjusted_mode->vsync_start = native_mode->panel_yres + native_mode->voverplus;
+                       adjusted_mode->vsync_end = adjusted_mode->vsync_start + native_mode->vsync_width;
+                       /* update crtc values */
+                       drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
+                       /* adjust crtc values */
+                       adjusted_mode->crtc_htotal = adjusted_mode->crtc_hdisplay + native_mode->hblank;
+                       adjusted_mode->crtc_hsync_start = adjusted_mode->crtc_hdisplay + native_mode->hoverplus;
+                       adjusted_mode->crtc_hsync_end = adjusted_mode->crtc_hsync_start + native_mode->hsync_width;
+                       adjusted_mode->crtc_vtotal = adjusted_mode->crtc_vdisplay + native_mode->vblank;
+                       adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + native_mode->voverplus;
+                       adjusted_mode->crtc_vsync_end = adjusted_mode->crtc_vsync_start + native_mode->vsync_width;
+               }
+               adjusted_mode->flags = native_mode->flags;
+               adjusted_mode->clock = native_mode->dotclock;
+       }
+}
+
+static bool radeon_atom_mode_fixup(struct drm_encoder *encoder,
+                                  struct drm_display_mode *mode,
+                                  struct drm_display_mode *adjusted_mode)
+{
+
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+
+       radeon_encoder->flags &= ~RADEON_USE_RMX;
+
+       drm_mode_set_crtcinfo(adjusted_mode, 0);
+
+       if (radeon_encoder->rmx_type != RMX_OFF)
+               radeon_rmx_mode_fixup(encoder, mode, adjusted_mode);
+
+       /* hw bug */
+       if ((mode->flags & DRM_MODE_FLAG_INTERLACE)
+           && (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2)))
+               adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2;
+
+       return true;
+}
+
+static void
+atombios_dac_setup(struct drm_encoder *encoder, int action)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       DAC_ENCODER_CONTROL_PS_ALLOCATION args;
+       int index = 0, num = 0;
+       /* fixme - fill in enc_priv for atom dac */
+       enum radeon_tv_std tv_std = TV_STD_NTSC;
+
+       memset(&args, 0, sizeof(args));
+
+       switch (radeon_encoder->encoder_id) {
+       case ENCODER_OBJECT_ID_INTERNAL_DAC1:
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
+               index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl);
+               num = 1;
+               break;
+       case ENCODER_OBJECT_ID_INTERNAL_DAC2:
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
+               index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl);
+               num = 2;
+               break;
+       }
+
+       args.ucAction = action;
+
+       if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT))
+               args.ucDacStandard = ATOM_DAC1_PS2;
+       else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT))
+               args.ucDacStandard = ATOM_DAC1_CV;
+       else {
+               switch (tv_std) {
+               case TV_STD_PAL:
+               case TV_STD_PAL_M:
+               case TV_STD_SCART_PAL:
+               case TV_STD_SECAM:
+               case TV_STD_PAL_CN:
+                       args.ucDacStandard = ATOM_DAC1_PAL;
+                       break;
+               case TV_STD_NTSC:
+               case TV_STD_NTSC_J:
+               case TV_STD_PAL_60:
+               default:
+                       args.ucDacStandard = ATOM_DAC1_NTSC;
+                       break;
+               }
+       }
+       args.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+}
+
+static void
+atombios_tv_setup(struct drm_encoder *encoder, int action)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       TV_ENCODER_CONTROL_PS_ALLOCATION args;
+       int index = 0;
+       /* fixme - fill in enc_priv for atom dac */
+       enum radeon_tv_std tv_std = TV_STD_NTSC;
+
+       memset(&args, 0, sizeof(args));
+
+       index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl);
+
+       args.sTVEncoder.ucAction = action;
+
+       if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT))
+               args.sTVEncoder.ucTvStandard = ATOM_TV_CV;
+       else {
+               switch (tv_std) {
+               case TV_STD_NTSC:
+                       args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC;
+                       break;
+               case TV_STD_PAL:
+                       args.sTVEncoder.ucTvStandard = ATOM_TV_PAL;
+                       break;
+               case TV_STD_PAL_M:
+                       args.sTVEncoder.ucTvStandard = ATOM_TV_PALM;
+                       break;
+               case TV_STD_PAL_60:
+                       args.sTVEncoder.ucTvStandard = ATOM_TV_PAL60;
+                       break;
+               case TV_STD_NTSC_J:
+                       args.sTVEncoder.ucTvStandard = ATOM_TV_NTSCJ;
+                       break;
+               case TV_STD_SCART_PAL:
+                       args.sTVEncoder.ucTvStandard = ATOM_TV_PAL; /* ??? */
+                       break;
+               case TV_STD_SECAM:
+                       args.sTVEncoder.ucTvStandard = ATOM_TV_SECAM;
+                       break;
+               case TV_STD_PAL_CN:
+                       args.sTVEncoder.ucTvStandard = ATOM_TV_PALCN;
+                       break;
+               default:
+                       args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC;
+                       break;
+               }
+       }
+
+       args.sTVEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+}
+
+void
+atombios_external_tmds_setup(struct drm_encoder *encoder, int action)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION args;
+       int index = 0;
+
+       memset(&args, 0, sizeof(args));
+
+       index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
+
+       args.sXTmdsEncoder.ucEnable = action;
+
+       if (radeon_encoder->pixel_clock > 165000)
+               args.sXTmdsEncoder.ucMisc = PANEL_ENCODER_MISC_DUAL;
+
+       /*if (pScrn->rgbBits == 8)*/
+       args.sXTmdsEncoder.ucMisc |= (1 << 1);
+
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+}
+
+static void
+atombios_ddia_setup(struct drm_encoder *encoder, int action)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       DVO_ENCODER_CONTROL_PS_ALLOCATION args;
+       int index = 0;
+
+       memset(&args, 0, sizeof(args));
+
+       index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl);
+
+       args.sDVOEncoder.ucAction = action;
+       args.sDVOEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+
+       if (radeon_encoder->pixel_clock > 165000)
+               args.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute = PANEL_ENCODER_MISC_DUAL;
+
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+}
+
+union lvds_encoder_control {
+       LVDS_ENCODER_CONTROL_PS_ALLOCATION    v1;
+       LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 v2;
+};
+
+static void
+atombios_digital_setup(struct drm_encoder *encoder, int action)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       union lvds_encoder_control args;
+       int index = 0;
+       uint8_t frev, crev;
+       struct radeon_encoder_atom_dig *dig;
+       struct drm_connector *connector;
+       struct radeon_connector *radeon_connector;
+       struct radeon_connector_atom_dig *dig_connector;
+
+       connector = radeon_get_connector_for_encoder(encoder);
+       if (!connector)
+               return;
+
+       radeon_connector = to_radeon_connector(connector);
+
+       if (!radeon_encoder->enc_priv)
+               return;
+
+       dig = radeon_encoder->enc_priv;
+
+       if (!radeon_connector->con_priv)
+               return;
+
+       dig_connector = radeon_connector->con_priv;
+
+       memset(&args, 0, sizeof(args));
+
+       switch (radeon_encoder->encoder_id) {
+       case ENCODER_OBJECT_ID_INTERNAL_LVDS:
+               index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl);
+               break;
+       case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
+               index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl);
+               break;
+       case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
+               if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
+                       index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl);
+               else
+                       index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl);
+               break;
+       }
+
+       atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev);
+
+       switch (frev) {
+       case 1:
+       case 2:
+               switch (crev) {
+               case 1:
+                       args.v1.ucMisc = 0;
+                       args.v1.ucAction = action;
+                       if (drm_detect_hdmi_monitor((struct edid *)connector->edid_blob_ptr))
+                               args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
+                       args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+                       if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+                               if (dig->lvds_misc & (1 << 0))
+                                       args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL;
+                               if (dig->lvds_misc & (1 << 1))
+                                       args.v1.ucMisc |= (1 << 1);
+                       } else {
+                               if (dig_connector->linkb)
+                                       args.v1.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB;
+                               if (radeon_encoder->pixel_clock > 165000)
+                                       args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL;
+                               /*if (pScrn->rgbBits == 8) */
+                               args.v1.ucMisc |= (1 << 1);
+                       }
+                       break;
+               case 2:
+               case 3:
+                       args.v2.ucMisc = 0;
+                       args.v2.ucAction = action;
+                       if (crev == 3) {
+                               if (dig->coherent_mode)
+                                       args.v2.ucMisc |= PANEL_ENCODER_MISC_COHERENT;
+                       }
+                       if (drm_detect_hdmi_monitor((struct edid *)connector->edid_blob_ptr))
+                               args.v2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE;
+                       args.v2.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+                       args.v2.ucTruncate = 0;
+                       args.v2.ucSpatial = 0;
+                       args.v2.ucTemporal = 0;
+                       args.v2.ucFRC = 0;
+                       if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+                               if (dig->lvds_misc & (1 << 0))
+                                       args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL;
+                               if (dig->lvds_misc & (1 << 5)) {
+                                       args.v2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN;
+                                       if (dig->lvds_misc & (1 << 1))
+                                               args.v2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH;
+                               }
+                               if (dig->lvds_misc & (1 << 6)) {
+                                       args.v2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN;
+                                       if (dig->lvds_misc & (1 << 1))
+                                               args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH;
+                                       if (((dig->lvds_misc >> 2) & 0x3) == 2)
+                                               args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4;
+                               }
+                       } else {
+                               if (dig_connector->linkb)
+                                       args.v2.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB;
+                               if (radeon_encoder->pixel_clock > 165000)
+                                       args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL;
+                       }
+                       break;
+               default:
+                       DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+                       break;
+               }
+               break;
+       default:
+               DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+               break;
+       }
+
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+}
+
+int
+atombios_get_encoder_mode(struct drm_encoder *encoder)
+{
+       struct drm_connector *connector;
+       struct radeon_connector *radeon_connector;
+
+       connector = radeon_get_connector_for_encoder(encoder);
+       if (!connector)
+               return 0;
+
+       radeon_connector = to_radeon_connector(connector);
+
+       switch (connector->connector_type) {
+       case DRM_MODE_CONNECTOR_DVII:
+               if (drm_detect_hdmi_monitor((struct edid *)connector->edid_blob_ptr))
+                       return ATOM_ENCODER_MODE_HDMI;
+               else if (radeon_connector->use_digital)
+                       return ATOM_ENCODER_MODE_DVI;
+               else
+                       return ATOM_ENCODER_MODE_CRT;
+               break;
+       case DRM_MODE_CONNECTOR_DVID:
+       case DRM_MODE_CONNECTOR_HDMIA:
+       case DRM_MODE_CONNECTOR_HDMIB:
+       default:
+               if (drm_detect_hdmi_monitor((struct edid *)connector->edid_blob_ptr))
+                       return ATOM_ENCODER_MODE_HDMI;
+               else
+                       return ATOM_ENCODER_MODE_DVI;
+               break;
+       case DRM_MODE_CONNECTOR_LVDS:
+               return ATOM_ENCODER_MODE_LVDS;
+               break;
+       case DRM_MODE_CONNECTOR_DisplayPort:
+               /*if (radeon_output->MonType == MT_DP)
+                 return ATOM_ENCODER_MODE_DP;
+                 else*/
+               if (drm_detect_hdmi_monitor((struct edid *)connector->edid_blob_ptr))
+                       return ATOM_ENCODER_MODE_HDMI;
+               else
+                       return ATOM_ENCODER_MODE_DVI;
+               break;
+       case CONNECTOR_DVI_A:
+       case CONNECTOR_VGA:
+               return ATOM_ENCODER_MODE_CRT;
+               break;
+       case CONNECTOR_STV:
+       case CONNECTOR_CTV:
+       case CONNECTOR_DIN:
+               /* fix me */
+               return ATOM_ENCODER_MODE_TV;
+               /*return ATOM_ENCODER_MODE_CV;*/
+               break;
+       }
+}
+
+static void
+atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       DIG_ENCODER_CONTROL_PS_ALLOCATION args;
+       int index = 0, num = 0;
+       uint8_t frev, crev;
+       struct radeon_encoder_atom_dig *dig;
+       struct drm_connector *connector;
+       struct radeon_connector *radeon_connector;
+       struct radeon_connector_atom_dig *dig_connector;
+
+       connector = radeon_get_connector_for_encoder(encoder);
+       if (!connector)
+               return;
+
+       radeon_connector = to_radeon_connector(connector);
+
+       if (!radeon_connector->con_priv)
+               return;
+
+       dig_connector = radeon_connector->con_priv;
+
+       if (!radeon_encoder->enc_priv)
+               return;
+
+       dig = radeon_encoder->enc_priv;
+
+       memset(&args, 0, sizeof(args));
+
+       if (ASIC_IS_DCE32(rdev)) {
+               if (dig->dig_block)
+                       index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl);
+               else
+                       index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl);
+               num = dig->dig_block + 1;
+       } else {
+               switch (radeon_encoder->encoder_id) {
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+                       index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl);
+                       num = 1;
+                       break;
+               case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+                       index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl);
+                       num = 2;
+                       break;
+               }
+       }
+
+       atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev);
+
+       args.ucAction = action;
+       args.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+
+       if (ASIC_IS_DCE32(rdev)) {
+               switch (radeon_encoder->encoder_id) {
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+                       args.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1;
+                       break;
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+                       args.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER2;
+                       break;
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+                       args.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3;
+                       break;
+               }
+       } else {
+               switch (radeon_encoder->encoder_id) {
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+                       args.ucConfig = ATOM_ENCODER_CONFIG_TRANSMITTER1;
+                       break;
+               case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+                       args.ucConfig = ATOM_ENCODER_CONFIG_TRANSMITTER2;
+                       break;
+               }
+       }
+
+       if (radeon_encoder->pixel_clock > 165000) {
+               args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA_B;
+               args.ucLaneNum = 8;
+       } else {
+               if (dig_connector->linkb)
+                       args.ucConfig |= ATOM_ENCODER_CONFIG_LINKB;
+               else
+                       args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA;
+               args.ucLaneNum = 4;
+       }
+
+       args.ucEncoderMode = atombios_get_encoder_mode(encoder);
+
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+}
+
+union dig_transmitter_control {
+       DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1;
+       DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2;
+};
+
+static void
+atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       union dig_transmitter_control args;
+       int index = 0, num = 0;
+       uint8_t frev, crev;
+       struct radeon_encoder_atom_dig *dig;
+       struct drm_connector *connector;
+       struct radeon_connector *radeon_connector;
+       struct radeon_connector_atom_dig *dig_connector;
+
+       connector = radeon_get_connector_for_encoder(encoder);
+       if (!connector)
+               return;
+
+       radeon_connector = to_radeon_connector(connector);
+
+       if (!radeon_encoder->enc_priv)
+               return;
+
+       dig = radeon_encoder->enc_priv;
+
+       if (!radeon_connector->con_priv)
+               return;
+
+       dig_connector = radeon_connector->con_priv;
+
+       memset(&args, 0, sizeof(args));
+
+       if (ASIC_IS_DCE32(rdev))
+               index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl);
+       else {
+               switch (radeon_encoder->encoder_id) {
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+                       index = GetIndexIntoMasterTable(COMMAND, DIG1TransmitterControl);
+                       break;
+               case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+                       index = GetIndexIntoMasterTable(COMMAND, DIG2TransmitterControl);
+                       break;
+               }
+       }
+
+       atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev);
+
+       args.v1.ucAction = action;
+
+       if (ASIC_IS_DCE32(rdev)) {
+               if (radeon_encoder->pixel_clock > 165000) {
+                       args.v2.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock * 10 * 2) / 100);
+                       args.v2.acConfig.fDualLinkConnector = 1;
+               } else {
+                       args.v2.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock * 10 * 4) / 100);
+               }
+               if (dig->dig_block)
+                       args.v2.acConfig.ucEncoderSel = 1;
+
+               switch (radeon_encoder->encoder_id) {
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+                       args.v2.acConfig.ucTransmitterSel = 0;
+                       num = 0;
+                       break;
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+                       args.v2.acConfig.ucTransmitterSel = 1;
+                       num = 1;
+                       break;
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+                       args.v2.acConfig.ucTransmitterSel = 2;
+                       num = 2;
+                       break;
+               }
+
+               if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
+                       if (dig->coherent_mode)
+                               args.v2.acConfig.fCoherentMode = 1;
+               }
+       } else {
+               args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL;
+               args.v1.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock) / 10);
+
+               switch (radeon_encoder->encoder_id) {
+               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+                       args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER;
+                       if (rdev->flags & RADEON_IS_IGP) {
+                               if (radeon_encoder->pixel_clock > 165000) {
+                                       args.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK |
+                                                            ATOM_TRANSMITTER_CONFIG_LINKA_B);
+                                       if (dig_connector->igp_lane_info & 0x3)
+                                               args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7;
+                                       else if (dig_connector->igp_lane_info & 0xc)
+                                               args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15;
+                               } else {
+                                       args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA;
+                                       if (dig_connector->igp_lane_info & 0x1)
+                                               args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3;
+                                       else if (dig_connector->igp_lane_info & 0x2)
+                                               args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_4_7;
+                                       else if (dig_connector->igp_lane_info & 0x4)
+                                               args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_11;
+                                       else if (dig_connector->igp_lane_info & 0x8)
+                                               args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15;
+                               }
+                       } else {
+                               if (radeon_encoder->pixel_clock > 165000)
+                                       args.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK |
+                                                            ATOM_TRANSMITTER_CONFIG_LINKA_B |
+                                                            ATOM_TRANSMITTER_CONFIG_LANE_0_7);
+                               else {
+                                       if (dig_connector->linkb)
+                                               args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
+                                       else
+                                               args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
+                               }
+                       }
+                       break;
+               case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+                       args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER;
+                       if (radeon_encoder->pixel_clock > 165000)
+                               args.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK |
+                                                    ATOM_TRANSMITTER_CONFIG_LINKA_B |
+                                                    ATOM_TRANSMITTER_CONFIG_LANE_0_7);
+                       else {
+                               if (dig_connector->linkb)
+                                       args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
+                               else
+                                       args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
+                       }
+                       break;
+               }
+
+               if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
+                       if (dig->coherent_mode)
+                               args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT;
+               }
+       }
+
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+}
+
+static void atom_rv515_force_tv_scaler(struct radeon_device *rdev)
+{
+
+       WREG32(0x659C, 0x0);
+       WREG32(0x6594, 0x705);
+       WREG32(0x65A4, 0x10001);
+       WREG32(0x65D8, 0x0);
+       WREG32(0x65B0, 0x0);
+       WREG32(0x65C0, 0x0);
+       WREG32(0x65D4, 0x0);
+       WREG32(0x6578, 0x0);
+       WREG32(0x657C, 0x841880A8);
+       WREG32(0x6578, 0x1);
+       WREG32(0x657C, 0x84208680);
+       WREG32(0x6578, 0x2);
+       WREG32(0x657C, 0xBFF880B0);
+       WREG32(0x6578, 0x100);
+       WREG32(0x657C, 0x83D88088);
+       WREG32(0x6578, 0x101);
+       WREG32(0x657C, 0x84608680);
+       WREG32(0x6578, 0x102);
+       WREG32(0x657C, 0xBFF080D0);
+       WREG32(0x6578, 0x200);
+       WREG32(0x657C, 0x83988068);
+       WREG32(0x6578, 0x201);
+       WREG32(0x657C, 0x84A08680);
+       WREG32(0x6578, 0x202);
+       WREG32(0x657C, 0xBFF080F8);
+       WREG32(0x6578, 0x300);
+       WREG32(0x657C, 0x83588058);
+       WREG32(0x6578, 0x301);
+       WREG32(0x657C, 0x84E08660);
+       WREG32(0x6578, 0x302);
+       WREG32(0x657C, 0xBFF88120);
+       WREG32(0x6578, 0x400);
+       WREG32(0x657C, 0x83188040);
+       WREG32(0x6578, 0x401);
+       WREG32(0x657C, 0x85008660);
+       WREG32(0x6578, 0x402);
+       WREG32(0x657C, 0xBFF88150);
+       WREG32(0x6578, 0x500);
+       WREG32(0x657C, 0x82D88030);
+       WREG32(0x6578, 0x501);
+       WREG32(0x657C, 0x85408640);
+       WREG32(0x6578, 0x502);
+       WREG32(0x657C, 0xBFF88180);
+       WREG32(0x6578, 0x600);
+       WREG32(0x657C, 0x82A08018);
+       WREG32(0x6578, 0x601);
+       WREG32(0x657C, 0x85808620);
+       WREG32(0x6578, 0x602);
+       WREG32(0x657C, 0xBFF081B8);
+       WREG32(0x6578, 0x700);
+       WREG32(0x657C, 0x82608010);
+       WREG32(0x6578, 0x701);
+       WREG32(0x657C, 0x85A08600);
+       WREG32(0x6578, 0x702);
+       WREG32(0x657C, 0x800081F0);
+       WREG32(0x6578, 0x800);
+       WREG32(0x657C, 0x8228BFF8);
+       WREG32(0x6578, 0x801);
+       WREG32(0x657C, 0x85E085E0);
+       WREG32(0x6578, 0x802);
+       WREG32(0x657C, 0xBFF88228);
+       WREG32(0x6578, 0x10000);
+       WREG32(0x657C, 0x82A8BF00);
+       WREG32(0x6578, 0x10001);
+       WREG32(0x657C, 0x82A08CC0);
+       WREG32(0x6578, 0x10002);
+       WREG32(0x657C, 0x8008BEF8);
+       WREG32(0x6578, 0x10100);
+       WREG32(0x657C, 0x81F0BF28);
+       WREG32(0x6578, 0x10101);
+       WREG32(0x657C, 0x83608CA0);
+       WREG32(0x6578, 0x10102);
+       WREG32(0x657C, 0x8018BED0);
+       WREG32(0x6578, 0x10200);
+       WREG32(0x657C, 0x8148BF38);
+       WREG32(0x6578, 0x10201);
+       WREG32(0x657C, 0x84408C80);
+       WREG32(0x6578, 0x10202);
+       WREG32(0x657C, 0x8008BEB8);
+       WREG32(0x6578, 0x10300);
+       WREG32(0x657C, 0x80B0BF78);
+       WREG32(0x6578, 0x10301);
+       WREG32(0x657C, 0x85008C20);
+       WREG32(0x6578, 0x10302);
+       WREG32(0x657C, 0x8020BEA0);
+       WREG32(0x6578, 0x10400);
+       WREG32(0x657C, 0x8028BF90);
+       WREG32(0x6578, 0x10401);
+       WREG32(0x657C, 0x85E08BC0);
+       WREG32(0x6578, 0x10402);
+       WREG32(0x657C, 0x8018BE90);
+       WREG32(0x6578, 0x10500);
+       WREG32(0x657C, 0xBFB8BFB0);
+       WREG32(0x6578, 0x10501);
+       WREG32(0x657C, 0x86C08B40);
+       WREG32(0x6578, 0x10502);
+       WREG32(0x657C, 0x8010BE90);
+       WREG32(0x6578, 0x10600);
+       WREG32(0x657C, 0xBF58BFC8);
+       WREG32(0x6578, 0x10601);
+       WREG32(0x657C, 0x87A08AA0);
+       WREG32(0x6578, 0x10602);
+       WREG32(0x657C, 0x8010BE98);
+       WREG32(0x6578, 0x10700);
+       WREG32(0x657C, 0xBF10BFF0);
+       WREG32(0x6578, 0x10701);
+       WREG32(0x657C, 0x886089E0);
+       WREG32(0x6578, 0x10702);
+       WREG32(0x657C, 0x8018BEB0);
+       WREG32(0x6578, 0x10800);
+       WREG32(0x657C, 0xBED8BFE8);
+       WREG32(0x6578, 0x10801);
+       WREG32(0x657C, 0x89408940);
+       WREG32(0x6578, 0x10802);
+       WREG32(0x657C, 0xBFE8BED8);
+       WREG32(0x6578, 0x20000);
+       WREG32(0x657C, 0x80008000);
+       WREG32(0x6578, 0x20001);
+       WREG32(0x657C, 0x90008000);
+       WREG32(0x6578, 0x20002);
+       WREG32(0x657C, 0x80008000);
+       WREG32(0x6578, 0x20003);
+       WREG32(0x657C, 0x80008000);
+       WREG32(0x6578, 0x20100);
+       WREG32(0x657C, 0x80108000);
+       WREG32(0x6578, 0x20101);
+       WREG32(0x657C, 0x8FE0BF70);
+       WREG32(0x6578, 0x20102);
+       WREG32(0x657C, 0xBFE880C0);
+       WREG32(0x6578, 0x20103);
+       WREG32(0x657C, 0x80008000);
+       WREG32(0x6578, 0x20200);
+       WREG32(0x657C, 0x8018BFF8);
+       WREG32(0x6578, 0x20201);
+       WREG32(0x657C, 0x8F80BF08);
+       WREG32(0x6578, 0x20202);
+       WREG32(0x657C, 0xBFD081A0);
+       WREG32(0x6578, 0x20203);
+       WREG32(0x657C, 0xBFF88000);
+       WREG32(0x6578, 0x20300);
+       WREG32(0x657C, 0x80188000);
+       WREG32(0x6578, 0x20301);
+       WREG32(0x657C, 0x8EE0BEC0);
+       WREG32(0x6578, 0x20302);
+       WREG32(0x657C, 0xBFB082A0);
+       WREG32(0x6578, 0x20303);
+       WREG32(0x657C, 0x80008000);
+       WREG32(0x6578, 0x20400);
+       WREG32(0x657C, 0x80188000);
+       WREG32(0x6578, 0x20401);
+       WREG32(0x657C, 0x8E00BEA0);
+       WREG32(0x6578, 0x20402);
+       WREG32(0x657C, 0xBF8883C0);
+       WREG32(0x6578, 0x20403);
+       WREG32(0x657C, 0x80008000);
+       WREG32(0x6578, 0x20500);
+       WREG32(0x657C, 0x80188000);
+       WREG32(0x6578, 0x20501);
+       WREG32(0x657C, 0x8D00BE90);
+       WREG32(0x6578, 0x20502);
+       WREG32(0x657C, 0xBF588500);
+       WREG32(0x6578, 0x20503);
+       WREG32(0x657C, 0x80008008);
+       WREG32(0x6578, 0x20600);
+       WREG32(0x657C, 0x80188000);
+       WREG32(0x6578, 0x20601);
+       WREG32(0x657C, 0x8BC0BE98);
+       WREG32(0x6578, 0x20602);
+       WREG32(0x657C, 0xBF308660);
+       WREG32(0x6578, 0x20603);
+       WREG32(0x657C, 0x80008008);
+       WREG32(0x6578, 0x20700);
+       WREG32(0x657C, 0x80108000);
+       WREG32(0x6578, 0x20701);
+       WREG32(0x657C, 0x8A80BEB0);
+       WREG32(0x6578, 0x20702);
+       WREG32(0x657C, 0xBF0087C0);
+       WREG32(0x6578, 0x20703);
+       WREG32(0x657C, 0x80008008);
+       WREG32(0x6578, 0x20800);
+       WREG32(0x657C, 0x80108000);
+       WREG32(0x6578, 0x20801);
+       WREG32(0x657C, 0x8920BED0);
+       WREG32(0x6578, 0x20802);
+       WREG32(0x657C, 0xBED08920);
+       WREG32(0x6578, 0x20803);
+       WREG32(0x657C, 0x80008010);
+       WREG32(0x6578, 0x30000);
+       WREG32(0x657C, 0x90008000);
+       WREG32(0x6578, 0x30001);
+       WREG32(0x657C, 0x80008000);
+       WREG32(0x6578, 0x30100);
+       WREG32(0x657C, 0x8FE0BF90);
+       WREG32(0x6578, 0x30101);
+       WREG32(0x657C, 0xBFF880A0);
+       WREG32(0x6578, 0x30200);
+       WREG32(0x657C, 0x8F60BF40);
+       WREG32(0x6578, 0x30201);
+       WREG32(0x657C, 0xBFE88180);
+       WREG32(0x6578, 0x30300);
+       WREG32(0x657C, 0x8EC0BF00);
+       WREG32(0x6578, 0x30301);
+       WREG32(0x657C, 0xBFC88280);
+       WREG32(0x6578, 0x30400);
+       WREG32(0x657C, 0x8DE0BEE0);
+       WREG32(0x6578, 0x30401);
+       WREG32(0x657C, 0xBFA083A0);
+       WREG32(0x6578, 0x30500);
+       WREG32(0x657C, 0x8CE0BED0);
+       WREG32(0x6578, 0x30501);
+       WREG32(0x657C, 0xBF7884E0);
+       WREG32(0x6578, 0x30600);
+       WREG32(0x657C, 0x8BA0BED8);
+       WREG32(0x6578, 0x30601);
+       WREG32(0x657C, 0xBF508640);
+       WREG32(0x6578, 0x30700);
+       WREG32(0x657C, 0x8A60BEE8);
+       WREG32(0x6578, 0x30701);
+       WREG32(0x657C, 0xBF2087A0);
+       WREG32(0x6578, 0x30800);
+       WREG32(0x657C, 0x8900BF00);
+       WREG32(0x6578, 0x30801);
+       WREG32(0x657C, 0xBF008900);
+}
+
+static void
+atombios_yuv_setup(struct drm_encoder *encoder, bool enable)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
+       ENABLE_YUV_PS_ALLOCATION args;
+       int index = GetIndexIntoMasterTable(COMMAND, EnableYUV);
+       uint32_t temp, reg;
+
+       memset(&args, 0, sizeof(args));
+
+       if (rdev->family >= CHIP_R600)
+               reg = R600_BIOS_3_SCRATCH;
+       else
+               reg = RADEON_BIOS_3_SCRATCH;
+
+       /* XXX: fix up scratch reg handling */
+       temp = RREG32(reg);
+       if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT))
+               WREG32(reg, (ATOM_S3_TV1_ACTIVE |
+                            (radeon_crtc->crtc_id << 18)));
+       else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT))
+               WREG32(reg, (ATOM_S3_CV_ACTIVE | (radeon_crtc->crtc_id << 24)));
+       else
+               WREG32(reg, 0);
+
+       if (enable)
+               args.ucEnable = ATOM_ENABLE;
+       args.ucCRTC = radeon_crtc->crtc_id;
+
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+       WREG32(reg, temp);
+}
+
+static void
+atombios_overscan_setup(struct drm_encoder *encoder,
+                       struct drm_display_mode *mode,
+                       struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
+       SET_CRTC_OVERSCAN_PS_ALLOCATION args;
+       int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_OverScan);
+
+       memset(&args, 0, sizeof(args));
+
+       args.usOverscanRight = 0;
+       args.usOverscanLeft = 0;
+       args.usOverscanBottom = 0;
+       args.usOverscanTop = 0;
+       args.ucCRTC = radeon_crtc->crtc_id;
+
+       if (radeon_encoder->flags & RADEON_USE_RMX) {
+               if (radeon_encoder->rmx_type == RMX_FULL) {
+                       args.usOverscanRight = 0;
+                       args.usOverscanLeft = 0;
+                       args.usOverscanBottom = 0;
+                       args.usOverscanTop = 0;
+               } else if (radeon_encoder->rmx_type == RMX_CENTER) {
+                       args.usOverscanTop = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2;
+                       args.usOverscanBottom = (adjusted_mode->crtc_vdisplay - mode->crtc_vdisplay) / 2;
+                       args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2;
+                       args.usOverscanRight = (adjusted_mode->crtc_hdisplay - mode->crtc_hdisplay) / 2;
+               } else if (radeon_encoder->rmx_type == RMX_ASPECT) {
+                       int a1 = mode->crtc_vdisplay * adjusted_mode->crtc_hdisplay;
+                       int a2 = adjusted_mode->crtc_vdisplay * mode->crtc_hdisplay;
+
+                       if (a1 > a2) {
+                               args.usOverscanLeft = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2;
+                               args.usOverscanRight = (adjusted_mode->crtc_hdisplay - (a2 / mode->crtc_vdisplay)) / 2;
+                       } else if (a2 > a1) {
+                               args.usOverscanLeft = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2;
+                               args.usOverscanRight = (adjusted_mode->crtc_vdisplay - (a1 / mode->crtc_hdisplay)) / 2;
+                       }
+               }
+       }
+
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+}
+
+static void
+atombios_scaler_setup(struct drm_encoder *encoder)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
+       ENABLE_SCALER_PS_ALLOCATION args;
+       int index = GetIndexIntoMasterTable(COMMAND, EnableScaler);
+       /* fixme - fill in enc_priv for atom dac */
+       enum radeon_tv_std tv_std = TV_STD_NTSC;
+
+       if (!ASIC_IS_AVIVO(rdev) && radeon_crtc->crtc_id)
+               return;
+
+       memset(&args, 0, sizeof(args));
+
+       args.ucScaler = radeon_crtc->crtc_id;
+
+       if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT)) {
+               switch (tv_std) {
+               case TV_STD_NTSC:
+               default:
+                       args.ucTVStandard = ATOM_TV_NTSC;
+                       break;
+               case TV_STD_PAL:
+                       args.ucTVStandard = ATOM_TV_PAL;
+                       break;
+               case TV_STD_PAL_M:
+                       args.ucTVStandard = ATOM_TV_PALM;
+                       break;
+               case TV_STD_PAL_60:
+                       args.ucTVStandard = ATOM_TV_PAL60;
+                       break;
+               case TV_STD_NTSC_J:
+                       args.ucTVStandard = ATOM_TV_NTSCJ;
+                       break;
+               case TV_STD_SCART_PAL:
+                       args.ucTVStandard = ATOM_TV_PAL; /* ??? */
+                       break;
+               case TV_STD_SECAM:
+                       args.ucTVStandard = ATOM_TV_SECAM;
+                       break;
+               case TV_STD_PAL_CN:
+                       args.ucTVStandard = ATOM_TV_PALCN;
+                       break;
+               }
+               args.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
+       } else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT)) {
+               args.ucTVStandard = ATOM_TV_CV;
+               args.ucEnable = SCALER_ENABLE_MULTITAP_MODE;
+       } else if (radeon_encoder->flags & RADEON_USE_RMX) {
+               if (radeon_encoder->rmx_type == RMX_FULL)
+                       args.ucEnable = ATOM_SCALER_EXPANSION;
+               else if (radeon_encoder->rmx_type == RMX_CENTER)
+                       args.ucEnable = ATOM_SCALER_CENTER;
+               else if (radeon_encoder->rmx_type == RMX_ASPECT)
+                       args.ucEnable = ATOM_SCALER_EXPANSION;
+       } else {
+               if (ASIC_IS_AVIVO(rdev))
+                       args.ucEnable = ATOM_SCALER_DISABLE;
+               else
+                       args.ucEnable = ATOM_SCALER_CENTER;
+       }
+
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+       if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)
+           && rdev->family >= CHIP_RV515 && rdev->family <= CHIP_RV570) {
+               atom_rv515_force_tv_scaler(rdev);
+       }
+
+}
+
+static void
+radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args;
+       int index = 0;
+       bool is_dig = false;
+
+       memset(&args, 0, sizeof(args));
+
+       switch (radeon_encoder->encoder_id) {
+       case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
+               index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl);
+               break;
+       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+               is_dig = true;
+               break;
+       case ENCODER_OBJECT_ID_INTERNAL_DVO1:
+       case ENCODER_OBJECT_ID_INTERNAL_DDI:
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+               index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
+               break;
+       case ENCODER_OBJECT_ID_INTERNAL_LVDS:
+               index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
+               break;
+       case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
+               if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
+                       index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl);
+               else
+                       index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl);
+               break;
+       case ENCODER_OBJECT_ID_INTERNAL_DAC1:
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
+               if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT))
+                       index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
+               else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT))
+                       index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
+               else
+                       index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl);
+               break;
+       case ENCODER_OBJECT_ID_INTERNAL_DAC2:
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
+               if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT))
+                       index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
+               else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT))
+                       index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
+               else
+                       index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl);
+               break;
+       }
+
+       if (is_dig) {
+               switch (mode) {
+               case DRM_MODE_DPMS_ON:
+                       atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE);
+                       break;
+               case DRM_MODE_DPMS_STANDBY:
+               case DRM_MODE_DPMS_SUSPEND:
+               case DRM_MODE_DPMS_OFF:
+                       atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE);
+                       break;
+               }
+       } else {
+               switch (mode) {
+               case DRM_MODE_DPMS_ON:
+                       args.ucAction = ATOM_ENABLE;
+                       break;
+               case DRM_MODE_DPMS_STANDBY:
+               case DRM_MODE_DPMS_SUSPEND:
+               case DRM_MODE_DPMS_OFF:
+                       args.ucAction = ATOM_DISABLE;
+                       break;
+               }
+               atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+       }
+       radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
+}
+
+union crtc_sourc_param {
+       SELECT_CRTC_SOURCE_PS_ALLOCATION v1;
+       SELECT_CRTC_SOURCE_PARAMETERS_V2 v2;
+};
+
+static void
+atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
+       union crtc_sourc_param args;
+       int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source);
+       uint8_t frev, crev;
+
+       memset(&args, 0, sizeof(args));
+
+       atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev);
+
+       switch (frev) {
+       case 1:
+               switch (crev) {
+               case 1:
+               default:
+                       if (ASIC_IS_AVIVO(rdev))
+                               args.v1.ucCRTC = radeon_crtc->crtc_id;
+                       else {
+                               if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) {
+                                       args.v1.ucCRTC = radeon_crtc->crtc_id;
+                               } else {
+                                       args.v1.ucCRTC = radeon_crtc->crtc_id << 2;
+                               }
+                       }
+                       switch (radeon_encoder->encoder_id) {
+                       case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
+                       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
+                               args.v1.ucDevice = ATOM_DEVICE_DFP1_INDEX;
+                               break;
+                       case ENCODER_OBJECT_ID_INTERNAL_LVDS:
+                       case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
+                               if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT)
+                                       args.v1.ucDevice = ATOM_DEVICE_LCD1_INDEX;
+                               else
+                                       args.v1.ucDevice = ATOM_DEVICE_DFP3_INDEX;
+                               break;
+                       case ENCODER_OBJECT_ID_INTERNAL_DVO1:
+                       case ENCODER_OBJECT_ID_INTERNAL_DDI:
+                       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+                               args.v1.ucDevice = ATOM_DEVICE_DFP2_INDEX;
+                               break;
+                       case ENCODER_OBJECT_ID_INTERNAL_DAC1:
+                       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
+                               if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT))
+                                       args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX;
+                               else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT))
+                                       args.v1.ucDevice = ATOM_DEVICE_CV_INDEX;
+                               else
+                                       args.v1.ucDevice = ATOM_DEVICE_CRT1_INDEX;
+                               break;
+                       case ENCODER_OBJECT_ID_INTERNAL_DAC2:
+                       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
+                               if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT))
+                                       args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX;
+                               else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT))
+                                       args.v1.ucDevice = ATOM_DEVICE_CV_INDEX;
+                               else
+                                       args.v1.ucDevice = ATOM_DEVICE_CRT2_INDEX;
+                               break;
+                       }
+                       break;
+               case 2:
+                       args.v2.ucCRTC = radeon_crtc->crtc_id;
+                       args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder);
+                       switch (radeon_encoder->encoder_id) {
+                       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+                       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+                       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+                               if (ASIC_IS_DCE32(rdev)) {
+                                       if (radeon_crtc->crtc_id)
+                                               args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
+                                       else
+                                               args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
+                               } else
+                                       args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
+                               break;
+                       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+                               args.v2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID;
+                               break;
+                       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+                               args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
+                               break;
+                       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
+                               if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT))
+                                       args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
+                               else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT))
+                                       args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
+                               else
+                                       args.v2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID;
+                               break;
+                       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
+                               if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT))
+                                       args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
+                               else if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT))
+                                       args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID;
+                               else
+                                       args.v2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID;
+                               break;
+                       }
+                       break;
+               }
+               break;
+       default:
+               DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
+               break;
+       }
+
+       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+}
+
+static void
+atombios_apply_encoder_quirks(struct drm_encoder *encoder,
+                             struct drm_display_mode *mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
+
+       /* Funky macbooks */
+       if ((dev->pdev->device == 0x71C5) &&
+           (dev->pdev->subsystem_vendor == 0x106b) &&
+           (dev->pdev->subsystem_device == 0x0080)) {
+               if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) {
+                       uint32_t lvtma_bit_depth_control = RREG32(AVIVO_LVTMA_BIT_DEPTH_CONTROL);
+
+                       lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_EN;
+                       lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN;
+
+                       WREG32(AVIVO_LVTMA_BIT_DEPTH_CONTROL, lvtma_bit_depth_control);
+               }
+       }
+
+       /* set scaler clears this on some chips */
+       if (ASIC_IS_AVIVO(rdev) && (mode->flags & DRM_MODE_FLAG_INTERLACE))
+               WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, AVIVO_D1MODE_INTERLEAVE_EN);
+}
+
+static void
+radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
+                            struct drm_display_mode *mode,
+                            struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
+
+       if (radeon_encoder->enc_priv) {
+               struct radeon_encoder_atom_dig *dig;
+
+               dig = radeon_encoder->enc_priv;
+               dig->dig_block = radeon_crtc->crtc_id;
+       }
+       radeon_encoder->pixel_clock = adjusted_mode->clock;
+
+       radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
+       atombios_overscan_setup(encoder, mode, adjusted_mode);
+       atombios_scaler_setup(encoder);
+       atombios_set_encoder_crtc_source(encoder);
+
+       if (ASIC_IS_AVIVO(rdev)) {
+               if (radeon_encoder->devices & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT))
+                       atombios_yuv_setup(encoder, true);
+               else
+                       atombios_yuv_setup(encoder, false);
+       }
+
+       switch (radeon_encoder->encoder_id) {
+       case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
+       case ENCODER_OBJECT_ID_INTERNAL_LVDS:
+       case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
+               atombios_digital_setup(encoder, PANEL_ENCODER_ACTION_ENABLE);
+               break;
+       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+               /* disable the encoder and transmitter */
+               atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE);
+               atombios_dig_encoder_setup(encoder, ATOM_DISABLE);
+
+               /* setup and enable the encoder and transmitter */
+               atombios_dig_encoder_setup(encoder, ATOM_ENABLE);
+               atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP);
+               atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE);
+               break;
+       case ENCODER_OBJECT_ID_INTERNAL_DDI:
+               atombios_ddia_setup(encoder, ATOM_ENABLE);
+               break;
+       case ENCODER_OBJECT_ID_INTERNAL_DVO1:
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+               atombios_external_tmds_setup(encoder, ATOM_ENABLE);
+               break;
+       case ENCODER_OBJECT_ID_INTERNAL_DAC1:
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
+       case ENCODER_OBJECT_ID_INTERNAL_DAC2:
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
+               atombios_dac_setup(encoder, ATOM_ENABLE);
+               if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT))
+                       atombios_tv_setup(encoder, ATOM_ENABLE);
+               break;
+       }
+       atombios_apply_encoder_quirks(encoder, adjusted_mode);
+}
+
+static bool
+atombios_dac_load_detect(struct drm_encoder *encoder)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+
+       if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT |
+                                      ATOM_DEVICE_CV_SUPPORT |
+                                      ATOM_DEVICE_CRT_SUPPORT)) {
+               DAC_LOAD_DETECTION_PS_ALLOCATION args;
+               int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection);
+               uint8_t frev, crev;
+
+               memset(&args, 0, sizeof(args));
+
+               atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev);
+
+               args.sDacload.ucMisc = 0;
+
+               if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) ||
+                   (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1))
+                       args.sDacload.ucDacType = ATOM_DAC_A;
+               else
+                       args.sDacload.ucDacType = ATOM_DAC_B;
+
+               if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT)
+                       args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT);
+               else if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT)
+                       args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT);
+               else if (radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) {
+                       args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT);
+                       if (crev >= 3)
+                               args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
+               } else if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) {
+                       args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT);
+                       if (crev >= 3)
+                               args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb;
+               }
+
+               atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+               return true;
+       } else
+               return false;
+}
+
+static enum drm_connector_status
+radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       uint32_t bios_0_scratch;
+
+       if (!atombios_dac_load_detect(encoder)) {
+               DRM_DEBUG("detect returned false \n");
+               return connector_status_unknown;
+       }
+
+       if (rdev->family >= CHIP_R600)
+               bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH);
+       else
+               bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH);
+
+       DRM_DEBUG("Bios 0 scratch %x\n", bios_0_scratch);
+       if (radeon_encoder->devices & ATOM_DEVICE_CRT1_SUPPORT) {
+               if (bios_0_scratch & ATOM_S0_CRT1_MASK)
+                       return connector_status_connected;
+       } else if (radeon_encoder->devices & ATOM_DEVICE_CRT2_SUPPORT) {
+               if (bios_0_scratch & ATOM_S0_CRT2_MASK)
+                       return connector_status_connected;
+       } else if (radeon_encoder->devices & ATOM_DEVICE_CV_SUPPORT) {
+               if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A))
+                       return connector_status_connected;
+       } else if (radeon_encoder->devices & ATOM_DEVICE_TV1_SUPPORT) {
+               if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A))
+                       return connector_status_connected; /* CTV */
+               else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A))
+                       return connector_status_connected; /* STV */
+       }
+       return connector_status_disconnected;
+}
+
+static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
+{
+       radeon_atom_output_lock(encoder, true);
+       radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+}
+
+static void radeon_atom_encoder_commit(struct drm_encoder *encoder)
+{
+       radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
+       radeon_atom_output_lock(encoder, false);
+}
+
+static const struct drm_encoder_helper_funcs radeon_atom_dig_helper_funcs = {
+       .dpms = radeon_atom_encoder_dpms,
+       .mode_fixup = radeon_atom_mode_fixup,
+       .prepare = radeon_atom_encoder_prepare,
+       .mode_set = radeon_atom_encoder_mode_set,
+       .commit = radeon_atom_encoder_commit,
+       /* no detect for TMDS/LVDS yet */
+};
+
+static const struct drm_encoder_helper_funcs radeon_atom_dac_helper_funcs = {
+       .dpms = radeon_atom_encoder_dpms,
+       .mode_fixup = radeon_atom_mode_fixup,
+       .prepare = radeon_atom_encoder_prepare,
+       .mode_set = radeon_atom_encoder_mode_set,
+       .commit = radeon_atom_encoder_commit,
+       .detect = radeon_atom_dac_detect,
+};
+
+void radeon_enc_destroy(struct drm_encoder *encoder)
+{
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       kfree(radeon_encoder->enc_priv);
+       drm_encoder_cleanup(encoder);
+       kfree(radeon_encoder);
+}
+
+static const struct drm_encoder_funcs radeon_atom_enc_funcs = {
+       .destroy = radeon_enc_destroy,
+};
+
+struct radeon_encoder_atom_dig *
+radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder)
+{
+       struct radeon_encoder_atom_dig *dig = kzalloc(sizeof(struct radeon_encoder_atom_dig), GFP_KERNEL);
+
+       if (!dig)
+               return NULL;
+
+       /* coherent mode by default */
+       dig->coherent_mode = true;
+
+       return dig;
+}
+
+void
+radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t supported_device)
+{
+       struct drm_encoder *encoder;
+       struct radeon_encoder *radeon_encoder;
+
+       /* see if we already added it */
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               radeon_encoder = to_radeon_encoder(encoder);
+               if (radeon_encoder->encoder_id == encoder_id) {
+                       radeon_encoder->devices |= supported_device;
+                       return;
+               }
+
+       }
+
+       /* add a new one */
+       radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL);
+       if (!radeon_encoder)
+               return;
+
+       encoder = &radeon_encoder->base;
+       encoder->possible_crtcs = 0x3;
+       encoder->possible_clones = 0;
+
+       radeon_encoder->enc_priv = NULL;
+
+       radeon_encoder->encoder_id = encoder_id;
+       radeon_encoder->devices = supported_device;
+
+       switch (radeon_encoder->encoder_id) {
+       case ENCODER_OBJECT_ID_INTERNAL_LVDS:
+       case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
+       case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
+               if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) {
+                       radeon_encoder->rmx_type = RMX_FULL;
+                       drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS);
+                       radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder);
+               } else {
+                       drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS);
+                       radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
+               }
+               drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs);
+               break;
+       case ENCODER_OBJECT_ID_INTERNAL_DAC1:
+               drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC);
+               drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs);
+               break;
+       case ENCODER_OBJECT_ID_INTERNAL_DAC2:
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
+               drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TVDAC);
+               drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs);
+               break;
+       case ENCODER_OBJECT_ID_INTERNAL_DVO1:
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+       case ENCODER_OBJECT_ID_INTERNAL_DDI:
+       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+       case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+               drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS);
+               radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
+               drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs);
+               break;
+       }
+}
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
new file mode 100644 (file)
index 0000000..fa86d39
--- /dev/null
@@ -0,0 +1,825 @@
+/*
+ * Copyright Â© 2007 David Airlie
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *     David Airlie
+ */
+    /*
+     *  Modularization
+     */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+#include "radeon_drm.h"
+#include "radeon.h"
+
+struct radeon_fb_device {
+       struct radeon_device            *rdev;
+       struct drm_display_mode         *mode;
+       struct radeon_framebuffer       *rfb;
+       int                             crtc_count;
+       /* crtc currently bound to this */
+       uint32_t                        crtc_ids[2];
+};
+
+static int radeonfb_setcolreg(unsigned regno,
+                             unsigned red,
+                             unsigned green,
+                             unsigned blue,
+                             unsigned transp,
+                             struct fb_info *info)
+{
+       struct radeon_fb_device *rfbdev = info->par;
+       struct drm_device *dev = rfbdev->rdev->ddev;
+       struct drm_crtc *crtc;
+       int i;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+               struct drm_mode_set *modeset = &radeon_crtc->mode_set;
+               struct drm_framebuffer *fb = modeset->fb;
+
+               for (i = 0; i < rfbdev->crtc_count; i++) {
+                       if (crtc->base.id == rfbdev->crtc_ids[i]) {
+                               break;
+                       }
+               }
+               if (i == rfbdev->crtc_count) {
+                       continue;
+               }
+               if (regno > 255) {
+                       return 1;
+               }
+               if (fb->depth == 8) {
+                       radeon_crtc_fb_gamma_set(crtc, red, green, blue, regno);
+                       return 0;
+               }
+
+               if (regno < 16) {
+                       switch (fb->depth) {
+                       case 15:
+                               fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) |
+                                       ((green & 0xf800) >>  6) |
+                                       ((blue & 0xf800) >> 11);
+                               break;
+                       case 16:
+                               fb->pseudo_palette[regno] = (red & 0xf800) |
+                                       ((green & 0xfc00) >>  5) |
+                                       ((blue  & 0xf800) >> 11);
+                               break;
+                       case 24:
+                       case 32:
+                               fb->pseudo_palette[regno] = ((red & 0xff00) << 8) |
+                                       (green & 0xff00) |
+                                       ((blue  & 0xff00) >> 8);
+                               break;
+                       }
+               }
+       }
+       return 0;
+}
+
+static int radeonfb_check_var(struct fb_var_screeninfo *var,
+                             struct fb_info *info)
+{
+       struct radeon_fb_device *rfbdev = info->par;
+       struct radeon_framebuffer *rfb = rfbdev->rfb;
+       struct drm_framebuffer *fb = &rfb->base;
+       int depth;
+
+       if (var->pixclock == -1 || !var->pixclock) {
+               return -EINVAL;
+       }
+       /* Need to resize the fb object !!! */
+       if (var->xres > fb->width || var->yres > fb->height) {
+               DRM_ERROR("Requested width/height is greater than current fb "
+                          "object %dx%d > %dx%d\n", var->xres, var->yres,
+                          fb->width, fb->height);
+               DRM_ERROR("Need resizing code.\n");
+               return -EINVAL;
+       }
+
+       switch (var->bits_per_pixel) {
+       case 16:
+               depth = (var->green.length == 6) ? 16 : 15;
+               break;
+       case 32:
+               depth = (var->transp.length > 0) ? 32 : 24;
+               break;
+       default:
+               depth = var->bits_per_pixel;
+               break;
+       }
+
+       switch (depth) {
+       case 8:
+               var->red.offset = 0;
+               var->green.offset = 0;
+               var->blue.offset = 0;
+               var->red.length = 8;
+               var->green.length = 8;
+               var->blue.length = 8;
+               var->transp.length = 0;
+               var->transp.offset = 0;
+               break;
+       case 15:
+               var->red.offset = 10;
+               var->green.offset = 5;
+               var->blue.offset = 0;
+               var->red.length = 5;
+               var->green.length = 5;
+               var->blue.length = 5;
+               var->transp.length = 1;
+               var->transp.offset = 15;
+               break;
+       case 16:
+               var->red.offset = 11;
+               var->green.offset = 5;
+               var->blue.offset = 0;
+               var->red.length = 5;
+               var->green.length = 6;
+               var->blue.length = 5;
+               var->transp.length = 0;
+               var->transp.offset = 0;
+               break;
+       case 24:
+               var->red.offset = 16;
+               var->green.offset = 8;
+               var->blue.offset = 0;
+               var->red.length = 8;
+               var->green.length = 8;
+               var->blue.length = 8;
+               var->transp.length = 0;
+               var->transp.offset = 0;
+               break;
+       case 32:
+               var->red.offset = 16;
+               var->green.offset = 8;
+               var->blue.offset = 0;
+               var->red.length = 8;
+               var->green.length = 8;
+               var->blue.length = 8;
+               var->transp.length = 8;
+               var->transp.offset = 24;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/* this will let fbcon do the mode init */
+static int radeonfb_set_par(struct fb_info *info)
+{
+       struct radeon_fb_device *rfbdev = info->par;
+       struct drm_device *dev = rfbdev->rdev->ddev;
+       struct fb_var_screeninfo *var = &info->var;
+       struct drm_crtc *crtc;
+       int ret;
+       int i;
+
+       if (var->pixclock != -1) {
+               DRM_ERROR("PIXEL CLCOK SET\n");
+               return -EINVAL;
+       }
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+
+               for (i = 0; i < rfbdev->crtc_count; i++) {
+                       if (crtc->base.id == rfbdev->crtc_ids[i]) {
+                               break;
+                       }
+               }
+               if (i == rfbdev->crtc_count) {
+                       continue;
+               }
+               if (crtc->fb == radeon_crtc->mode_set.fb) {
+                       mutex_lock(&dev->mode_config.mutex);
+                       ret = crtc->funcs->set_config(&radeon_crtc->mode_set);
+                       mutex_unlock(&dev->mode_config.mutex);
+                       if (ret) {
+                               return ret;
+                       }
+               }
+       }
+       return 0;
+}
+
+static int radeonfb_pan_display(struct fb_var_screeninfo *var,
+                               struct fb_info *info)
+{
+       struct radeon_fb_device *rfbdev = info->par;
+       struct drm_device *dev = rfbdev->rdev->ddev;
+       struct drm_mode_set *modeset;
+       struct drm_crtc *crtc;
+       struct radeon_crtc *radeon_crtc;
+       int ret = 0;
+       int i;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               for (i = 0; i < rfbdev->crtc_count; i++) {
+                       if (crtc->base.id == rfbdev->crtc_ids[i]) {
+                               break;
+                       }
+               }
+
+               if (i == rfbdev->crtc_count) {
+                       continue;
+               }
+
+               radeon_crtc = to_radeon_crtc(crtc);
+               modeset = &radeon_crtc->mode_set;
+
+               modeset->x = var->xoffset;
+               modeset->y = var->yoffset;
+
+               if (modeset->num_connectors) {
+                       mutex_lock(&dev->mode_config.mutex);
+                       ret = crtc->funcs->set_config(modeset);
+                       mutex_unlock(&dev->mode_config.mutex);
+                       if (!ret) {
+                               info->var.xoffset = var->xoffset;
+                               info->var.yoffset = var->yoffset;
+                       }
+               }
+       }
+       return ret;
+}
+
+static void radeonfb_on(struct fb_info *info)
+{
+       struct radeon_fb_device *rfbdev = info->par;
+       struct drm_device *dev = rfbdev->rdev->ddev;
+       struct drm_crtc *crtc;
+       struct drm_encoder *encoder;
+       int i;
+
+       /*
+        * For each CRTC in this fb, find all associated encoders
+        * and turn them off, then turn off the CRTC.
+        */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+
+               for (i = 0; i < rfbdev->crtc_count; i++) {
+                       if (crtc->base.id == rfbdev->crtc_ids[i]) {
+                               break;
+                       }
+               }
+
+               mutex_lock(&dev->mode_config.mutex);
+               crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
+               mutex_unlock(&dev->mode_config.mutex);
+
+               /* Found a CRTC on this fb, now find encoders */
+               list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+                       if (encoder->crtc == crtc) {
+                               struct drm_encoder_helper_funcs *encoder_funcs;
+
+                               encoder_funcs = encoder->helper_private;
+                               mutex_lock(&dev->mode_config.mutex);
+                               encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
+                               mutex_unlock(&dev->mode_config.mutex);
+                       }
+               }
+       }
+}
+
+static void radeonfb_off(struct fb_info *info, int dpms_mode)
+{
+       struct radeon_fb_device *rfbdev = info->par;
+       struct drm_device *dev = rfbdev->rdev->ddev;
+       struct drm_crtc *crtc;
+       struct drm_encoder *encoder;
+       int i;
+
+       /*
+        * For each CRTC in this fb, find all associated encoders
+        * and turn them off, then turn off the CRTC.
+        */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+
+               for (i = 0; i < rfbdev->crtc_count; i++) {
+                       if (crtc->base.id == rfbdev->crtc_ids[i]) {
+                               break;
+                       }
+               }
+
+               /* Found a CRTC on this fb, now find encoders */
+               list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+                       if (encoder->crtc == crtc) {
+                               struct drm_encoder_helper_funcs *encoder_funcs;
+
+                               encoder_funcs = encoder->helper_private;
+                               mutex_lock(&dev->mode_config.mutex);
+                               encoder_funcs->dpms(encoder, dpms_mode);
+                               mutex_unlock(&dev->mode_config.mutex);
+                       }
+               }
+               if (dpms_mode == DRM_MODE_DPMS_OFF) {
+                       mutex_lock(&dev->mode_config.mutex);
+                       crtc_funcs->dpms(crtc, dpms_mode);
+                       mutex_unlock(&dev->mode_config.mutex);
+               }
+       }
+}
+
+int radeonfb_blank(int blank, struct fb_info *info)
+{
+       switch (blank) {
+       case FB_BLANK_UNBLANK:
+               radeonfb_on(info);
+               break;
+       case FB_BLANK_NORMAL:
+               radeonfb_off(info, DRM_MODE_DPMS_STANDBY);
+               break;
+       case FB_BLANK_HSYNC_SUSPEND:
+               radeonfb_off(info, DRM_MODE_DPMS_STANDBY);
+               break;
+       case FB_BLANK_VSYNC_SUSPEND:
+               radeonfb_off(info, DRM_MODE_DPMS_SUSPEND);
+               break;
+       case FB_BLANK_POWERDOWN:
+               radeonfb_off(info, DRM_MODE_DPMS_OFF);
+               break;
+       }
+       return 0;
+}
+
+static struct fb_ops radeonfb_ops = {
+       .owner = THIS_MODULE,
+       .fb_check_var = radeonfb_check_var,
+       .fb_set_par = radeonfb_set_par,
+       .fb_setcolreg = radeonfb_setcolreg,
+       .fb_fillrect = cfb_fillrect,
+       .fb_copyarea = cfb_copyarea,
+       .fb_imageblit = cfb_imageblit,
+       .fb_pan_display = radeonfb_pan_display,
+       .fb_blank = radeonfb_blank,
+};
+
+/**
+ * Curretly it is assumed that the old framebuffer is reused.
+ *
+ * LOCKING
+ * caller should hold the mode config lock.
+ *
+ */
+int radeonfb_resize(struct drm_device *dev, struct drm_crtc *crtc)
+{
+       struct fb_info *info;
+       struct drm_framebuffer *fb;
+       struct drm_display_mode *mode = crtc->desired_mode;
+
+       fb = crtc->fb;
+       if (fb == NULL) {
+               return 1;
+       }
+       info = fb->fbdev;
+       if (info == NULL) {
+               return 1;
+       }
+       if (mode == NULL) {
+               return 1;
+       }
+       info->var.xres = mode->hdisplay;
+       info->var.right_margin = mode->hsync_start - mode->hdisplay;
+       info->var.hsync_len = mode->hsync_end - mode->hsync_start;
+       info->var.left_margin = mode->htotal - mode->hsync_end;
+       info->var.yres = mode->vdisplay;
+       info->var.lower_margin = mode->vsync_start - mode->vdisplay;
+       info->var.vsync_len = mode->vsync_end - mode->vsync_start;
+       info->var.upper_margin = mode->vtotal - mode->vsync_end;
+       info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100;
+       /* avoid overflow */
+       info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh;
+
+       return 0;
+}
+EXPORT_SYMBOL(radeonfb_resize);
+
+static struct drm_mode_set panic_mode;
+
+int radeonfb_panic(struct notifier_block *n, unsigned long ununsed,
+                 void *panic_str)
+{
+       DRM_ERROR("panic occurred, switching back to text console\n");
+       drm_crtc_helper_set_config(&panic_mode);
+       return 0;
+}
+EXPORT_SYMBOL(radeonfb_panic);
+
+static struct notifier_block paniced = {
+       .notifier_call = radeonfb_panic,
+};
+
+static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp)
+{
+       int aligned = width;
+       int align_large = (ASIC_IS_AVIVO(rdev));
+       int pitch_mask = 0;
+
+       switch (bpp / 8) {
+       case 1:
+               pitch_mask = align_large ? 255 : 127;
+               break;
+       case 2:
+               pitch_mask = align_large ? 127 : 31;
+               break;
+       case 3:
+       case 4:
+               pitch_mask = align_large ? 63 : 15;
+               break;
+       }
+
+       aligned += pitch_mask;
+       aligned &= ~pitch_mask;
+       return aligned;
+}
+
+int radeonfb_create(struct radeon_device *rdev,
+                   uint32_t fb_width, uint32_t fb_height,
+                   uint32_t surface_width, uint32_t surface_height,
+                   struct radeon_framebuffer **rfb_p)
+{
+       struct fb_info *info;
+       struct radeon_fb_device *rfbdev;
+       struct drm_framebuffer *fb;
+       struct radeon_framebuffer *rfb;
+       struct drm_mode_fb_cmd mode_cmd;
+       struct drm_gem_object *gobj = NULL;
+       struct radeon_object *robj = NULL;
+       struct device *device = &rdev->pdev->dev;
+       int size, aligned_size, ret;
+       void *fbptr = NULL;
+
+       mode_cmd.width = surface_width;
+       mode_cmd.height = surface_height;
+       mode_cmd.bpp = 32;
+       /* need to align pitch with crtc limits */
+       mode_cmd.pitch = radeon_align_pitch(rdev, mode_cmd.width, mode_cmd.bpp) * ((mode_cmd.bpp + 1) / 8);
+       mode_cmd.depth = 24;
+
+       size = mode_cmd.pitch * mode_cmd.height;
+       aligned_size = ALIGN(size, PAGE_SIZE);
+
+       ret = radeon_gem_object_create(rdev, aligned_size, 0,
+                                      RADEON_GEM_DOMAIN_VRAM,
+                                      false, ttm_bo_type_kernel,
+                                      false, &gobj);
+       if (ret) {
+               printk(KERN_ERR "failed to allocate framebuffer\n");
+               ret = -ENOMEM;
+               goto out;
+       }
+       robj = gobj->driver_private;
+
+       mutex_lock(&rdev->ddev->struct_mutex);
+       fb = radeon_framebuffer_create(rdev->ddev, &mode_cmd, gobj);
+       if (fb == NULL) {
+               DRM_ERROR("failed to allocate fb.\n");
+               ret = -ENOMEM;
+               goto out_unref;
+       }
+
+       list_add(&fb->filp_head, &rdev->ddev->mode_config.fb_kernel_list);
+
+       rfb = to_radeon_framebuffer(fb);
+       *rfb_p = rfb;
+       rdev->fbdev_rfb = rfb;
+
+       info = framebuffer_alloc(sizeof(struct radeon_fb_device), device);
+       if (info == NULL) {
+               ret = -ENOMEM;
+               goto out_unref;
+       }
+       rfbdev = info->par;
+
+       ret = radeon_object_kmap(robj, &fbptr);
+       if (ret) {
+               goto out_unref;
+       }
+
+       strcpy(info->fix.id, "radeondrmfb");
+       info->fix.type = FB_TYPE_PACKED_PIXELS;
+       info->fix.visual = FB_VISUAL_TRUECOLOR;
+       info->fix.type_aux = 0;
+       info->fix.xpanstep = 1; /* doing it in hw */
+       info->fix.ypanstep = 1; /* doing it in hw */
+       info->fix.ywrapstep = 0;
+       info->fix.accel = FB_ACCEL_I830;
+       info->fix.type_aux = 0;
+       info->flags = FBINFO_DEFAULT;
+       info->fbops = &radeonfb_ops;
+       info->fix.line_length = fb->pitch;
+       info->screen_base = fbptr;
+       info->fix.smem_start = (unsigned long)fbptr;
+       info->fix.smem_len = size;
+       info->screen_base = fbptr;
+       info->screen_size = size;
+       info->pseudo_palette = fb->pseudo_palette;
+       info->var.xres_virtual = fb->width;
+       info->var.yres_virtual = fb->height;
+       info->var.bits_per_pixel = fb->bits_per_pixel;
+       info->var.xoffset = 0;
+       info->var.yoffset = 0;
+       info->var.activate = FB_ACTIVATE_NOW;
+       info->var.height = -1;
+       info->var.width = -1;
+       info->var.xres = fb_width;
+       info->var.yres = fb_height;
+       info->fix.mmio_start = pci_resource_start(rdev->pdev, 2);
+       info->fix.mmio_len = pci_resource_len(rdev->pdev, 2);
+       info->pixmap.size = 64*1024;
+       info->pixmap.buf_align = 8;
+       info->pixmap.access_align = 32;
+       info->pixmap.flags = FB_PIXMAP_SYSTEM;
+       info->pixmap.scan_align = 1;
+       if (info->screen_base == NULL) {
+               ret = -ENOSPC;
+               goto out_unref;
+       }
+       DRM_INFO("fb mappable at 0x%lX\n",  info->fix.smem_start);
+       DRM_INFO("vram apper at 0x%lX\n",  (unsigned long)rdev->mc.aper_base);
+       DRM_INFO("size %lu\n", (unsigned long)size);
+       DRM_INFO("fb depth is %d\n", fb->depth);
+       DRM_INFO("   pitch is %d\n", fb->pitch);
+
+       switch (fb->depth) {
+       case 8:
+               info->var.red.offset = 0;
+               info->var.green.offset = 0;
+               info->var.blue.offset = 0;
+               info->var.red.length = 8; /* 8bit DAC */
+               info->var.green.length = 8;
+               info->var.blue.length = 8;
+               info->var.transp.offset = 0;
+               info->var.transp.length = 0;
+               break;
+       case 15:
+               info->var.red.offset = 10;
+               info->var.green.offset = 5;
+               info->var.blue.offset = 0;
+               info->var.red.length = 5;
+               info->var.green.length = 5;
+               info->var.blue.length = 5;
+               info->var.transp.offset = 15;
+               info->var.transp.length = 1;
+               break;
+       case 16:
+               info->var.red.offset = 11;
+               info->var.green.offset = 5;
+               info->var.blue.offset = 0;
+               info->var.red.length = 5;
+               info->var.green.length = 6;
+               info->var.blue.length = 5;
+               info->var.transp.offset = 0;
+               break;
+       case 24:
+               info->var.red.offset = 16;
+               info->var.green.offset = 8;
+               info->var.blue.offset = 0;
+               info->var.red.length = 8;
+               info->var.green.length = 8;
+               info->var.blue.length = 8;
+               info->var.transp.offset = 0;
+               info->var.transp.length = 0;
+               break;
+       case 32:
+               info->var.red.offset = 16;
+               info->var.green.offset = 8;
+               info->var.blue.offset = 0;
+               info->var.red.length = 8;
+               info->var.green.length = 8;
+               info->var.blue.length = 8;
+               info->var.transp.offset = 24;
+               info->var.transp.length = 8;
+               break;
+       default:
+               break;
+       }
+
+       fb->fbdev = info;
+       rfbdev->rfb = rfb;
+       rfbdev->rdev = rdev;
+
+       mutex_unlock(&rdev->ddev->struct_mutex);
+       return 0;
+
+out_unref:
+       if (robj) {
+               radeon_object_kunmap(robj);
+       }
+       if (ret) {
+               list_del(&fb->filp_head);
+               drm_gem_object_unreference(gobj);
+               drm_framebuffer_cleanup(fb);
+               kfree(fb);
+       }
+       drm_gem_object_unreference(gobj);
+       mutex_unlock(&rdev->ddev->struct_mutex);
+out:
+       return ret;
+}
+
+static int radeonfb_single_fb_probe(struct radeon_device *rdev)
+{
+       struct drm_crtc *crtc;
+       struct drm_connector *connector;
+       unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1;
+       unsigned int surface_width = 0, surface_height = 0;
+       int new_fb = 0;
+       int crtc_count = 0;
+       int ret, i, conn_count = 0;
+       struct radeon_framebuffer *rfb;
+       struct fb_info *info;
+       struct radeon_fb_device *rfbdev;
+       struct drm_mode_set *modeset = NULL;
+
+       /* first up get a count of crtcs now in use and new min/maxes width/heights */
+       list_for_each_entry(crtc, &rdev->ddev->mode_config.crtc_list, head) {
+               if (drm_helper_crtc_in_use(crtc)) {
+                       if (crtc->desired_mode) {
+                               if (crtc->desired_mode->hdisplay < fb_width)
+                                       fb_width = crtc->desired_mode->hdisplay;
+
+                               if (crtc->desired_mode->vdisplay < fb_height)
+                                       fb_height = crtc->desired_mode->vdisplay;
+
+                               if (crtc->desired_mode->hdisplay > surface_width)
+                                       surface_width = crtc->desired_mode->hdisplay;
+
+                               if (crtc->desired_mode->vdisplay > surface_height)
+                                       surface_height = crtc->desired_mode->vdisplay;
+                       }
+                       crtc_count++;
+               }
+       }
+
+       if (crtc_count == 0 || fb_width == -1 || fb_height == -1) {
+               /* hmm everyone went away - assume VGA cable just fell out
+                  and will come back later. */
+               return 0;
+       }
+
+       /* do we have an fb already? */
+       if (list_empty(&rdev->ddev->mode_config.fb_kernel_list)) {
+               /* create an fb if we don't have one */
+               ret = radeonfb_create(rdev, fb_width, fb_height, surface_width, surface_height, &rfb);
+               if (ret) {
+                       return -EINVAL;
+               }
+               new_fb = 1;
+       } else {
+               struct drm_framebuffer *fb;
+               fb = list_first_entry(&rdev->ddev->mode_config.fb_kernel_list, struct drm_framebuffer, filp_head);
+               rfb = to_radeon_framebuffer(fb);
+
+               /* if someone hotplugs something bigger than we have already allocated, we are pwned.
+                  As really we can't resize an fbdev that is in the wild currently due to fbdev
+                  not really being designed for the lower layers moving stuff around under it.
+                  - so in the grand style of things - punt. */
+               if ((fb->width < surface_width) || (fb->height < surface_height)) {
+                       DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
+                       return -EINVAL;
+               }
+       }
+
+       info = rfb->base.fbdev;
+       rdev->fbdev_info = info;
+       rfbdev = info->par;
+
+       crtc_count = 0;
+       /* okay we need to setup new connector sets in the crtcs */
+       list_for_each_entry(crtc, &rdev->ddev->mode_config.crtc_list, head) {
+               struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+               modeset = &radeon_crtc->mode_set;
+               modeset->fb = &rfb->base;
+               conn_count = 0;
+               list_for_each_entry(connector, &rdev->ddev->mode_config.connector_list, head) {
+                       if (connector->encoder)
+                               if (connector->encoder->crtc == modeset->crtc) {
+                                       modeset->connectors[conn_count] = connector;
+                                       conn_count++;
+                                       if (conn_count > RADEONFB_CONN_LIMIT)
+                                               BUG();
+                               }
+               }
+
+               for (i = conn_count; i < RADEONFB_CONN_LIMIT; i++)
+                       modeset->connectors[i] = NULL;
+
+
+               rfbdev->crtc_ids[crtc_count++] = crtc->base.id;
+
+               modeset->num_connectors = conn_count;
+               if (modeset->crtc->desired_mode) {
+                       if (modeset->mode) {
+                               drm_mode_destroy(rdev->ddev, modeset->mode);
+                       }
+                       modeset->mode = drm_mode_duplicate(rdev->ddev,
+                                                          modeset->crtc->desired_mode);
+               }
+       }
+       rfbdev->crtc_count = crtc_count;
+
+       if (new_fb) {
+               info->var.pixclock = -1;
+               if (register_framebuffer(info) < 0)
+                       return -EINVAL;
+       } else {
+               radeonfb_set_par(info);
+       }
+       printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
+              info->fix.id);
+
+       /* Switch back to kernel console on panic */
+       panic_mode = *modeset;
+       atomic_notifier_chain_register(&panic_notifier_list, &paniced);
+       printk(KERN_INFO "registered panic notifier\n");
+
+       return 0;
+}
+
+int radeonfb_probe(struct drm_device *dev)
+{
+       int ret;
+
+       /* something has changed in the lower levels of hell - deal with it
+          here */
+
+       /* two modes : a) 1 fb to rule all crtcs.
+                      b) one fb per crtc.
+          two actions 1) new connected device
+                      2) device removed.
+          case a/1 : if the fb surface isn't big enough - resize the surface fb.
+                     if the fb size isn't big enough - resize fb into surface.
+                     if everything big enough configure the new crtc/etc.
+          case a/2 : undo the configuration
+                     possibly resize down the fb to fit the new configuration.
+           case b/1 : see if it is on a new crtc - setup a new fb and add it.
+          case b/2 : teardown the new fb.
+       */
+       ret = radeonfb_single_fb_probe(dev->dev_private);
+       return ret;
+}
+EXPORT_SYMBOL(radeonfb_probe);
+
+int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb)
+{
+       struct fb_info *info;
+       struct radeon_framebuffer *rfb = to_radeon_framebuffer(fb);
+       struct radeon_object *robj;
+
+       if (!fb) {
+               return -EINVAL;
+       }
+       info = fb->fbdev;
+       if (info) {
+               robj = rfb->obj->driver_private;
+               unregister_framebuffer(info);
+               radeon_object_kunmap(robj);
+               framebuffer_release(info);
+       }
+
+       printk(KERN_INFO "unregistered panic notifier\n");
+       atomic_notifier_chain_unregister(&panic_notifier_list, &paniced);
+       memset(&panic_mode, 0, sizeof(struct drm_mode_set));
+       return 0;
+}
+EXPORT_SYMBOL(radeonfb_remove);
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c
new file mode 100644 (file)
index 0000000..96afbf5
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+ * Copyright 2009 Jerome Glisse.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors:
+ *    Jerome Glisse <glisse@freedesktop.org>
+ *    Dave Airlie
+ */
+#include <linux/seq_file.h>
+#include <asm/atomic.h>
+#include <linux/wait.h>
+#include <linux/list.h>
+#include <linux/kref.h>
+#include "drmP.h"
+#include "drm.h"
+#include "radeon_reg.h"
+#include "radeon.h"
+
+int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence)
+{
+       unsigned long irq_flags;
+
+       write_lock_irqsave(&rdev->fence_drv.lock, irq_flags);
+       if (fence->emited) {
+               write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
+               return 0;
+       }
+       fence->seq = atomic_add_return(1, &rdev->fence_drv.seq);
+       if (!rdev->cp.ready) {
+               /* FIXME: cp is not running assume everythings is done right
+                * away
+                */
+               WREG32(rdev->fence_drv.scratch_reg, fence->seq);
+       } else {
+               radeon_fence_ring_emit(rdev, fence);
+       }
+       fence->emited = true;
+       fence->timeout = jiffies + ((2000 * HZ) / 1000);
+       list_del(&fence->list);
+       list_add_tail(&fence->list, &rdev->fence_drv.emited);
+       write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
+       return 0;
+}
+
+static bool radeon_fence_poll_locked(struct radeon_device *rdev)
+{
+       struct radeon_fence *fence;
+       struct list_head *i, *n;
+       uint32_t seq;
+       bool wake = false;
+
+       if (rdev == NULL) {
+               return true;
+       }
+       if (rdev->shutdown) {
+               return true;
+       }
+       seq = RREG32(rdev->fence_drv.scratch_reg);
+       rdev->fence_drv.last_seq = seq;
+       n = NULL;
+       list_for_each(i, &rdev->fence_drv.emited) {
+               fence = list_entry(i, struct radeon_fence, list);
+               if (fence->seq == seq) {
+                       n = i;
+                       break;
+               }
+       }
+       /* all fence previous to this one are considered as signaled */
+       if (n) {
+               i = n;
+               do {
+                       n = i->prev;
+                       list_del(i);
+                       list_add_tail(i, &rdev->fence_drv.signaled);
+                       fence = list_entry(i, struct radeon_fence, list);
+                       fence->signaled = true;
+                       i = n;
+               } while (i != &rdev->fence_drv.emited);
+               wake = true;
+       }
+       return wake;
+}
+
+static void radeon_fence_destroy(struct kref *kref)
+{
+       unsigned long irq_flags;
+        struct radeon_fence *fence;
+
+       fence = container_of(kref, struct radeon_fence, kref);
+       write_lock_irqsave(&fence->rdev->fence_drv.lock, irq_flags);
+       list_del(&fence->list);
+       fence->emited = false;
+       write_unlock_irqrestore(&fence->rdev->fence_drv.lock, irq_flags);
+       kfree(fence);
+}
+
+int radeon_fence_create(struct radeon_device *rdev, struct radeon_fence **fence)
+{
+       unsigned long irq_flags;
+
+       *fence = kmalloc(sizeof(struct radeon_fence), GFP_KERNEL);
+       if ((*fence) == NULL) {
+               return -ENOMEM;
+       }
+       kref_init(&((*fence)->kref));
+       (*fence)->rdev = rdev;
+       (*fence)->emited = false;
+       (*fence)->signaled = false;
+       (*fence)->seq = 0;
+       INIT_LIST_HEAD(&(*fence)->list);
+
+       write_lock_irqsave(&rdev->fence_drv.lock, irq_flags);
+       list_add_tail(&(*fence)->list, &rdev->fence_drv.created);
+       write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
+       return 0;
+}
+
+
+bool radeon_fence_signaled(struct radeon_fence *fence)
+{
+       struct radeon_device *rdev = fence->rdev;
+       unsigned long irq_flags;
+       bool signaled = false;
+
+       if (rdev->gpu_lockup) {
+               return true;
+       }
+       if (fence == NULL) {
+               return true;
+       }
+       write_lock_irqsave(&fence->rdev->fence_drv.lock, irq_flags);
+       signaled = fence->signaled;
+       /* if we are shuting down report all fence as signaled */
+       if (fence->rdev->shutdown) {
+               signaled = true;
+       }
+       if (!fence->emited) {
+               WARN(1, "Querying an unemited fence : %p !\n", fence);
+               signaled = true;
+       }
+       if (!signaled) {
+               radeon_fence_poll_locked(fence->rdev);
+               signaled = fence->signaled;
+       }
+       write_unlock_irqrestore(&fence->rdev->fence_drv.lock, irq_flags);
+       return signaled;
+}
+
+int radeon_fence_wait(struct radeon_fence *fence, bool interruptible)
+{
+       struct radeon_device *rdev;
+       unsigned long cur_jiffies;
+       unsigned long timeout;
+       bool expired = false;
+       int r;
+
+
+       if (fence == NULL) {
+               WARN(1, "Querying an invalid fence : %p !\n", fence);
+               return 0;
+       }
+       rdev = fence->rdev;
+       if (radeon_fence_signaled(fence)) {
+               return 0;
+       }
+retry:
+       cur_jiffies = jiffies;
+       timeout = HZ / 100;
+       if (time_after(fence->timeout, cur_jiffies)) {
+               timeout = fence->timeout - cur_jiffies;
+       }
+       if (interruptible) {
+               r = wait_event_interruptible_timeout(rdev->fence_drv.queue,
+                               radeon_fence_signaled(fence), timeout);
+               if (unlikely(r == -ERESTARTSYS)) {
+                       return -ERESTART;
+               }
+       } else {
+               r = wait_event_timeout(rdev->fence_drv.queue,
+                        radeon_fence_signaled(fence), timeout);
+       }
+       if (unlikely(!radeon_fence_signaled(fence))) {
+               if (unlikely(r == 0)) {
+                       expired = true;
+               }
+               if (unlikely(expired)) {
+                       timeout = 1;
+                       if (time_after(cur_jiffies, fence->timeout)) {
+                               timeout = cur_jiffies - fence->timeout;
+                       }
+                       timeout = jiffies_to_msecs(timeout);
+                       if (timeout > 500) {
+                               DRM_ERROR("fence(%p:0x%08X) %lums timeout "
+                                         "going to reset GPU\n",
+                                         fence, fence->seq, timeout);
+                               radeon_gpu_reset(rdev);
+                               WREG32(rdev->fence_drv.scratch_reg, fence->seq);
+                       }
+               }
+               goto retry;
+       }
+       if (unlikely(expired)) {
+               rdev->fence_drv.count_timeout++;
+               cur_jiffies = jiffies;
+               timeout = 1;
+               if (time_after(cur_jiffies, fence->timeout)) {
+                       timeout = cur_jiffies - fence->timeout;
+               }
+               timeout = jiffies_to_msecs(timeout);
+               DRM_ERROR("fence(%p:0x%08X) %lums timeout\n",
+                         fence, fence->seq, timeout);
+               DRM_ERROR("last signaled fence(0x%08X)\n",
+                         rdev->fence_drv.last_seq);
+       }
+       return 0;
+}
+
+int radeon_fence_wait_next(struct radeon_device *rdev)
+{
+       unsigned long irq_flags;
+       struct radeon_fence *fence;
+       int r;
+
+       if (rdev->gpu_lockup) {
+               return 0;
+       }
+       write_lock_irqsave(&rdev->fence_drv.lock, irq_flags);
+       if (list_empty(&rdev->fence_drv.emited)) {
+               write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
+               return 0;
+       }
+       fence = list_entry(rdev->fence_drv.emited.next,
+                          struct radeon_fence, list);
+       radeon_fence_ref(fence);
+       write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
+       r = radeon_fence_wait(fence, false);
+       radeon_fence_unref(&fence);
+       return r;
+}
+
+int radeon_fence_wait_last(struct radeon_device *rdev)
+{
+       unsigned long irq_flags;
+       struct radeon_fence *fence;
+       int r;
+
+       if (rdev->gpu_lockup) {
+               return 0;
+       }
+       write_lock_irqsave(&rdev->fence_drv.lock, irq_flags);
+       if (list_empty(&rdev->fence_drv.emited)) {
+               write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
+               return 0;
+       }
+       fence = list_entry(rdev->fence_drv.emited.prev,
+                          struct radeon_fence, list);
+       radeon_fence_ref(fence);
+       write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
+       r = radeon_fence_wait(fence, false);
+       radeon_fence_unref(&fence);
+       return r;
+}
+
+struct radeon_fence *radeon_fence_ref(struct radeon_fence *fence)
+{
+       kref_get(&fence->kref);
+       return fence;
+}
+
+void radeon_fence_unref(struct radeon_fence **fence)
+{
+       struct radeon_fence *tmp = *fence;
+
+       *fence = NULL;
+       if (tmp) {
+               kref_put(&tmp->kref, &radeon_fence_destroy);
+       }
+}
+
+void radeon_fence_process(struct radeon_device *rdev)
+{
+       unsigned long irq_flags;
+       bool wake;
+
+       write_lock_irqsave(&rdev->fence_drv.lock, irq_flags);
+       wake = radeon_fence_poll_locked(rdev);
+       write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
+       if (wake) {
+               wake_up_all(&rdev->fence_drv.queue);
+       }
+}
+
+int radeon_fence_driver_init(struct radeon_device *rdev)
+{
+       unsigned long irq_flags;
+       int r;
+
+       write_lock_irqsave(&rdev->fence_drv.lock, irq_flags);
+       r = radeon_scratch_get(rdev, &rdev->fence_drv.scratch_reg);
+       if (r) {
+               DRM_ERROR("Fence failed to get a scratch register.");
+               write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
+               return r;
+       }
+       WREG32(rdev->fence_drv.scratch_reg, 0);
+       atomic_set(&rdev->fence_drv.seq, 0);
+       INIT_LIST_HEAD(&rdev->fence_drv.created);
+       INIT_LIST_HEAD(&rdev->fence_drv.emited);
+       INIT_LIST_HEAD(&rdev->fence_drv.signaled);
+       rdev->fence_drv.count_timeout = 0;
+       init_waitqueue_head(&rdev->fence_drv.queue);
+       write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
+       if (radeon_debugfs_fence_init(rdev)) {
+               DRM_ERROR("Failed to register debugfs file for fence !\n");
+       }
+       return 0;
+}
+
+void radeon_fence_driver_fini(struct radeon_device *rdev)
+{
+       unsigned long irq_flags;
+
+       wake_up_all(&rdev->fence_drv.queue);
+       write_lock_irqsave(&rdev->fence_drv.lock, irq_flags);
+       radeon_scratch_free(rdev, rdev->fence_drv.scratch_reg);
+       write_unlock_irqrestore(&rdev->fence_drv.lock, irq_flags);
+       DRM_INFO("radeon: fence finalized\n");
+}
+
+
+/*
+ * Fence debugfs
+ */
+#if defined(CONFIG_DEBUG_FS)
+static int radeon_debugfs_fence_info(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *)m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_fence *fence;
+
+       seq_printf(m, "Last signaled fence 0x%08X\n",
+                  RREG32(rdev->fence_drv.scratch_reg));
+       if (!list_empty(&rdev->fence_drv.emited)) {
+                  fence = list_entry(rdev->fence_drv.emited.prev,
+                                     struct radeon_fence, list);
+                  seq_printf(m, "Last emited fence %p with 0x%08X\n",
+                             fence,  fence->seq);
+       }
+       return 0;
+}
+
+static struct drm_info_list radeon_debugfs_fence_list[] = {
+       {"radeon_fence_info", &radeon_debugfs_fence_info, 0, NULL},
+};
+#endif
+
+int radeon_debugfs_fence_init(struct radeon_device *rdev)
+{
+#if defined(CONFIG_DEBUG_FS)
+       return radeon_debugfs_add_files(rdev, radeon_debugfs_fence_list, 1);
+#else
+       return 0;
+#endif
+}
diff --git a/drivers/gpu/drm/radeon/radeon_fixed.h b/drivers/gpu/drm/radeon/radeon_fixed.h
new file mode 100644 (file)
index 0000000..90187d1
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2009 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ */
+#ifndef RADEON_FIXED_H
+#define RADEON_FIXED_H
+
+typedef union rfixed {
+       u32 full;
+} fixed20_12;
+
+
+#define rfixed_const(A) (u32)(((A) << 12))/*  + ((B + 0.000122)*4096)) */
+#define rfixed_const_half(A) (u32)(((A) << 12) + 2048)
+#define rfixed_const_666(A) (u32)(((A) << 12) + 2731)
+#define rfixed_const_8(A) (u32)(((A) << 12) + 3277)
+#define rfixed_mul(A, B) ((u64)((u64)(A).full * (B).full + 2048) >> 12)
+#define fixed_init(A) { .full = rfixed_const((A)) }
+#define fixed_init_half(A) { .full = rfixed_const_half((A)) }
+#define rfixed_trunc(A) ((A).full >> 12)
+
+static inline u32 rfixed_div(fixed20_12 A, fixed20_12 B)
+{
+       u64 tmp = ((u64)A.full << 13);
+
+       do_div(tmp, B.full);
+       tmp += 1;
+       tmp /= 2;
+       return lower_32_bits(tmp);
+}
+#endif
diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c
new file mode 100644 (file)
index 0000000..d343a15
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ *          Jerome Glisse
+ */
+#include "drmP.h"
+#include "radeon_drm.h"
+#include "radeon.h"
+#include "radeon_reg.h"
+
+/*
+ * Common GART table functions.
+ */
+int radeon_gart_table_ram_alloc(struct radeon_device *rdev)
+{
+       void *ptr;
+
+       ptr = pci_alloc_consistent(rdev->pdev, rdev->gart.table_size,
+                                  &rdev->gart.table_addr);
+       if (ptr == NULL) {
+               return -ENOMEM;
+       }
+#ifdef CONFIG_X86
+       if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480 ||
+           rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) {
+               set_memory_uc((unsigned long)ptr,
+                             rdev->gart.table_size >> PAGE_SHIFT);
+       }
+#endif
+       rdev->gart.table.ram.ptr = ptr;
+       memset((void *)rdev->gart.table.ram.ptr, 0, rdev->gart.table_size);
+       return 0;
+}
+
+void radeon_gart_table_ram_free(struct radeon_device *rdev)
+{
+       if (rdev->gart.table.ram.ptr == NULL) {
+               return;
+       }
+#ifdef CONFIG_X86
+       if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480 ||
+           rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) {
+               set_memory_wb((unsigned long)rdev->gart.table.ram.ptr,
+                             rdev->gart.table_size >> PAGE_SHIFT);
+       }
+#endif
+       pci_free_consistent(rdev->pdev, rdev->gart.table_size,
+                           (void *)rdev->gart.table.ram.ptr,
+                           rdev->gart.table_addr);
+       rdev->gart.table.ram.ptr = NULL;
+       rdev->gart.table_addr = 0;
+}
+
+int radeon_gart_table_vram_alloc(struct radeon_device *rdev)
+{
+       uint64_t gpu_addr;
+       int r;
+
+       if (rdev->gart.table.vram.robj == NULL) {
+               r = radeon_object_create(rdev, NULL,
+                                        rdev->gart.table_size,
+                                        true,
+                                        RADEON_GEM_DOMAIN_VRAM,
+                                        false, &rdev->gart.table.vram.robj);
+               if (r) {
+                       return r;
+               }
+       }
+       r = radeon_object_pin(rdev->gart.table.vram.robj,
+                             RADEON_GEM_DOMAIN_VRAM, &gpu_addr);
+       if (r) {
+               radeon_object_unref(&rdev->gart.table.vram.robj);
+               return r;
+       }
+       r = radeon_object_kmap(rdev->gart.table.vram.robj,
+                              (void **)&rdev->gart.table.vram.ptr);
+       if (r) {
+               radeon_object_unpin(rdev->gart.table.vram.robj);
+               radeon_object_unref(&rdev->gart.table.vram.robj);
+               DRM_ERROR("radeon: failed to map gart vram table.\n");
+               return r;
+       }
+       rdev->gart.table_addr = gpu_addr;
+       return 0;
+}
+
+void radeon_gart_table_vram_free(struct radeon_device *rdev)
+{
+       if (rdev->gart.table.vram.robj == NULL) {
+               return;
+       }
+       radeon_object_kunmap(rdev->gart.table.vram.robj);
+       radeon_object_unpin(rdev->gart.table.vram.robj);
+       radeon_object_unref(&rdev->gart.table.vram.robj);
+}
+
+
+
+
+/*
+ * Common gart functions.
+ */
+void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset,
+                       int pages)
+{
+       unsigned t;
+       unsigned p;
+       int i, j;
+
+       if (!rdev->gart.ready) {
+               WARN(1, "trying to unbind memory to unitialized GART !\n");
+               return;
+       }
+       t = offset / 4096;
+       p = t / (PAGE_SIZE / 4096);
+       for (i = 0; i < pages; i++, p++) {
+               if (rdev->gart.pages[p]) {
+                       pci_unmap_page(rdev->pdev, rdev->gart.pages_addr[p],
+                                      PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+                       rdev->gart.pages[p] = NULL;
+                       rdev->gart.pages_addr[p] = 0;
+                       for (j = 0; j < (PAGE_SIZE / 4096); j++, t++) {
+                               radeon_gart_set_page(rdev, t, 0);
+                       }
+               }
+       }
+       mb();
+       radeon_gart_tlb_flush(rdev);
+}
+
+int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
+                    int pages, struct page **pagelist)
+{
+       unsigned t;
+       unsigned p;
+       uint64_t page_base;
+       int i, j;
+
+       if (!rdev->gart.ready) {
+               DRM_ERROR("trying to bind memory to unitialized GART !\n");
+               return -EINVAL;
+       }
+       t = offset / 4096;
+       p = t / (PAGE_SIZE / 4096);
+
+       for (i = 0; i < pages; i++, p++) {
+               /* we need to support large memory configurations */
+               /* assume that unbind have already been call on the range */
+               rdev->gart.pages_addr[p] = pci_map_page(rdev->pdev, pagelist[i],
+                                                       0, PAGE_SIZE,
+                                                       PCI_DMA_BIDIRECTIONAL);
+               if (pci_dma_mapping_error(rdev->pdev, rdev->gart.pages_addr[p])) {
+                       /* FIXME: failed to map page (return -ENOMEM?) */
+                       radeon_gart_unbind(rdev, offset, pages);
+                       return -ENOMEM;
+               }
+               rdev->gart.pages[p] = pagelist[i];
+               page_base = (uint32_t)rdev->gart.pages_addr[p];
+               for (j = 0; j < (PAGE_SIZE / 4096); j++, t++) {
+                       radeon_gart_set_page(rdev, t, page_base);
+                       page_base += 4096;
+               }
+       }
+       mb();
+       radeon_gart_tlb_flush(rdev);
+       return 0;
+}
+
+int radeon_gart_init(struct radeon_device *rdev)
+{
+       if (rdev->gart.pages) {
+               return 0;
+       }
+       /* We need PAGE_SIZE >= 4096 */
+       if (PAGE_SIZE < 4096) {
+               DRM_ERROR("Page size is smaller than GPU page size!\n");
+               return -EINVAL;
+       }
+       /* Compute table size */
+       rdev->gart.num_cpu_pages = rdev->mc.gtt_size / PAGE_SIZE;
+       rdev->gart.num_gpu_pages = rdev->mc.gtt_size / 4096;
+       DRM_INFO("GART: num cpu pages %u, num gpu pages %u\n",
+                rdev->gart.num_cpu_pages, rdev->gart.num_gpu_pages);
+       /* Allocate pages table */
+       rdev->gart.pages = kzalloc(sizeof(void *) * rdev->gart.num_cpu_pages,
+                                  GFP_KERNEL);
+       if (rdev->gart.pages == NULL) {
+               radeon_gart_fini(rdev);
+               return -ENOMEM;
+       }
+       rdev->gart.pages_addr = kzalloc(sizeof(dma_addr_t) *
+                                       rdev->gart.num_cpu_pages, GFP_KERNEL);
+       if (rdev->gart.pages_addr == NULL) {
+               radeon_gart_fini(rdev);
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+void radeon_gart_fini(struct radeon_device *rdev)
+{
+       if (rdev->gart.pages && rdev->gart.pages_addr && rdev->gart.ready) {
+               /* unbind pages */
+               radeon_gart_unbind(rdev, 0, rdev->gart.num_cpu_pages);
+       }
+       rdev->gart.ready = false;
+       kfree(rdev->gart.pages);
+       kfree(rdev->gart.pages_addr);
+       rdev->gart.pages = NULL;
+       rdev->gart.pages_addr = NULL;
+}
diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c
new file mode 100644 (file)
index 0000000..eb51603
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ *          Jerome Glisse
+ */
+#include "drmP.h"
+#include "drm.h"
+#include "radeon_drm.h"
+#include "radeon.h"
+
+int radeon_gem_object_init(struct drm_gem_object *obj)
+{
+       /* we do nothings here */
+       return 0;
+}
+
+void radeon_gem_object_free(struct drm_gem_object *gobj)
+{
+       struct radeon_object *robj = gobj->driver_private;
+
+       gobj->driver_private = NULL;
+       if (robj) {
+               radeon_object_unref(&robj);
+       }
+}
+
+int radeon_gem_object_create(struct radeon_device *rdev, int size,
+                            int alignment, int initial_domain,
+                            bool discardable, bool kernel,
+                            bool interruptible,
+                            struct drm_gem_object **obj)
+{
+       struct drm_gem_object *gobj;
+       struct radeon_object *robj;
+       int r;
+
+       *obj = NULL;
+       gobj = drm_gem_object_alloc(rdev->ddev, size);
+       if (!gobj) {
+               return -ENOMEM;
+       }
+       /* At least align on page size */
+       if (alignment < PAGE_SIZE) {
+               alignment = PAGE_SIZE;
+       }
+       r = radeon_object_create(rdev, gobj, size, kernel, initial_domain,
+                                interruptible, &robj);
+       if (r) {
+               DRM_ERROR("Failed to allocate GEM object (%d, %d, %u)\n",
+                         size, initial_domain, alignment);
+               mutex_lock(&rdev->ddev->struct_mutex);
+               drm_gem_object_unreference(gobj);
+               mutex_unlock(&rdev->ddev->struct_mutex);
+               return r;
+       }
+       gobj->driver_private = robj;
+       *obj = gobj;
+       return 0;
+}
+
+int radeon_gem_object_pin(struct drm_gem_object *obj, uint32_t pin_domain,
+                         uint64_t *gpu_addr)
+{
+       struct radeon_object *robj = obj->driver_private;
+       uint32_t flags;
+
+       switch (pin_domain) {
+       case RADEON_GEM_DOMAIN_VRAM:
+               flags = TTM_PL_FLAG_VRAM;
+               break;
+       case RADEON_GEM_DOMAIN_GTT:
+               flags = TTM_PL_FLAG_TT;
+               break;
+       default:
+               flags = TTM_PL_FLAG_SYSTEM;
+               break;
+       }
+       return radeon_object_pin(robj, flags, gpu_addr);
+}
+
+void radeon_gem_object_unpin(struct drm_gem_object *obj)
+{
+       struct radeon_object *robj = obj->driver_private;
+       radeon_object_unpin(robj);
+}
+
+int radeon_gem_set_domain(struct drm_gem_object *gobj,
+                         uint32_t rdomain, uint32_t wdomain)
+{
+       struct radeon_object *robj;
+       uint32_t domain;
+       int r;
+
+       /* FIXME: reeimplement */
+       robj = gobj->driver_private;
+       /* work out where to validate the buffer to */
+       domain = wdomain;
+       if (!domain) {
+               domain = rdomain;
+       }
+       if (!domain) {
+               /* Do nothings */
+               printk(KERN_WARNING "Set domain withou domain !\n");
+               return 0;
+       }
+       if (domain == RADEON_GEM_DOMAIN_CPU) {
+               /* Asking for cpu access wait for object idle */
+               r = radeon_object_wait(robj);
+               if (r) {
+                       printk(KERN_ERR "Failed to wait for object !\n");
+                       return r;
+               }
+       }
+       return 0;
+}
+
+int radeon_gem_init(struct radeon_device *rdev)
+{
+       INIT_LIST_HEAD(&rdev->gem.objects);
+       return 0;
+}
+
+void radeon_gem_fini(struct radeon_device *rdev)
+{
+       radeon_object_force_delete(rdev);
+}
+
+
+/*
+ * GEM ioctls.
+ */
+int radeon_gem_info_ioctl(struct drm_device *dev, void *data,
+                         struct drm_file *filp)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       struct drm_radeon_gem_info *args = data;
+
+       args->vram_size = rdev->mc.vram_size;
+       /* FIXME: report somethings that makes sense */
+       args->vram_visible = rdev->mc.vram_size - (4 * 1024 * 1024);
+       args->gart_size = rdev->mc.gtt_size;
+       return 0;
+}
+
+int radeon_gem_pread_ioctl(struct drm_device *dev, void *data,
+                          struct drm_file *filp)
+{
+       /* TODO: implement */
+       DRM_ERROR("unimplemented %s\n", __func__);
+       return -ENOSYS;
+}
+
+int radeon_gem_pwrite_ioctl(struct drm_device *dev, void *data,
+                           struct drm_file *filp)
+{
+       /* TODO: implement */
+       DRM_ERROR("unimplemented %s\n", __func__);
+       return -ENOSYS;
+}
+
+int radeon_gem_create_ioctl(struct drm_device *dev, void *data,
+                           struct drm_file *filp)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       struct drm_radeon_gem_create *args = data;
+       struct drm_gem_object *gobj;
+       uint32_t handle;
+       int r;
+
+       /* create a gem object to contain this object in */
+       args->size = roundup(args->size, PAGE_SIZE);
+       r = radeon_gem_object_create(rdev, args->size, args->alignment,
+                                    args->initial_domain, false,
+                                    false, true, &gobj);
+       if (r) {
+               return r;
+       }
+       r = drm_gem_handle_create(filp, gobj, &handle);
+       if (r) {
+               mutex_lock(&dev->struct_mutex);
+               drm_gem_object_unreference(gobj);
+               mutex_unlock(&dev->struct_mutex);
+               return r;
+       }
+       mutex_lock(&dev->struct_mutex);
+       drm_gem_object_handle_unreference(gobj);
+       mutex_unlock(&dev->struct_mutex);
+       args->handle = handle;
+       return 0;
+}
+
+int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data,
+                               struct drm_file *filp)
+{
+       /* transition the BO to a domain -
+        * just validate the BO into a certain domain */
+       struct drm_radeon_gem_set_domain *args = data;
+       struct drm_gem_object *gobj;
+       struct radeon_object *robj;
+       int r;
+
+       /* for now if someone requests domain CPU -
+        * just make sure the buffer is finished with */
+
+       /* just do a BO wait for now */
+       gobj = drm_gem_object_lookup(dev, filp, args->handle);
+       if (gobj == NULL) {
+               return -EINVAL;
+       }
+       robj = gobj->driver_private;
+
+       r = radeon_gem_set_domain(gobj, args->read_domains, args->write_domain);
+
+       mutex_lock(&dev->struct_mutex);
+       drm_gem_object_unreference(gobj);
+       mutex_unlock(&dev->struct_mutex);
+       return r;
+}
+
+int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data,
+                         struct drm_file *filp)
+{
+       struct drm_radeon_gem_mmap *args = data;
+       struct drm_gem_object *gobj;
+       struct radeon_object *robj;
+       int r;
+
+       gobj = drm_gem_object_lookup(dev, filp, args->handle);
+       if (gobj == NULL) {
+               return -EINVAL;
+       }
+       robj = gobj->driver_private;
+       r = radeon_object_mmap(robj, &args->addr_ptr);
+       mutex_lock(&dev->struct_mutex);
+       drm_gem_object_unreference(gobj);
+       mutex_unlock(&dev->struct_mutex);
+       return r;
+}
+
+int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,
+                         struct drm_file *filp)
+{
+       /* FIXME: implement */
+       return 0;
+}
+
+int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
+                             struct drm_file *filp)
+{
+       struct drm_radeon_gem_wait_idle *args = data;
+       struct drm_gem_object *gobj;
+       struct radeon_object *robj;
+       int r;
+
+       gobj = drm_gem_object_lookup(dev, filp, args->handle);
+       if (gobj == NULL) {
+               return -EINVAL;
+       }
+       robj = gobj->driver_private;
+       r = radeon_object_wait(robj);
+       mutex_lock(&dev->struct_mutex);
+       drm_gem_object_unreference(gobj);
+       mutex_unlock(&dev->struct_mutex);
+       return r;
+}
diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c
new file mode 100644 (file)
index 0000000..71465ed
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2007-8 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ */
+#include "drmP.h"
+#include "radeon_drm.h"
+#include "radeon.h"
+
+/**
+ * radeon_ddc_probe
+ *
+ */
+bool radeon_ddc_probe(struct radeon_connector *radeon_connector)
+{
+       u8 out_buf[] = { 0x0, 0x0};
+       u8 buf[2];
+       int ret;
+       struct i2c_msg msgs[] = {
+               {
+                       .addr = 0x50,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = out_buf,
+               },
+               {
+                       .addr = 0x50,
+                       .flags = I2C_M_RD,
+                       .len = 1,
+                       .buf = buf,
+               }
+       };
+
+       ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2);
+       if (ret == 2)
+               return true;
+
+       return false;
+}
+
+
+void radeon_i2c_do_lock(struct radeon_connector *radeon_connector, int lock_state)
+{
+       struct radeon_device *rdev = radeon_connector->base.dev->dev_private;
+       uint32_t temp;
+       struct radeon_i2c_bus_rec *rec = &radeon_connector->ddc_bus->rec;
+
+       /* RV410 appears to have a bug where the hw i2c in reset
+        * holds the i2c port in a bad state - switch hw i2c away before
+        * doing DDC - do this for all r200s/r300s/r400s for safety sake
+        */
+       if ((rdev->family >= CHIP_R200) && !ASIC_IS_AVIVO(rdev)) {
+               if (rec->a_clk_reg == RADEON_GPIO_MONID) {
+                       WREG32(RADEON_DVI_I2C_CNTL_0, (RADEON_I2C_SOFT_RST |
+                                               R200_DVI_I2C_PIN_SEL(R200_SEL_DDC1)));
+               } else {
+                       WREG32(RADEON_DVI_I2C_CNTL_0, (RADEON_I2C_SOFT_RST |
+                                               R200_DVI_I2C_PIN_SEL(R200_SEL_DDC3)));
+               }
+       }
+       if (lock_state) {
+               temp = RREG32(rec->a_clk_reg);
+               temp &= ~(rec->a_clk_mask);
+               WREG32(rec->a_clk_reg, temp);
+
+               temp = RREG32(rec->a_data_reg);
+               temp &= ~(rec->a_data_mask);
+               WREG32(rec->a_data_reg, temp);
+       }
+
+       temp = RREG32(rec->mask_clk_reg);
+       if (lock_state)
+               temp |= rec->mask_clk_mask;
+       else
+               temp &= ~rec->mask_clk_mask;
+       WREG32(rec->mask_clk_reg, temp);
+       temp = RREG32(rec->mask_clk_reg);
+
+       temp = RREG32(rec->mask_data_reg);
+       if (lock_state)
+               temp |= rec->mask_data_mask;
+       else
+               temp &= ~rec->mask_data_mask;
+       WREG32(rec->mask_data_reg, temp);
+       temp = RREG32(rec->mask_data_reg);
+}
+
+static int get_clock(void *i2c_priv)
+{
+       struct radeon_i2c_chan *i2c = i2c_priv;
+       struct radeon_device *rdev = i2c->dev->dev_private;
+       struct radeon_i2c_bus_rec *rec = &i2c->rec;
+       uint32_t val;
+
+       val = RREG32(rec->get_clk_reg);
+       val &= rec->get_clk_mask;
+
+       return (val != 0);
+}
+
+
+static int get_data(void *i2c_priv)
+{
+       struct radeon_i2c_chan *i2c = i2c_priv;
+       struct radeon_device *rdev = i2c->dev->dev_private;
+       struct radeon_i2c_bus_rec *rec = &i2c->rec;
+       uint32_t val;
+
+       val = RREG32(rec->get_data_reg);
+       val &= rec->get_data_mask;
+       return (val != 0);
+}
+
+static void set_clock(void *i2c_priv, int clock)
+{
+       struct radeon_i2c_chan *i2c = i2c_priv;
+       struct radeon_device *rdev = i2c->dev->dev_private;
+       struct radeon_i2c_bus_rec *rec = &i2c->rec;
+       uint32_t val;
+
+       val = RREG32(rec->put_clk_reg) & (uint32_t)~(rec->put_clk_mask);
+       val |= clock ? 0 : rec->put_clk_mask;
+       WREG32(rec->put_clk_reg, val);
+}
+
+static void set_data(void *i2c_priv, int data)
+{
+       struct radeon_i2c_chan *i2c = i2c_priv;
+       struct radeon_device *rdev = i2c->dev->dev_private;
+       struct radeon_i2c_bus_rec *rec = &i2c->rec;
+       uint32_t val;
+
+       val = RREG32(rec->put_data_reg) & (uint32_t)~(rec->put_data_mask);
+       val |= data ? 0 : rec->put_data_mask;
+       WREG32(rec->put_data_reg, val);
+}
+
+struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
+               struct radeon_i2c_bus_rec *rec,
+               const char *name)
+{
+       struct radeon_i2c_chan *i2c;
+       int ret;
+
+       i2c = drm_calloc(1, sizeof(struct radeon_i2c_chan), DRM_MEM_DRIVER);
+       if (i2c == NULL)
+               return NULL;
+
+       i2c->adapter.owner = THIS_MODULE;
+       i2c->adapter.algo_data = &i2c->algo;
+       i2c->dev = dev;
+       i2c->algo.setsda = set_data;
+       i2c->algo.setscl = set_clock;
+       i2c->algo.getsda = get_data;
+       i2c->algo.getscl = get_clock;
+       i2c->algo.udelay = 20;
+       /* vesa says 2.2 ms is enough, 1 jiffy doesn't seem to always
+        * make this, 2 jiffies is a lot more reliable */
+       i2c->algo.timeout = 2;
+       i2c->algo.data = i2c;
+       i2c->rec = *rec;
+       i2c_set_adapdata(&i2c->adapter, i2c);
+
+       ret = i2c_bit_add_bus(&i2c->adapter);
+       if (ret) {
+               DRM_INFO("Failed to register i2c %s\n", name);
+               goto out_free;
+       }
+
+       return i2c;
+out_free:
+       drm_free(i2c, sizeof(struct radeon_i2c_chan), DRM_MEM_DRIVER);
+       return NULL;
+
+}
+
+void radeon_i2c_destroy(struct radeon_i2c_chan *i2c)
+{
+       if (!i2c)
+               return;
+
+       i2c_del_adapter(&i2c->adapter);
+       drm_free(i2c, sizeof(struct radeon_i2c_chan), DRM_MEM_DRIVER);
+}
+
+struct drm_encoder *radeon_best_encoder(struct drm_connector *connector)
+{
+       return NULL;
+}
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
new file mode 100644 (file)
index 0000000..491d569
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ *          Jerome Glisse
+ */
+#include "drmP.h"
+#include "radeon_drm.h"
+#include "radeon_reg.h"
+#include "radeon_microcode.h"
+#include "radeon.h"
+#include "atom.h"
+
+static inline uint32_t r100_irq_ack(struct radeon_device *rdev)
+{
+       uint32_t irqs = RREG32(RADEON_GEN_INT_STATUS);
+       uint32_t irq_mask = RADEON_SW_INT_TEST;
+
+       if (irqs) {
+               WREG32(RADEON_GEN_INT_STATUS, irqs);
+       }
+       return irqs & irq_mask;
+}
+
+int r100_irq_set(struct radeon_device *rdev)
+{
+       uint32_t tmp = 0;
+
+       if (rdev->irq.sw_int) {
+               tmp |= RADEON_SW_INT_ENABLE;
+       }
+       /* Todo go through CRTC and enable vblank int or not */
+       WREG32(RADEON_GEN_INT_CNTL, tmp);
+       return 0;
+}
+
+int r100_irq_process(struct radeon_device *rdev)
+{
+       uint32_t status;
+
+       status = r100_irq_ack(rdev);
+       if (!status) {
+               return IRQ_NONE;
+       }
+       while (status) {
+               /* SW interrupt */
+               if (status & RADEON_SW_INT_TEST) {
+                       radeon_fence_process(rdev);
+               }
+               status = r100_irq_ack(rdev);
+       }
+       return IRQ_HANDLED;
+}
+
+int rs600_irq_set(struct radeon_device *rdev)
+{
+       uint32_t tmp = 0;
+
+       if (rdev->irq.sw_int) {
+               tmp |= RADEON_SW_INT_ENABLE;
+       }
+       WREG32(RADEON_GEN_INT_CNTL, tmp);
+       /* Todo go through CRTC and enable vblank int or not */
+       WREG32(R500_DxMODE_INT_MASK, 0);
+       return 0;
+}
+
+irqreturn_t radeon_driver_irq_handler_kms(DRM_IRQ_ARGS)
+{
+       struct drm_device *dev = (struct drm_device *) arg;
+       struct radeon_device *rdev = dev->dev_private;
+
+       return radeon_irq_process(rdev);
+}
+
+void radeon_driver_irq_preinstall_kms(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       unsigned i;
+
+       /* Disable *all* interrupts */
+       rdev->irq.sw_int = false;
+       for (i = 0; i < 2; i++) {
+               rdev->irq.crtc_vblank_int[i] = false;
+       }
+       radeon_irq_set(rdev);
+       /* Clear bits */
+       radeon_irq_process(rdev);
+}
+
+int radeon_driver_irq_postinstall_kms(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+
+       dev->max_vblank_count = 0x001fffff;
+       rdev->irq.sw_int = true;
+       radeon_irq_set(rdev);
+       return 0;
+}
+
+void radeon_driver_irq_uninstall_kms(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       unsigned i;
+
+       if (rdev == NULL) {
+               return;
+       }
+       /* Disable *all* interrupts */
+       rdev->irq.sw_int = false;
+       for (i = 0; i < 2; i++) {
+               rdev->irq.crtc_vblank_int[i] = false;
+       }
+       radeon_irq_set(rdev);
+}
+
+int radeon_irq_kms_init(struct radeon_device *rdev)
+{
+       int r = 0;
+
+       r = drm_vblank_init(rdev->ddev, 2);
+       if (r) {
+               return r;
+       }
+       drm_irq_install(rdev->ddev);
+       rdev->irq.installed = true;
+       DRM_INFO("radeon: irq initialized.\n");
+       return 0;
+}
+
+void radeon_irq_kms_fini(struct radeon_device *rdev)
+{
+       if (rdev->irq.installed) {
+               rdev->irq.installed = false;
+               drm_irq_uninstall(rdev->ddev);
+       }
+}
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
new file mode 100644 (file)
index 0000000..b0ce44b
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ *          Jerome Glisse
+ */
+#include "drmP.h"
+#include "drm_sarea.h"
+#include "radeon.h"
+#include "radeon_drm.h"
+
+
+/*
+ * Driver load/unload
+ */
+int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags)
+{
+       struct radeon_device *rdev;
+       int r;
+
+       rdev = kzalloc(sizeof(struct radeon_device), GFP_KERNEL);
+       if (rdev == NULL) {
+               return -ENOMEM;
+       }
+       dev->dev_private = (void *)rdev;
+
+       /* update BUS flag */
+       if (drm_device_is_agp(dev)) {
+               flags |= RADEON_IS_AGP;
+       } else if (drm_device_is_pcie(dev)) {
+               flags |= RADEON_IS_PCIE;
+       } else {
+               flags |= RADEON_IS_PCI;
+       }
+
+       r = radeon_device_init(rdev, dev, dev->pdev, flags);
+       if (r) {
+               DRM_ERROR("Failed to initialize radeon, disabling IOCTL\n");
+               radeon_device_fini(rdev);
+               return r;
+       }
+       return 0;
+}
+
+int radeon_driver_unload_kms(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+
+       radeon_device_fini(rdev);
+       kfree(rdev);
+       dev->dev_private = NULL;
+       return 0;
+}
+
+
+/*
+ * Userspace get informations ioctl
+ */
+int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       struct drm_radeon_info *info;
+       uint32_t *value_ptr;
+       uint32_t value;
+
+       info = data;
+       value_ptr = (uint32_t *)((unsigned long)info->value);
+       switch (info->request) {
+       case RADEON_INFO_DEVICE_ID:
+               value = dev->pci_device;
+               break;
+       case RADEON_INFO_NUM_GB_PIPES:
+               value = rdev->num_gb_pipes;
+               break;
+       default:
+               DRM_DEBUG("Invalid request %d\n", info->request);
+               return -EINVAL;
+       }
+       if (DRM_COPY_TO_USER(value_ptr, &value, sizeof(uint32_t))) {
+               DRM_ERROR("copy_to_user\n");
+               return -EFAULT;
+       }
+       return 0;
+}
+
+
+/*
+ * Outdated mess for old drm with Xorg being in charge (void function now).
+ */
+int radeon_driver_firstopen_kms(struct drm_device *dev)
+{
+       return 0;
+}
+
+
+void radeon_driver_lastclose_kms(struct drm_device *dev)
+{
+}
+
+int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
+{
+       return 0;
+}
+
+void radeon_driver_postclose_kms(struct drm_device *dev,
+                                struct drm_file *file_priv)
+{
+}
+
+void radeon_driver_preclose_kms(struct drm_device *dev,
+                               struct drm_file *file_priv)
+{
+}
+
+
+/*
+ * VBlank related functions.
+ */
+u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc)
+{
+       /* FIXME: implement */
+       return 0;
+}
+
+int radeon_enable_vblank_kms(struct drm_device *dev, int crtc)
+{
+       /* FIXME: implement */
+       return 0;
+}
+
+void radeon_disable_vblank_kms(struct drm_device *dev, int crtc)
+{
+       /* FIXME: implement */
+}
+
+
+/*
+ * For multiple master (like multiple X).
+ */
+struct drm_radeon_master_private {
+       drm_local_map_t *sarea;
+       drm_radeon_sarea_t *sarea_priv;
+};
+
+int radeon_master_create_kms(struct drm_device *dev, struct drm_master *master)
+{
+       struct drm_radeon_master_private *master_priv;
+       unsigned long sareapage;
+       int ret;
+
+       master_priv = drm_calloc(1, sizeof(*master_priv), DRM_MEM_DRIVER);
+       if (master_priv == NULL) {
+               return -ENOMEM;
+       }
+       /* prebuild the SAREA */
+       sareapage = max_t(unsigned long, SAREA_MAX, PAGE_SIZE);
+       ret = drm_addmap(dev, 0, sareapage, _DRM_SHM,
+                        _DRM_CONTAINS_LOCK|_DRM_DRIVER,
+                        &master_priv->sarea);
+       if (ret) {
+               DRM_ERROR("SAREA setup failed\n");
+               return ret;
+       }
+       master_priv->sarea_priv = master_priv->sarea->handle + sizeof(struct drm_sarea);
+       master_priv->sarea_priv->pfCurrentPage = 0;
+       master->driver_priv = master_priv;
+       return 0;
+}
+
+void radeon_master_destroy_kms(struct drm_device *dev,
+                              struct drm_master *master)
+{
+       struct drm_radeon_master_private *master_priv = master->driver_priv;
+
+       if (master_priv == NULL) {
+               return;
+       }
+       if (master_priv->sarea) {
+               drm_rmmap_locked(dev, master_priv->sarea);
+       }
+       drm_free(master_priv, sizeof(*master_priv), DRM_MEM_DRIVER);
+       master->driver_priv = NULL;
+}
+
+
+/*
+ * IOCTL.
+ */
+int radeon_dma_ioctl_kms(struct drm_device *dev, void *data,
+                        struct drm_file *file_priv)
+{
+       /* Not valid in KMS. */
+       return -EINVAL;
+}
+
+#define KMS_INVALID_IOCTL(name)                                                \
+int name(struct drm_device *dev, void *data, struct drm_file *file_priv)\
+{                                                                      \
+       DRM_ERROR("invalid ioctl with kms %s\n", __func__);             \
+       return -EINVAL;                                                 \
+}
+
+/*
+ * All these ioctls are invalid in kms world.
+ */
+KMS_INVALID_IOCTL(radeon_cp_init_kms)
+KMS_INVALID_IOCTL(radeon_cp_start_kms)
+KMS_INVALID_IOCTL(radeon_cp_stop_kms)
+KMS_INVALID_IOCTL(radeon_cp_reset_kms)
+KMS_INVALID_IOCTL(radeon_cp_idle_kms)
+KMS_INVALID_IOCTL(radeon_cp_resume_kms)
+KMS_INVALID_IOCTL(radeon_engine_reset_kms)
+KMS_INVALID_IOCTL(radeon_fullscreen_kms)
+KMS_INVALID_IOCTL(radeon_cp_swap_kms)
+KMS_INVALID_IOCTL(radeon_cp_clear_kms)
+KMS_INVALID_IOCTL(radeon_cp_vertex_kms)
+KMS_INVALID_IOCTL(radeon_cp_indices_kms)
+KMS_INVALID_IOCTL(radeon_cp_texture_kms)
+KMS_INVALID_IOCTL(radeon_cp_stipple_kms)
+KMS_INVALID_IOCTL(radeon_cp_indirect_kms)
+KMS_INVALID_IOCTL(radeon_cp_vertex2_kms)
+KMS_INVALID_IOCTL(radeon_cp_cmdbuf_kms)
+KMS_INVALID_IOCTL(radeon_cp_getparam_kms)
+KMS_INVALID_IOCTL(radeon_cp_flip_kms)
+KMS_INVALID_IOCTL(radeon_mem_alloc_kms)
+KMS_INVALID_IOCTL(radeon_mem_free_kms)
+KMS_INVALID_IOCTL(radeon_mem_init_heap_kms)
+KMS_INVALID_IOCTL(radeon_irq_emit_kms)
+KMS_INVALID_IOCTL(radeon_irq_wait_kms)
+KMS_INVALID_IOCTL(radeon_cp_setparam_kms)
+KMS_INVALID_IOCTL(radeon_surface_alloc_kms)
+KMS_INVALID_IOCTL(radeon_surface_free_kms)
+
+
+struct drm_ioctl_desc radeon_ioctls_kms[] = {
+       DRM_IOCTL_DEF(DRM_RADEON_CP_INIT, radeon_cp_init_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_RADEON_CP_START, radeon_cp_start_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_RADEON_CP_STOP, radeon_cp_stop_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_RADEON_CP_RESET, radeon_cp_reset_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_RADEON_CP_IDLE, radeon_cp_idle_kms, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_CP_RESUME, radeon_cp_resume_kms, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_RESET, radeon_engine_reset_kms, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_FULLSCREEN, radeon_fullscreen_kms, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_SWAP, radeon_cp_swap_kms, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_CLEAR, radeon_cp_clear_kms, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_VERTEX, radeon_cp_vertex_kms, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_INDICES, radeon_cp_indices_kms, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_TEXTURE, radeon_cp_texture_kms, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_STIPPLE, radeon_cp_stipple_kms, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_INDIRECT, radeon_cp_indirect_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_RADEON_VERTEX2, radeon_cp_vertex2_kms, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_CMDBUF, radeon_cp_cmdbuf_kms, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_GETPARAM, radeon_cp_getparam_kms, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_FLIP, radeon_cp_flip_kms, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_ALLOC, radeon_mem_alloc_kms, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_FREE, radeon_mem_free_kms, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_INIT_HEAP, radeon_mem_init_heap_kms, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+       DRM_IOCTL_DEF(DRM_RADEON_IRQ_EMIT, radeon_irq_emit_kms, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_IRQ_WAIT, radeon_irq_wait_kms, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_SETPARAM, radeon_cp_setparam_kms, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_SURF_ALLOC, radeon_surface_alloc_kms, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_SURF_FREE, radeon_surface_free_kms, DRM_AUTH),
+       /* KMS */
+       DRM_IOCTL_DEF(DRM_RADEON_GEM_INFO, radeon_gem_info_ioctl, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_GEM_CREATE, radeon_gem_create_ioctl, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_GEM_MMAP, radeon_gem_mmap_ioctl, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_GEM_SET_DOMAIN, radeon_gem_set_domain_ioctl, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_GEM_PREAD, radeon_gem_pread_ioctl, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_GEM_PWRITE, radeon_gem_pwrite_ioctl, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_GEM_WAIT_IDLE, radeon_gem_wait_idle_ioctl, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_CS, radeon_cs_ioctl, DRM_AUTH),
+       DRM_IOCTL_DEF(DRM_RADEON_INFO, radeon_info_ioctl, DRM_AUTH),
+};
+int radeon_max_kms_ioctl = DRM_ARRAY_SIZE(radeon_ioctls_kms);
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
new file mode 100644 (file)
index 0000000..8086ecf
--- /dev/null
@@ -0,0 +1,1276 @@
+/*
+ * Copyright 2007-8 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ */
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/radeon_drm.h>
+#include "radeon_fixed.h"
+#include "radeon.h"
+
+void radeon_restore_common_regs(struct drm_device *dev)
+{
+       /* don't need this yet */
+}
+
+static void radeon_pll_wait_for_read_update_complete(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       int i = 0;
+
+       /* FIXME: Certain revisions of R300 can't recover here.  Not sure of
+          the cause yet, but this workaround will mask the problem for now.
+          Other chips usually will pass at the very first test, so the
+          workaround shouldn't have any effect on them. */
+       for (i = 0;
+            (i < 10000 &&
+             RREG32_PLL(RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R);
+            i++);
+}
+
+static void radeon_pll_write_update(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+
+       while (RREG32_PLL(RADEON_PPLL_REF_DIV) & RADEON_PPLL_ATOMIC_UPDATE_R);
+
+       WREG32_PLL_P(RADEON_PPLL_REF_DIV,
+                          RADEON_PPLL_ATOMIC_UPDATE_W,
+                          ~(RADEON_PPLL_ATOMIC_UPDATE_W));
+}
+
+static void radeon_pll2_wait_for_read_update_complete(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       int i = 0;
+
+
+       /* FIXME: Certain revisions of R300 can't recover here.  Not sure of
+          the cause yet, but this workaround will mask the problem for now.
+          Other chips usually will pass at the very first test, so the
+          workaround shouldn't have any effect on them. */
+       for (i = 0;
+            (i < 10000 &&
+             RREG32_PLL(RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R);
+            i++);
+}
+
+static void radeon_pll2_write_update(struct drm_device *dev)
+{
+       struct radeon_device *rdev = dev->dev_private;
+
+       while (RREG32_PLL(RADEON_P2PLL_REF_DIV) & RADEON_P2PLL_ATOMIC_UPDATE_R);
+
+       WREG32_PLL_P(RADEON_P2PLL_REF_DIV,
+                          RADEON_P2PLL_ATOMIC_UPDATE_W,
+                          ~(RADEON_P2PLL_ATOMIC_UPDATE_W));
+}
+
+static uint8_t radeon_compute_pll_gain(uint16_t ref_freq, uint16_t ref_div,
+                                      uint16_t fb_div)
+{
+       unsigned int vcoFreq;
+
+       if (!ref_div)
+               return 1;
+
+       vcoFreq = ((unsigned)ref_freq & fb_div) / ref_div;
+
+       /*
+        * This is horribly crude: the VCO frequency range is divided into
+        * 3 parts, each part having a fixed PLL gain value.
+        */
+       if (vcoFreq >= 30000)
+               /*
+                * [300..max] MHz : 7
+                */
+               return 7;
+       else if (vcoFreq >= 18000)
+               /*
+                * [180..300) MHz : 4
+                */
+               return 4;
+       else
+               /*
+                * [0..180) MHz : 1
+                */
+               return 1;
+}
+
+void radeon_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t mask;
+
+       if (radeon_crtc->crtc_id)
+               mask = (RADEON_CRTC2_EN |
+                       RADEON_CRTC2_DISP_DIS |
+                       RADEON_CRTC2_VSYNC_DIS |
+                       RADEON_CRTC2_HSYNC_DIS |
+                       RADEON_CRTC2_DISP_REQ_EN_B);
+       else
+               mask = (RADEON_CRTC_DISPLAY_DIS |
+                       RADEON_CRTC_VSYNC_DIS |
+                       RADEON_CRTC_HSYNC_DIS);
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               if (radeon_crtc->crtc_id)
+                       WREG32_P(RADEON_CRTC2_GEN_CNTL, RADEON_CRTC2_EN, ~mask);
+               else {
+                       WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_EN, ~(RADEON_CRTC_EN |
+                                                                        RADEON_CRTC_DISP_REQ_EN_B));
+                       WREG32_P(RADEON_CRTC_EXT_CNTL, 0, ~mask);
+               }
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               if (radeon_crtc->crtc_id)
+                       WREG32_P(RADEON_CRTC2_GEN_CNTL, mask, ~mask);
+               else {
+                       WREG32_P(RADEON_CRTC_GEN_CNTL, RADEON_CRTC_DISP_REQ_EN_B, ~(RADEON_CRTC_EN |
+                                                                                   RADEON_CRTC_DISP_REQ_EN_B));
+                       WREG32_P(RADEON_CRTC_EXT_CNTL, mask, ~mask);
+               }
+               break;
+       }
+
+       if (mode != DRM_MODE_DPMS_OFF) {
+               radeon_crtc_load_lut(crtc);
+       }
+}
+
+/* properly set crtc bpp when using atombios */
+void radeon_legacy_atom_set_surface(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       int format;
+       uint32_t crtc_gen_cntl;
+       uint32_t disp_merge_cntl;
+       uint32_t crtc_pitch;
+
+       switch (crtc->fb->bits_per_pixel) {
+       case 15:      /*  555 */
+               format = 3;
+               break;
+       case 16:      /*  565 */
+               format = 4;
+               break;
+       case 24:      /*  RGB */
+               format = 5;
+               break;
+       case 32:      /* xRGB */
+               format = 6;
+               break;
+       default:
+               return;
+       }
+
+       crtc_pitch  = ((((crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8)) * crtc->fb->bits_per_pixel) +
+                       ((crtc->fb->bits_per_pixel * 8) - 1)) /
+                      (crtc->fb->bits_per_pixel * 8));
+       crtc_pitch |= crtc_pitch << 16;
+
+       WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch);
+
+       switch (radeon_crtc->crtc_id) {
+       case 0:
+               disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL);
+               disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN;
+               WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl);
+
+               crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL) & 0xfffff0ff;
+               crtc_gen_cntl |= (format << 8);
+               crtc_gen_cntl |= RADEON_CRTC_EXT_DISP_EN;
+               WREG32(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl);
+               break;
+       case 1:
+               disp_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL);
+               disp_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN;
+               WREG32(RADEON_DISP2_MERGE_CNTL, disp_merge_cntl);
+
+               crtc_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL) & 0xfffff0ff;
+               crtc_gen_cntl |= (format << 8);
+               WREG32(RADEON_CRTC2_GEN_CNTL, crtc_gen_cntl);
+               WREG32(RADEON_FP_H2_SYNC_STRT_WID,   RREG32(RADEON_CRTC2_H_SYNC_STRT_WID));
+               WREG32(RADEON_FP_V2_SYNC_STRT_WID,   RREG32(RADEON_CRTC2_V_SYNC_STRT_WID));
+               break;
+       }
+}
+
+int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
+                        struct drm_framebuffer *old_fb)
+{
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct radeon_framebuffer *radeon_fb;
+       struct drm_gem_object *obj;
+       uint64_t base;
+       uint32_t crtc_offset, crtc_offset_cntl, crtc_tile_x0_y0 = 0;
+       uint32_t crtc_pitch, pitch_pixels;
+
+       DRM_DEBUG("\n");
+
+       radeon_fb = to_radeon_framebuffer(crtc->fb);
+
+       obj = radeon_fb->obj;
+       if (radeon_gem_object_pin(obj, RADEON_GEM_DOMAIN_VRAM, &base)) {
+               return -EINVAL;
+       }
+       crtc_offset = (u32)base;
+       crtc_offset_cntl = 0;
+
+       pitch_pixels = crtc->fb->pitch / (crtc->fb->bits_per_pixel / 8);
+       crtc_pitch  = (((pitch_pixels * crtc->fb->bits_per_pixel) +
+                       ((crtc->fb->bits_per_pixel * 8) - 1)) /
+                      (crtc->fb->bits_per_pixel * 8));
+       crtc_pitch |= crtc_pitch << 16;
+
+       /* TODO tiling */
+       if (0) {
+               if (ASIC_IS_R300(rdev))
+                       crtc_offset_cntl |= (R300_CRTC_X_Y_MODE_EN |
+                                            R300_CRTC_MICRO_TILE_BUFFER_DIS |
+                                            R300_CRTC_MACRO_TILE_EN);
+               else
+                       crtc_offset_cntl |= RADEON_CRTC_TILE_EN;
+       } else {
+               if (ASIC_IS_R300(rdev))
+                       crtc_offset_cntl &= ~(R300_CRTC_X_Y_MODE_EN |
+                                             R300_CRTC_MICRO_TILE_BUFFER_DIS |
+                                             R300_CRTC_MACRO_TILE_EN);
+               else
+                       crtc_offset_cntl &= ~RADEON_CRTC_TILE_EN;
+       }
+
+
+       /* TODO more tiling */
+       if (0) {
+               if (ASIC_IS_R300(rdev)) {
+                       crtc_tile_x0_y0 = x | (y << 16);
+                       base &= ~0x7ff;
+               } else {
+                       int byteshift = crtc->fb->bits_per_pixel >> 4;
+                       int tile_addr = (((y >> 3) * crtc->fb->width + x) >> (8 - byteshift)) << 11;
+                       base += tile_addr + ((x << byteshift) % 256) + ((y % 8) << 8);
+                       crtc_offset_cntl |= (y % 16);
+               }
+       } else {
+               int offset = y * pitch_pixels + x;
+               switch (crtc->fb->bits_per_pixel) {
+               case 15:
+               case 16:
+                       offset *= 2;
+                       break;
+               case 24:
+                       offset *= 3;
+                       break;
+               case 32:
+                       offset *= 4;
+                       break;
+               default:
+                       return false;
+               }
+               base += offset;
+       }
+
+       base &= ~7;
+
+       /* update sarea TODO */
+
+       crtc_offset = (u32)base;
+
+       WREG32(RADEON_DISPLAY_BASE_ADDR + radeon_crtc->crtc_offset, rdev->mc.vram_location);
+
+       if (ASIC_IS_R300(rdev)) {
+               if (radeon_crtc->crtc_id)
+                       WREG32(R300_CRTC2_TILE_X0_Y0, crtc_tile_x0_y0);
+               else
+                       WREG32(R300_CRTC_TILE_X0_Y0, crtc_tile_x0_y0);
+       }
+       WREG32(RADEON_CRTC_OFFSET_CNTL + radeon_crtc->crtc_offset, crtc_offset_cntl);
+       WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, crtc_offset);
+       WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch);
+
+       if (old_fb && old_fb != crtc->fb) {
+               radeon_fb = to_radeon_framebuffer(old_fb);
+               radeon_gem_object_unpin(radeon_fb->obj);
+       }
+       return 0;
+}
+
+static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mode *mode)
+{
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       int format;
+       int hsync_start;
+       int hsync_wid;
+       int vsync_wid;
+       uint32_t crtc_h_total_disp;
+       uint32_t crtc_h_sync_strt_wid;
+       uint32_t crtc_v_total_disp;
+       uint32_t crtc_v_sync_strt_wid;
+
+       DRM_DEBUG("\n");
+
+       switch (crtc->fb->bits_per_pixel) {
+       case 15:      /*  555 */
+               format = 3;
+               break;
+       case 16:      /*  565 */
+               format = 4;
+               break;
+       case 24:      /*  RGB */
+               format = 5;
+               break;
+       case 32:      /* xRGB */
+               format = 6;
+               break;
+       default:
+               return false;
+       }
+
+       crtc_h_total_disp = ((((mode->crtc_htotal / 8) - 1) & 0x3ff)
+                            | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16));
+
+       hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8;
+       if (!hsync_wid)
+               hsync_wid = 1;
+       hsync_start = mode->crtc_hsync_start - 8;
+
+       crtc_h_sync_strt_wid = ((hsync_start & 0x1fff)
+                               | ((hsync_wid & 0x3f) << 16)
+                               | ((mode->flags & DRM_MODE_FLAG_NHSYNC)
+                                  ? RADEON_CRTC_H_SYNC_POL
+                                  : 0));
+
+       /* This works for double scan mode. */
+       crtc_v_total_disp = (((mode->crtc_vtotal - 1) & 0xffff)
+                            | ((mode->crtc_vdisplay - 1) << 16));
+
+       vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start;
+       if (!vsync_wid)
+               vsync_wid = 1;
+
+       crtc_v_sync_strt_wid = (((mode->crtc_vsync_start - 1) & 0xfff)
+                               | ((vsync_wid & 0x1f) << 16)
+                               | ((mode->flags & DRM_MODE_FLAG_NVSYNC)
+                                  ? RADEON_CRTC_V_SYNC_POL
+                                  : 0));
+
+       /* TODO -> Dell Server */
+       if (0) {
+               uint32_t disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG);
+               uint32_t tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL);
+               uint32_t dac2_cntl = RREG32(RADEON_DAC_CNTL2);
+               uint32_t crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL);
+
+               dac2_cntl &= ~RADEON_DAC2_DAC_CLK_SEL;
+               dac2_cntl |= RADEON_DAC2_DAC2_CLK_SEL;
+
+               /* For CRT on DAC2, don't turn it on if BIOS didn't
+                  enable it, even it's detected.
+               */
+               disp_hw_debug |= RADEON_CRT2_DISP1_SEL;
+               tv_dac_cntl &= ~((1<<2) | (3<<8) | (7<<24) | (0xff<<16));
+               tv_dac_cntl |= (0x03 | (2<<8) | (0x58<<16));
+
+               WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl);
+               WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug);
+               WREG32(RADEON_DAC_CNTL2, dac2_cntl);
+               WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
+       }
+
+       if (radeon_crtc->crtc_id) {
+               uint32_t crtc2_gen_cntl;
+               uint32_t disp2_merge_cntl;
+
+               /* check to see if TV DAC is enabled for another crtc and keep it enabled */
+               if (RREG32(RADEON_CRTC2_GEN_CNTL) & RADEON_CRTC2_CRT2_ON)
+                       crtc2_gen_cntl = RADEON_CRTC2_CRT2_ON;
+               else
+                       crtc2_gen_cntl = 0;
+
+               crtc2_gen_cntl |= ((format << 8)
+                                  | RADEON_CRTC2_VSYNC_DIS
+                                  | RADEON_CRTC2_HSYNC_DIS
+                                  | RADEON_CRTC2_DISP_DIS
+                                  | RADEON_CRTC2_DISP_REQ_EN_B
+                                  | ((mode->flags & DRM_MODE_FLAG_DBLSCAN)
+                                     ? RADEON_CRTC2_DBL_SCAN_EN
+                                     : 0)
+                                  | ((mode->flags & DRM_MODE_FLAG_CSYNC)
+                                     ? RADEON_CRTC2_CSYNC_EN
+                                     : 0)
+                                  | ((mode->flags & DRM_MODE_FLAG_INTERLACE)
+                                     ? RADEON_CRTC2_INTERLACE_EN
+                                     : 0));
+
+               disp2_merge_cntl = RREG32(RADEON_DISP2_MERGE_CNTL);
+               disp2_merge_cntl &= ~RADEON_DISP2_RGB_OFFSET_EN;
+
+               WREG32(RADEON_DISP2_MERGE_CNTL, disp2_merge_cntl);
+               WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
+       } else {
+               uint32_t crtc_gen_cntl;
+               uint32_t crtc_ext_cntl;
+               uint32_t disp_merge_cntl;
+
+               crtc_gen_cntl = (RADEON_CRTC_EXT_DISP_EN
+                                | (format << 8)
+                                | RADEON_CRTC_DISP_REQ_EN_B
+                                | ((mode->flags & DRM_MODE_FLAG_DBLSCAN)
+                                   ? RADEON_CRTC_DBL_SCAN_EN
+                                   : 0)
+                                | ((mode->flags & DRM_MODE_FLAG_CSYNC)
+                                   ? RADEON_CRTC_CSYNC_EN
+                                   : 0)
+                                | ((mode->flags & DRM_MODE_FLAG_INTERLACE)
+                                   ? RADEON_CRTC_INTERLACE_EN
+                                   : 0));
+
+               crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL);
+               crtc_ext_cntl |= (RADEON_XCRT_CNT_EN |
+                                 RADEON_CRTC_VSYNC_DIS |
+                                 RADEON_CRTC_HSYNC_DIS |
+                                 RADEON_CRTC_DISPLAY_DIS);
+
+               disp_merge_cntl = RREG32(RADEON_DISP_MERGE_CNTL);
+               disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN;
+
+               WREG32(RADEON_DISP_MERGE_CNTL, disp_merge_cntl);
+               WREG32(RADEON_CRTC_GEN_CNTL, crtc_gen_cntl);
+               WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl);
+       }
+
+       WREG32(RADEON_CRTC_H_TOTAL_DISP + radeon_crtc->crtc_offset, crtc_h_total_disp);
+       WREG32(RADEON_CRTC_H_SYNC_STRT_WID + radeon_crtc->crtc_offset, crtc_h_sync_strt_wid);
+       WREG32(RADEON_CRTC_V_TOTAL_DISP + radeon_crtc->crtc_offset, crtc_v_total_disp);
+       WREG32(RADEON_CRTC_V_SYNC_STRT_WID + radeon_crtc->crtc_offset, crtc_v_sync_strt_wid);
+
+       return true;
+}
+
+static void radeon_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
+{
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct drm_encoder *encoder;
+       uint32_t feedback_div = 0;
+       uint32_t frac_fb_div = 0;
+       uint32_t reference_div = 0;
+       uint32_t post_divider = 0;
+       uint32_t freq = 0;
+       uint8_t pll_gain;
+       int pll_flags = RADEON_PLL_LEGACY;
+       bool use_bios_divs = false;
+       /* PLL registers */
+       uint32_t pll_ref_div = 0;
+       uint32_t pll_fb_post_div = 0;
+       uint32_t htotal_cntl = 0;
+
+       struct radeon_pll *pll;
+
+       struct {
+               int divider;
+               int bitvalue;
+       } *post_div, post_divs[]   = {
+               /* From RAGE 128 VR/RAGE 128 GL Register
+                * Reference Manual (Technical Reference
+                * Manual P/N RRG-G04100-C Rev. 0.04), page
+                * 3-17 (PLL_DIV_[3:0]).
+                */
+               {  1, 0 },              /* VCLK_SRC                 */
+               {  2, 1 },              /* VCLK_SRC/2               */
+               {  4, 2 },              /* VCLK_SRC/4               */
+               {  8, 3 },              /* VCLK_SRC/8               */
+               {  3, 4 },              /* VCLK_SRC/3               */
+               { 16, 5 },              /* VCLK_SRC/16              */
+               {  6, 6 },              /* VCLK_SRC/6               */
+               { 12, 7 },              /* VCLK_SRC/12              */
+               {  0, 0 }
+       };
+
+       if (radeon_crtc->crtc_id)
+               pll = &rdev->clock.p2pll;
+       else
+               pll = &rdev->clock.p1pll;
+
+       if (mode->clock > 200000) /* range limits??? */
+               pll_flags |= RADEON_PLL_PREFER_HIGH_FB_DIV;
+       else
+               pll_flags |= RADEON_PLL_PREFER_LOW_REF_DIV;
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               if (encoder->crtc == crtc) {
+                       if (encoder->encoder_type != DRM_MODE_ENCODER_DAC)
+                               pll_flags |= RADEON_PLL_NO_ODD_POST_DIV;
+                       if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS) {
+                               struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+                               struct radeon_encoder_lvds *lvds = (struct radeon_encoder_lvds *)radeon_encoder->enc_priv;
+                               if (lvds) {
+                                       if (lvds->use_bios_dividers) {
+                                               pll_ref_div = lvds->panel_ref_divider;
+                                               pll_fb_post_div   = (lvds->panel_fb_divider |
+                                                                    (lvds->panel_post_divider << 16));
+                                               htotal_cntl  = 0;
+                                               use_bios_divs = true;
+                                       }
+                               }
+                               pll_flags |= RADEON_PLL_USE_REF_DIV;
+                       }
+               }
+       }
+
+       DRM_DEBUG("\n");
+
+       if (!use_bios_divs) {
+               radeon_compute_pll(pll, mode->clock,
+                                  &freq, &feedback_div, &frac_fb_div,
+                                  &reference_div, &post_divider,
+                                  pll_flags);
+
+               for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
+                       if (post_div->divider == post_divider)
+                               break;
+               }
+
+               if (!post_div->divider)
+                       post_div = &post_divs[0];
+
+               DRM_DEBUG("dc=%u, fd=%d, rd=%d, pd=%d\n",
+                         (unsigned)freq,
+                         feedback_div,
+                         reference_div,
+                         post_divider);
+
+               pll_ref_div   = reference_div;
+#if defined(__powerpc__) && (0) /* TODO */
+               /* apparently programming this otherwise causes a hang??? */
+               if (info->MacModel == RADEON_MAC_IBOOK)
+                       pll_fb_post_div = 0x000600ad;
+               else
+#endif
+                       pll_fb_post_div     = (feedback_div | (post_div->bitvalue << 16));
+
+               htotal_cntl    = mode->htotal & 0x7;
+
+       }
+
+       pll_gain = radeon_compute_pll_gain(pll->reference_freq,
+                                          pll_ref_div & 0x3ff,
+                                          pll_fb_post_div & 0x7ff);
+
+       if (radeon_crtc->crtc_id) {
+               uint32_t pixclks_cntl = ((RREG32_PLL(RADEON_PIXCLKS_CNTL) &
+                                         ~(RADEON_PIX2CLK_SRC_SEL_MASK)) |
+                                        RADEON_PIX2CLK_SRC_SEL_P2PLLCLK);
+
+               WREG32_PLL_P(RADEON_PIXCLKS_CNTL,
+                            RADEON_PIX2CLK_SRC_SEL_CPUCLK,
+                            ~(RADEON_PIX2CLK_SRC_SEL_MASK));
+
+               WREG32_PLL_P(RADEON_P2PLL_CNTL,
+                            RADEON_P2PLL_RESET
+                            | RADEON_P2PLL_ATOMIC_UPDATE_EN
+                            | ((uint32_t)pll_gain << RADEON_P2PLL_PVG_SHIFT),
+                            ~(RADEON_P2PLL_RESET
+                              | RADEON_P2PLL_ATOMIC_UPDATE_EN
+                              | RADEON_P2PLL_PVG_MASK));
+
+               WREG32_PLL_P(RADEON_P2PLL_REF_DIV,
+                            pll_ref_div,
+                            ~RADEON_P2PLL_REF_DIV_MASK);
+
+               WREG32_PLL_P(RADEON_P2PLL_DIV_0,
+                            pll_fb_post_div,
+                            ~RADEON_P2PLL_FB0_DIV_MASK);
+
+               WREG32_PLL_P(RADEON_P2PLL_DIV_0,
+                            pll_fb_post_div,
+                            ~RADEON_P2PLL_POST0_DIV_MASK);
+
+               radeon_pll2_write_update(dev);
+               radeon_pll2_wait_for_read_update_complete(dev);
+
+               WREG32_PLL(RADEON_HTOTAL2_CNTL, htotal_cntl);
+
+               WREG32_PLL_P(RADEON_P2PLL_CNTL,
+                            0,
+                            ~(RADEON_P2PLL_RESET
+                              | RADEON_P2PLL_SLEEP
+                              | RADEON_P2PLL_ATOMIC_UPDATE_EN));
+
+               DRM_DEBUG("Wrote2: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
+                         (unsigned)pll_ref_div,
+                         (unsigned)pll_fb_post_div,
+                         (unsigned)htotal_cntl,
+                         RREG32_PLL(RADEON_P2PLL_CNTL));
+               DRM_DEBUG("Wrote2: rd=%u, fd=%u, pd=%u\n",
+                         (unsigned)pll_ref_div & RADEON_P2PLL_REF_DIV_MASK,
+                         (unsigned)pll_fb_post_div & RADEON_P2PLL_FB0_DIV_MASK,
+                         (unsigned)((pll_fb_post_div &
+                                     RADEON_P2PLL_POST0_DIV_MASK) >> 16));
+
+               mdelay(50); /* Let the clock to lock */
+
+               WREG32_PLL_P(RADEON_PIXCLKS_CNTL,
+                            RADEON_PIX2CLK_SRC_SEL_P2PLLCLK,
+                            ~(RADEON_PIX2CLK_SRC_SEL_MASK));
+
+               WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl);
+       } else {
+               if (rdev->flags & RADEON_IS_MOBILITY) {
+                       /* A temporal workaround for the occational blanking on certain laptop panels.
+                          This appears to related to the PLL divider registers (fail to lock?).
+                          It occurs even when all dividers are the same with their old settings.
+                          In this case we really don't need to fiddle with PLL registers.
+                          By doing this we can avoid the blanking problem with some panels.
+                       */
+                       if ((pll_ref_div == (RREG32_PLL(RADEON_PPLL_REF_DIV) & RADEON_PPLL_REF_DIV_MASK)) &&
+                           (pll_fb_post_div == (RREG32_PLL(RADEON_PPLL_DIV_3) &
+                                                (RADEON_PPLL_POST3_DIV_MASK | RADEON_PPLL_FB3_DIV_MASK)))) {
+                               WREG32_P(RADEON_CLOCK_CNTL_INDEX,
+                                        RADEON_PLL_DIV_SEL,
+                                        ~(RADEON_PLL_DIV_SEL));
+                               r100_pll_errata_after_index(rdev);
+                               return;
+                       }
+               }
+
+               WREG32_PLL_P(RADEON_VCLK_ECP_CNTL,
+                            RADEON_VCLK_SRC_SEL_CPUCLK,
+                            ~(RADEON_VCLK_SRC_SEL_MASK));
+               WREG32_PLL_P(RADEON_PPLL_CNTL,
+                            RADEON_PPLL_RESET
+                            | RADEON_PPLL_ATOMIC_UPDATE_EN
+                            | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN
+                            | ((uint32_t)pll_gain << RADEON_PPLL_PVG_SHIFT),
+                            ~(RADEON_PPLL_RESET
+                              | RADEON_PPLL_ATOMIC_UPDATE_EN
+                              | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN
+                              | RADEON_PPLL_PVG_MASK));
+
+               WREG32_P(RADEON_CLOCK_CNTL_INDEX,
+                        RADEON_PLL_DIV_SEL,
+                        ~(RADEON_PLL_DIV_SEL));
+               r100_pll_errata_after_index(rdev);
+
+               if (ASIC_IS_R300(rdev) ||
+                   (rdev->family == CHIP_RS300) ||
+                   (rdev->family == CHIP_RS400) ||
+                   (rdev->family == CHIP_RS480)) {
+                       if (pll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) {
+                               /* When restoring console mode, use saved PPLL_REF_DIV
+                                * setting.
+                                */
+                               WREG32_PLL_P(RADEON_PPLL_REF_DIV,
+                                            pll_ref_div,
+                                            0);
+                       } else {
+                               /* R300 uses ref_div_acc field as real ref divider */
+                               WREG32_PLL_P(RADEON_PPLL_REF_DIV,
+                                            (pll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT),
+                                            ~R300_PPLL_REF_DIV_ACC_MASK);
+                       }
+               } else
+                       WREG32_PLL_P(RADEON_PPLL_REF_DIV,
+                                    pll_ref_div,
+                                    ~RADEON_PPLL_REF_DIV_MASK);
+
+               WREG32_PLL_P(RADEON_PPLL_DIV_3,
+                            pll_fb_post_div,
+                            ~RADEON_PPLL_FB3_DIV_MASK);
+
+               WREG32_PLL_P(RADEON_PPLL_DIV_3,
+                            pll_fb_post_div,
+                            ~RADEON_PPLL_POST3_DIV_MASK);
+
+               radeon_pll_write_update(dev);
+               radeon_pll_wait_for_read_update_complete(dev);
+
+               WREG32_PLL(RADEON_HTOTAL_CNTL, htotal_cntl);
+
+               WREG32_PLL_P(RADEON_PPLL_CNTL,
+                            0,
+                            ~(RADEON_PPLL_RESET
+                              | RADEON_PPLL_SLEEP
+                              | RADEON_PPLL_ATOMIC_UPDATE_EN
+                              | RADEON_PPLL_VGA_ATOMIC_UPDATE_EN));
+
+               DRM_DEBUG("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
+                         pll_ref_div,
+                         pll_fb_post_div,
+                         (unsigned)htotal_cntl,
+                         RREG32_PLL(RADEON_PPLL_CNTL));
+               DRM_DEBUG("Wrote: rd=%d, fd=%d, pd=%d\n",
+                         pll_ref_div & RADEON_PPLL_REF_DIV_MASK,
+                         pll_fb_post_div & RADEON_PPLL_FB3_DIV_MASK,
+                         (pll_fb_post_div & RADEON_PPLL_POST3_DIV_MASK) >> 16);
+
+               mdelay(50); /* Let the clock to lock */
+
+               WREG32_PLL_P(RADEON_VCLK_ECP_CNTL,
+                            RADEON_VCLK_SRC_SEL_PPLLCLK,
+                            ~(RADEON_VCLK_SRC_SEL_MASK));
+
+       }
+}
+
+static bool radeon_crtc_mode_fixup(struct drm_crtc *crtc,
+                                  struct drm_display_mode *mode,
+                                  struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static int radeon_crtc_mode_set(struct drm_crtc *crtc,
+                                struct drm_display_mode *mode,
+                                struct drm_display_mode *adjusted_mode,
+                                int x, int y, struct drm_framebuffer *old_fb)
+{
+
+       DRM_DEBUG("\n");
+
+       /* TODO TV */
+
+       radeon_crtc_set_base(crtc, x, y, old_fb);
+       radeon_set_crtc_timing(crtc, adjusted_mode);
+       radeon_set_pll(crtc, adjusted_mode);
+       radeon_init_disp_bandwidth(crtc->dev);
+
+       return 0;
+}
+
+static void radeon_crtc_prepare(struct drm_crtc *crtc)
+{
+       radeon_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+}
+
+static void radeon_crtc_commit(struct drm_crtc *crtc)
+{
+       radeon_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+}
+
+static const struct drm_crtc_helper_funcs legacy_helper_funcs = {
+       .dpms = radeon_crtc_dpms,
+       .mode_fixup = radeon_crtc_mode_fixup,
+       .mode_set = radeon_crtc_mode_set,
+       .mode_set_base = radeon_crtc_set_base,
+       .prepare = radeon_crtc_prepare,
+       .commit = radeon_crtc_commit,
+};
+
+
+void radeon_legacy_init_crtc(struct drm_device *dev,
+                              struct radeon_crtc *radeon_crtc)
+{
+       if (radeon_crtc->crtc_id == 1)
+               radeon_crtc->crtc_offset = RADEON_CRTC2_H_TOTAL_DISP - RADEON_CRTC_H_TOTAL_DISP;
+       drm_crtc_helper_add(&radeon_crtc->base, &legacy_helper_funcs);
+}
+
+void radeon_init_disp_bw_legacy(struct drm_device *dev,
+                               struct drm_display_mode *mode1,
+                               uint32_t pixel_bytes1,
+                               struct drm_display_mode *mode2,
+                               uint32_t pixel_bytes2)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       fixed20_12 trcd_ff, trp_ff, tras_ff, trbs_ff, tcas_ff;
+       fixed20_12 sclk_ff, mclk_ff, sclk_eff_ff, sclk_delay_ff;
+       fixed20_12 peak_disp_bw, mem_bw, pix_clk, pix_clk2, temp_ff, crit_point_ff;
+       uint32_t temp, data, mem_trcd, mem_trp, mem_tras;
+       fixed20_12 memtcas_ff[8] = {
+               fixed_init(1),
+               fixed_init(2),
+               fixed_init(3),
+               fixed_init(0),
+               fixed_init_half(1),
+               fixed_init_half(2),
+               fixed_init(0),
+       };
+       fixed20_12 memtcas_rs480_ff[8] = {
+               fixed_init(0),
+               fixed_init(1),
+               fixed_init(2),
+               fixed_init(3),
+               fixed_init(0),
+               fixed_init_half(1),
+               fixed_init_half(2),
+               fixed_init_half(3),
+       };
+       fixed20_12 memtcas2_ff[8] = {
+               fixed_init(0),
+               fixed_init(1),
+               fixed_init(2),
+               fixed_init(3),
+               fixed_init(4),
+               fixed_init(5),
+               fixed_init(6),
+               fixed_init(7),
+       };
+       fixed20_12 memtrbs[8] = {
+               fixed_init(1),
+               fixed_init_half(1),
+               fixed_init(2),
+               fixed_init_half(2),
+               fixed_init(3),
+               fixed_init_half(3),
+               fixed_init(4),
+               fixed_init_half(4)
+       };
+       fixed20_12 memtrbs_r4xx[8] = {
+               fixed_init(4),
+               fixed_init(5),
+               fixed_init(6),
+               fixed_init(7),
+               fixed_init(8),
+               fixed_init(9),
+               fixed_init(10),
+               fixed_init(11)
+       };
+       fixed20_12 min_mem_eff;
+       fixed20_12 mc_latency_sclk, mc_latency_mclk, k1;
+       fixed20_12 cur_latency_mclk, cur_latency_sclk;
+       fixed20_12 disp_latency, disp_latency_overhead, disp_drain_rate,
+               disp_drain_rate2, read_return_rate;
+       fixed20_12 time_disp1_drop_priority;
+       int c;
+       int cur_size = 16;       /* in octawords */
+       int critical_point = 0, critical_point2;
+/*     uint32_t read_return_rate, time_disp1_drop_priority; */
+       int stop_req, max_stop_req;
+
+       min_mem_eff.full = rfixed_const_8(0);
+       /* get modes */
+       if ((rdev->disp_priority == 2) && ASIC_IS_R300(rdev)) {
+               uint32_t mc_init_misc_lat_timer = RREG32(R300_MC_INIT_MISC_LAT_TIMER);
+               mc_init_misc_lat_timer &= ~(R300_MC_DISP1R_INIT_LAT_MASK << R300_MC_DISP1R_INIT_LAT_SHIFT);
+               mc_init_misc_lat_timer &= ~(R300_MC_DISP0R_INIT_LAT_MASK << R300_MC_DISP0R_INIT_LAT_SHIFT);
+               /* check crtc enables */
+               if (mode2)
+                       mc_init_misc_lat_timer |= (1 << R300_MC_DISP1R_INIT_LAT_SHIFT);
+               if (mode1)
+                       mc_init_misc_lat_timer |= (1 << R300_MC_DISP0R_INIT_LAT_SHIFT);
+               WREG32(R300_MC_INIT_MISC_LAT_TIMER, mc_init_misc_lat_timer);
+       }
+
+       /*
+        * determine is there is enough bw for current mode
+        */
+       mclk_ff.full = rfixed_const(rdev->clock.default_mclk);
+       temp_ff.full = rfixed_const(100);
+       mclk_ff.full = rfixed_div(mclk_ff, temp_ff);
+       sclk_ff.full = rfixed_const(rdev->clock.default_sclk);
+       sclk_ff.full = rfixed_div(sclk_ff, temp_ff);
+
+       temp = (rdev->mc.vram_width / 8) * (rdev->mc.vram_is_ddr ? 2 : 1);
+       temp_ff.full = rfixed_const(temp);
+       mem_bw.full = rfixed_mul(mclk_ff, temp_ff);
+
+       pix_clk.full = 0;
+       pix_clk2.full = 0;
+       peak_disp_bw.full = 0;
+       if (mode1) {
+               temp_ff.full = rfixed_const(1000);
+               pix_clk.full = rfixed_const(mode1->clock); /* convert to fixed point */
+               pix_clk.full = rfixed_div(pix_clk, temp_ff);
+               temp_ff.full = rfixed_const(pixel_bytes1);
+               peak_disp_bw.full += rfixed_mul(pix_clk, temp_ff);
+       }
+       if (mode2) {
+               temp_ff.full = rfixed_const(1000);
+               pix_clk2.full = rfixed_const(mode2->clock); /* convert to fixed point */
+               pix_clk2.full = rfixed_div(pix_clk2, temp_ff);
+               temp_ff.full = rfixed_const(pixel_bytes2);
+               peak_disp_bw.full += rfixed_mul(pix_clk2, temp_ff);
+       }
+
+       mem_bw.full = rfixed_mul(mem_bw, min_mem_eff);
+       if (peak_disp_bw.full >= mem_bw.full) {
+               DRM_ERROR("You may not have enough display bandwidth for current mode\n"
+                         "If you have flickering problem, try to lower resolution, refresh rate, or color depth\n");
+       }
+
+       /*  Get values from the EXT_MEM_CNTL register...converting its contents. */
+       temp = RREG32(RADEON_MEM_TIMING_CNTL);
+       if ((rdev->family == CHIP_RV100) || (rdev->flags & RADEON_IS_IGP)) { /* RV100, M6, IGPs */
+               mem_trcd = ((temp >> 2) & 0x3) + 1;
+               mem_trp  = ((temp & 0x3)) + 1;
+               mem_tras = ((temp & 0x70) >> 4) + 1;
+       } else if (rdev->family == CHIP_R300 ||
+                  rdev->family == CHIP_R350) { /* r300, r350 */
+               mem_trcd = (temp & 0x7) + 1;
+               mem_trp = ((temp >> 8) & 0x7) + 1;
+               mem_tras = ((temp >> 11) & 0xf) + 4;
+       } else if (rdev->family == CHIP_RV350 ||
+                  rdev->family <= CHIP_RV380) {
+               /* rv3x0 */
+               mem_trcd = (temp & 0x7) + 3;
+               mem_trp = ((temp >> 8) & 0x7) + 3;
+               mem_tras = ((temp >> 11) & 0xf) + 6;
+       } else if (rdev->family == CHIP_R420 ||
+                  rdev->family == CHIP_R423 ||
+                  rdev->family == CHIP_RV410) {
+               /* r4xx */
+               mem_trcd = (temp & 0xf) + 3;
+               if (mem_trcd > 15)
+                       mem_trcd = 15;
+               mem_trp = ((temp >> 8) & 0xf) + 3;
+               if (mem_trp > 15)
+                       mem_trp = 15;
+               mem_tras = ((temp >> 12) & 0x1f) + 6;
+               if (mem_tras > 31)
+                       mem_tras = 31;
+       } else { /* RV200, R200 */
+               mem_trcd = (temp & 0x7) + 1;
+               mem_trp = ((temp >> 8) & 0x7) + 1;
+               mem_tras = ((temp >> 12) & 0xf) + 4;
+       }
+       /* convert to FF */
+       trcd_ff.full = rfixed_const(mem_trcd);
+       trp_ff.full = rfixed_const(mem_trp);
+       tras_ff.full = rfixed_const(mem_tras);
+
+       /* Get values from the MEM_SDRAM_MODE_REG register...converting its */
+       temp = RREG32(RADEON_MEM_SDRAM_MODE_REG);
+       data = (temp & (7 << 20)) >> 20;
+       if ((rdev->family == CHIP_RV100) || rdev->flags & RADEON_IS_IGP) {
+               if (rdev->family == CHIP_RS480) /* don't think rs400 */
+                       tcas_ff = memtcas_rs480_ff[data];
+               else
+                       tcas_ff = memtcas_ff[data];
+       } else
+               tcas_ff = memtcas2_ff[data];
+
+       if (rdev->family == CHIP_RS400 ||
+           rdev->family == CHIP_RS480) {
+               /* extra cas latency stored in bits 23-25 0-4 clocks */
+               data = (temp >> 23) & 0x7;
+               if (data < 5)
+                       tcas_ff.full += rfixed_const(data);
+       }
+
+       if (ASIC_IS_R300(rdev) && !(rdev->flags & RADEON_IS_IGP)) {
+               /* on the R300, Tcas is included in Trbs.
+                */
+               temp = RREG32(RADEON_MEM_CNTL);
+               data = (R300_MEM_NUM_CHANNELS_MASK & temp);
+               if (data == 1) {
+                       if (R300_MEM_USE_CD_CH_ONLY & temp) {
+                               temp = RREG32(R300_MC_IND_INDEX);
+                               temp &= ~R300_MC_IND_ADDR_MASK;
+                               temp |= R300_MC_READ_CNTL_CD_mcind;
+                               WREG32(R300_MC_IND_INDEX, temp);
+                               temp = RREG32(R300_MC_IND_DATA);
+                               data = (R300_MEM_RBS_POSITION_C_MASK & temp);
+                       } else {
+                               temp = RREG32(R300_MC_READ_CNTL_AB);
+                               data = (R300_MEM_RBS_POSITION_A_MASK & temp);
+                       }
+               } else {
+                       temp = RREG32(R300_MC_READ_CNTL_AB);
+                       data = (R300_MEM_RBS_POSITION_A_MASK & temp);
+               }
+               if (rdev->family == CHIP_RV410 ||
+                   rdev->family == CHIP_R420 ||
+                   rdev->family == CHIP_R423)
+                       trbs_ff = memtrbs_r4xx[data];
+               else
+                       trbs_ff = memtrbs[data];
+               tcas_ff.full += trbs_ff.full;
+       }
+
+       sclk_eff_ff.full = sclk_ff.full;
+
+       if (rdev->flags & RADEON_IS_AGP) {
+               fixed20_12 agpmode_ff;
+               agpmode_ff.full = rfixed_const(radeon_agpmode);
+               temp_ff.full = rfixed_const_666(16);
+               sclk_eff_ff.full -= rfixed_mul(agpmode_ff, temp_ff);
+       }
+       /* TODO PCIE lanes may affect this - agpmode == 16?? */
+
+       if (ASIC_IS_R300(rdev)) {
+               sclk_delay_ff.full = rfixed_const(250);
+       } else {
+               if ((rdev->family == CHIP_RV100) ||
+                   rdev->flags & RADEON_IS_IGP) {
+                       if (rdev->mc.vram_is_ddr)
+                               sclk_delay_ff.full = rfixed_const(41);
+                       else
+                               sclk_delay_ff.full = rfixed_const(33);
+               } else {
+                       if (rdev->mc.vram_width == 128)
+                               sclk_delay_ff.full = rfixed_const(57);
+                       else
+                               sclk_delay_ff.full = rfixed_const(41);
+               }
+       }
+
+       mc_latency_sclk.full = rfixed_div(sclk_delay_ff, sclk_eff_ff);
+
+       if (rdev->mc.vram_is_ddr) {
+               if (rdev->mc.vram_width == 32) {
+                       k1.full = rfixed_const(40);
+                       c  = 3;
+               } else {
+                       k1.full = rfixed_const(20);
+                       c  = 1;
+               }
+       } else {
+               k1.full = rfixed_const(40);
+               c  = 3;
+       }
+
+       temp_ff.full = rfixed_const(2);
+       mc_latency_mclk.full = rfixed_mul(trcd_ff, temp_ff);
+       temp_ff.full = rfixed_const(c);
+       mc_latency_mclk.full += rfixed_mul(tcas_ff, temp_ff);
+       temp_ff.full = rfixed_const(4);
+       mc_latency_mclk.full += rfixed_mul(tras_ff, temp_ff);
+       mc_latency_mclk.full += rfixed_mul(trp_ff, temp_ff);
+       mc_latency_mclk.full += k1.full;
+
+       mc_latency_mclk.full = rfixed_div(mc_latency_mclk, mclk_ff);
+       mc_latency_mclk.full += rfixed_div(temp_ff, sclk_eff_ff);
+
+       /*
+         HW cursor time assuming worst case of full size colour cursor.
+       */
+       temp_ff.full = rfixed_const((2 * (cur_size - (rdev->mc.vram_is_ddr + 1))));
+       temp_ff.full += trcd_ff.full;
+       if (temp_ff.full < tras_ff.full)
+               temp_ff.full = tras_ff.full;
+       cur_latency_mclk.full = rfixed_div(temp_ff, mclk_ff);
+
+       temp_ff.full = rfixed_const(cur_size);
+       cur_latency_sclk.full = rfixed_div(temp_ff, sclk_eff_ff);
+       /*
+         Find the total latency for the display data.
+       */
+       disp_latency_overhead.full = rfixed_const(80);
+       disp_latency_overhead.full = rfixed_div(disp_latency_overhead, sclk_ff);
+       mc_latency_mclk.full += disp_latency_overhead.full + cur_latency_mclk.full;
+       mc_latency_sclk.full += disp_latency_overhead.full + cur_latency_sclk.full;
+
+       if (mc_latency_mclk.full > mc_latency_sclk.full)
+               disp_latency.full = mc_latency_mclk.full;
+       else
+               disp_latency.full = mc_latency_sclk.full;
+
+       /* setup Max GRPH_STOP_REQ default value */
+       if (ASIC_IS_RV100(rdev))
+               max_stop_req = 0x5c;
+       else
+               max_stop_req = 0x7c;
+
+       if (mode1) {
+               /*  CRTC1
+                   Set GRPH_BUFFER_CNTL register using h/w defined optimal values.
+                   GRPH_STOP_REQ <= MIN[ 0x7C, (CRTC_H_DISP + 1) * (bit depth) / 0x10 ]
+               */
+               stop_req = mode1->hdisplay * pixel_bytes1 / 16;
+
+               if (stop_req > max_stop_req)
+                       stop_req = max_stop_req;
+
+               /*
+                 Find the drain rate of the display buffer.
+               */
+               temp_ff.full = rfixed_const((16/pixel_bytes1));
+               disp_drain_rate.full = rfixed_div(pix_clk, temp_ff);
+
+               /*
+                 Find the critical point of the display buffer.
+               */
+               crit_point_ff.full = rfixed_mul(disp_drain_rate, disp_latency);
+               crit_point_ff.full += rfixed_const_half(0);
+
+               critical_point = rfixed_trunc(crit_point_ff);
+
+               if (rdev->disp_priority == 2) {
+                       critical_point = 0;
+               }
+
+               /*
+                 The critical point should never be above max_stop_req-4.  Setting
+                 GRPH_CRITICAL_CNTL = 0 will thus force high priority all the time.
+               */
+               if (max_stop_req - critical_point < 4)
+                       critical_point = 0;
+
+               if (critical_point == 0 && mode2 && rdev->family == CHIP_R300) {
+                       /* some R300 cards have problem with this set to 0, when CRTC2 is enabled.*/
+                       critical_point = 0x10;
+               }
+
+               temp = RREG32(RADEON_GRPH_BUFFER_CNTL);
+               temp &= ~(RADEON_GRPH_STOP_REQ_MASK);
+               temp |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT);
+               temp &= ~(RADEON_GRPH_START_REQ_MASK);
+               if ((rdev->family == CHIP_R350) &&
+                   (stop_req > 0x15)) {
+                       stop_req -= 0x10;
+               }
+               temp |= (stop_req << RADEON_GRPH_START_REQ_SHIFT);
+               temp |= RADEON_GRPH_BUFFER_SIZE;
+               temp &= ~(RADEON_GRPH_CRITICAL_CNTL   |
+                         RADEON_GRPH_CRITICAL_AT_SOF |
+                         RADEON_GRPH_STOP_CNTL);
+               /*
+                 Write the result into the register.
+               */
+               WREG32(RADEON_GRPH_BUFFER_CNTL, ((temp & ~RADEON_GRPH_CRITICAL_POINT_MASK) |
+                                                      (critical_point << RADEON_GRPH_CRITICAL_POINT_SHIFT)));
+
+#if 0
+               if ((rdev->family == CHIP_RS400) ||
+                   (rdev->family == CHIP_RS480)) {
+                       /* attempt to program RS400 disp regs correctly ??? */
+                       temp = RREG32(RS400_DISP1_REG_CNTL);
+                       temp &= ~(RS400_DISP1_START_REQ_LEVEL_MASK |
+                                 RS400_DISP1_STOP_REQ_LEVEL_MASK);
+                       WREG32(RS400_DISP1_REQ_CNTL1, (temp |
+                                                      (critical_point << RS400_DISP1_START_REQ_LEVEL_SHIFT) |
+                                                      (critical_point << RS400_DISP1_STOP_REQ_LEVEL_SHIFT)));
+                       temp = RREG32(RS400_DMIF_MEM_CNTL1);
+                       temp &= ~(RS400_DISP1_CRITICAL_POINT_START_MASK |
+                                 RS400_DISP1_CRITICAL_POINT_STOP_MASK);
+                       WREG32(RS400_DMIF_MEM_CNTL1, (temp |
+                                                     (critical_point << RS400_DISP1_CRITICAL_POINT_START_SHIFT) |
+                                                     (critical_point << RS400_DISP1_CRITICAL_POINT_STOP_SHIFT)));
+               }
+#endif
+
+               DRM_DEBUG("GRPH_BUFFER_CNTL from to %x\n",
+                         /*      (unsigned int)info->SavedReg->grph_buffer_cntl, */
+                         (unsigned int)RREG32(RADEON_GRPH_BUFFER_CNTL));
+       }
+
+       if (mode2) {
+               u32 grph2_cntl;
+               stop_req = mode2->hdisplay * pixel_bytes2 / 16;
+
+               if (stop_req > max_stop_req)
+                       stop_req = max_stop_req;
+
+               /*
+                 Find the drain rate of the display buffer.
+               */
+               temp_ff.full = rfixed_const((16/pixel_bytes2));
+               disp_drain_rate2.full = rfixed_div(pix_clk2, temp_ff);
+
+               grph2_cntl = RREG32(RADEON_GRPH2_BUFFER_CNTL);
+               grph2_cntl &= ~(RADEON_GRPH_STOP_REQ_MASK);
+               grph2_cntl |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT);
+               grph2_cntl &= ~(RADEON_GRPH_START_REQ_MASK);
+               if ((rdev->family == CHIP_R350) &&
+                   (stop_req > 0x15)) {
+                       stop_req -= 0x10;
+               }
+               grph2_cntl |= (stop_req << RADEON_GRPH_START_REQ_SHIFT);
+               grph2_cntl |= RADEON_GRPH_BUFFER_SIZE;
+               grph2_cntl &= ~(RADEON_GRPH_CRITICAL_CNTL   |
+                         RADEON_GRPH_CRITICAL_AT_SOF |
+                         RADEON_GRPH_STOP_CNTL);
+
+               if ((rdev->family == CHIP_RS100) ||
+                   (rdev->family == CHIP_RS200))
+                       critical_point2 = 0;
+               else {
+                       temp = (rdev->mc.vram_width * rdev->mc.vram_is_ddr + 1)/128;
+                       temp_ff.full = rfixed_const(temp);
+                       temp_ff.full = rfixed_mul(mclk_ff, temp_ff);
+                       if (sclk_ff.full < temp_ff.full)
+                               temp_ff.full = sclk_ff.full;
+
+                       read_return_rate.full = temp_ff.full;
+
+                       if (mode1) {
+                               temp_ff.full = read_return_rate.full - disp_drain_rate.full;
+                               time_disp1_drop_priority.full = rfixed_div(crit_point_ff, temp_ff);
+                       } else {
+                               time_disp1_drop_priority.full = 0;
+                       }
+                       crit_point_ff.full = disp_latency.full + time_disp1_drop_priority.full + disp_latency.full;
+                       crit_point_ff.full = rfixed_mul(crit_point_ff, disp_drain_rate2);
+                       crit_point_ff.full += rfixed_const_half(0);
+
+                       critical_point2 = rfixed_trunc(crit_point_ff);
+
+                       if (rdev->disp_priority == 2) {
+                               critical_point2 = 0;
+                       }
+
+                       if (max_stop_req - critical_point2 < 4)
+                               critical_point2 = 0;
+
+               }
+
+               if (critical_point2 == 0 && rdev->family == CHIP_R300) {
+                       /* some R300 cards have problem with this set to 0 */
+                       critical_point2 = 0x10;
+               }
+
+               WREG32(RADEON_GRPH2_BUFFER_CNTL, ((grph2_cntl & ~RADEON_GRPH_CRITICAL_POINT_MASK) |
+                                                 (critical_point2 << RADEON_GRPH_CRITICAL_POINT_SHIFT)));
+
+               if ((rdev->family == CHIP_RS400) ||
+                   (rdev->family == CHIP_RS480)) {
+#if 0
+                       /* attempt to program RS400 disp2 regs correctly ??? */
+                       temp = RREG32(RS400_DISP2_REQ_CNTL1);
+                       temp &= ~(RS400_DISP2_START_REQ_LEVEL_MASK |
+                                 RS400_DISP2_STOP_REQ_LEVEL_MASK);
+                       WREG32(RS400_DISP2_REQ_CNTL1, (temp |
+                                                      (critical_point2 << RS400_DISP1_START_REQ_LEVEL_SHIFT) |
+                                                      (critical_point2 << RS400_DISP1_STOP_REQ_LEVEL_SHIFT)));
+                       temp = RREG32(RS400_DISP2_REQ_CNTL2);
+                       temp &= ~(RS400_DISP2_CRITICAL_POINT_START_MASK |
+                                 RS400_DISP2_CRITICAL_POINT_STOP_MASK);
+                       WREG32(RS400_DISP2_REQ_CNTL2, (temp |
+                                                      (critical_point2 << RS400_DISP2_CRITICAL_POINT_START_SHIFT) |
+                                                      (critical_point2 << RS400_DISP2_CRITICAL_POINT_STOP_SHIFT)));
+#endif
+                       WREG32(RS400_DISP2_REQ_CNTL1, 0x105DC1CC);
+                       WREG32(RS400_DISP2_REQ_CNTL2, 0x2749D000);
+                       WREG32(RS400_DMIF_MEM_CNTL1,  0x29CA71DC);
+                       WREG32(RS400_DISP1_REQ_CNTL1, 0x28FBC3AC);
+               }
+
+               DRM_DEBUG("GRPH2_BUFFER_CNTL from to %x\n",
+                         (unsigned int)RREG32(RADEON_GRPH2_BUFFER_CNTL));
+       }
+}
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
new file mode 100644 (file)
index 0000000..2c2f42d
--- /dev/null
@@ -0,0 +1,1288 @@
+/*
+ * Copyright 2007-8 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ */
+#include "drmP.h"
+#include "drm_crtc_helper.h"
+#include "radeon_drm.h"
+#include "radeon.h"
+#include "atom.h"
+
+
+static void radeon_legacy_rmx_mode_set(struct drm_encoder *encoder,
+                                      struct drm_display_mode *mode,
+                                      struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       int    xres = mode->hdisplay;
+       int    yres = mode->vdisplay;
+       bool   hscale = true, vscale = true;
+       int    hsync_wid;
+       int    vsync_wid;
+       int    hsync_start;
+       uint32_t scale, inc;
+       uint32_t fp_horz_stretch, fp_vert_stretch, crtc_more_cntl, fp_horz_vert_active;
+       uint32_t fp_h_sync_strt_wid, fp_v_sync_strt_wid, fp_crtc_h_total_disp, fp_crtc_v_total_disp;
+       struct radeon_native_mode *native_mode = &radeon_encoder->native_mode;
+
+       DRM_DEBUG("\n");
+
+       fp_vert_stretch = RREG32(RADEON_FP_VERT_STRETCH) &
+               (RADEON_VERT_STRETCH_RESERVED |
+                RADEON_VERT_AUTO_RATIO_INC);
+       fp_horz_stretch = RREG32(RADEON_FP_HORZ_STRETCH) &
+               (RADEON_HORZ_FP_LOOP_STRETCH |
+                RADEON_HORZ_AUTO_RATIO_INC);
+
+       crtc_more_cntl = 0;
+       if ((rdev->family == CHIP_RS100) ||
+           (rdev->family == CHIP_RS200)) {
+               /* This is to workaround the asic bug for RMX, some versions
+                  of BIOS dosen't have this register initialized correctly. */
+               crtc_more_cntl |= RADEON_CRTC_H_CUTOFF_ACTIVE_EN;
+       }
+
+
+       fp_crtc_h_total_disp = ((((mode->crtc_htotal / 8) - 1) & 0x3ff)
+                               | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16));
+
+       hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8;
+       if (!hsync_wid)
+               hsync_wid = 1;
+       hsync_start = mode->crtc_hsync_start - 8;
+
+       fp_h_sync_strt_wid = ((hsync_start & 0x1fff)
+                             | ((hsync_wid & 0x3f) << 16)
+                             | ((mode->flags & DRM_MODE_FLAG_NHSYNC)
+                                ? RADEON_CRTC_H_SYNC_POL
+                                : 0));
+
+       fp_crtc_v_total_disp = (((mode->crtc_vtotal - 1) & 0xffff)
+                               | ((mode->crtc_vdisplay - 1) << 16));
+
+       vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start;
+       if (!vsync_wid)
+               vsync_wid = 1;
+
+       fp_v_sync_strt_wid = (((mode->crtc_vsync_start - 1) & 0xfff)
+                             | ((vsync_wid & 0x1f) << 16)
+                             | ((mode->flags & DRM_MODE_FLAG_NVSYNC)
+                                ? RADEON_CRTC_V_SYNC_POL
+                                : 0));
+
+       fp_horz_vert_active = 0;
+
+       if (native_mode->panel_xres == 0 ||
+           native_mode->panel_yres == 0) {
+               hscale = false;
+               vscale = false;
+       } else {
+               if (xres > native_mode->panel_xres)
+                       xres = native_mode->panel_xres;
+               if (yres > native_mode->panel_yres)
+                       yres = native_mode->panel_yres;
+
+               if (xres == native_mode->panel_xres)
+                       hscale = false;
+               if (yres == native_mode->panel_yres)
+                       vscale = false;
+       }
+
+       if (radeon_encoder->flags & RADEON_USE_RMX) {
+               if (radeon_encoder->rmx_type != RMX_CENTER) {
+                       if (!hscale)
+                               fp_horz_stretch |= ((xres/8-1) << 16);
+                       else {
+                               inc = (fp_horz_stretch & RADEON_HORZ_AUTO_RATIO_INC) ? 1 : 0;
+                               scale = ((xres + inc) * RADEON_HORZ_STRETCH_RATIO_MAX)
+                                       / native_mode->panel_xres + 1;
+                               fp_horz_stretch |= (((scale) & RADEON_HORZ_STRETCH_RATIO_MASK) |
+                                                   RADEON_HORZ_STRETCH_BLEND |
+                                                   RADEON_HORZ_STRETCH_ENABLE |
+                                                   ((native_mode->panel_xres/8-1) << 16));
+                       }
+
+                       if (!vscale)
+                               fp_vert_stretch |= ((yres-1) << 12);
+                       else {
+                               inc = (fp_vert_stretch & RADEON_VERT_AUTO_RATIO_INC) ? 1 : 0;
+                               scale = ((yres + inc) * RADEON_VERT_STRETCH_RATIO_MAX)
+                                       / native_mode->panel_yres + 1;
+                               fp_vert_stretch |= (((scale) & RADEON_VERT_STRETCH_RATIO_MASK) |
+                                                   RADEON_VERT_STRETCH_ENABLE |
+                                                   RADEON_VERT_STRETCH_BLEND |
+                                                   ((native_mode->panel_yres-1) << 12));
+                       }
+               } else if (radeon_encoder->rmx_type == RMX_CENTER) {
+                       int    blank_width;
+
+                       fp_horz_stretch |= ((xres/8-1) << 16);
+                       fp_vert_stretch |= ((yres-1) << 12);
+
+                       crtc_more_cntl |= (RADEON_CRTC_AUTO_HORZ_CENTER_EN |
+                                          RADEON_CRTC_AUTO_VERT_CENTER_EN);
+
+                       blank_width = (mode->crtc_hblank_end - mode->crtc_hblank_start) / 8;
+                       if (blank_width > 110)
+                               blank_width = 110;
+
+                       fp_crtc_h_total_disp = (((blank_width) & 0x3ff)
+                                               | ((((mode->crtc_hdisplay / 8) - 1) & 0x1ff) << 16));
+
+                       hsync_wid = (mode->crtc_hsync_end - mode->crtc_hsync_start) / 8;
+                       if (!hsync_wid)
+                               hsync_wid = 1;
+
+                       fp_h_sync_strt_wid = ((((mode->crtc_hsync_start - mode->crtc_hblank_start) / 8) & 0x1fff)
+                                             | ((hsync_wid & 0x3f) << 16)
+                                             | ((mode->flags & DRM_MODE_FLAG_NHSYNC)
+                                                ? RADEON_CRTC_H_SYNC_POL
+                                                : 0));
+
+                       fp_crtc_v_total_disp = (((mode->crtc_vblank_end - mode->crtc_vblank_start) & 0xffff)
+                                               | ((mode->crtc_vdisplay - 1) << 16));
+
+                       vsync_wid = mode->crtc_vsync_end - mode->crtc_vsync_start;
+                       if (!vsync_wid)
+                               vsync_wid = 1;
+
+                       fp_v_sync_strt_wid = ((((mode->crtc_vsync_start - mode->crtc_vblank_start) & 0xfff)
+                                              | ((vsync_wid & 0x1f) << 16)
+                                              | ((mode->flags & DRM_MODE_FLAG_NVSYNC)
+                                                 ? RADEON_CRTC_V_SYNC_POL
+                                                 : 0)));
+
+                       fp_horz_vert_active = (((native_mode->panel_yres) & 0xfff) |
+                                              (((native_mode->panel_xres / 8) & 0x1ff) << 16));
+               }
+       } else {
+               fp_horz_stretch |= ((xres/8-1) << 16);
+               fp_vert_stretch |= ((yres-1) << 12);
+       }
+
+       WREG32(RADEON_FP_HORZ_STRETCH,      fp_horz_stretch);
+       WREG32(RADEON_FP_VERT_STRETCH,      fp_vert_stretch);
+       WREG32(RADEON_CRTC_MORE_CNTL,       crtc_more_cntl);
+       WREG32(RADEON_FP_HORZ_VERT_ACTIVE,  fp_horz_vert_active);
+       WREG32(RADEON_FP_H_SYNC_STRT_WID,   fp_h_sync_strt_wid);
+       WREG32(RADEON_FP_V_SYNC_STRT_WID,   fp_v_sync_strt_wid);
+       WREG32(RADEON_FP_CRTC_H_TOTAL_DISP, fp_crtc_h_total_disp);
+       WREG32(RADEON_FP_CRTC_V_TOTAL_DISP, fp_crtc_v_total_disp);
+
+}
+
+static void radeon_legacy_lvds_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       uint32_t lvds_gen_cntl, lvds_pll_cntl, pixclks_cntl, disp_pwr_man;
+       int panel_pwr_delay = 2000;
+       DRM_DEBUG("\n");
+
+       if (radeon_encoder->enc_priv) {
+               if (rdev->is_atom_bios) {
+                       struct radeon_encoder_atom_dig *lvds = radeon_encoder->enc_priv;
+                       panel_pwr_delay = lvds->panel_pwr_delay;
+               } else {
+                       struct radeon_encoder_lvds *lvds = radeon_encoder->enc_priv;
+                       panel_pwr_delay = lvds->panel_pwr_delay;
+               }
+       }
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               disp_pwr_man = RREG32(RADEON_DISP_PWR_MAN);
+               disp_pwr_man |= RADEON_AUTO_PWRUP_EN;
+               WREG32(RADEON_DISP_PWR_MAN, disp_pwr_man);
+               lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL);
+               lvds_pll_cntl |= RADEON_LVDS_PLL_EN;
+               WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl);
+               udelay(1000);
+
+               lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL);
+               lvds_pll_cntl &= ~RADEON_LVDS_PLL_RESET;
+               WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl);
+
+               lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL);
+               lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_EN | RADEON_LVDS_DIGON | RADEON_LVDS_BLON);
+               lvds_gen_cntl &= ~(RADEON_LVDS_DISPLAY_DIS);
+               udelay(panel_pwr_delay * 1000);
+               WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL);
+               WREG32_PLL_P(RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb);
+               lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL);
+               lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS;
+               lvds_gen_cntl &= ~(RADEON_LVDS_ON | RADEON_LVDS_BLON | RADEON_LVDS_EN | RADEON_LVDS_DIGON);
+               udelay(panel_pwr_delay * 1000);
+               WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
+               WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl);
+               break;
+       }
+
+       if (rdev->is_atom_bios)
+               radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
+       else
+               radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
+}
+
+static void radeon_legacy_lvds_prepare(struct drm_encoder *encoder)
+{
+       struct radeon_device *rdev = encoder->dev->dev_private;
+
+       if (rdev->is_atom_bios)
+               radeon_atom_output_lock(encoder, true);
+       else
+               radeon_combios_output_lock(encoder, true);
+       radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_OFF);
+}
+
+static void radeon_legacy_lvds_commit(struct drm_encoder *encoder)
+{
+       struct radeon_device *rdev = encoder->dev->dev_private;
+
+       radeon_legacy_lvds_dpms(encoder, DRM_MODE_DPMS_ON);
+       if (rdev->is_atom_bios)
+               radeon_atom_output_lock(encoder, false);
+       else
+               radeon_combios_output_lock(encoder, false);
+}
+
+static void radeon_legacy_lvds_mode_set(struct drm_encoder *encoder,
+                                       struct drm_display_mode *mode,
+                                       struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       uint32_t lvds_pll_cntl, lvds_gen_cntl, lvds_ss_gen_cntl;
+
+       DRM_DEBUG("\n");
+
+       if (radeon_crtc->crtc_id == 0)
+               radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode);
+
+       lvds_pll_cntl = RREG32(RADEON_LVDS_PLL_CNTL);
+       lvds_pll_cntl &= ~RADEON_LVDS_PLL_EN;
+
+       lvds_ss_gen_cntl = RREG32(RADEON_LVDS_SS_GEN_CNTL);
+       if ((!rdev->is_atom_bios)) {
+               struct radeon_encoder_lvds *lvds = (struct radeon_encoder_lvds *)radeon_encoder->enc_priv;
+               if (lvds) {
+                       DRM_DEBUG("bios LVDS_GEN_CNTL: 0x%x\n", lvds->lvds_gen_cntl);
+                       lvds_gen_cntl = lvds->lvds_gen_cntl;
+                       lvds_ss_gen_cntl &= ~((0xf << RADEON_LVDS_PWRSEQ_DELAY1_SHIFT) |
+                                             (0xf << RADEON_LVDS_PWRSEQ_DELAY2_SHIFT));
+                       lvds_ss_gen_cntl |= ((lvds->panel_digon_delay << RADEON_LVDS_PWRSEQ_DELAY1_SHIFT) |
+                                            (lvds->panel_blon_delay << RADEON_LVDS_PWRSEQ_DELAY2_SHIFT));
+               } else
+                       lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL);
+       } else
+               lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL);
+       lvds_gen_cntl |= RADEON_LVDS_DISPLAY_DIS;
+       lvds_gen_cntl &= ~(RADEON_LVDS_ON |
+                          RADEON_LVDS_BLON |
+                          RADEON_LVDS_EN |
+                          RADEON_LVDS_RST_FM);
+
+       if (ASIC_IS_R300(rdev))
+               lvds_pll_cntl &= ~(R300_LVDS_SRC_SEL_MASK);
+
+       if (radeon_crtc->crtc_id == 0) {
+               if (ASIC_IS_R300(rdev)) {
+                       if (radeon_encoder->flags & RADEON_USE_RMX)
+                               lvds_pll_cntl |= R300_LVDS_SRC_SEL_RMX;
+               } else
+                       lvds_gen_cntl &= ~RADEON_LVDS_SEL_CRTC2;
+       } else {
+               if (ASIC_IS_R300(rdev))
+                       lvds_pll_cntl |= R300_LVDS_SRC_SEL_CRTC2;
+               else
+                       lvds_gen_cntl |= RADEON_LVDS_SEL_CRTC2;
+       }
+
+       WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
+       WREG32(RADEON_LVDS_PLL_CNTL, lvds_pll_cntl);
+       WREG32(RADEON_LVDS_SS_GEN_CNTL, lvds_ss_gen_cntl);
+
+       if (rdev->family == CHIP_RV410)
+               WREG32(RADEON_CLOCK_CNTL_INDEX, 0);
+
+       if (rdev->is_atom_bios)
+               radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
+       else
+               radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
+}
+
+static bool radeon_legacy_lvds_mode_fixup(struct drm_encoder *encoder,
+                                         struct drm_display_mode *mode,
+                                         struct drm_display_mode *adjusted_mode)
+{
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+
+       drm_mode_set_crtcinfo(adjusted_mode, 0);
+
+       radeon_encoder->flags &= ~RADEON_USE_RMX;
+
+       if (radeon_encoder->rmx_type != RMX_OFF)
+               radeon_rmx_mode_fixup(encoder, mode, adjusted_mode);
+
+       return true;
+}
+
+static const struct drm_encoder_helper_funcs radeon_legacy_lvds_helper_funcs = {
+       .dpms = radeon_legacy_lvds_dpms,
+       .mode_fixup = radeon_legacy_lvds_mode_fixup,
+       .prepare = radeon_legacy_lvds_prepare,
+       .mode_set = radeon_legacy_lvds_mode_set,
+       .commit = radeon_legacy_lvds_commit,
+};
+
+
+static const struct drm_encoder_funcs radeon_legacy_lvds_enc_funcs = {
+       .destroy = radeon_enc_destroy,
+};
+
+static bool radeon_legacy_primary_dac_mode_fixup(struct drm_encoder *encoder,
+                                                struct drm_display_mode *mode,
+                                                struct drm_display_mode *adjusted_mode)
+{
+
+       drm_mode_set_crtcinfo(adjusted_mode, 0);
+
+       return true;
+}
+
+static void radeon_legacy_primary_dac_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL);
+       uint32_t dac_cntl = RREG32(RADEON_DAC_CNTL);
+       uint32_t dac_macro_cntl = RREG32(RADEON_DAC_MACRO_CNTL);
+
+       DRM_DEBUG("\n");
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               crtc_ext_cntl |= RADEON_CRTC_CRT_ON;
+               dac_cntl &= ~RADEON_DAC_PDWN;
+               dac_macro_cntl &= ~(RADEON_DAC_PDWN_R |
+                                   RADEON_DAC_PDWN_G |
+                                   RADEON_DAC_PDWN_B);
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               crtc_ext_cntl &= ~RADEON_CRTC_CRT_ON;
+               dac_cntl |= RADEON_DAC_PDWN;
+               dac_macro_cntl |= (RADEON_DAC_PDWN_R |
+                                  RADEON_DAC_PDWN_G |
+                                  RADEON_DAC_PDWN_B);
+               break;
+       }
+
+       WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl);
+       WREG32(RADEON_DAC_CNTL, dac_cntl);
+       WREG32(RADEON_DAC_MACRO_CNTL, dac_macro_cntl);
+
+       if (rdev->is_atom_bios)
+               radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
+       else
+               radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
+}
+
+static void radeon_legacy_primary_dac_prepare(struct drm_encoder *encoder)
+{
+       struct radeon_device *rdev = encoder->dev->dev_private;
+
+       if (rdev->is_atom_bios)
+               radeon_atom_output_lock(encoder, true);
+       else
+               radeon_combios_output_lock(encoder, true);
+       radeon_legacy_primary_dac_dpms(encoder, DRM_MODE_DPMS_OFF);
+}
+
+static void radeon_legacy_primary_dac_commit(struct drm_encoder *encoder)
+{
+       struct radeon_device *rdev = encoder->dev->dev_private;
+
+       radeon_legacy_primary_dac_dpms(encoder, DRM_MODE_DPMS_ON);
+
+       if (rdev->is_atom_bios)
+               radeon_atom_output_lock(encoder, false);
+       else
+               radeon_combios_output_lock(encoder, false);
+}
+
+static void radeon_legacy_primary_dac_mode_set(struct drm_encoder *encoder,
+                                              struct drm_display_mode *mode,
+                                              struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       uint32_t disp_output_cntl, dac_cntl, dac2_cntl, dac_macro_cntl;
+
+       DRM_DEBUG("\n");
+
+       if (radeon_crtc->crtc_id == 0)
+               radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode);
+
+       if (radeon_crtc->crtc_id == 0) {
+               if (rdev->family == CHIP_R200 || ASIC_IS_R300(rdev)) {
+                       disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL) &
+                               ~(RADEON_DISP_DAC_SOURCE_MASK);
+                       WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl);
+               } else {
+                       dac2_cntl = RREG32(RADEON_DAC_CNTL2)  & ~(RADEON_DAC2_DAC_CLK_SEL);
+                       WREG32(RADEON_DAC_CNTL2, dac2_cntl);
+               }
+       } else {
+               if (rdev->family == CHIP_R200 || ASIC_IS_R300(rdev)) {
+                       disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL) &
+                               ~(RADEON_DISP_DAC_SOURCE_MASK);
+                       disp_output_cntl |= RADEON_DISP_DAC_SOURCE_CRTC2;
+                       WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl);
+               } else {
+                       dac2_cntl = RREG32(RADEON_DAC_CNTL2) | RADEON_DAC2_DAC_CLK_SEL;
+                       WREG32(RADEON_DAC_CNTL2, dac2_cntl);
+               }
+       }
+
+       dac_cntl = (RADEON_DAC_MASK_ALL |
+                   RADEON_DAC_VGA_ADR_EN |
+                   /* TODO 6-bits */
+                   RADEON_DAC_8BIT_EN);
+
+       WREG32_P(RADEON_DAC_CNTL,
+                      dac_cntl,
+                      RADEON_DAC_RANGE_CNTL |
+                      RADEON_DAC_BLANKING);
+
+       if (radeon_encoder->enc_priv) {
+               struct radeon_encoder_primary_dac *p_dac = (struct radeon_encoder_primary_dac *)radeon_encoder->enc_priv;
+               dac_macro_cntl = p_dac->ps2_pdac_adj;
+       } else
+               dac_macro_cntl = RREG32(RADEON_DAC_MACRO_CNTL);
+       dac_macro_cntl |= RADEON_DAC_PDWN_R | RADEON_DAC_PDWN_G | RADEON_DAC_PDWN_B;
+       WREG32(RADEON_DAC_MACRO_CNTL, dac_macro_cntl);
+
+       if (rdev->is_atom_bios)
+               radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
+       else
+               radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
+}
+
+static enum drm_connector_status radeon_legacy_primary_dac_detect(struct drm_encoder *encoder,
+                                                                 struct drm_connector *connector)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t vclk_ecp_cntl, crtc_ext_cntl;
+       uint32_t dac_ext_cntl, dac_cntl, dac_macro_cntl, tmp;
+       enum drm_connector_status found = connector_status_disconnected;
+       bool color = true;
+
+       /* save the regs we need */
+       vclk_ecp_cntl = RREG32_PLL(RADEON_VCLK_ECP_CNTL);
+       crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL);
+       dac_ext_cntl = RREG32(RADEON_DAC_EXT_CNTL);
+       dac_cntl = RREG32(RADEON_DAC_CNTL);
+       dac_macro_cntl = RREG32(RADEON_DAC_MACRO_CNTL);
+
+       tmp = vclk_ecp_cntl &
+               ~(RADEON_PIXCLK_ALWAYS_ONb | RADEON_PIXCLK_DAC_ALWAYS_ONb);
+       WREG32_PLL(RADEON_VCLK_ECP_CNTL, tmp);
+
+       tmp = crtc_ext_cntl | RADEON_CRTC_CRT_ON;
+       WREG32(RADEON_CRTC_EXT_CNTL, tmp);
+
+       tmp = RADEON_DAC_FORCE_BLANK_OFF_EN |
+               RADEON_DAC_FORCE_DATA_EN;
+
+       if (color)
+               tmp |= RADEON_DAC_FORCE_DATA_SEL_RGB;
+       else
+               tmp |= RADEON_DAC_FORCE_DATA_SEL_G;
+
+       if (ASIC_IS_R300(rdev))
+               tmp |= (0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT);
+       else
+               tmp |= (0x180 << RADEON_DAC_FORCE_DATA_SHIFT);
+
+       WREG32(RADEON_DAC_EXT_CNTL, tmp);
+
+       tmp = dac_cntl & ~(RADEON_DAC_RANGE_CNTL_MASK | RADEON_DAC_PDWN);
+       tmp |= RADEON_DAC_RANGE_CNTL_PS2 | RADEON_DAC_CMP_EN;
+       WREG32(RADEON_DAC_CNTL, tmp);
+
+       tmp &= ~(RADEON_DAC_PDWN_R |
+                RADEON_DAC_PDWN_G |
+                RADEON_DAC_PDWN_B);
+
+       WREG32(RADEON_DAC_MACRO_CNTL, tmp);
+
+       udelay(2000);
+
+       if (RREG32(RADEON_DAC_CNTL) & RADEON_DAC_CMP_OUTPUT)
+               found = connector_status_connected;
+
+       /* restore the regs we used */
+       WREG32(RADEON_DAC_CNTL, dac_cntl);
+       WREG32(RADEON_DAC_MACRO_CNTL, dac_macro_cntl);
+       WREG32(RADEON_DAC_EXT_CNTL, dac_ext_cntl);
+       WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl);
+       WREG32_PLL(RADEON_VCLK_ECP_CNTL, vclk_ecp_cntl);
+
+       return found;
+}
+
+static const struct drm_encoder_helper_funcs radeon_legacy_primary_dac_helper_funcs = {
+       .dpms = radeon_legacy_primary_dac_dpms,
+       .mode_fixup = radeon_legacy_primary_dac_mode_fixup,
+       .prepare = radeon_legacy_primary_dac_prepare,
+       .mode_set = radeon_legacy_primary_dac_mode_set,
+       .commit = radeon_legacy_primary_dac_commit,
+       .detect = radeon_legacy_primary_dac_detect,
+};
+
+
+static const struct drm_encoder_funcs radeon_legacy_primary_dac_enc_funcs = {
+       .destroy = radeon_enc_destroy,
+};
+
+static bool radeon_legacy_tmds_int_mode_fixup(struct drm_encoder *encoder,
+                                             struct drm_display_mode *mode,
+                                             struct drm_display_mode *adjusted_mode)
+{
+
+       drm_mode_set_crtcinfo(adjusted_mode, 0);
+
+       return true;
+}
+
+static void radeon_legacy_tmds_int_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t fp_gen_cntl = RREG32(RADEON_FP_GEN_CNTL);
+       DRM_DEBUG("\n");
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               fp_gen_cntl |= (RADEON_FP_FPON | RADEON_FP_TMDS_EN);
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN);
+               break;
+       }
+
+       WREG32(RADEON_FP_GEN_CNTL, fp_gen_cntl);
+
+       if (rdev->is_atom_bios)
+               radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
+       else
+               radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
+}
+
+static void radeon_legacy_tmds_int_prepare(struct drm_encoder *encoder)
+{
+       struct radeon_device *rdev = encoder->dev->dev_private;
+
+       if (rdev->is_atom_bios)
+               radeon_atom_output_lock(encoder, true);
+       else
+               radeon_combios_output_lock(encoder, true);
+       radeon_legacy_tmds_int_dpms(encoder, DRM_MODE_DPMS_OFF);
+}
+
+static void radeon_legacy_tmds_int_commit(struct drm_encoder *encoder)
+{
+       struct radeon_device *rdev = encoder->dev->dev_private;
+
+       radeon_legacy_tmds_int_dpms(encoder, DRM_MODE_DPMS_ON);
+
+       if (rdev->is_atom_bios)
+               radeon_atom_output_lock(encoder, true);
+       else
+               radeon_combios_output_lock(encoder, true);
+}
+
+static void radeon_legacy_tmds_int_mode_set(struct drm_encoder *encoder,
+                                           struct drm_display_mode *mode,
+                                           struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       uint32_t tmp, tmds_pll_cntl, tmds_transmitter_cntl, fp_gen_cntl;
+       int i;
+
+       DRM_DEBUG("\n");
+
+       if (radeon_crtc->crtc_id == 0)
+               radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode);
+
+       tmp = tmds_pll_cntl = RREG32(RADEON_TMDS_PLL_CNTL);
+       tmp &= 0xfffff;
+       if (rdev->family == CHIP_RV280) {
+               /* bit 22 of TMDS_PLL_CNTL is read-back inverted */
+               tmp ^= (1 << 22);
+               tmds_pll_cntl ^= (1 << 22);
+       }
+
+       if (radeon_encoder->enc_priv) {
+               struct radeon_encoder_int_tmds *tmds = (struct radeon_encoder_int_tmds *)radeon_encoder->enc_priv;
+
+               for (i = 0; i < 4; i++) {
+                       if (tmds->tmds_pll[i].freq == 0)
+                               break;
+                       if ((uint32_t)(mode->clock / 10) < tmds->tmds_pll[i].freq) {
+                               tmp = tmds->tmds_pll[i].value ;
+                               break;
+                       }
+               }
+       }
+
+       if (ASIC_IS_R300(rdev) || (rdev->family == CHIP_RV280)) {
+               if (tmp & 0xfff00000)
+                       tmds_pll_cntl = tmp;
+               else {
+                       tmds_pll_cntl &= 0xfff00000;
+                       tmds_pll_cntl |= tmp;
+               }
+       } else
+               tmds_pll_cntl = tmp;
+
+       tmds_transmitter_cntl = RREG32(RADEON_TMDS_TRANSMITTER_CNTL) &
+               ~(RADEON_TMDS_TRANSMITTER_PLLRST);
+
+    if (rdev->family == CHIP_R200 ||
+       rdev->family == CHIP_R100 ||
+       ASIC_IS_R300(rdev))
+           tmds_transmitter_cntl &= ~(RADEON_TMDS_TRANSMITTER_PLLEN);
+    else /* RV chips got this bit reversed */
+           tmds_transmitter_cntl |= RADEON_TMDS_TRANSMITTER_PLLEN;
+
+    fp_gen_cntl = (RREG32(RADEON_FP_GEN_CNTL) |
+                  (RADEON_FP_CRTC_DONT_SHADOW_VPAR |
+                   RADEON_FP_CRTC_DONT_SHADOW_HEND));
+
+    fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN);
+
+    if (1) /*  FIXME rgbBits == 8 */
+           fp_gen_cntl |= RADEON_FP_PANEL_FORMAT;  /* 24 bit format */
+    else
+           fp_gen_cntl &= ~RADEON_FP_PANEL_FORMAT;/* 18 bit format */
+
+    if (radeon_crtc->crtc_id == 0) {
+           if (ASIC_IS_R300(rdev) || rdev->family == CHIP_R200) {
+                   fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK;
+                   if (radeon_encoder->flags & RADEON_USE_RMX)
+                           fp_gen_cntl |= R200_FP_SOURCE_SEL_RMX;
+                   else
+                           fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC1;
+           } else
+                   fp_gen_cntl |= RADEON_FP_SEL_CRTC1;
+    } else {
+           if (ASIC_IS_R300(rdev) || rdev->family == CHIP_R200) {
+                   fp_gen_cntl &= ~R200_FP_SOURCE_SEL_MASK;
+                   fp_gen_cntl |= R200_FP_SOURCE_SEL_CRTC2;
+           } else
+                   fp_gen_cntl |= RADEON_FP_SEL_CRTC2;
+    }
+
+    WREG32(RADEON_TMDS_PLL_CNTL, tmds_pll_cntl);
+    WREG32(RADEON_TMDS_TRANSMITTER_CNTL, tmds_transmitter_cntl);
+    WREG32(RADEON_FP_GEN_CNTL, fp_gen_cntl);
+
+       if (rdev->is_atom_bios)
+               radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
+       else
+               radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
+}
+
+static const struct drm_encoder_helper_funcs radeon_legacy_tmds_int_helper_funcs = {
+       .dpms = radeon_legacy_tmds_int_dpms,
+       .mode_fixup = radeon_legacy_tmds_int_mode_fixup,
+       .prepare = radeon_legacy_tmds_int_prepare,
+       .mode_set = radeon_legacy_tmds_int_mode_set,
+       .commit = radeon_legacy_tmds_int_commit,
+};
+
+
+static const struct drm_encoder_funcs radeon_legacy_tmds_int_enc_funcs = {
+       .destroy = radeon_enc_destroy,
+};
+
+static bool radeon_legacy_tmds_ext_mode_fixup(struct drm_encoder *encoder,
+                                             struct drm_display_mode *mode,
+                                             struct drm_display_mode *adjusted_mode)
+{
+
+       drm_mode_set_crtcinfo(adjusted_mode, 0);
+
+       return true;
+}
+
+static void radeon_legacy_tmds_ext_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
+       DRM_DEBUG("\n");
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               fp2_gen_cntl &= ~RADEON_FP2_BLANK_EN;
+               fp2_gen_cntl |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN);
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               fp2_gen_cntl |= RADEON_FP2_BLANK_EN;
+               fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN);
+               break;
+       }
+
+       WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl);
+
+       if (rdev->is_atom_bios)
+               radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
+       else
+               radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
+}
+
+static void radeon_legacy_tmds_ext_prepare(struct drm_encoder *encoder)
+{
+       struct radeon_device *rdev = encoder->dev->dev_private;
+
+       if (rdev->is_atom_bios)
+               radeon_atom_output_lock(encoder, true);
+       else
+               radeon_combios_output_lock(encoder, true);
+       radeon_legacy_tmds_ext_dpms(encoder, DRM_MODE_DPMS_OFF);
+}
+
+static void radeon_legacy_tmds_ext_commit(struct drm_encoder *encoder)
+{
+       struct radeon_device *rdev = encoder->dev->dev_private;
+       radeon_legacy_tmds_ext_dpms(encoder, DRM_MODE_DPMS_ON);
+
+       if (rdev->is_atom_bios)
+               radeon_atom_output_lock(encoder, false);
+       else
+               radeon_combios_output_lock(encoder, false);
+}
+
+static void radeon_legacy_tmds_ext_mode_set(struct drm_encoder *encoder,
+                                           struct drm_display_mode *mode,
+                                           struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       uint32_t fp2_gen_cntl;
+
+       DRM_DEBUG("\n");
+
+       if (radeon_crtc->crtc_id == 0)
+               radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode);
+
+       if (rdev->is_atom_bios) {
+               radeon_encoder->pixel_clock = adjusted_mode->clock;
+               atombios_external_tmds_setup(encoder, ATOM_ENABLE);
+               fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
+       } else {
+               fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
+
+               if (1) /*  FIXME rgbBits == 8 */
+                       fp2_gen_cntl |= RADEON_FP2_PANEL_FORMAT; /* 24 bit format, */
+               else
+                       fp2_gen_cntl &= ~RADEON_FP2_PANEL_FORMAT;/* 18 bit format, */
+
+               fp2_gen_cntl &= ~(RADEON_FP2_ON |
+                                 RADEON_FP2_DVO_EN |
+                                 RADEON_FP2_DVO_RATE_SEL_SDR);
+
+               /* XXX: these are oem specific */
+               if (ASIC_IS_R300(rdev)) {
+                       if ((dev->pdev->device == 0x4850) &&
+                           (dev->pdev->subsystem_vendor == 0x1028) &&
+                           (dev->pdev->subsystem_device == 0x2001)) /* Dell Inspiron 8600 */
+                               fp2_gen_cntl |= R300_FP2_DVO_CLOCK_MODE_SINGLE;
+                       else
+                               fp2_gen_cntl |= RADEON_FP2_PAD_FLOP_EN | R300_FP2_DVO_CLOCK_MODE_SINGLE;
+
+                       /*if (mode->clock > 165000)
+                         fp2_gen_cntl |= R300_FP2_DVO_DUAL_CHANNEL_EN;*/
+               }
+       }
+
+       if (radeon_crtc->crtc_id == 0) {
+               if ((rdev->family == CHIP_R200) || ASIC_IS_R300(rdev)) {
+                       fp2_gen_cntl &= ~R200_FP2_SOURCE_SEL_MASK;
+                       if (radeon_encoder->flags & RADEON_USE_RMX)
+                               fp2_gen_cntl |= R200_FP2_SOURCE_SEL_RMX;
+                       else
+                               fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC1;
+               } else
+                       fp2_gen_cntl &= ~RADEON_FP2_SRC_SEL_CRTC2;
+       } else {
+               if ((rdev->family == CHIP_R200) || ASIC_IS_R300(rdev)) {
+                       fp2_gen_cntl &= ~R200_FP2_SOURCE_SEL_MASK;
+                       fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC2;
+               } else
+                       fp2_gen_cntl |= RADEON_FP2_SRC_SEL_CRTC2;
+       }
+
+       WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl);
+
+       if (rdev->is_atom_bios)
+               radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
+       else
+               radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
+}
+
+static const struct drm_encoder_helper_funcs radeon_legacy_tmds_ext_helper_funcs = {
+       .dpms = radeon_legacy_tmds_ext_dpms,
+       .mode_fixup = radeon_legacy_tmds_ext_mode_fixup,
+       .prepare = radeon_legacy_tmds_ext_prepare,
+       .mode_set = radeon_legacy_tmds_ext_mode_set,
+       .commit = radeon_legacy_tmds_ext_commit,
+};
+
+
+static const struct drm_encoder_funcs radeon_legacy_tmds_ext_enc_funcs = {
+       .destroy = radeon_enc_destroy,
+};
+
+static bool radeon_legacy_tv_dac_mode_fixup(struct drm_encoder *encoder,
+                                           struct drm_display_mode *mode,
+                                           struct drm_display_mode *adjusted_mode)
+{
+
+       drm_mode_set_crtcinfo(adjusted_mode, 0);
+
+       return true;
+}
+
+static void radeon_legacy_tv_dac_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t fp2_gen_cntl = 0, crtc2_gen_cntl = 0, tv_dac_cntl = 0;
+       /* uint32_t tv_master_cntl = 0; */
+
+       DRM_DEBUG("\n");
+
+       if (rdev->family == CHIP_R200)
+               fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
+       else {
+               crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL);
+               /*  FIXME TV */
+               /* tv_master_cntl = RREG32(RADEON_TV_MASTER_CNTL); */
+               tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL);
+       }
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               if (rdev->family == CHIP_R200) {
+                       fp2_gen_cntl |= (RADEON_FP2_ON | RADEON_FP2_DVO_EN);
+               } else {
+                       crtc2_gen_cntl |= RADEON_CRTC2_CRT2_ON;
+                       /* tv_master_cntl |= RADEON_TV_ON; */
+                       if (rdev->family == CHIP_R420 ||
+                                       rdev->family == CHIP_R423 ||
+                                       rdev->family == CHIP_RV410)
+                               tv_dac_cntl &= ~(R420_TV_DAC_RDACPD |
+                                               R420_TV_DAC_GDACPD |
+                                               R420_TV_DAC_BDACPD |
+                                               RADEON_TV_DAC_BGSLEEP);
+                       else
+                               tv_dac_cntl &= ~(RADEON_TV_DAC_RDACPD |
+                                               RADEON_TV_DAC_GDACPD |
+                                               RADEON_TV_DAC_BDACPD |
+                                               RADEON_TV_DAC_BGSLEEP);
+               }
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               if (rdev->family == CHIP_R200)
+                       fp2_gen_cntl &= ~(RADEON_FP2_ON | RADEON_FP2_DVO_EN);
+               else {
+                       crtc2_gen_cntl &= ~RADEON_CRTC2_CRT2_ON;
+                       /* tv_master_cntl &= ~RADEON_TV_ON; */
+                       if (rdev->family == CHIP_R420 ||
+                                       rdev->family == CHIP_R423 ||
+                                       rdev->family == CHIP_RV410)
+                               tv_dac_cntl |= (R420_TV_DAC_RDACPD |
+                                               R420_TV_DAC_GDACPD |
+                                               R420_TV_DAC_BDACPD |
+                                               RADEON_TV_DAC_BGSLEEP);
+                       else
+                               tv_dac_cntl |= (RADEON_TV_DAC_RDACPD |
+                                               RADEON_TV_DAC_GDACPD |
+                                               RADEON_TV_DAC_BDACPD |
+                                               RADEON_TV_DAC_BGSLEEP);
+               }
+               break;
+       }
+
+       if (rdev->family == CHIP_R200) {
+               WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl);
+       } else {
+               WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
+               /* WREG32(RADEON_TV_MASTER_CNTL, tv_master_cntl); */
+               WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl);
+       }
+
+       if (rdev->is_atom_bios)
+               radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
+       else
+               radeon_combios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
+}
+
+static void radeon_legacy_tv_dac_prepare(struct drm_encoder *encoder)
+{
+       struct radeon_device *rdev = encoder->dev->dev_private;
+
+       if (rdev->is_atom_bios)
+               radeon_atom_output_lock(encoder, true);
+       else
+               radeon_combios_output_lock(encoder, true);
+       radeon_legacy_tv_dac_dpms(encoder, DRM_MODE_DPMS_OFF);
+}
+
+static void radeon_legacy_tv_dac_commit(struct drm_encoder *encoder)
+{
+       struct radeon_device *rdev = encoder->dev->dev_private;
+
+       radeon_legacy_tv_dac_dpms(encoder, DRM_MODE_DPMS_ON);
+
+       if (rdev->is_atom_bios)
+               radeon_atom_output_lock(encoder, true);
+       else
+               radeon_combios_output_lock(encoder, true);
+}
+
+static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder,
+               struct drm_display_mode *mode,
+               struct drm_display_mode *adjusted_mode)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       uint32_t tv_dac_cntl, gpiopad_a = 0, dac2_cntl, disp_output_cntl = 0;
+       uint32_t disp_hw_debug = 0, fp2_gen_cntl = 0;
+
+       DRM_DEBUG("\n");
+
+       if (radeon_crtc->crtc_id == 0)
+               radeon_legacy_rmx_mode_set(encoder, mode, adjusted_mode);
+
+       if (rdev->family != CHIP_R200) {
+               tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL);
+               if (rdev->family == CHIP_R420 ||
+                               rdev->family == CHIP_R423 ||
+                               rdev->family == CHIP_RV410) {
+                       tv_dac_cntl &= ~(RADEON_TV_DAC_STD_MASK |
+                                       RADEON_TV_DAC_BGADJ_MASK |
+                                       R420_TV_DAC_DACADJ_MASK |
+                                       R420_TV_DAC_RDACPD |
+                                       R420_TV_DAC_GDACPD |
+                                       R420_TV_DAC_GDACPD |
+                                       R420_TV_DAC_TVENABLE);
+               } else {
+                       tv_dac_cntl &= ~(RADEON_TV_DAC_STD_MASK |
+                                       RADEON_TV_DAC_BGADJ_MASK |
+                                       RADEON_TV_DAC_DACADJ_MASK |
+                                       RADEON_TV_DAC_RDACPD |
+                                       RADEON_TV_DAC_GDACPD |
+                                       RADEON_TV_DAC_GDACPD);
+               }
+
+               /*  FIXME TV */
+               if (radeon_encoder->enc_priv) {
+                       struct radeon_encoder_tv_dac *tv_dac = radeon_encoder->enc_priv;
+                       tv_dac_cntl |= (RADEON_TV_DAC_NBLANK |
+                                       RADEON_TV_DAC_NHOLD |
+                                       RADEON_TV_DAC_STD_PS2 |
+                                       tv_dac->ps2_tvdac_adj);
+               } else
+                       tv_dac_cntl |= (RADEON_TV_DAC_NBLANK |
+                                       RADEON_TV_DAC_NHOLD |
+                                       RADEON_TV_DAC_STD_PS2);
+
+               WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl);
+       }
+
+       if (ASIC_IS_R300(rdev)) {
+               gpiopad_a = RREG32(RADEON_GPIOPAD_A) | 1;
+               disp_output_cntl = RREG32(RADEON_DISP_OUTPUT_CNTL);
+       } else if (rdev->family == CHIP_R200)
+               fp2_gen_cntl = RREG32(RADEON_FP2_GEN_CNTL);
+       else
+               disp_hw_debug = RREG32(RADEON_DISP_HW_DEBUG);
+
+       dac2_cntl = RREG32(RADEON_DAC_CNTL2) | RADEON_DAC2_DAC2_CLK_SEL;
+
+       if (radeon_crtc->crtc_id == 0) {
+               if (ASIC_IS_R300(rdev)) {
+                       disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK;
+                       disp_output_cntl |= RADEON_DISP_TVDAC_SOURCE_CRTC;
+               } else if (rdev->family == CHIP_R200) {
+                       fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK |
+                                         RADEON_FP2_DVO_RATE_SEL_SDR);
+               } else
+                       disp_hw_debug |= RADEON_CRT2_DISP1_SEL;
+       } else {
+               if (ASIC_IS_R300(rdev)) {
+                       disp_output_cntl &= ~RADEON_DISP_TVDAC_SOURCE_MASK;
+                       disp_output_cntl |= RADEON_DISP_TVDAC_SOURCE_CRTC2;
+               } else if (rdev->family == CHIP_R200) {
+                       fp2_gen_cntl &= ~(R200_FP2_SOURCE_SEL_MASK |
+                                         RADEON_FP2_DVO_RATE_SEL_SDR);
+                       fp2_gen_cntl |= R200_FP2_SOURCE_SEL_CRTC2;
+               } else
+                       disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL;
+       }
+
+       WREG32(RADEON_DAC_CNTL2, dac2_cntl);
+
+       if (ASIC_IS_R300(rdev)) {
+               WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1);
+               WREG32(RADEON_DISP_TV_OUT_CNTL, disp_output_cntl);
+       } else if (rdev->family == CHIP_R200)
+               WREG32(RADEON_FP2_GEN_CNTL, fp2_gen_cntl);
+       else
+               WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug);
+
+       if (rdev->is_atom_bios)
+               radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
+       else
+               radeon_combios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id);
+
+}
+
+static enum drm_connector_status radeon_legacy_tv_dac_detect(struct drm_encoder *encoder,
+                                                            struct drm_connector *connector)
+{
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t crtc2_gen_cntl, tv_dac_cntl, dac_cntl2, dac_ext_cntl;
+       uint32_t disp_hw_debug, disp_output_cntl, gpiopad_a, pixclks_cntl, tmp;
+       enum drm_connector_status found = connector_status_disconnected;
+       bool color = true;
+
+       /*  FIXME tv */
+
+       /* save the regs we need */
+       pixclks_cntl = RREG32_PLL(RADEON_PIXCLKS_CNTL);
+       gpiopad_a = ASIC_IS_R300(rdev) ? RREG32(RADEON_GPIOPAD_A) : 0;
+       disp_output_cntl = ASIC_IS_R300(rdev) ? RREG32(RADEON_DISP_OUTPUT_CNTL) : 0;
+       disp_hw_debug = ASIC_IS_R300(rdev) ? 0 : RREG32(RADEON_DISP_HW_DEBUG);
+       crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL);
+       tv_dac_cntl = RREG32(RADEON_TV_DAC_CNTL);
+       dac_ext_cntl = RREG32(RADEON_DAC_EXT_CNTL);
+       dac_cntl2 = RREG32(RADEON_DAC_CNTL2);
+
+       tmp = pixclks_cntl & ~(RADEON_PIX2CLK_ALWAYS_ONb
+                              | RADEON_PIX2CLK_DAC_ALWAYS_ONb);
+       WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp);
+
+       if (ASIC_IS_R300(rdev))
+               WREG32_P(RADEON_GPIOPAD_A, 1, ~1);
+
+       tmp = crtc2_gen_cntl & ~RADEON_CRTC2_PIX_WIDTH_MASK;
+       tmp |= RADEON_CRTC2_CRT2_ON |
+               (2 << RADEON_CRTC2_PIX_WIDTH_SHIFT);
+
+       WREG32(RADEON_CRTC2_GEN_CNTL, tmp);
+
+       if (ASIC_IS_R300(rdev)) {
+               tmp = disp_output_cntl & ~RADEON_DISP_TVDAC_SOURCE_MASK;
+               tmp |= RADEON_DISP_TVDAC_SOURCE_CRTC2;
+               WREG32(RADEON_DISP_OUTPUT_CNTL, tmp);
+       } else {
+               tmp = disp_hw_debug & ~RADEON_CRT2_DISP1_SEL;
+               WREG32(RADEON_DISP_HW_DEBUG, tmp);
+       }
+
+       tmp = RADEON_TV_DAC_NBLANK |
+               RADEON_TV_DAC_NHOLD |
+               RADEON_TV_MONITOR_DETECT_EN |
+               RADEON_TV_DAC_STD_PS2;
+
+       WREG32(RADEON_TV_DAC_CNTL, tmp);
+
+       tmp = RADEON_DAC2_FORCE_BLANK_OFF_EN |
+               RADEON_DAC2_FORCE_DATA_EN;
+
+       if (color)
+               tmp |= RADEON_DAC_FORCE_DATA_SEL_RGB;
+       else
+               tmp |= RADEON_DAC_FORCE_DATA_SEL_G;
+
+       if (ASIC_IS_R300(rdev))
+               tmp |= (0x1b6 << RADEON_DAC_FORCE_DATA_SHIFT);
+       else
+               tmp |= (0x180 << RADEON_DAC_FORCE_DATA_SHIFT);
+
+       WREG32(RADEON_DAC_EXT_CNTL, tmp);
+
+       tmp = dac_cntl2 | RADEON_DAC2_DAC2_CLK_SEL | RADEON_DAC2_CMP_EN;
+       WREG32(RADEON_DAC_CNTL2, tmp);
+
+       udelay(10000);
+
+       if (ASIC_IS_R300(rdev)) {
+               if (RREG32(RADEON_DAC_CNTL2) & RADEON_DAC2_CMP_OUT_B)
+                       found = connector_status_connected;
+       } else {
+               if (RREG32(RADEON_DAC_CNTL2) & RADEON_DAC2_CMP_OUTPUT)
+                       found = connector_status_connected;
+       }
+
+       /* restore regs we used */
+       WREG32(RADEON_DAC_CNTL2, dac_cntl2);
+       WREG32(RADEON_DAC_EXT_CNTL, dac_ext_cntl);
+       WREG32(RADEON_TV_DAC_CNTL, tv_dac_cntl);
+       WREG32(RADEON_CRTC2_GEN_CNTL, crtc2_gen_cntl);
+
+       if (ASIC_IS_R300(rdev)) {
+               WREG32(RADEON_DISP_OUTPUT_CNTL, disp_output_cntl);
+               WREG32_P(RADEON_GPIOPAD_A, gpiopad_a, ~1);
+       } else {
+               WREG32(RADEON_DISP_HW_DEBUG, disp_hw_debug);
+       }
+       WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl);
+
+       /* return found; */
+       return connector_status_disconnected;
+
+}
+
+static const struct drm_encoder_helper_funcs radeon_legacy_tv_dac_helper_funcs = {
+       .dpms = radeon_legacy_tv_dac_dpms,
+       .mode_fixup = radeon_legacy_tv_dac_mode_fixup,
+       .prepare = radeon_legacy_tv_dac_prepare,
+       .mode_set = radeon_legacy_tv_dac_mode_set,
+       .commit = radeon_legacy_tv_dac_commit,
+       .detect = radeon_legacy_tv_dac_detect,
+};
+
+
+static const struct drm_encoder_funcs radeon_legacy_tv_dac_enc_funcs = {
+       .destroy = radeon_enc_destroy,
+};
+
+void
+radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t supported_device)
+{
+       struct radeon_device *rdev = dev->dev_private;
+       struct drm_encoder *encoder;
+       struct radeon_encoder *radeon_encoder;
+
+       /* see if we already added it */
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               radeon_encoder = to_radeon_encoder(encoder);
+               if (radeon_encoder->encoder_id == encoder_id) {
+                       radeon_encoder->devices |= supported_device;
+                       return;
+               }
+
+       }
+
+       /* add a new one */
+       radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL);
+       if (!radeon_encoder)
+               return;
+
+       encoder = &radeon_encoder->base;
+       encoder->possible_crtcs = 0x3;
+       encoder->possible_clones = 0;
+
+       radeon_encoder->enc_priv = NULL;
+
+       radeon_encoder->encoder_id = encoder_id;
+       radeon_encoder->devices = supported_device;
+
+       switch (radeon_encoder->encoder_id) {
+       case ENCODER_OBJECT_ID_INTERNAL_LVDS:
+               drm_encoder_init(dev, encoder, &radeon_legacy_lvds_enc_funcs, DRM_MODE_ENCODER_LVDS);
+               drm_encoder_helper_add(encoder, &radeon_legacy_lvds_helper_funcs);
+               if (rdev->is_atom_bios)
+                       radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder);
+               else
+                       radeon_encoder->enc_priv = radeon_combios_get_lvds_info(radeon_encoder);
+               radeon_encoder->rmx_type = RMX_FULL;
+               break;
+       case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
+               drm_encoder_init(dev, encoder, &radeon_legacy_tmds_int_enc_funcs, DRM_MODE_ENCODER_TMDS);
+               drm_encoder_helper_add(encoder, &radeon_legacy_tmds_int_helper_funcs);
+               if (rdev->is_atom_bios)
+                       radeon_encoder->enc_priv = radeon_atombios_get_tmds_info(radeon_encoder);
+               else
+                       radeon_encoder->enc_priv = radeon_combios_get_tmds_info(radeon_encoder);
+               break;
+       case ENCODER_OBJECT_ID_INTERNAL_DAC1:
+               drm_encoder_init(dev, encoder, &radeon_legacy_primary_dac_enc_funcs, DRM_MODE_ENCODER_DAC);
+               drm_encoder_helper_add(encoder, &radeon_legacy_primary_dac_helper_funcs);
+               if (rdev->is_atom_bios)
+                       radeon_encoder->enc_priv = radeon_atombios_get_primary_dac_info(radeon_encoder);
+               else
+                       radeon_encoder->enc_priv = radeon_combios_get_primary_dac_info(radeon_encoder);
+               break;
+       case ENCODER_OBJECT_ID_INTERNAL_DAC2:
+               drm_encoder_init(dev, encoder, &radeon_legacy_tv_dac_enc_funcs, DRM_MODE_ENCODER_TVDAC);
+               drm_encoder_helper_add(encoder, &radeon_legacy_tv_dac_helper_funcs);
+               if (rdev->is_atom_bios)
+                       radeon_encoder->enc_priv = radeon_atombios_get_tv_dac_info(radeon_encoder);
+               else
+                       radeon_encoder->enc_priv = radeon_combios_get_tv_dac_info(radeon_encoder);
+               break;
+       case ENCODER_OBJECT_ID_INTERNAL_DVO1:
+               drm_encoder_init(dev, encoder, &radeon_legacy_tmds_ext_enc_funcs, DRM_MODE_ENCODER_TMDS);
+               drm_encoder_helper_add(encoder, &radeon_legacy_tmds_ext_helper_funcs);
+               if (!rdev->is_atom_bios)
+                       radeon_combios_get_ext_tmds_info(radeon_encoder);
+               break;
+       }
+}
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
new file mode 100644 (file)
index 0000000..9173b68
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
+ *                VA Linux Systems Inc., Fremont, California.
+ * Copyright 2008 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Original Authors:
+ *   Kevin E. Martin, Rickard E. Faith, Alan Hourihane
+ *
+ * Kernel port Author: Dave Airlie
+ */
+
+#ifndef RADEON_MODE_H
+#define RADEON_MODE_H
+
+#include <drm_crtc.h>
+#include <drm_mode.h>
+#include <drm_edid.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/i2c-algo-bit.h>
+
+#define to_radeon_crtc(x) container_of(x, struct radeon_crtc, base)
+#define to_radeon_connector(x) container_of(x, struct radeon_connector, base)
+#define to_radeon_encoder(x) container_of(x, struct radeon_encoder, base)
+#define to_radeon_framebuffer(x) container_of(x, struct radeon_framebuffer, base)
+
+enum radeon_connector_type {
+       CONNECTOR_NONE,
+       CONNECTOR_VGA,
+       CONNECTOR_DVI_I,
+       CONNECTOR_DVI_D,
+       CONNECTOR_DVI_A,
+       CONNECTOR_STV,
+       CONNECTOR_CTV,
+       CONNECTOR_LVDS,
+       CONNECTOR_DIGITAL,
+       CONNECTOR_SCART,
+       CONNECTOR_HDMI_TYPE_A,
+       CONNECTOR_HDMI_TYPE_B,
+       CONNECTOR_0XC,
+       CONNECTOR_0XD,
+       CONNECTOR_DIN,
+       CONNECTOR_DISPLAY_PORT,
+       CONNECTOR_UNSUPPORTED
+};
+
+enum radeon_dvi_type {
+       DVI_AUTO,
+       DVI_DIGITAL,
+       DVI_ANALOG
+};
+
+enum radeon_rmx_type {
+       RMX_OFF,
+       RMX_FULL,
+       RMX_CENTER,
+       RMX_ASPECT
+};
+
+enum radeon_tv_std {
+       TV_STD_NTSC,
+       TV_STD_PAL,
+       TV_STD_PAL_M,
+       TV_STD_PAL_60,
+       TV_STD_NTSC_J,
+       TV_STD_SCART_PAL,
+       TV_STD_SECAM,
+       TV_STD_PAL_CN,
+};
+
+struct radeon_i2c_bus_rec {
+       bool valid;
+       uint32_t mask_clk_reg;
+       uint32_t mask_data_reg;
+       uint32_t a_clk_reg;
+       uint32_t a_data_reg;
+       uint32_t put_clk_reg;
+       uint32_t put_data_reg;
+       uint32_t get_clk_reg;
+       uint32_t get_data_reg;
+       uint32_t mask_clk_mask;
+       uint32_t mask_data_mask;
+       uint32_t put_clk_mask;
+       uint32_t put_data_mask;
+       uint32_t get_clk_mask;
+       uint32_t get_data_mask;
+       uint32_t a_clk_mask;
+       uint32_t a_data_mask;
+};
+
+struct radeon_tmds_pll {
+    uint32_t freq;
+    uint32_t value;
+};
+
+#define RADEON_MAX_BIOS_CONNECTOR 16
+
+#define RADEON_PLL_USE_BIOS_DIVS        (1 << 0)
+#define RADEON_PLL_NO_ODD_POST_DIV      (1 << 1)
+#define RADEON_PLL_USE_REF_DIV          (1 << 2)
+#define RADEON_PLL_LEGACY               (1 << 3)
+#define RADEON_PLL_PREFER_LOW_REF_DIV   (1 << 4)
+#define RADEON_PLL_PREFER_HIGH_REF_DIV  (1 << 5)
+#define RADEON_PLL_PREFER_LOW_FB_DIV    (1 << 6)
+#define RADEON_PLL_PREFER_HIGH_FB_DIV   (1 << 7)
+#define RADEON_PLL_PREFER_LOW_POST_DIV  (1 << 8)
+#define RADEON_PLL_PREFER_HIGH_POST_DIV (1 << 9)
+#define RADEON_PLL_USE_FRAC_FB_DIV      (1 << 10)
+
+struct radeon_pll {
+       uint16_t reference_freq;
+       uint16_t reference_div;
+       uint32_t pll_in_min;
+       uint32_t pll_in_max;
+       uint32_t pll_out_min;
+       uint32_t pll_out_max;
+       uint16_t xclk;
+
+       uint32_t min_ref_div;
+       uint32_t max_ref_div;
+       uint32_t min_post_div;
+       uint32_t max_post_div;
+       uint32_t min_feedback_div;
+       uint32_t max_feedback_div;
+       uint32_t min_frac_feedback_div;
+       uint32_t max_frac_feedback_div;
+       uint32_t best_vco;
+};
+
+struct radeon_i2c_chan {
+       struct drm_device *dev;
+       struct i2c_adapter adapter;
+       struct i2c_algo_bit_data algo;
+       struct radeon_i2c_bus_rec rec;
+};
+
+/* mostly for macs, but really any system without connector tables */
+enum radeon_connector_table {
+       CT_NONE,
+       CT_GENERIC,
+       CT_IBOOK,
+       CT_POWERBOOK_EXTERNAL,
+       CT_POWERBOOK_INTERNAL,
+       CT_POWERBOOK_VGA,
+       CT_MINI_EXTERNAL,
+       CT_MINI_INTERNAL,
+       CT_IMAC_G5_ISIGHT,
+       CT_EMAC,
+};
+
+struct radeon_mode_info {
+       struct atom_context *atom_context;
+       enum radeon_connector_table connector_table;
+       bool mode_config_initialized;
+};
+
+struct radeon_crtc {
+       struct drm_crtc base;
+       int crtc_id;
+       u16 lut_r[256], lut_g[256], lut_b[256];
+       bool enabled;
+       bool can_tile;
+       uint32_t crtc_offset;
+       struct radeon_framebuffer *fbdev_fb;
+       struct drm_mode_set mode_set;
+       struct drm_gem_object *cursor_bo;
+       uint64_t cursor_addr;
+       int cursor_width;
+       int cursor_height;
+};
+
+#define RADEON_USE_RMX 1
+
+struct radeon_native_mode {
+       /* preferred mode */
+       uint32_t panel_xres, panel_yres;
+       uint32_t hoverplus, hsync_width;
+       uint32_t hblank;
+       uint32_t voverplus, vsync_width;
+       uint32_t vblank;
+       uint32_t dotclock;
+       uint32_t flags;
+};
+
+struct radeon_encoder_primary_dac {
+       /* legacy primary dac */
+       uint32_t ps2_pdac_adj;
+};
+
+struct radeon_encoder_lvds {
+       /* legacy lvds */
+       uint16_t panel_vcc_delay;
+       uint8_t  panel_pwr_delay;
+       uint8_t  panel_digon_delay;
+       uint8_t  panel_blon_delay;
+       uint16_t panel_ref_divider;
+       uint8_t  panel_post_divider;
+       uint16_t panel_fb_divider;
+       bool     use_bios_dividers;
+       uint32_t lvds_gen_cntl;
+       /* panel mode */
+       struct radeon_native_mode native_mode;
+};
+
+struct radeon_encoder_tv_dac {
+       /* legacy tv dac */
+       uint32_t ps2_tvdac_adj;
+       uint32_t ntsc_tvdac_adj;
+       uint32_t pal_tvdac_adj;
+
+       enum radeon_tv_std tv_std;
+};
+
+struct radeon_encoder_int_tmds {
+       /* legacy int tmds */
+       struct radeon_tmds_pll tmds_pll[4];
+};
+
+struct radeon_encoder_atom_dig {
+       /* atom dig */
+       bool coherent_mode;
+       int dig_block;
+       /* atom lvds */
+       uint32_t lvds_misc;
+       uint16_t panel_pwr_delay;
+       /* panel mode */
+       struct radeon_native_mode native_mode;
+};
+
+struct radeon_encoder {
+       struct drm_encoder base;
+       uint32_t encoder_id;
+       uint32_t devices;
+       uint32_t flags;
+       uint32_t pixel_clock;
+       enum radeon_rmx_type rmx_type;
+       struct radeon_native_mode native_mode;
+       void *enc_priv;
+};
+
+struct radeon_connector_atom_dig {
+       uint32_t igp_lane_info;
+       bool linkb;
+};
+
+struct radeon_connector {
+       struct drm_connector base;
+       uint32_t connector_id;
+       uint32_t devices;
+       struct radeon_i2c_chan *ddc_bus;
+       int use_digital;
+       void *con_priv;
+};
+
+struct radeon_framebuffer {
+       struct drm_framebuffer base;
+       struct drm_gem_object *obj;
+};
+
+extern struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
+                                                struct radeon_i2c_bus_rec *rec,
+                                                const char *name);
+extern void radeon_i2c_destroy(struct radeon_i2c_chan *i2c);
+extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector);
+extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector);
+
+extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector);
+
+extern void radeon_compute_pll(struct radeon_pll *pll,
+                              uint64_t freq,
+                              uint32_t *dot_clock_p,
+                              uint32_t *fb_div_p,
+                              uint32_t *frac_fb_div_p,
+                              uint32_t *ref_div_p,
+                              uint32_t *post_div_p,
+                              int flags);
+
+struct drm_encoder *radeon_encoder_legacy_lvds_add(struct drm_device *dev, int bios_index);
+struct drm_encoder *radeon_encoder_legacy_primary_dac_add(struct drm_device *dev, int bios_index, int with_tv);
+struct drm_encoder *radeon_encoder_legacy_tv_dac_add(struct drm_device *dev, int bios_index, int with_tv);
+struct drm_encoder *radeon_encoder_legacy_tmds_int_add(struct drm_device *dev, int bios_index);
+struct drm_encoder *radeon_encoder_legacy_tmds_ext_add(struct drm_device *dev, int bios_index);
+extern void atombios_external_tmds_setup(struct drm_encoder *encoder, int action);
+extern int atombios_get_encoder_mode(struct drm_encoder *encoder);
+
+extern void radeon_crtc_load_lut(struct drm_crtc *crtc);
+extern int atombios_crtc_set_base(struct drm_crtc *crtc, int x, int y,
+                                  struct drm_framebuffer *old_fb);
+extern int atombios_crtc_mode_set(struct drm_crtc *crtc,
+                                  struct drm_display_mode *mode,
+                                  struct drm_display_mode *adjusted_mode,
+                                  int x, int y,
+                                  struct drm_framebuffer *old_fb);
+extern void atombios_crtc_dpms(struct drm_crtc *crtc, int mode);
+
+extern int radeon_crtc_set_base(struct drm_crtc *crtc, int x, int y,
+                                struct drm_framebuffer *old_fb);
+extern void radeon_legacy_atom_set_surface(struct drm_crtc *crtc);
+
+extern int radeon_crtc_cursor_set(struct drm_crtc *crtc,
+                                 struct drm_file *file_priv,
+                                 uint32_t handle,
+                                 uint32_t width,
+                                 uint32_t height);
+extern int radeon_crtc_cursor_move(struct drm_crtc *crtc,
+                                  int x, int y);
+
+extern bool radeon_atom_get_clock_info(struct drm_device *dev);
+extern bool radeon_combios_get_clock_info(struct drm_device *dev);
+extern struct radeon_encoder_atom_dig *
+radeon_atombios_get_lvds_info(struct radeon_encoder *encoder);
+extern struct radeon_encoder_int_tmds *
+radeon_atombios_get_tmds_info(struct radeon_encoder *encoder);
+extern struct radeon_encoder_primary_dac *
+radeon_atombios_get_primary_dac_info(struct radeon_encoder *encoder);
+extern struct radeon_encoder_tv_dac *
+radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder);
+extern struct radeon_encoder_lvds *
+radeon_combios_get_lvds_info(struct radeon_encoder *encoder);
+extern struct radeon_encoder_int_tmds *
+radeon_combios_get_tmds_info(struct radeon_encoder *encoder);
+extern void radeon_combios_get_ext_tmds_info(struct radeon_encoder *encoder);
+extern struct radeon_encoder_tv_dac *
+radeon_combios_get_tv_dac_info(struct radeon_encoder *encoder);
+extern struct radeon_encoder_primary_dac *
+radeon_combios_get_primary_dac_info(struct radeon_encoder *encoder);
+extern void radeon_combios_output_lock(struct drm_encoder *encoder, bool lock);
+extern void radeon_combios_initialize_bios_scratch_regs(struct drm_device *dev);
+extern void radeon_atom_output_lock(struct drm_encoder *encoder, bool lock);
+extern void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev);
+extern void
+radeon_atombios_encoder_crtc_scratch_regs(struct drm_encoder *encoder, int crtc);
+extern void
+radeon_atombios_encoder_dpms_scratch_regs(struct drm_encoder *encoder, bool on);
+extern void
+radeon_combios_encoder_crtc_scratch_regs(struct drm_encoder *encoder, int crtc);
+extern void
+radeon_combios_encoder_dpms_scratch_regs(struct drm_encoder *encoder, bool on);
+extern void radeon_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
+                                    u16 blue, int regno);
+struct drm_framebuffer *radeon_framebuffer_create(struct drm_device *dev,
+                                                 struct drm_mode_fb_cmd *mode_cmd,
+                                                 struct drm_gem_object *obj);
+
+int radeonfb_probe(struct drm_device *dev);
+
+int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
+bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev);
+bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev);
+void radeon_atombios_init_crtc(struct drm_device *dev,
+                              struct radeon_crtc *radeon_crtc);
+void radeon_legacy_init_crtc(struct drm_device *dev,
+                            struct radeon_crtc *radeon_crtc);
+void radeon_i2c_do_lock(struct radeon_connector *radeon_connector, int lock_state);
+
+void radeon_get_clock_info(struct drm_device *dev);
+
+extern bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev);
+extern bool radeon_get_atom_connector_info_from_supported_devices_table(struct drm_device *dev);
+
+void radeon_rmx_mode_fixup(struct drm_encoder *encoder,
+                          struct drm_display_mode *mode,
+                          struct drm_display_mode *adjusted_mode);
+void radeon_enc_destroy(struct drm_encoder *encoder);
+void radeon_copy_fb(struct drm_device *dev, struct drm_gem_object *dst_obj);
+void radeon_combios_asic_init(struct drm_device *dev);
+extern int radeon_static_clocks_init(struct drm_device *dev);
+void radeon_init_disp_bw_legacy(struct drm_device *dev,
+                               struct drm_display_mode *mode1,
+                               uint32_t pixel_bytes1,
+                               struct drm_display_mode *mode2,
+                               uint32_t pixel_bytes2);
+void radeon_init_disp_bw_avivo(struct drm_device *dev,
+                              struct drm_display_mode *mode1,
+                              uint32_t pixel_bytes1,
+                              struct drm_display_mode *mode2,
+                              uint32_t pixel_bytes2);
+void radeon_init_disp_bandwidth(struct drm_device *dev);
+
+#endif
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
new file mode 100644 (file)
index 0000000..983e8df
--- /dev/null
@@ -0,0 +1,511 @@
+/*
+ * Copyright 2009 Jerome Glisse.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors:
+ *    Jerome Glisse <glisse@freedesktop.org>
+ *    Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
+ *    Dave Airlie
+ */
+#include <linux/list.h>
+#include <drm/drmP.h>
+#include "radeon_drm.h"
+#include "radeon.h"
+
+struct radeon_object {
+       struct ttm_buffer_object        tobj;
+       struct list_head                list;
+       struct radeon_device            *rdev;
+       struct drm_gem_object           *gobj;
+       struct ttm_bo_kmap_obj          kmap;
+       unsigned                        pin_count;
+       uint64_t                        gpu_addr;
+       void                            *kptr;
+       bool                            is_iomem;
+};
+
+int radeon_ttm_init(struct radeon_device *rdev);
+void radeon_ttm_fini(struct radeon_device *rdev);
+
+/*
+ * To exclude mutual BO access we rely on bo_reserve exclusion, as all
+ * function are calling it.
+ */
+
+static int radeon_object_reserve(struct radeon_object *robj, bool interruptible)
+{
+       return ttm_bo_reserve(&robj->tobj, interruptible, false, false, 0);
+}
+
+static void radeon_object_unreserve(struct radeon_object *robj)
+{
+       ttm_bo_unreserve(&robj->tobj);
+}
+
+static void radeon_ttm_object_object_destroy(struct ttm_buffer_object *tobj)
+{
+       struct radeon_object *robj;
+
+       robj = container_of(tobj, struct radeon_object, tobj);
+       list_del_init(&robj->list);
+       kfree(robj);
+}
+
+static inline void radeon_object_gpu_addr(struct radeon_object *robj)
+{
+       /* Default gpu address */
+       robj->gpu_addr = 0xFFFFFFFFFFFFFFFFULL;
+       if (robj->tobj.mem.mm_node == NULL) {
+               return;
+       }
+       robj->gpu_addr = ((u64)robj->tobj.mem.mm_node->start) << PAGE_SHIFT;
+       switch (robj->tobj.mem.mem_type) {
+       case TTM_PL_VRAM:
+               robj->gpu_addr += (u64)robj->rdev->mc.vram_location;
+               break;
+       case TTM_PL_TT:
+               robj->gpu_addr += (u64)robj->rdev->mc.gtt_location;
+               break;
+       default:
+               DRM_ERROR("Unknown placement %d\n", robj->tobj.mem.mem_type);
+               robj->gpu_addr = 0xFFFFFFFFFFFFFFFFULL;
+               return;
+       }
+}
+
+static inline uint32_t radeon_object_flags_from_domain(uint32_t domain)
+{
+       uint32_t flags = 0;
+       if (domain & RADEON_GEM_DOMAIN_VRAM) {
+               flags |= TTM_PL_FLAG_VRAM;
+       }
+       if (domain & RADEON_GEM_DOMAIN_GTT) {
+               flags |= TTM_PL_FLAG_TT;
+       }
+       if (domain & RADEON_GEM_DOMAIN_CPU) {
+               flags |= TTM_PL_FLAG_SYSTEM;
+       }
+       if (!flags) {
+               flags |= TTM_PL_FLAG_SYSTEM;
+       }
+       return flags;
+}
+
+int radeon_object_create(struct radeon_device *rdev,
+                        struct drm_gem_object *gobj,
+                        unsigned long size,
+                        bool kernel,
+                        uint32_t domain,
+                        bool interruptible,
+                        struct radeon_object **robj_ptr)
+{
+       struct radeon_object *robj;
+       enum ttm_bo_type type;
+       uint32_t flags;
+       int r;
+
+       if (unlikely(rdev->mman.bdev.dev_mapping == NULL)) {
+               rdev->mman.bdev.dev_mapping = rdev->ddev->dev_mapping;
+       }
+       if (kernel) {
+               type = ttm_bo_type_kernel;
+       } else {
+               type = ttm_bo_type_device;
+       }
+       *robj_ptr = NULL;
+       robj = kzalloc(sizeof(struct radeon_object), GFP_KERNEL);
+       if (robj == NULL) {
+               return -ENOMEM;
+       }
+       robj->rdev = rdev;
+       robj->gobj = gobj;
+       INIT_LIST_HEAD(&robj->list);
+
+       flags = radeon_object_flags_from_domain(domain);
+       r = ttm_buffer_object_init(&rdev->mman.bdev, &robj->tobj, size, type, flags,
+                                  0, 0, false, NULL, size,
+                                  &radeon_ttm_object_object_destroy);
+       if (unlikely(r != 0)) {
+               /* ttm call radeon_ttm_object_object_destroy if error happen */
+               DRM_ERROR("Failed to allocate TTM object (%ld, 0x%08X, %u)\n",
+                         size, flags, 0);
+               return r;
+       }
+       *robj_ptr = robj;
+       if (gobj) {
+               list_add_tail(&robj->list, &rdev->gem.objects);
+       }
+       return 0;
+}
+
+int radeon_object_kmap(struct radeon_object *robj, void **ptr)
+{
+       int r;
+
+       spin_lock(&robj->tobj.lock);
+       if (robj->kptr) {
+               if (ptr) {
+                       *ptr = robj->kptr;
+               }
+               spin_unlock(&robj->tobj.lock);
+               return 0;
+       }
+       spin_unlock(&robj->tobj.lock);
+       r = ttm_bo_kmap(&robj->tobj, 0, robj->tobj.num_pages, &robj->kmap);
+       if (r) {
+               return r;
+       }
+       spin_lock(&robj->tobj.lock);
+       robj->kptr = ttm_kmap_obj_virtual(&robj->kmap, &robj->is_iomem);
+       spin_unlock(&robj->tobj.lock);
+       if (ptr) {
+               *ptr = robj->kptr;
+       }
+       return 0;
+}
+
+void radeon_object_kunmap(struct radeon_object *robj)
+{
+       spin_lock(&robj->tobj.lock);
+       if (robj->kptr == NULL) {
+               spin_unlock(&robj->tobj.lock);
+               return;
+       }
+       robj->kptr = NULL;
+       spin_unlock(&robj->tobj.lock);
+       ttm_bo_kunmap(&robj->kmap);
+}
+
+void radeon_object_unref(struct radeon_object **robj)
+{
+       struct ttm_buffer_object *tobj;
+
+       if ((*robj) == NULL) {
+               return;
+       }
+       tobj = &((*robj)->tobj);
+       ttm_bo_unref(&tobj);
+       if (tobj == NULL) {
+               *robj = NULL;
+       }
+}
+
+int radeon_object_mmap(struct radeon_object *robj, uint64_t *offset)
+{
+       *offset = robj->tobj.addr_space_offset;
+       return 0;
+}
+
+int radeon_object_pin(struct radeon_object *robj, uint32_t domain,
+                     uint64_t *gpu_addr)
+{
+       uint32_t flags;
+       uint32_t tmp;
+       void *fbptr;
+       int r;
+
+       flags = radeon_object_flags_from_domain(domain);
+       spin_lock(&robj->tobj.lock);
+       if (robj->pin_count) {
+               robj->pin_count++;
+               if (gpu_addr != NULL) {
+                       *gpu_addr = robj->gpu_addr;
+               }
+               spin_unlock(&robj->tobj.lock);
+               return 0;
+       }
+       spin_unlock(&robj->tobj.lock);
+       r = radeon_object_reserve(robj, false);
+       if (unlikely(r != 0)) {
+               DRM_ERROR("radeon: failed to reserve object for pinning it.\n");
+               return r;
+       }
+       if (robj->rdev->fbdev_robj == robj) {
+               mutex_lock(&robj->rdev->fbdev_info->lock);
+               radeon_object_kunmap(robj);
+       }
+       tmp = robj->tobj.mem.placement;
+       ttm_flag_masked(&tmp, flags, TTM_PL_MASK_MEM);
+       robj->tobj.proposed_placement = tmp | TTM_PL_FLAG_NO_EVICT | TTM_PL_MASK_CACHING;
+       r = ttm_buffer_object_validate(&robj->tobj,
+                                      robj->tobj.proposed_placement,
+                                      false, false);
+       radeon_object_gpu_addr(robj);
+       if (gpu_addr != NULL) {
+               *gpu_addr = robj->gpu_addr;
+       }
+       robj->pin_count = 1;
+       if (unlikely(r != 0)) {
+               DRM_ERROR("radeon: failed to pin object.\n");
+       }
+       radeon_object_unreserve(robj);
+       if (robj->rdev->fbdev_robj == robj) {
+               if (!r) {
+                       r = radeon_object_kmap(robj, &fbptr);
+               }
+               if (!r) {
+                       robj->rdev->fbdev_info->screen_base = fbptr;
+                       robj->rdev->fbdev_info->fix.smem_start = (unsigned long)fbptr;
+               }
+               mutex_unlock(&robj->rdev->fbdev_info->lock);
+       }
+       return r;
+}
+
+void radeon_object_unpin(struct radeon_object *robj)
+{
+       uint32_t flags;
+       void *fbptr;
+       int r;
+
+       spin_lock(&robj->tobj.lock);
+       if (!robj->pin_count) {
+               spin_unlock(&robj->tobj.lock);
+               printk(KERN_WARNING "Unpin not necessary for %p !\n", robj);
+               return;
+       }
+       robj->pin_count--;
+       if (robj->pin_count) {
+               spin_unlock(&robj->tobj.lock);
+               return;
+       }
+       spin_unlock(&robj->tobj.lock);
+       r = radeon_object_reserve(robj, false);
+       if (unlikely(r != 0)) {
+               DRM_ERROR("radeon: failed to reserve object for unpinning it.\n");
+               return;
+       }
+       if (robj->rdev->fbdev_robj == robj) {
+               mutex_lock(&robj->rdev->fbdev_info->lock);
+               radeon_object_kunmap(robj);
+       }
+       flags = robj->tobj.mem.placement;
+       robj->tobj.proposed_placement = flags & ~TTM_PL_FLAG_NO_EVICT;
+       r = ttm_buffer_object_validate(&robj->tobj,
+                                      robj->tobj.proposed_placement,
+                                      false, false);
+       if (unlikely(r != 0)) {
+               DRM_ERROR("radeon: failed to unpin buffer.\n");
+       }
+       radeon_object_unreserve(robj);
+       if (robj->rdev->fbdev_robj == robj) {
+               if (!r) {
+                       r = radeon_object_kmap(robj, &fbptr);
+               }
+               if (!r) {
+                       robj->rdev->fbdev_info->screen_base = fbptr;
+                       robj->rdev->fbdev_info->fix.smem_start = (unsigned long)fbptr;
+               }
+               mutex_unlock(&robj->rdev->fbdev_info->lock);
+       }
+}
+
+int radeon_object_wait(struct radeon_object *robj)
+{
+       int r = 0;
+
+       /* FIXME: should use block reservation instead */
+       r = radeon_object_reserve(robj, true);
+       if (unlikely(r != 0)) {
+               DRM_ERROR("radeon: failed to reserve object for waiting.\n");
+               return r;
+       }
+       spin_lock(&robj->tobj.lock);
+       if (robj->tobj.sync_obj) {
+               r = ttm_bo_wait(&robj->tobj, true, false, false);
+       }
+       spin_unlock(&robj->tobj.lock);
+       radeon_object_unreserve(robj);
+       return r;
+}
+
+int radeon_object_evict_vram(struct radeon_device *rdev)
+{
+       if (rdev->flags & RADEON_IS_IGP) {
+               /* Useless to evict on IGP chips */
+               return 0;
+       }
+       return ttm_bo_evict_mm(&rdev->mman.bdev, TTM_PL_VRAM);
+}
+
+void radeon_object_force_delete(struct radeon_device *rdev)
+{
+       struct radeon_object *robj, *n;
+       struct drm_gem_object *gobj;
+
+       if (list_empty(&rdev->gem.objects)) {
+               return;
+       }
+       DRM_ERROR("Userspace still has active objects !\n");
+       list_for_each_entry_safe(robj, n, &rdev->gem.objects, list) {
+               mutex_lock(&rdev->ddev->struct_mutex);
+               gobj = robj->gobj;
+               DRM_ERROR("Force free for (%p,%p,%lu,%lu)\n",
+                         gobj, robj, (unsigned long)gobj->size,
+                         *((unsigned long *)&gobj->refcount));
+               list_del_init(&robj->list);
+               radeon_object_unref(&robj);
+               gobj->driver_private = NULL;
+               drm_gem_object_unreference(gobj);
+               mutex_unlock(&rdev->ddev->struct_mutex);
+       }
+}
+
+int radeon_object_init(struct radeon_device *rdev)
+{
+       return radeon_ttm_init(rdev);
+}
+
+void radeon_object_fini(struct radeon_device *rdev)
+{
+       radeon_ttm_fini(rdev);
+}
+
+void radeon_object_list_add_object(struct radeon_object_list *lobj,
+                                  struct list_head *head)
+{
+       if (lobj->wdomain) {
+               list_add(&lobj->list, head);
+       } else {
+               list_add_tail(&lobj->list, head);
+       }
+}
+
+int radeon_object_list_reserve(struct list_head *head)
+{
+       struct radeon_object_list *lobj;
+       struct list_head *i;
+       int r;
+
+       list_for_each(i, head) {
+               lobj = list_entry(i, struct radeon_object_list, list);
+               if (!lobj->robj->pin_count) {
+                       r = radeon_object_reserve(lobj->robj, true);
+                       if (unlikely(r != 0)) {
+                               DRM_ERROR("radeon: failed to reserve object.\n");
+                               return r;
+                       }
+               } else {
+               }
+       }
+       return 0;
+}
+
+void radeon_object_list_unreserve(struct list_head *head)
+{
+       struct radeon_object_list *lobj;
+       struct list_head *i;
+
+       list_for_each(i, head) {
+               lobj = list_entry(i, struct radeon_object_list, list);
+               if (!lobj->robj->pin_count) {
+                       radeon_object_unreserve(lobj->robj);
+               } else {
+               }
+       }
+}
+
+int radeon_object_list_validate(struct list_head *head, void *fence)
+{
+       struct radeon_object_list *lobj;
+       struct radeon_object *robj;
+       struct radeon_fence *old_fence = NULL;
+       struct list_head *i;
+       uint32_t flags;
+       int r;
+
+       r = radeon_object_list_reserve(head);
+       if (unlikely(r != 0)) {
+               radeon_object_list_unreserve(head);
+               return r;
+       }
+       list_for_each(i, head) {
+               lobj = list_entry(i, struct radeon_object_list, list);
+               robj = lobj->robj;
+               if (lobj->wdomain) {
+                       flags = radeon_object_flags_from_domain(lobj->wdomain);
+                       flags |= TTM_PL_FLAG_TT;
+               } else {
+                       flags = radeon_object_flags_from_domain(lobj->rdomain);
+                       flags |= TTM_PL_FLAG_TT;
+                       flags |= TTM_PL_FLAG_VRAM;
+               }
+               if (!robj->pin_count) {
+                       robj->tobj.proposed_placement = flags | TTM_PL_MASK_CACHING;
+                       r = ttm_buffer_object_validate(&robj->tobj,
+                                                      robj->tobj.proposed_placement,
+                                                      true, false);
+                       if (unlikely(r)) {
+                               radeon_object_list_unreserve(head);
+                               DRM_ERROR("radeon: failed to validate.\n");
+                               return r;
+                       }
+                       radeon_object_gpu_addr(robj);
+               }
+               lobj->gpu_offset = robj->gpu_addr;
+               if (fence) {
+                       old_fence = (struct radeon_fence *)robj->tobj.sync_obj;
+                       robj->tobj.sync_obj = radeon_fence_ref(fence);
+                       robj->tobj.sync_obj_arg = NULL;
+               }
+               if (old_fence) {
+                       radeon_fence_unref(&old_fence);
+               }
+       }
+       return 0;
+}
+
+void radeon_object_list_unvalidate(struct list_head *head)
+{
+       struct radeon_object_list *lobj;
+       struct radeon_fence *old_fence = NULL;
+       struct list_head *i;
+
+       list_for_each(i, head) {
+               lobj = list_entry(i, struct radeon_object_list, list);
+               old_fence = (struct radeon_fence *)lobj->robj->tobj.sync_obj;
+               lobj->robj->tobj.sync_obj = NULL;
+               if (old_fence) {
+                       radeon_fence_unref(&old_fence);
+               }
+       }
+       radeon_object_list_unreserve(head);
+}
+
+void radeon_object_list_clean(struct list_head *head)
+{
+       radeon_object_list_unreserve(head);
+}
+
+int radeon_object_fbdev_mmap(struct radeon_object *robj,
+                            struct vm_area_struct *vma)
+{
+       return ttm_fbdev_mmap(vma, &robj->tobj);
+}
+
+unsigned long radeon_object_size(struct radeon_object *robj)
+{
+       return robj->tobj.num_pages << PAGE_SHIFT;
+}
diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h
new file mode 100644 (file)
index 0000000..473e477
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ *          Jerome Glisse
+ */
+#ifndef __RADEON_OBJECT_H__
+#define __RADEON_OBJECT_H__
+
+#include <ttm/ttm_bo_api.h>
+#include <ttm/ttm_bo_driver.h>
+#include <ttm/ttm_placement.h>
+#include <ttm/ttm_module.h>
+
+/*
+ * TTM.
+ */
+struct radeon_mman {
+       struct ttm_global_reference     mem_global_ref;
+       bool                            mem_global_referenced;
+       struct ttm_bo_device            bdev;
+};
+
+#endif
diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h
new file mode 100644 (file)
index 0000000..6d3d904
--- /dev/null
@@ -0,0 +1,3570 @@
+/*
+ * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
+ *                VA Linux Systems Inc., Fremont, California.
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation on the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR
+ * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * Authors:
+ *   Kevin E. Martin <martin@xfree86.org>
+ *   Rickard E. Faith <faith@valinux.com>
+ *   Alan Hourihane <alanh@fairlite.demon.co.uk>
+ *
+ * References:
+ *
+ * !!!! FIXME !!!!
+ *   RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical
+ *   Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April
+ *   1999.
+ *
+ * !!!! FIXME !!!!
+ *   RAGE 128 Software Development Manual (Technical Reference Manual P/N
+ *   SDK-G04000 Rev. 0.01), ATI Technologies: June 1999.
+ *
+ */
+
+/* !!!! FIXME !!!!  NOTE: THIS FILE HAS BEEN CONVERTED FROM r128_reg.h
+ * AND CONTAINS REGISTERS AND REGISTER DEFINITIONS THAT ARE NOT CORRECT
+ * ON THE RADEON.  A FULL AUDIT OF THIS CODE IS NEEDED!  */
+#ifndef _RADEON_REG_H_
+#define _RADEON_REG_H_
+
+#include "r300_reg.h"
+#include "r500_reg.h"
+#include "r600_reg.h"
+
+
+#define RADEON_MC_AGP_LOCATION         0x014c
+#define                RADEON_MC_AGP_START_MASK        0x0000FFFF
+#define                RADEON_MC_AGP_START_SHIFT       0
+#define                RADEON_MC_AGP_TOP_MASK          0xFFFF0000
+#define                RADEON_MC_AGP_TOP_SHIFT         16
+#define RADEON_MC_FB_LOCATION          0x0148
+#define                RADEON_MC_FB_START_MASK         0x0000FFFF
+#define                RADEON_MC_FB_START_SHIFT        0
+#define                RADEON_MC_FB_TOP_MASK           0xFFFF0000
+#define                RADEON_MC_FB_TOP_SHIFT          16
+#define RADEON_AGP_BASE_2              0x015c /* r200+ only */
+#define RADEON_AGP_BASE                        0x0170
+
+#define ATI_DATATYPE_VQ                                0
+#define ATI_DATATYPE_CI4                       1
+#define ATI_DATATYPE_CI8                       2
+#define ATI_DATATYPE_ARGB1555                  3
+#define ATI_DATATYPE_RGB565                    4
+#define ATI_DATATYPE_RGB888                    5
+#define ATI_DATATYPE_ARGB8888                  6
+#define ATI_DATATYPE_RGB332                    7
+#define ATI_DATATYPE_Y8                                8
+#define ATI_DATATYPE_RGB8                      9
+#define ATI_DATATYPE_CI16                      10
+#define ATI_DATATYPE_VYUY_422                  11
+#define ATI_DATATYPE_YVYU_422                  12
+#define ATI_DATATYPE_AYUV_444                  14
+#define ATI_DATATYPE_ARGB4444                  15
+
+                               /* Registers for 2D/Video/Overlay */
+#define RADEON_ADAPTER_ID                   0x0f2c /* PCI */
+#define RADEON_AGP_BASE                     0x0170
+#define RADEON_AGP_CNTL                     0x0174
+#       define RADEON_AGP_APER_SIZE_256MB   (0x00 << 0)
+#       define RADEON_AGP_APER_SIZE_128MB   (0x20 << 0)
+#       define RADEON_AGP_APER_SIZE_64MB    (0x30 << 0)
+#       define RADEON_AGP_APER_SIZE_32MB    (0x38 << 0)
+#       define RADEON_AGP_APER_SIZE_16MB    (0x3c << 0)
+#       define RADEON_AGP_APER_SIZE_8MB     (0x3e << 0)
+#       define RADEON_AGP_APER_SIZE_4MB     (0x3f << 0)
+#       define RADEON_AGP_APER_SIZE_MASK    (0x3f << 0)
+#define RADEON_STATUS_PCI_CONFIG            0x06
+#       define RADEON_CAP_LIST              0x100000
+#define RADEON_CAPABILITIES_PTR_PCI_CONFIG  0x34 /* offset in PCI config*/
+#       define RADEON_CAP_PTR_MASK          0xfc /* mask off reserved bits of CAP_PTR */
+#       define RADEON_CAP_ID_NULL           0x00 /* End of capability list */
+#       define RADEON_CAP_ID_AGP            0x02 /* AGP capability ID */
+#       define RADEON_CAP_ID_EXP            0x10 /* PCI Express */
+#define RADEON_AGP_COMMAND                  0x0f60 /* PCI */
+#define RADEON_AGP_COMMAND_PCI_CONFIG       0x0060 /* offset in PCI config*/
+#       define RADEON_AGP_ENABLE            (1<<8)
+#define RADEON_AGP_PLL_CNTL                 0x000b /* PLL */
+#define RADEON_AGP_STATUS                   0x0f5c /* PCI */
+#       define RADEON_AGP_1X_MODE           0x01
+#       define RADEON_AGP_2X_MODE           0x02
+#       define RADEON_AGP_4X_MODE           0x04
+#       define RADEON_AGP_FW_MODE           0x10
+#       define RADEON_AGP_MODE_MASK         0x17
+#       define RADEON_AGPv3_MODE            0x08
+#       define RADEON_AGPv3_4X_MODE         0x01
+#       define RADEON_AGPv3_8X_MODE         0x02
+#define RADEON_ATTRDR                       0x03c1 /* VGA */
+#define RADEON_ATTRDW                       0x03c0 /* VGA */
+#define RADEON_ATTRX                        0x03c0 /* VGA */
+#define RADEON_AUX_SC_CNTL                  0x1660
+#       define RADEON_AUX1_SC_EN            (1 << 0)
+#       define RADEON_AUX1_SC_MODE_OR       (0 << 1)
+#       define RADEON_AUX1_SC_MODE_NAND     (1 << 1)
+#       define RADEON_AUX2_SC_EN            (1 << 2)
+#       define RADEON_AUX2_SC_MODE_OR       (0 << 3)
+#       define RADEON_AUX2_SC_MODE_NAND     (1 << 3)
+#       define RADEON_AUX3_SC_EN            (1 << 4)
+#       define RADEON_AUX3_SC_MODE_OR       (0 << 5)
+#       define RADEON_AUX3_SC_MODE_NAND     (1 << 5)
+#define RADEON_AUX1_SC_BOTTOM               0x1670
+#define RADEON_AUX1_SC_LEFT                 0x1664
+#define RADEON_AUX1_SC_RIGHT                0x1668
+#define RADEON_AUX1_SC_TOP                  0x166c
+#define RADEON_AUX2_SC_BOTTOM               0x1680
+#define RADEON_AUX2_SC_LEFT                 0x1674
+#define RADEON_AUX2_SC_RIGHT                0x1678
+#define RADEON_AUX2_SC_TOP                  0x167c
+#define RADEON_AUX3_SC_BOTTOM               0x1690
+#define RADEON_AUX3_SC_LEFT                 0x1684
+#define RADEON_AUX3_SC_RIGHT                0x1688
+#define RADEON_AUX3_SC_TOP                  0x168c
+#define RADEON_AUX_WINDOW_HORZ_CNTL         0x02d8
+#define RADEON_AUX_WINDOW_VERT_CNTL         0x02dc
+
+#define RADEON_BASE_CODE                    0x0f0b
+#define RADEON_BIOS_0_SCRATCH               0x0010
+#       define RADEON_FP_PANEL_SCALABLE     (1 << 16)
+#       define RADEON_FP_PANEL_SCALE_EN     (1 << 17)
+#       define RADEON_FP_CHIP_SCALE_EN      (1 << 18)
+#       define RADEON_DRIVER_BRIGHTNESS_EN  (1 << 26)
+#       define RADEON_DISPLAY_ROT_MASK      (3 << 28)
+#       define RADEON_DISPLAY_ROT_00        (0 << 28)
+#       define RADEON_DISPLAY_ROT_90        (1 << 28)
+#       define RADEON_DISPLAY_ROT_180       (2 << 28)
+#       define RADEON_DISPLAY_ROT_270       (3 << 28)
+#define RADEON_BIOS_1_SCRATCH               0x0014
+#define RADEON_BIOS_2_SCRATCH               0x0018
+#define RADEON_BIOS_3_SCRATCH               0x001c
+#define RADEON_BIOS_4_SCRATCH               0x0020
+#       define RADEON_CRT1_ATTACHED_MASK    (3 << 0)
+#       define RADEON_CRT1_ATTACHED_MONO    (1 << 0)
+#       define RADEON_CRT1_ATTACHED_COLOR   (2 << 0)
+#       define RADEON_LCD1_ATTACHED         (1 << 2)
+#       define RADEON_DFP1_ATTACHED         (1 << 3)
+#       define RADEON_TV1_ATTACHED_MASK     (3 << 4)
+#       define RADEON_TV1_ATTACHED_COMP     (1 << 4)
+#       define RADEON_TV1_ATTACHED_SVIDEO   (2 << 4)
+#       define RADEON_CRT2_ATTACHED_MASK    (3 << 8)
+#       define RADEON_CRT2_ATTACHED_MONO    (1 << 8)
+#       define RADEON_CRT2_ATTACHED_COLOR   (2 << 8)
+#       define RADEON_DFP2_ATTACHED         (1 << 11)
+#define RADEON_BIOS_5_SCRATCH               0x0024
+#       define RADEON_LCD1_ON               (1 << 0)
+#       define RADEON_CRT1_ON               (1 << 1)
+#       define RADEON_TV1_ON                (1 << 2)
+#       define RADEON_DFP1_ON               (1 << 3)
+#       define RADEON_CRT2_ON               (1 << 5)
+#       define RADEON_CV1_ON                (1 << 6)
+#       define RADEON_DFP2_ON               (1 << 7)
+#       define RADEON_LCD1_CRTC_MASK        (1 << 8)
+#       define RADEON_LCD1_CRTC_SHIFT       8
+#       define RADEON_CRT1_CRTC_MASK        (1 << 9)
+#       define RADEON_CRT1_CRTC_SHIFT       9
+#       define RADEON_TV1_CRTC_MASK         (1 << 10)
+#       define RADEON_TV1_CRTC_SHIFT        10
+#       define RADEON_DFP1_CRTC_MASK        (1 << 11)
+#       define RADEON_DFP1_CRTC_SHIFT       11
+#       define RADEON_CRT2_CRTC_MASK        (1 << 12)
+#       define RADEON_CRT2_CRTC_SHIFT       12
+#       define RADEON_CV1_CRTC_MASK         (1 << 13)
+#       define RADEON_CV1_CRTC_SHIFT        13
+#       define RADEON_DFP2_CRTC_MASK        (1 << 14)
+#       define RADEON_DFP2_CRTC_SHIFT       14
+#       define RADEON_ACC_REQ_LCD1          (1 << 16)
+#       define RADEON_ACC_REQ_CRT1          (1 << 17)
+#       define RADEON_ACC_REQ_TV1           (1 << 18)
+#       define RADEON_ACC_REQ_DFP1          (1 << 19)
+#       define RADEON_ACC_REQ_CRT2          (1 << 21)
+#       define RADEON_ACC_REQ_TV2           (1 << 22)
+#       define RADEON_ACC_REQ_DFP2          (1 << 23)
+#define RADEON_BIOS_6_SCRATCH               0x0028
+#       define RADEON_ACC_MODE_CHANGE       (1 << 2)
+#       define RADEON_EXT_DESKTOP_MODE      (1 << 3)
+#       define RADEON_LCD_DPMS_ON           (1 << 20)
+#       define RADEON_CRT_DPMS_ON           (1 << 21)
+#       define RADEON_TV_DPMS_ON            (1 << 22)
+#       define RADEON_DFP_DPMS_ON           (1 << 23)
+#       define RADEON_DPMS_MASK             (3 << 24)
+#       define RADEON_DPMS_ON               (0 << 24)
+#       define RADEON_DPMS_STANDBY          (1 << 24)
+#       define RADEON_DPMS_SUSPEND          (2 << 24)
+#       define RADEON_DPMS_OFF              (3 << 24)
+#       define RADEON_SCREEN_BLANKING       (1 << 26)
+#       define RADEON_DRIVER_CRITICAL       (1 << 27)
+#       define RADEON_DISPLAY_SWITCHING_DIS (1 << 30)
+#define RADEON_BIOS_7_SCRATCH               0x002c
+#       define RADEON_SYS_HOTKEY            (1 << 10)
+#       define RADEON_DRV_LOADED            (1 << 12)
+#define RADEON_BIOS_ROM                     0x0f30 /* PCI */
+#define RADEON_BIST                         0x0f0f /* PCI */
+#define RADEON_BRUSH_DATA0                  0x1480
+#define RADEON_BRUSH_DATA1                  0x1484
+#define RADEON_BRUSH_DATA10                 0x14a8
+#define RADEON_BRUSH_DATA11                 0x14ac
+#define RADEON_BRUSH_DATA12                 0x14b0
+#define RADEON_BRUSH_DATA13                 0x14b4
+#define RADEON_BRUSH_DATA14                 0x14b8
+#define RADEON_BRUSH_DATA15                 0x14bc
+#define RADEON_BRUSH_DATA16                 0x14c0
+#define RADEON_BRUSH_DATA17                 0x14c4
+#define RADEON_BRUSH_DATA18                 0x14c8
+#define RADEON_BRUSH_DATA19                 0x14cc
+#define RADEON_BRUSH_DATA2                  0x1488
+#define RADEON_BRUSH_DATA20                 0x14d0
+#define RADEON_BRUSH_DATA21                 0x14d4
+#define RADEON_BRUSH_DATA22                 0x14d8
+#define RADEON_BRUSH_DATA23                 0x14dc
+#define RADEON_BRUSH_DATA24                 0x14e0
+#define RADEON_BRUSH_DATA25                 0x14e4
+#define RADEON_BRUSH_DATA26                 0x14e8
+#define RADEON_BRUSH_DATA27                 0x14ec
+#define RADEON_BRUSH_DATA28                 0x14f0
+#define RADEON_BRUSH_DATA29                 0x14f4
+#define RADEON_BRUSH_DATA3                  0x148c
+#define RADEON_BRUSH_DATA30                 0x14f8
+#define RADEON_BRUSH_DATA31                 0x14fc
+#define RADEON_BRUSH_DATA32                 0x1500
+#define RADEON_BRUSH_DATA33                 0x1504
+#define RADEON_BRUSH_DATA34                 0x1508
+#define RADEON_BRUSH_DATA35                 0x150c
+#define RADEON_BRUSH_DATA36                 0x1510
+#define RADEON_BRUSH_DATA37                 0x1514
+#define RADEON_BRUSH_DATA38                 0x1518
+#define RADEON_BRUSH_DATA39                 0x151c
+#define RADEON_BRUSH_DATA4                  0x1490
+#define RADEON_BRUSH_DATA40                 0x1520
+#define RADEON_BRUSH_DATA41                 0x1524
+#define RADEON_BRUSH_DATA42                 0x1528
+#define RADEON_BRUSH_DATA43                 0x152c
+#define RADEON_BRUSH_DATA44                 0x1530
+#define RADEON_BRUSH_DATA45                 0x1534
+#define RADEON_BRUSH_DATA46                 0x1538
+#define RADEON_BRUSH_DATA47                 0x153c
+#define RADEON_BRUSH_DATA48                 0x1540
+#define RADEON_BRUSH_DATA49                 0x1544
+#define RADEON_BRUSH_DATA5                  0x1494
+#define RADEON_BRUSH_DATA50                 0x1548
+#define RADEON_BRUSH_DATA51                 0x154c
+#define RADEON_BRUSH_DATA52                 0x1550
+#define RADEON_BRUSH_DATA53                 0x1554
+#define RADEON_BRUSH_DATA54                 0x1558
+#define RADEON_BRUSH_DATA55                 0x155c
+#define RADEON_BRUSH_DATA56                 0x1560
+#define RADEON_BRUSH_DATA57                 0x1564
+#define RADEON_BRUSH_DATA58                 0x1568
+#define RADEON_BRUSH_DATA59                 0x156c
+#define RADEON_BRUSH_DATA6                  0x1498
+#define RADEON_BRUSH_DATA60                 0x1570
+#define RADEON_BRUSH_DATA61                 0x1574
+#define RADEON_BRUSH_DATA62                 0x1578
+#define RADEON_BRUSH_DATA63                 0x157c
+#define RADEON_BRUSH_DATA7                  0x149c
+#define RADEON_BRUSH_DATA8                  0x14a0
+#define RADEON_BRUSH_DATA9                  0x14a4
+#define RADEON_BRUSH_SCALE                  0x1470
+#define RADEON_BRUSH_Y_X                    0x1474
+#define RADEON_BUS_CNTL                     0x0030
+#       define RADEON_BUS_MASTER_DIS         (1 << 6)
+#       define RADEON_BUS_BIOS_DIS_ROM       (1 << 12)
+#       define RADEON_BUS_RD_DISCARD_EN      (1 << 24)
+#       define RADEON_BUS_RD_ABORT_EN        (1 << 25)
+#       define RADEON_BUS_MSTR_DISCONNECT_EN (1 << 28)
+#       define RADEON_BUS_WRT_BURST          (1 << 29)
+#       define RADEON_BUS_READ_BURST         (1 << 30)
+#define RADEON_BUS_CNTL1                    0x0034
+#       define RADEON_BUS_WAIT_ON_LOCK_EN    (1 << 4)
+
+/* #define RADEON_PCIE_INDEX                   0x0030 */
+/* #define RADEON_PCIE_DATA                    0x0034 */
+#define RADEON_PCIE_LC_LINK_WIDTH_CNTL             0xa2 /* PCIE */
+#       define RADEON_PCIE_LC_LINK_WIDTH_SHIFT     0
+#       define RADEON_PCIE_LC_LINK_WIDTH_MASK      0x7
+#       define RADEON_PCIE_LC_LINK_WIDTH_X0        0
+#       define RADEON_PCIE_LC_LINK_WIDTH_X1        1
+#       define RADEON_PCIE_LC_LINK_WIDTH_X2        2
+#       define RADEON_PCIE_LC_LINK_WIDTH_X4        3
+#       define RADEON_PCIE_LC_LINK_WIDTH_X8        4
+#       define RADEON_PCIE_LC_LINK_WIDTH_X12       5
+#       define RADEON_PCIE_LC_LINK_WIDTH_X16       6
+#       define RADEON_PCIE_LC_LINK_WIDTH_RD_SHIFT  4
+#       define RADEON_PCIE_LC_LINK_WIDTH_RD_MASK   0x70
+#       define RADEON_PCIE_LC_RECONFIG_NOW         (1 << 8)
+#       define RADEON_PCIE_LC_RECONFIG_LATER       (1 << 9)
+#       define RADEON_PCIE_LC_SHORT_RECONFIG_EN    (1 << 10)
+
+#define RADEON_CACHE_CNTL                   0x1724
+#define RADEON_CACHE_LINE                   0x0f0c /* PCI */
+#define RADEON_CAPABILITIES_ID              0x0f50 /* PCI */
+#define RADEON_CAPABILITIES_PTR             0x0f34 /* PCI */
+#define RADEON_CLK_PIN_CNTL                 0x0001 /* PLL */
+#       define RADEON_DONT_USE_XTALIN       (1 << 4)
+#       define RADEON_SCLK_DYN_START_CNTL   (1 << 15)
+#define RADEON_CLOCK_CNTL_DATA              0x000c
+#define RADEON_CLOCK_CNTL_INDEX             0x0008
+#       define RADEON_PLL_WR_EN             (1 << 7)
+#       define RADEON_PLL_DIV_SEL           (3 << 8)
+#       define RADEON_PLL2_DIV_SEL_MASK     (~(3 << 8))
+#define RADEON_CLK_PWRMGT_CNTL              0x0014
+#       define RADEON_ENGIN_DYNCLK_MODE     (1 << 12)
+#       define RADEON_ACTIVE_HILO_LAT_MASK  (3 << 13)
+#       define RADEON_ACTIVE_HILO_LAT_SHIFT 13
+#       define RADEON_DISP_DYN_STOP_LAT_MASK (1 << 12)
+#       define RADEON_MC_BUSY               (1 << 16)
+#       define RADEON_DLL_READY             (1 << 19)
+#       define RADEON_CG_NO1_DEBUG_0        (1 << 24)
+#       define RADEON_CG_NO1_DEBUG_MASK     (0x1f << 24)
+#       define RADEON_DYN_STOP_MODE_MASK    (7 << 21)
+#       define RADEON_TVPLL_PWRMGT_OFF      (1 << 30)
+#       define RADEON_TVCLK_TURNOFF         (1 << 31)
+#define RADEON_PLL_PWRMGT_CNTL              0x0015 /* PLL */
+#       define RADEON_TCL_BYPASS_DISABLE    (1 << 20)
+#define RADEON_CLR_CMP_CLR_3D               0x1a24
+#define RADEON_CLR_CMP_CLR_DST              0x15c8
+#define RADEON_CLR_CMP_CLR_SRC              0x15c4
+#define RADEON_CLR_CMP_CNTL                 0x15c0
+#       define RADEON_SRC_CMP_EQ_COLOR      (4 <<  0)
+#       define RADEON_SRC_CMP_NEQ_COLOR     (5 <<  0)
+#       define RADEON_CLR_CMP_SRC_SOURCE    (1 << 24)
+#define RADEON_CLR_CMP_MASK                 0x15cc
+#       define RADEON_CLR_CMP_MSK           0xffffffff
+#define RADEON_CLR_CMP_MASK_3D              0x1A28
+#define RADEON_COMMAND                      0x0f04 /* PCI */
+#define RADEON_COMPOSITE_SHADOW_ID          0x1a0c
+#define RADEON_CONFIG_APER_0_BASE           0x0100
+#define RADEON_CONFIG_APER_1_BASE           0x0104
+#define RADEON_CONFIG_APER_SIZE             0x0108
+#define RADEON_CONFIG_BONDS                 0x00e8
+#define RADEON_CONFIG_CNTL                  0x00e0
+#       define RADEON_CFG_ATI_REV_A11       (0   << 16)
+#       define RADEON_CFG_ATI_REV_A12       (1   << 16)
+#       define RADEON_CFG_ATI_REV_A13       (2   << 16)
+#       define RADEON_CFG_ATI_REV_ID_MASK   (0xf << 16)
+#define RADEON_CONFIG_MEMSIZE               0x00f8
+#define RADEON_CONFIG_MEMSIZE_EMBEDDED      0x0114
+#define RADEON_CONFIG_REG_1_BASE            0x010c
+#define RADEON_CONFIG_REG_APER_SIZE         0x0110
+#define RADEON_CONFIG_XSTRAP                0x00e4
+#define RADEON_CONSTANT_COLOR_C             0x1d34
+#       define RADEON_CONSTANT_COLOR_MASK   0x00ffffff
+#       define RADEON_CONSTANT_COLOR_ONE    0x00ffffff
+#       define RADEON_CONSTANT_COLOR_ZERO   0x00000000
+#define RADEON_CRC_CMDFIFO_ADDR             0x0740
+#define RADEON_CRC_CMDFIFO_DOUT             0x0744
+#define RADEON_GRPH_BUFFER_CNTL             0x02f0
+#       define RADEON_GRPH_START_REQ_MASK          (0x7f)
+#       define RADEON_GRPH_START_REQ_SHIFT         0
+#       define RADEON_GRPH_STOP_REQ_MASK           (0x7f<<8)
+#       define RADEON_GRPH_STOP_REQ_SHIFT          8
+#       define RADEON_GRPH_CRITICAL_POINT_MASK     (0x7f<<16)
+#       define RADEON_GRPH_CRITICAL_POINT_SHIFT    16
+#       define RADEON_GRPH_CRITICAL_CNTL           (1<<28)
+#       define RADEON_GRPH_BUFFER_SIZE             (1<<29)
+#       define RADEON_GRPH_CRITICAL_AT_SOF         (1<<30)
+#       define RADEON_GRPH_STOP_CNTL               (1<<31)
+#define RADEON_GRPH2_BUFFER_CNTL            0x03f0
+#       define RADEON_GRPH2_START_REQ_MASK         (0x7f)
+#       define RADEON_GRPH2_START_REQ_SHIFT         0
+#       define RADEON_GRPH2_STOP_REQ_MASK          (0x7f<<8)
+#       define RADEON_GRPH2_STOP_REQ_SHIFT         8
+#       define RADEON_GRPH2_CRITICAL_POINT_MASK    (0x7f<<16)
+#       define RADEON_GRPH2_CRITICAL_POINT_SHIFT   16
+#       define RADEON_GRPH2_CRITICAL_CNTL          (1<<28)
+#       define RADEON_GRPH2_BUFFER_SIZE            (1<<29)
+#       define RADEON_GRPH2_CRITICAL_AT_SOF        (1<<30)
+#       define RADEON_GRPH2_STOP_CNTL              (1<<31)
+#define RADEON_CRTC_CRNT_FRAME              0x0214
+#define RADEON_CRTC_EXT_CNTL                0x0054
+#       define RADEON_CRTC_VGA_XOVERSCAN    (1 <<  0)
+#       define RADEON_VGA_ATI_LINEAR        (1 <<  3)
+#       define RADEON_XCRT_CNT_EN           (1 <<  6)
+#       define RADEON_CRTC_HSYNC_DIS        (1 <<  8)
+#       define RADEON_CRTC_VSYNC_DIS        (1 <<  9)
+#       define RADEON_CRTC_DISPLAY_DIS      (1 << 10)
+#       define RADEON_CRTC_SYNC_TRISTAT     (1 << 11)
+#       define RADEON_CRTC_CRT_ON           (1 << 15)
+#define RADEON_CRTC_EXT_CNTL_DPMS_BYTE      0x0055
+#       define RADEON_CRTC_HSYNC_DIS_BYTE   (1 <<  0)
+#       define RADEON_CRTC_VSYNC_DIS_BYTE   (1 <<  1)
+#       define RADEON_CRTC_DISPLAY_DIS_BYTE (1 <<  2)
+#define RADEON_CRTC_GEN_CNTL                0x0050
+#       define RADEON_CRTC_DBL_SCAN_EN      (1 <<  0)
+#       define RADEON_CRTC_INTERLACE_EN     (1 <<  1)
+#       define RADEON_CRTC_CSYNC_EN         (1 <<  4)
+#       define RADEON_CRTC_ICON_EN          (1 << 15)
+#       define RADEON_CRTC_CUR_EN           (1 << 16)
+#       define RADEON_CRTC_CUR_MODE_MASK    (7 << 20)
+#       define RADEON_CRTC_CUR_MODE_SHIFT   20
+#       define RADEON_CRTC_CUR_MODE_MONO    0
+#       define RADEON_CRTC_CUR_MODE_24BPP   2
+#       define RADEON_CRTC_EXT_DISP_EN      (1 << 24)
+#       define RADEON_CRTC_EN               (1 << 25)
+#       define RADEON_CRTC_DISP_REQ_EN_B    (1 << 26)
+#define RADEON_CRTC2_GEN_CNTL               0x03f8
+#       define RADEON_CRTC2_DBL_SCAN_EN     (1 <<  0)
+#       define RADEON_CRTC2_INTERLACE_EN    (1 <<  1)
+#       define RADEON_CRTC2_SYNC_TRISTAT    (1 <<  4)
+#       define RADEON_CRTC2_HSYNC_TRISTAT   (1 <<  5)
+#       define RADEON_CRTC2_VSYNC_TRISTAT   (1 <<  6)
+#       define RADEON_CRTC2_CRT2_ON         (1 <<  7)
+#       define RADEON_CRTC2_PIX_WIDTH_SHIFT 8
+#       define RADEON_CRTC2_PIX_WIDTH_MASK  (0xf << 8)
+#       define RADEON_CRTC2_ICON_EN         (1 << 15)
+#       define RADEON_CRTC2_CUR_EN          (1 << 16)
+#       define RADEON_CRTC2_CUR_MODE_MASK   (7 << 20)
+#       define RADEON_CRTC2_DISP_DIS        (1 << 23)
+#       define RADEON_CRTC2_EN              (1 << 25)
+#       define RADEON_CRTC2_DISP_REQ_EN_B   (1 << 26)
+#       define RADEON_CRTC2_CSYNC_EN        (1 << 27)
+#       define RADEON_CRTC2_HSYNC_DIS       (1 << 28)
+#       define RADEON_CRTC2_VSYNC_DIS       (1 << 29)
+#define RADEON_CRTC_MORE_CNTL               0x27c
+#       define RADEON_CRTC_AUTO_HORZ_CENTER_EN (1<<2)
+#       define RADEON_CRTC_AUTO_VERT_CENTER_EN (1<<3)
+#       define RADEON_CRTC_H_CUTOFF_ACTIVE_EN (1<<4)
+#       define RADEON_CRTC_V_CUTOFF_ACTIVE_EN (1<<5)
+#define RADEON_CRTC_GUI_TRIG_VLINE          0x0218
+#define RADEON_CRTC_H_SYNC_STRT_WID         0x0204
+#       define RADEON_CRTC_H_SYNC_STRT_PIX        (0x07  <<  0)
+#       define RADEON_CRTC_H_SYNC_STRT_CHAR       (0x3ff <<  3)
+#       define RADEON_CRTC_H_SYNC_STRT_CHAR_SHIFT 3
+#       define RADEON_CRTC_H_SYNC_WID             (0x3f  << 16)
+#       define RADEON_CRTC_H_SYNC_WID_SHIFT       16
+#       define RADEON_CRTC_H_SYNC_POL             (1     << 23)
+#define RADEON_CRTC2_H_SYNC_STRT_WID        0x0304
+#       define RADEON_CRTC2_H_SYNC_STRT_PIX        (0x07  <<  0)
+#       define RADEON_CRTC2_H_SYNC_STRT_CHAR       (0x3ff <<  3)
+#       define RADEON_CRTC2_H_SYNC_STRT_CHAR_SHIFT 3
+#       define RADEON_CRTC2_H_SYNC_WID             (0x3f  << 16)
+#       define RADEON_CRTC2_H_SYNC_WID_SHIFT       16
+#       define RADEON_CRTC2_H_SYNC_POL             (1     << 23)
+#define RADEON_CRTC_H_TOTAL_DISP            0x0200
+#       define RADEON_CRTC_H_TOTAL          (0x03ff << 0)
+#       define RADEON_CRTC_H_TOTAL_SHIFT    0
+#       define RADEON_CRTC_H_DISP           (0x01ff << 16)
+#       define RADEON_CRTC_H_DISP_SHIFT     16
+#define RADEON_CRTC2_H_TOTAL_DISP           0x0300
+#       define RADEON_CRTC2_H_TOTAL         (0x03ff << 0)
+#       define RADEON_CRTC2_H_TOTAL_SHIFT   0
+#       define RADEON_CRTC2_H_DISP          (0x01ff << 16)
+#       define RADEON_CRTC2_H_DISP_SHIFT    16
+
+#define RADEON_CRTC_OFFSET_RIGHT           0x0220
+#define RADEON_CRTC_OFFSET                  0x0224
+#      define RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET (1<<30)
+#      define RADEON_CRTC_OFFSET__OFFSET_LOCK     (1<<31)
+
+#define RADEON_CRTC2_OFFSET                 0x0324
+#      define RADEON_CRTC2_OFFSET__GUI_TRIG_OFFSET (1<<30)
+#      define RADEON_CRTC2_OFFSET__OFFSET_LOCK     (1<<31)
+#define RADEON_CRTC_OFFSET_CNTL             0x0228
+#       define RADEON_CRTC_TILE_LINE_SHIFT              0
+#       define RADEON_CRTC_TILE_LINE_RIGHT_SHIFT        4
+#      define R300_CRTC_X_Y_MODE_EN_RIGHT              (1 << 6)
+#      define R300_CRTC_MICRO_TILE_BUFFER_RIGHT_MASK   (3 << 7)
+#      define R300_CRTC_MICRO_TILE_BUFFER_RIGHT_AUTO   (0 << 7)
+#      define R300_CRTC_MICRO_TILE_BUFFER_RIGHT_SINGLE (1 << 7)
+#      define R300_CRTC_MICRO_TILE_BUFFER_RIGHT_DOUBLE (2 << 7)
+#      define R300_CRTC_MICRO_TILE_BUFFER_RIGHT_DIS    (3 << 7)
+#      define R300_CRTC_X_Y_MODE_EN                    (1 << 9)
+#      define R300_CRTC_MICRO_TILE_BUFFER_MASK         (3 << 10)
+#      define R300_CRTC_MICRO_TILE_BUFFER_AUTO         (0 << 10)
+#      define R300_CRTC_MICRO_TILE_BUFFER_SINGLE       (1 << 10)
+#      define R300_CRTC_MICRO_TILE_BUFFER_DOUBLE       (2 << 10)
+#      define R300_CRTC_MICRO_TILE_BUFFER_DIS          (3 << 10)
+#      define R300_CRTC_MICRO_TILE_EN_RIGHT            (1 << 12)
+#      define R300_CRTC_MICRO_TILE_EN                  (1 << 13)
+#      define R300_CRTC_MACRO_TILE_EN_RIGHT            (1 << 14)
+#       define R300_CRTC_MACRO_TILE_EN                  (1 << 15)
+#       define RADEON_CRTC_TILE_EN_RIGHT                (1 << 14)
+#       define RADEON_CRTC_TILE_EN                      (1 << 15)
+#       define RADEON_CRTC_OFFSET_FLIP_CNTL             (1 << 16)
+#       define RADEON_CRTC_STEREO_OFFSET_EN             (1 << 17)
+
+#define R300_CRTC_TILE_X0_Y0               0x0350
+#define R300_CRTC2_TILE_X0_Y0              0x0358
+
+#define RADEON_CRTC2_OFFSET_CNTL            0x0328
+#       define RADEON_CRTC2_OFFSET_FLIP_CNTL (1 << 16)
+#       define RADEON_CRTC2_TILE_EN         (1 << 15)
+#define RADEON_CRTC_PITCH                   0x022c
+#      define RADEON_CRTC_PITCH__SHIFT          0
+#      define RADEON_CRTC_PITCH__RIGHT_SHIFT   16
+
+#define RADEON_CRTC2_PITCH                  0x032c
+#define RADEON_CRTC_STATUS                  0x005c
+#       define RADEON_CRTC_VBLANK_SAVE      (1 <<  1)
+#       define RADEON_CRTC_VBLANK_SAVE_CLEAR  (1 <<  1)
+#define RADEON_CRTC2_STATUS                  0x03fc
+#       define RADEON_CRTC2_VBLANK_SAVE      (1 <<  1)
+#       define RADEON_CRTC2_VBLANK_SAVE_CLEAR  (1 <<  1)
+#define RADEON_CRTC_V_SYNC_STRT_WID         0x020c
+#       define RADEON_CRTC_V_SYNC_STRT        (0x7ff <<  0)
+#       define RADEON_CRTC_V_SYNC_STRT_SHIFT  0
+#       define RADEON_CRTC_V_SYNC_WID         (0x1f  << 16)
+#       define RADEON_CRTC_V_SYNC_WID_SHIFT   16
+#       define RADEON_CRTC_V_SYNC_POL         (1     << 23)
+#define RADEON_CRTC2_V_SYNC_STRT_WID        0x030c
+#       define RADEON_CRTC2_V_SYNC_STRT       (0x7ff <<  0)
+#       define RADEON_CRTC2_V_SYNC_STRT_SHIFT 0
+#       define RADEON_CRTC2_V_SYNC_WID        (0x1f  << 16)
+#       define RADEON_CRTC2_V_SYNC_WID_SHIFT  16
+#       define RADEON_CRTC2_V_SYNC_POL        (1     << 23)
+#define RADEON_CRTC_V_TOTAL_DISP            0x0208
+#       define RADEON_CRTC_V_TOTAL          (0x07ff << 0)
+#       define RADEON_CRTC_V_TOTAL_SHIFT    0
+#       define RADEON_CRTC_V_DISP           (0x07ff << 16)
+#       define RADEON_CRTC_V_DISP_SHIFT     16
+#define RADEON_CRTC2_V_TOTAL_DISP           0x0308
+#       define RADEON_CRTC2_V_TOTAL         (0x07ff << 0)
+#       define RADEON_CRTC2_V_TOTAL_SHIFT   0
+#       define RADEON_CRTC2_V_DISP          (0x07ff << 16)
+#       define RADEON_CRTC2_V_DISP_SHIFT    16
+#define RADEON_CRTC_VLINE_CRNT_VLINE        0x0210
+#       define RADEON_CRTC_CRNT_VLINE_MASK  (0x7ff << 16)
+#define RADEON_CRTC2_CRNT_FRAME             0x0314
+#define RADEON_CRTC2_GUI_TRIG_VLINE         0x0318
+#define RADEON_CRTC2_STATUS                 0x03fc
+#define RADEON_CRTC2_VLINE_CRNT_VLINE       0x0310
+#define RADEON_CRTC8_DATA                   0x03d5 /* VGA, 0x3b5 */
+#define RADEON_CRTC8_IDX                    0x03d4 /* VGA, 0x3b4 */
+#define RADEON_CUR_CLR0                     0x026c
+#define RADEON_CUR_CLR1                     0x0270
+#define RADEON_CUR_HORZ_VERT_OFF            0x0268
+#define RADEON_CUR_HORZ_VERT_POSN           0x0264
+#define RADEON_CUR_OFFSET                   0x0260
+#       define RADEON_CUR_LOCK              (1 << 31)
+#define RADEON_CUR2_CLR0                    0x036c
+#define RADEON_CUR2_CLR1                    0x0370
+#define RADEON_CUR2_HORZ_VERT_OFF           0x0368
+#define RADEON_CUR2_HORZ_VERT_POSN          0x0364
+#define RADEON_CUR2_OFFSET                  0x0360
+#       define RADEON_CUR2_LOCK             (1 << 31)
+
+#define RADEON_DAC_CNTL                     0x0058
+#       define RADEON_DAC_RANGE_CNTL        (3 <<  0)
+#       define RADEON_DAC_RANGE_CNTL_PS2    (2 <<  0)
+#       define RADEON_DAC_RANGE_CNTL_MASK   0x03
+#       define RADEON_DAC_BLANKING          (1 <<  2)
+#       define RADEON_DAC_CMP_EN            (1 <<  3)
+#       define RADEON_DAC_CMP_OUTPUT        (1 <<  7)
+#       define RADEON_DAC_8BIT_EN           (1 <<  8)
+#       define RADEON_DAC_TVO_EN            (1 << 10)
+#       define RADEON_DAC_VGA_ADR_EN        (1 << 13)
+#       define RADEON_DAC_PDWN              (1 << 15)
+#       define RADEON_DAC_MASK_ALL          (0xff << 24)
+#define RADEON_DAC_CNTL2                    0x007c
+#       define RADEON_DAC2_TV_CLK_SEL       (0 <<  1)
+#       define RADEON_DAC2_DAC_CLK_SEL      (1 <<  0)
+#       define RADEON_DAC2_DAC2_CLK_SEL     (1 <<  1)
+#       define RADEON_DAC2_PALETTE_ACC_CTL  (1 <<  5)
+#       define RADEON_DAC2_CMP_EN           (1 <<  7)
+#       define RADEON_DAC2_CMP_OUT_R        (1 <<  8)
+#       define RADEON_DAC2_CMP_OUT_G        (1 <<  9)
+#       define RADEON_DAC2_CMP_OUT_B        (1 << 10)
+#       define RADEON_DAC2_CMP_OUTPUT       (1 << 11)
+#define RADEON_DAC_EXT_CNTL                 0x0280
+#       define RADEON_DAC2_FORCE_BLANK_OFF_EN (1 << 0)
+#       define RADEON_DAC2_FORCE_DATA_EN      (1 << 1)
+#       define RADEON_DAC_FORCE_BLANK_OFF_EN  (1 << 4)
+#       define RADEON_DAC_FORCE_DATA_EN       (1 << 5)
+#       define RADEON_DAC_FORCE_DATA_SEL_MASK (3 << 6)
+#       define RADEON_DAC_FORCE_DATA_SEL_R    (0 << 6)
+#       define RADEON_DAC_FORCE_DATA_SEL_G    (1 << 6)
+#       define RADEON_DAC_FORCE_DATA_SEL_B    (2 << 6)
+#       define RADEON_DAC_FORCE_DATA_SEL_RGB  (3 << 6)
+#       define RADEON_DAC_FORCE_DATA_MASK   0x0003ff00
+#       define RADEON_DAC_FORCE_DATA_SHIFT  8
+#define RADEON_DAC_MACRO_CNTL               0x0d04
+#       define RADEON_DAC_PDWN_R            (1 << 16)
+#       define RADEON_DAC_PDWN_G            (1 << 17)
+#       define RADEON_DAC_PDWN_B            (1 << 18)
+#define RADEON_DISP_PWR_MAN                 0x0d08
+#       define RADEON_DISP_PWR_MAN_D3_CRTC_EN      (1 << 0)
+#       define RADEON_DISP_PWR_MAN_D3_CRTC2_EN     (1 << 4)
+#       define RADEON_DISP_PWR_MAN_DPMS_ON  (0 << 8)
+#       define RADEON_DISP_PWR_MAN_DPMS_STANDBY    (1 << 8)
+#       define RADEON_DISP_PWR_MAN_DPMS_SUSPEND    (2 << 8)
+#       define RADEON_DISP_PWR_MAN_DPMS_OFF (3 << 8)
+#       define RADEON_DISP_D3_RST           (1 << 16)
+#       define RADEON_DISP_D3_REG_RST       (1 << 17)
+#       define RADEON_DISP_D3_GRPH_RST      (1 << 18)
+#       define RADEON_DISP_D3_SUBPIC_RST    (1 << 19)
+#       define RADEON_DISP_D3_OV0_RST       (1 << 20)
+#       define RADEON_DISP_D1D2_GRPH_RST    (1 << 21)
+#       define RADEON_DISP_D1D2_SUBPIC_RST  (1 << 22)
+#       define RADEON_DISP_D1D2_OV0_RST     (1 << 23)
+#       define RADEON_DIG_TMDS_ENABLE_RST   (1 << 24)
+#       define RADEON_TV_ENABLE_RST         (1 << 25)
+#       define RADEON_AUTO_PWRUP_EN         (1 << 26)
+#define RADEON_TV_DAC_CNTL                  0x088c
+#       define RADEON_TV_DAC_NBLANK         (1 << 0)
+#       define RADEON_TV_DAC_NHOLD          (1 << 1)
+#       define RADEON_TV_DAC_PEDESTAL       (1 <<  2)
+#       define RADEON_TV_MONITOR_DETECT_EN  (1 <<  4)
+#       define RADEON_TV_DAC_CMPOUT         (1 <<  5)
+#       define RADEON_TV_DAC_STD_MASK       (3 <<  8)
+#       define RADEON_TV_DAC_STD_PAL        (0 <<  8)
+#       define RADEON_TV_DAC_STD_NTSC       (1 <<  8)
+#       define RADEON_TV_DAC_STD_PS2        (2 <<  8)
+#       define RADEON_TV_DAC_STD_RS343      (3 <<  8)
+#       define RADEON_TV_DAC_BGSLEEP        (1 <<  6)
+#       define RADEON_TV_DAC_BGADJ_MASK     (0xf <<  16)
+#       define RADEON_TV_DAC_BGADJ_SHIFT    16
+#       define RADEON_TV_DAC_DACADJ_MASK    (0xf <<  20)
+#       define RADEON_TV_DAC_DACADJ_SHIFT   20
+#       define RADEON_TV_DAC_RDACPD         (1 <<  24)
+#       define RADEON_TV_DAC_GDACPD         (1 <<  25)
+#       define RADEON_TV_DAC_BDACPD         (1 <<  26)
+#       define RADEON_TV_DAC_RDACDET        (1 << 29)
+#       define RADEON_TV_DAC_GDACDET        (1 << 30)
+#       define RADEON_TV_DAC_BDACDET        (1 << 31)
+#       define R420_TV_DAC_DACADJ_MASK      (0x1f <<  20)
+#       define R420_TV_DAC_RDACPD           (1 <<  25)
+#       define R420_TV_DAC_GDACPD           (1 <<  26)
+#       define R420_TV_DAC_BDACPD           (1 <<  27)
+#       define R420_TV_DAC_TVENABLE         (1 <<  28)
+#define RADEON_DISP_HW_DEBUG                0x0d14
+#       define RADEON_CRT2_DISP1_SEL        (1 <<  5)
+#define RADEON_DISP_OUTPUT_CNTL             0x0d64
+#       define RADEON_DISP_DAC_SOURCE_MASK  0x03
+#       define RADEON_DISP_DAC2_SOURCE_MASK  0x0c
+#       define RADEON_DISP_DAC_SOURCE_CRTC2 0x01
+#       define RADEON_DISP_DAC_SOURCE_RMX   0x02
+#       define RADEON_DISP_DAC_SOURCE_LTU   0x03
+#       define RADEON_DISP_DAC2_SOURCE_CRTC2 0x04
+#       define RADEON_DISP_TVDAC_SOURCE_MASK  (0x03 << 2)
+#       define RADEON_DISP_TVDAC_SOURCE_CRTC  0x0
+#       define RADEON_DISP_TVDAC_SOURCE_CRTC2 (0x01 << 2)
+#       define RADEON_DISP_TVDAC_SOURCE_RMX   (0x02 << 2)
+#       define RADEON_DISP_TVDAC_SOURCE_LTU   (0x03 << 2)
+#       define RADEON_DISP_TRANS_MATRIX_MASK  (0x03 << 4)
+#       define RADEON_DISP_TRANS_MATRIX_ALPHA_MSB (0x00 << 4)
+#       define RADEON_DISP_TRANS_MATRIX_GRAPHICS  (0x01 << 4)
+#       define RADEON_DISP_TRANS_MATRIX_VIDEO     (0x02 << 4)
+#       define RADEON_DISP_TV_SOURCE_CRTC   (1 << 16) /* crtc1 or crtc2 */
+#       define RADEON_DISP_TV_SOURCE_LTU    (0 << 16) /* linear transform unit */
+#define RADEON_DISP_TV_OUT_CNTL             0x0d6c
+#       define RADEON_DISP_TV_PATH_SRC_CRTC2 (1 << 16)
+#       define RADEON_DISP_TV_PATH_SRC_CRTC1 (0 << 16)
+#define RADEON_DAC_CRC_SIG                  0x02cc
+#define RADEON_DAC_DATA                     0x03c9 /* VGA */
+#define RADEON_DAC_MASK                     0x03c6 /* VGA */
+#define RADEON_DAC_R_INDEX                  0x03c7 /* VGA */
+#define RADEON_DAC_W_INDEX                  0x03c8 /* VGA */
+#define RADEON_DDA_CONFIG                   0x02e0
+#define RADEON_DDA_ON_OFF                   0x02e4
+#define RADEON_DEFAULT_OFFSET               0x16e0
+#define RADEON_DEFAULT_PITCH                0x16e4
+#define RADEON_DEFAULT_SC_BOTTOM_RIGHT      0x16e8
+#       define RADEON_DEFAULT_SC_RIGHT_MAX  (0x1fff <<  0)
+#       define RADEON_DEFAULT_SC_BOTTOM_MAX (0x1fff << 16)
+#define RADEON_DESTINATION_3D_CLR_CMP_VAL   0x1820
+#define RADEON_DESTINATION_3D_CLR_CMP_MSK   0x1824
+#define RADEON_DEVICE_ID                    0x0f02 /* PCI */
+#define RADEON_DISP_MISC_CNTL               0x0d00
+#       define RADEON_SOFT_RESET_GRPH_PP    (1 << 0)
+#define RADEON_DISP_MERGE_CNTL           0x0d60
+#       define RADEON_DISP_ALPHA_MODE_MASK  0x03
+#       define RADEON_DISP_ALPHA_MODE_KEY   0
+#       define RADEON_DISP_ALPHA_MODE_PER_PIXEL 1
+#       define RADEON_DISP_ALPHA_MODE_GLOBAL 2
+#       define RADEON_DISP_RGB_OFFSET_EN    (1 << 8)
+#       define RADEON_DISP_GRPH_ALPHA_MASK  (0xff << 16)
+#       define RADEON_DISP_OV0_ALPHA_MASK   (0xff << 24)
+#      define RADEON_DISP_LIN_TRANS_BYPASS (0x01 << 9)
+#define RADEON_DISP2_MERGE_CNTL                    0x0d68
+#       define RADEON_DISP2_RGB_OFFSET_EN   (1 << 8)
+#define RADEON_DISP_LIN_TRANS_GRPH_A        0x0d80
+#define RADEON_DISP_LIN_TRANS_GRPH_B        0x0d84
+#define RADEON_DISP_LIN_TRANS_GRPH_C        0x0d88
+#define RADEON_DISP_LIN_TRANS_GRPH_D        0x0d8c
+#define RADEON_DISP_LIN_TRANS_GRPH_E        0x0d90
+#define RADEON_DISP_LIN_TRANS_GRPH_F        0x0d98
+#define RADEON_DP_BRUSH_BKGD_CLR            0x1478
+#define RADEON_DP_BRUSH_FRGD_CLR            0x147c
+#define RADEON_DP_CNTL                      0x16c0
+#       define RADEON_DST_X_LEFT_TO_RIGHT   (1 <<  0)
+#       define RADEON_DST_Y_TOP_TO_BOTTOM   (1 <<  1)
+#       define RADEON_DP_DST_TILE_LINEAR    (0 <<  3)
+#       define RADEON_DP_DST_TILE_MACRO     (1 <<  3)
+#       define RADEON_DP_DST_TILE_MICRO     (2 <<  3)
+#       define RADEON_DP_DST_TILE_BOTH      (3 <<  3)
+#define RADEON_DP_CNTL_XDIR_YDIR_YMAJOR     0x16d0
+#       define RADEON_DST_Y_MAJOR             (1 <<  2)
+#       define RADEON_DST_Y_DIR_TOP_TO_BOTTOM (1 << 15)
+#       define RADEON_DST_X_DIR_LEFT_TO_RIGHT (1 << 31)
+#define RADEON_DP_DATATYPE                  0x16c4
+#       define RADEON_HOST_BIG_ENDIAN_EN    (1 << 29)
+#define RADEON_DP_GUI_MASTER_CNTL           0x146c
+#       define RADEON_GMC_SRC_PITCH_OFFSET_CNTL   (1    <<  0)
+#       define RADEON_GMC_DST_PITCH_OFFSET_CNTL   (1    <<  1)
+#       define RADEON_GMC_SRC_CLIPPING            (1    <<  2)
+#       define RADEON_GMC_DST_CLIPPING            (1    <<  3)
+#       define RADEON_GMC_BRUSH_DATATYPE_MASK     (0x0f <<  4)
+#       define RADEON_GMC_BRUSH_8X8_MONO_FG_BG    (0    <<  4)
+#       define RADEON_GMC_BRUSH_8X8_MONO_FG_LA    (1    <<  4)
+#       define RADEON_GMC_BRUSH_1X8_MONO_FG_BG    (4    <<  4)
+#       define RADEON_GMC_BRUSH_1X8_MONO_FG_LA    (5    <<  4)
+#       define RADEON_GMC_BRUSH_32x1_MONO_FG_BG   (6    <<  4)
+#       define RADEON_GMC_BRUSH_32x1_MONO_FG_LA   (7    <<  4)
+#       define RADEON_GMC_BRUSH_32x32_MONO_FG_BG  (8    <<  4)
+#       define RADEON_GMC_BRUSH_32x32_MONO_FG_LA  (9    <<  4)
+#       define RADEON_GMC_BRUSH_8x8_COLOR         (10   <<  4)
+#       define RADEON_GMC_BRUSH_1X8_COLOR         (12   <<  4)
+#       define RADEON_GMC_BRUSH_SOLID_COLOR       (13   <<  4)
+#       define RADEON_GMC_BRUSH_NONE              (15   <<  4)
+#       define RADEON_GMC_DST_8BPP_CI             (2    <<  8)
+#       define RADEON_GMC_DST_15BPP               (3    <<  8)
+#       define RADEON_GMC_DST_16BPP               (4    <<  8)
+#       define RADEON_GMC_DST_24BPP               (5    <<  8)
+#       define RADEON_GMC_DST_32BPP               (6    <<  8)
+#       define RADEON_GMC_DST_8BPP_RGB            (7    <<  8)
+#       define RADEON_GMC_DST_Y8                  (8    <<  8)
+#       define RADEON_GMC_DST_RGB8                (9    <<  8)
+#       define RADEON_GMC_DST_VYUY                (11   <<  8)
+#       define RADEON_GMC_DST_YVYU                (12   <<  8)
+#       define RADEON_GMC_DST_AYUV444             (14   <<  8)
+#       define RADEON_GMC_DST_ARGB4444            (15   <<  8)
+#       define RADEON_GMC_DST_DATATYPE_MASK       (0x0f <<  8)
+#       define RADEON_GMC_DST_DATATYPE_SHIFT      8
+#       define RADEON_GMC_SRC_DATATYPE_MASK       (3    << 12)
+#       define RADEON_GMC_SRC_DATATYPE_MONO_FG_BG (0    << 12)
+#       define RADEON_GMC_SRC_DATATYPE_MONO_FG_LA (1    << 12)
+#       define RADEON_GMC_SRC_DATATYPE_COLOR      (3    << 12)
+#       define RADEON_GMC_BYTE_PIX_ORDER          (1    << 14)
+#       define RADEON_GMC_BYTE_MSB_TO_LSB         (0    << 14)
+#       define RADEON_GMC_BYTE_LSB_TO_MSB         (1    << 14)
+#       define RADEON_GMC_CONVERSION_TEMP         (1    << 15)
+#       define RADEON_GMC_CONVERSION_TEMP_6500    (0    << 15)
+#       define RADEON_GMC_CONVERSION_TEMP_9300    (1    << 15)
+#       define RADEON_GMC_ROP3_MASK               (0xff << 16)
+#       define RADEON_DP_SRC_SOURCE_MASK          (7    << 24)
+#       define RADEON_DP_SRC_SOURCE_MEMORY        (2    << 24)
+#       define RADEON_DP_SRC_SOURCE_HOST_DATA     (3    << 24)
+#       define RADEON_GMC_3D_FCN_EN               (1    << 27)
+#       define RADEON_GMC_CLR_CMP_CNTL_DIS        (1    << 28)
+#       define RADEON_GMC_AUX_CLIP_DIS            (1    << 29)
+#       define RADEON_GMC_WR_MSK_DIS              (1    << 30)
+#       define RADEON_GMC_LD_BRUSH_Y_X            (1    << 31)
+#       define RADEON_ROP3_ZERO             0x00000000
+#       define RADEON_ROP3_DSa              0x00880000
+#       define RADEON_ROP3_SDna             0x00440000
+#       define RADEON_ROP3_S                0x00cc0000
+#       define RADEON_ROP3_DSna             0x00220000
+#       define RADEON_ROP3_D                0x00aa0000
+#       define RADEON_ROP3_DSx              0x00660000
+#       define RADEON_ROP3_DSo              0x00ee0000
+#       define RADEON_ROP3_DSon             0x00110000
+#       define RADEON_ROP3_DSxn             0x00990000
+#       define RADEON_ROP3_Dn               0x00550000
+#       define RADEON_ROP3_SDno             0x00dd0000
+#       define RADEON_ROP3_Sn               0x00330000
+#       define RADEON_ROP3_DSno             0x00bb0000
+#       define RADEON_ROP3_DSan             0x00770000
+#       define RADEON_ROP3_ONE              0x00ff0000
+#       define RADEON_ROP3_DPa              0x00a00000
+#       define RADEON_ROP3_PDna             0x00500000
+#       define RADEON_ROP3_P                0x00f00000
+#       define RADEON_ROP3_DPna             0x000a0000
+#       define RADEON_ROP3_D                0x00aa0000
+#       define RADEON_ROP3_DPx              0x005a0000
+#       define RADEON_ROP3_DPo              0x00fa0000
+#       define RADEON_ROP3_DPon             0x00050000
+#       define RADEON_ROP3_PDxn             0x00a50000
+#       define RADEON_ROP3_PDno             0x00f50000
+#       define RADEON_ROP3_Pn               0x000f0000
+#       define RADEON_ROP3_DPno             0x00af0000
+#       define RADEON_ROP3_DPan             0x005f0000
+#define RADEON_DP_GUI_MASTER_CNTL_C         0x1c84
+#define RADEON_DP_MIX                       0x16c8
+#define RADEON_DP_SRC_BKGD_CLR              0x15dc
+#define RADEON_DP_SRC_FRGD_CLR              0x15d8
+#define RADEON_DP_WRITE_MASK                0x16cc
+#define RADEON_DST_BRES_DEC                 0x1630
+#define RADEON_DST_BRES_ERR                 0x1628
+#define RADEON_DST_BRES_INC                 0x162c
+#define RADEON_DST_BRES_LNTH                0x1634
+#define RADEON_DST_BRES_LNTH_SUB            0x1638
+#define RADEON_DST_HEIGHT                   0x1410
+#define RADEON_DST_HEIGHT_WIDTH             0x143c
+#define RADEON_DST_HEIGHT_WIDTH_8           0x158c
+#define RADEON_DST_HEIGHT_WIDTH_BW          0x15b4
+#define RADEON_DST_HEIGHT_Y                 0x15a0
+#define RADEON_DST_LINE_START               0x1600
+#define RADEON_DST_LINE_END                 0x1604
+#define RADEON_DST_LINE_PATCOUNT            0x1608
+#       define RADEON_BRES_CNTL_SHIFT       8
+#define RADEON_DST_OFFSET                   0x1404
+#define RADEON_DST_PITCH                    0x1408
+#define RADEON_DST_PITCH_OFFSET             0x142c
+#define RADEON_DST_PITCH_OFFSET_C           0x1c80
+#       define RADEON_PITCH_SHIFT           21
+#       define RADEON_DST_TILE_LINEAR       (0 << 30)
+#       define RADEON_DST_TILE_MACRO        (1 << 30)
+#       define RADEON_DST_TILE_MICRO        (2 << 30)
+#       define RADEON_DST_TILE_BOTH         (3 << 30)
+#define RADEON_DST_WIDTH                    0x140c
+#define RADEON_DST_WIDTH_HEIGHT             0x1598
+#define RADEON_DST_WIDTH_X                  0x1588
+#define RADEON_DST_WIDTH_X_INCY             0x159c
+#define RADEON_DST_X                        0x141c
+#define RADEON_DST_X_SUB                    0x15a4
+#define RADEON_DST_X_Y                      0x1594
+#define RADEON_DST_Y                        0x1420
+#define RADEON_DST_Y_SUB                    0x15a8
+#define RADEON_DST_Y_X                      0x1438
+
+#define RADEON_FCP_CNTL                     0x0910
+#      define RADEON_FCP0_SRC_PCICLK             0
+#      define RADEON_FCP0_SRC_PCLK               1
+#      define RADEON_FCP0_SRC_PCLKb              2
+#      define RADEON_FCP0_SRC_HREF               3
+#      define RADEON_FCP0_SRC_GND                4
+#      define RADEON_FCP0_SRC_HREFb              5
+#define RADEON_FLUSH_1                      0x1704
+#define RADEON_FLUSH_2                      0x1708
+#define RADEON_FLUSH_3                      0x170c
+#define RADEON_FLUSH_4                      0x1710
+#define RADEON_FLUSH_5                      0x1714
+#define RADEON_FLUSH_6                      0x1718
+#define RADEON_FLUSH_7                      0x171c
+#define RADEON_FOG_3D_TABLE_START           0x1810
+#define RADEON_FOG_3D_TABLE_END             0x1814
+#define RADEON_FOG_3D_TABLE_DENSITY         0x181c
+#define RADEON_FOG_TABLE_INDEX              0x1a14
+#define RADEON_FOG_TABLE_DATA               0x1a18
+#define RADEON_FP_CRTC_H_TOTAL_DISP         0x0250
+#define RADEON_FP_CRTC_V_TOTAL_DISP         0x0254
+#       define RADEON_FP_CRTC_H_TOTAL_MASK      0x000003ff
+#       define RADEON_FP_CRTC_H_DISP_MASK       0x01ff0000
+#       define RADEON_FP_CRTC_V_TOTAL_MASK      0x00000fff
+#       define RADEON_FP_CRTC_V_DISP_MASK       0x0fff0000
+#       define RADEON_FP_H_SYNC_STRT_CHAR_MASK  0x00001ff8
+#       define RADEON_FP_H_SYNC_WID_MASK        0x003f0000
+#       define RADEON_FP_V_SYNC_STRT_MASK       0x00000fff
+#       define RADEON_FP_V_SYNC_WID_MASK        0x001f0000
+#       define RADEON_FP_CRTC_H_TOTAL_SHIFT     0x00000000
+#       define RADEON_FP_CRTC_H_DISP_SHIFT      0x00000010
+#       define RADEON_FP_CRTC_V_TOTAL_SHIFT     0x00000000
+#       define RADEON_FP_CRTC_V_DISP_SHIFT      0x00000010
+#       define RADEON_FP_H_SYNC_STRT_CHAR_SHIFT 0x00000003
+#       define RADEON_FP_H_SYNC_WID_SHIFT       0x00000010
+#       define RADEON_FP_V_SYNC_STRT_SHIFT      0x00000000
+#       define RADEON_FP_V_SYNC_WID_SHIFT       0x00000010
+#define RADEON_FP_GEN_CNTL                  0x0284
+#       define RADEON_FP_FPON                  (1 <<  0)
+#       define RADEON_FP_BLANK_EN              (1 <<  1)
+#       define RADEON_FP_TMDS_EN               (1 <<  2)
+#       define RADEON_FP_PANEL_FORMAT          (1 <<  3)
+#       define RADEON_FP_EN_TMDS               (1 <<  7)
+#       define RADEON_FP_DETECT_SENSE          (1 <<  8)
+#       define R200_FP_SOURCE_SEL_MASK         (3 <<  10)
+#       define R200_FP_SOURCE_SEL_CRTC1        (0 <<  10)
+#       define R200_FP_SOURCE_SEL_CRTC2        (1 <<  10)
+#       define R200_FP_SOURCE_SEL_RMX          (2 <<  10)
+#       define R200_FP_SOURCE_SEL_TRANS        (3 <<  10)
+#       define RADEON_FP_SEL_CRTC1             (0 << 13)
+#       define RADEON_FP_SEL_CRTC2             (1 << 13)
+#       define RADEON_FP_CRTC_DONT_SHADOW_HPAR (1 << 15)
+#       define RADEON_FP_CRTC_DONT_SHADOW_VPAR (1 << 16)
+#       define RADEON_FP_CRTC_DONT_SHADOW_HEND (1 << 17)
+#       define RADEON_FP_CRTC_USE_SHADOW_VEND  (1 << 18)
+#       define RADEON_FP_RMX_HVSYNC_CONTROL_EN (1 << 20)
+#       define RADEON_FP_DFP_SYNC_SEL          (1 << 21)
+#       define RADEON_FP_CRTC_LOCK_8DOT        (1 << 22)
+#       define RADEON_FP_CRT_SYNC_SEL          (1 << 23)
+#       define RADEON_FP_USE_SHADOW_EN         (1 << 24)
+#       define RADEON_FP_CRT_SYNC_ALT          (1 << 26)
+#define RADEON_FP2_GEN_CNTL                 0x0288
+#       define RADEON_FP2_BLANK_EN             (1 <<  1)
+#       define RADEON_FP2_ON                   (1 <<  2)
+#       define RADEON_FP2_PANEL_FORMAT         (1 <<  3)
+#       define RADEON_FP2_DETECT_SENSE         (1 <<  8)
+#       define R200_FP2_SOURCE_SEL_MASK        (3 << 10)
+#       define R200_FP2_SOURCE_SEL_CRTC1       (0 << 10)
+#       define R200_FP2_SOURCE_SEL_CRTC2       (1 << 10)
+#       define R200_FP2_SOURCE_SEL_RMX         (2 << 10)
+#       define R200_FP2_SOURCE_SEL_TRANS_UNIT  (3 << 10)
+#       define RADEON_FP2_SRC_SEL_MASK         (3 << 13)
+#       define RADEON_FP2_SRC_SEL_CRTC2        (1 << 13)
+#       define RADEON_FP2_FP_POL               (1 << 16)
+#       define RADEON_FP2_LP_POL               (1 << 17)
+#       define RADEON_FP2_SCK_POL              (1 << 18)
+#       define RADEON_FP2_LCD_CNTL_MASK        (7 << 19)
+#       define RADEON_FP2_PAD_FLOP_EN          (1 << 22)
+#       define RADEON_FP2_CRC_EN               (1 << 23)
+#       define RADEON_FP2_CRC_READ_EN          (1 << 24)
+#       define RADEON_FP2_DVO_EN               (1 << 25)
+#       define RADEON_FP2_DVO_RATE_SEL_SDR     (1 << 26)
+#       define R200_FP2_DVO_RATE_SEL_SDR       (1 << 27)
+#       define R300_FP2_DVO_CLOCK_MODE_SINGLE  (1 << 28)
+#       define R300_FP2_DVO_DUAL_CHANNEL_EN    (1 << 29)
+#define RADEON_FP_H_SYNC_STRT_WID           0x02c4
+#define RADEON_FP_H2_SYNC_STRT_WID          0x03c4
+#define RADEON_FP_HORZ_STRETCH              0x028c
+#define RADEON_FP_HORZ2_STRETCH             0x038c
+#       define RADEON_HORZ_STRETCH_RATIO_MASK 0xffff
+#       define RADEON_HORZ_STRETCH_RATIO_MAX  4096
+#       define RADEON_HORZ_PANEL_SIZE         (0x1ff   << 16)
+#       define RADEON_HORZ_PANEL_SHIFT        16
+#       define RADEON_HORZ_STRETCH_PIXREP     (0      << 25)
+#       define RADEON_HORZ_STRETCH_BLEND      (1      << 26)
+#       define RADEON_HORZ_STRETCH_ENABLE     (1      << 25)
+#       define RADEON_HORZ_AUTO_RATIO         (1      << 27)
+#       define RADEON_HORZ_FP_LOOP_STRETCH    (0x7    << 28)
+#       define RADEON_HORZ_AUTO_RATIO_INC     (1      << 31)
+#define RADEON_FP_HORZ_VERT_ACTIVE          0x0278
+#define RADEON_FP_V_SYNC_STRT_WID           0x02c8
+#define RADEON_FP_VERT_STRETCH              0x0290
+#define RADEON_FP_V2_SYNC_STRT_WID          0x03c8
+#define RADEON_FP_VERT2_STRETCH             0x0390
+#       define RADEON_VERT_PANEL_SIZE          (0xfff << 12)
+#       define RADEON_VERT_PANEL_SHIFT         12
+#       define RADEON_VERT_STRETCH_RATIO_MASK  0xfff
+#       define RADEON_VERT_STRETCH_RATIO_SHIFT 0
+#       define RADEON_VERT_STRETCH_RATIO_MAX   4096
+#       define RADEON_VERT_STRETCH_ENABLE      (1     << 25)
+#       define RADEON_VERT_STRETCH_LINEREP     (0     << 26)
+#       define RADEON_VERT_STRETCH_BLEND       (1     << 26)
+#       define RADEON_VERT_AUTO_RATIO_EN       (1     << 27)
+#      define RADEON_VERT_AUTO_RATIO_INC      (1     << 31)
+#       define RADEON_VERT_STRETCH_RESERVED    0x71000000
+#define RS400_FP_2ND_GEN_CNTL               0x0384
+#       define RS400_FP_2ND_ON              (1 << 0)
+#       define RS400_FP_2ND_BLANK_EN        (1 << 1)
+#       define RS400_TMDS_2ND_EN            (1 << 2)
+#       define RS400_PANEL_FORMAT_2ND       (1 << 3)
+#       define RS400_FP_2ND_EN_TMDS         (1 << 7)
+#       define RS400_FP_2ND_DETECT_SENSE    (1 << 8)
+#       define RS400_FP_2ND_SOURCE_SEL_MASK        (3 << 10)
+#       define RS400_FP_2ND_SOURCE_SEL_CRTC1       (0 << 10)
+#       define RS400_FP_2ND_SOURCE_SEL_CRTC2       (1 << 10)
+#       define RS400_FP_2ND_SOURCE_SEL_RMX         (2 << 10)
+#       define RS400_FP_2ND_DETECT_EN       (1 << 12)
+#       define RS400_HPD_2ND_SEL            (1 << 13)
+#define RS400_FP2_2_GEN_CNTL                0x0388
+#       define RS400_FP2_2_BLANK_EN         (1 << 1)
+#       define RS400_FP2_2_ON               (1 << 2)
+#       define RS400_FP2_2_PANEL_FORMAT     (1 << 3)
+#       define RS400_FP2_2_DETECT_SENSE     (1 << 8)
+#       define RS400_FP2_2_SOURCE_SEL_MASK        (3 << 10)
+#       define RS400_FP2_2_SOURCE_SEL_CRTC1       (0 << 10)
+#       define RS400_FP2_2_SOURCE_SEL_CRTC2       (1 << 10)
+#       define RS400_FP2_2_SOURCE_SEL_RMX         (2 << 10)
+#       define RS400_FP2_2_DVO2_EN          (1 << 25)
+#define RS400_TMDS2_CNTL                    0x0394
+#define RS400_TMDS2_TRANSMITTER_CNTL        0x03a4
+#       define RS400_TMDS2_PLLEN            (1 << 0)
+#       define RS400_TMDS2_PLLRST           (1 << 1)
+
+#define RADEON_GEN_INT_CNTL                 0x0040
+#      define RADEON_SW_INT_ENABLE             (1 << 25)
+#define RADEON_GEN_INT_STATUS               0x0044
+#       define RADEON_VSYNC_INT_AK          (1 <<  2)
+#       define RADEON_VSYNC_INT             (1 <<  2)
+#       define RADEON_VSYNC2_INT_AK         (1 <<  6)
+#       define RADEON_VSYNC2_INT            (1 <<  6)
+#      define RADEON_SW_INT_FIRE               (1 << 26)
+#      define RADEON_SW_INT_TEST               (1 << 25)
+#      define RADEON_SW_INT_TEST_ACK           (1 << 25)
+#define RADEON_GENENB                       0x03c3 /* VGA */
+#define RADEON_GENFC_RD                     0x03ca /* VGA */
+#define RADEON_GENFC_WT                     0x03da /* VGA, 0x03ba */
+#define RADEON_GENMO_RD                     0x03cc /* VGA */
+#define RADEON_GENMO_WT                     0x03c2 /* VGA */
+#define RADEON_GENS0                        0x03c2 /* VGA */
+#define RADEON_GENS1                        0x03da /* VGA, 0x03ba */
+#define RADEON_GPIO_MONID                   0x0068 /* DDC interface via I2C */ /* DDC3 */
+#define RADEON_GPIO_MONIDB                  0x006c
+#define RADEON_GPIO_CRT2_DDC                0x006c
+#define RADEON_GPIO_DVI_DDC                 0x0064 /* DDC2 */
+#define RADEON_GPIO_VGA_DDC                 0x0060 /* DDC1 */
+#       define RADEON_GPIO_A_0              (1 <<  0)
+#       define RADEON_GPIO_A_1              (1 <<  1)
+#       define RADEON_GPIO_Y_0              (1 <<  8)
+#       define RADEON_GPIO_Y_1              (1 <<  9)
+#       define RADEON_GPIO_Y_SHIFT_0        8
+#       define RADEON_GPIO_Y_SHIFT_1        9
+#       define RADEON_GPIO_EN_0             (1 << 16)
+#       define RADEON_GPIO_EN_1             (1 << 17)
+#       define RADEON_GPIO_MASK_0           (1 << 24) /*??*/
+#       define RADEON_GPIO_MASK_1           (1 << 25) /*??*/
+#define RADEON_GRPH8_DATA                   0x03cf /* VGA */
+#define RADEON_GRPH8_IDX                    0x03ce /* VGA */
+#define RADEON_GUI_SCRATCH_REG0             0x15e0
+#define RADEON_GUI_SCRATCH_REG1             0x15e4
+#define RADEON_GUI_SCRATCH_REG2             0x15e8
+#define RADEON_GUI_SCRATCH_REG3             0x15ec
+#define RADEON_GUI_SCRATCH_REG4             0x15f0
+#define RADEON_GUI_SCRATCH_REG5             0x15f4
+
+#define RADEON_HEADER                       0x0f0e /* PCI */
+#define RADEON_HOST_DATA0                   0x17c0
+#define RADEON_HOST_DATA1                   0x17c4
+#define RADEON_HOST_DATA2                   0x17c8
+#define RADEON_HOST_DATA3                   0x17cc
+#define RADEON_HOST_DATA4                   0x17d0
+#define RADEON_HOST_DATA5                   0x17d4
+#define RADEON_HOST_DATA6                   0x17d8
+#define RADEON_HOST_DATA7                   0x17dc
+#define RADEON_HOST_DATA_LAST               0x17e0
+#define RADEON_HOST_PATH_CNTL               0x0130
+#      define RADEON_HP_LIN_RD_CACHE_DIS   (1 << 24)
+#      define RADEON_HDP_READ_BUFFER_INVALIDATE   (1 << 27)
+#       define RADEON_HDP_SOFT_RESET        (1 << 26)
+#       define RADEON_HDP_APER_CNTL         (1 << 23)
+#define RADEON_HTOTAL_CNTL                  0x0009 /* PLL */
+#       define RADEON_HTOT_CNTL_VGA_EN      (1 << 28)
+#define RADEON_HTOTAL2_CNTL                 0x002e /* PLL */
+
+       /* Multimedia I2C bus */
+#define RADEON_I2C_CNTL_0                  0x0090
+#define RADEON_I2C_DONE (1<<0)
+#define RADEON_I2C_NACK (1<<1)
+#define RADEON_I2C_HALT (1<<2)
+#define RADEON_I2C_SOFT_RST (1<<5)
+#define RADEON_I2C_DRIVE_EN (1<<6)
+#define RADEON_I2C_DRIVE_SEL (1<<7)
+#define RADEON_I2C_START (1<<8)
+#define RADEON_I2C_STOP (1<<9)
+#define RADEON_I2C_RECEIVE (1<<10)
+#define RADEON_I2C_ABORT (1<<11)
+#define RADEON_I2C_GO (1<<12)
+#define RADEON_I2C_CNTL_1                   0x0094
+#define RADEON_I2C_SEL         (1<<16)
+#define RADEON_I2C_EN          (1<<17)
+#define RADEON_I2C_DATA                            0x0098
+
+#define RADEON_DVI_I2C_CNTL_0              0x02e0
+#       define R200_DVI_I2C_PIN_SEL(x)      ((x) << 3)
+#       define R200_SEL_DDC1                0 /* 0x60 - VGA_DDC */
+#       define R200_SEL_DDC2                1 /* 0x64 - DVI_DDC */
+#       define R200_SEL_DDC3                2 /* 0x68 - MONID_DDC */
+#define RADEON_DVI_I2C_CNTL_1               0x02e4 /* ? */
+#define RADEON_DVI_I2C_DATA                0x02e8
+
+#define RADEON_INTERRUPT_LINE               0x0f3c /* PCI */
+#define RADEON_INTERRUPT_PIN                0x0f3d /* PCI */
+#define RADEON_IO_BASE                      0x0f14 /* PCI */
+
+#define RADEON_LATENCY                      0x0f0d /* PCI */
+#define RADEON_LEAD_BRES_DEC                0x1608
+#define RADEON_LEAD_BRES_LNTH               0x161c
+#define RADEON_LEAD_BRES_LNTH_SUB           0x1624
+#define RADEON_LVDS_GEN_CNTL                0x02d0
+#       define RADEON_LVDS_ON               (1   <<  0)
+#       define RADEON_LVDS_DISPLAY_DIS      (1   <<  1)
+#       define RADEON_LVDS_PANEL_TYPE       (1   <<  2)
+#       define RADEON_LVDS_PANEL_FORMAT     (1   <<  3)
+#       define RADEON_LVDS_NO_FM            (0   <<  4)
+#       define RADEON_LVDS_2_GREY           (1   <<  4)
+#       define RADEON_LVDS_4_GREY           (2   <<  4)
+#       define RADEON_LVDS_RST_FM           (1   <<  6)
+#       define RADEON_LVDS_EN               (1   <<  7)
+#       define RADEON_LVDS_BL_MOD_LEVEL_SHIFT 8
+#       define RADEON_LVDS_BL_MOD_LEVEL_MASK (0xff << 8)
+#       define RADEON_LVDS_BL_MOD_EN        (1   << 16)
+#       define RADEON_LVDS_BL_CLK_SEL       (1   << 17)
+#       define RADEON_LVDS_DIGON            (1   << 18)
+#       define RADEON_LVDS_BLON             (1   << 19)
+#       define RADEON_LVDS_FP_POL_LOW       (1   << 20)
+#       define RADEON_LVDS_LP_POL_LOW       (1   << 21)
+#       define RADEON_LVDS_DTM_POL_LOW      (1   << 22)
+#       define RADEON_LVDS_SEL_CRTC2        (1   << 23)
+#       define RADEON_LVDS_FPDI_EN          (1   << 27)
+#       define RADEON_LVDS_HSYNC_DELAY_SHIFT        28
+#define RADEON_LVDS_PLL_CNTL                0x02d4
+#       define RADEON_HSYNC_DELAY_SHIFT     28
+#       define RADEON_HSYNC_DELAY_MASK      (0xf << 28)
+#       define RADEON_LVDS_PLL_EN           (1   << 16)
+#       define RADEON_LVDS_PLL_RESET        (1   << 17)
+#       define R300_LVDS_SRC_SEL_MASK       (3   << 18)
+#       define R300_LVDS_SRC_SEL_CRTC1      (0   << 18)
+#       define R300_LVDS_SRC_SEL_CRTC2      (1   << 18)
+#       define R300_LVDS_SRC_SEL_RMX        (2   << 18)
+#define RADEON_LVDS_SS_GEN_CNTL             0x02ec
+#       define RADEON_LVDS_PWRSEQ_DELAY1_SHIFT     16
+#       define RADEON_LVDS_PWRSEQ_DELAY2_SHIFT     20
+
+#define RADEON_MAX_LATENCY                  0x0f3f /* PCI */
+#define RADEON_DISPLAY_BASE_ADDR            0x23c
+#define RADEON_DISPLAY2_BASE_ADDR           0x33c
+#define RADEON_OV0_BASE_ADDR                0x43c
+#define RADEON_NB_TOM                       0x15c
+#define R300_MC_INIT_MISC_LAT_TIMER         0x180
+#       define R300_MC_DISP0R_INIT_LAT_SHIFT 8
+#       define R300_MC_DISP0R_INIT_LAT_MASK  0xf
+#       define R300_MC_DISP1R_INIT_LAT_SHIFT 12
+#       define R300_MC_DISP1R_INIT_LAT_MASK  0xf
+#define RADEON_MCLK_CNTL                    0x0012 /* PLL */
+#       define RADEON_MCLKA_SRC_SEL_MASK    0x7
+#       define RADEON_FORCEON_MCLKA         (1 << 16)
+#       define RADEON_FORCEON_MCLKB         (1 << 17)
+#       define RADEON_FORCEON_YCLKA         (1 << 18)
+#       define RADEON_FORCEON_YCLKB         (1 << 19)
+#       define RADEON_FORCEON_MC            (1 << 20)
+#       define RADEON_FORCEON_AIC           (1 << 21)
+#       define R300_DISABLE_MC_MCLKA        (1 << 21)
+#       define R300_DISABLE_MC_MCLKB        (1 << 21)
+#define RADEON_MCLK_MISC                    0x001f /* PLL */
+#       define RADEON_MC_MCLK_MAX_DYN_STOP_LAT (1 << 12)
+#       define RADEON_IO_MCLK_MAX_DYN_STOP_LAT (1 << 13)
+#       define RADEON_MC_MCLK_DYN_ENABLE    (1 << 14)
+#       define RADEON_IO_MCLK_DYN_ENABLE    (1 << 15)
+#define RADEON_LCD_GPIO_MASK                0x01a0
+#define RADEON_GPIOPAD_EN                   0x01a0
+#define RADEON_LCD_GPIO_Y_REG               0x01a4
+#define RADEON_MDGPIO_A_REG                 0x01ac
+#define RADEON_MDGPIO_EN_REG                0x01b0
+#define RADEON_MDGPIO_MASK                  0x0198
+#define RADEON_GPIOPAD_MASK                 0x0198
+#define RADEON_GPIOPAD_A                   0x019c
+#define RADEON_MDGPIO_Y_REG                 0x01b4
+#define RADEON_MEM_ADDR_CONFIG              0x0148
+#define RADEON_MEM_BASE                     0x0f10 /* PCI */
+#define RADEON_MEM_CNTL                     0x0140
+#       define RADEON_MEM_NUM_CHANNELS_MASK 0x01
+#       define RADEON_MEM_USE_B_CH_ONLY     (1 <<  1)
+#       define RV100_HALF_MODE              (1 <<  3)
+#       define R300_MEM_NUM_CHANNELS_MASK   0x03
+#       define R300_MEM_USE_CD_CH_ONLY      (1 <<  2)
+#define RADEON_MEM_TIMING_CNTL              0x0144 /* EXT_MEM_CNTL */
+#define RADEON_MEM_INIT_LAT_TIMER           0x0154
+#define RADEON_MEM_INTF_CNTL                0x014c
+#define RADEON_MEM_SDRAM_MODE_REG           0x0158
+#       define RADEON_SDRAM_MODE_MASK       0xffff0000
+#       define RADEON_B3MEM_RESET_MASK      0x6fffffff
+#       define RADEON_MEM_CFG_TYPE_DDR      (1 << 30)
+#define RADEON_MEM_STR_CNTL                 0x0150
+#       define RADEON_MEM_PWRUP_COMPL_A     (1 <<  0)
+#       define RADEON_MEM_PWRUP_COMPL_B     (1 <<  1)
+#       define R300_MEM_PWRUP_COMPL_C       (1 <<  2)
+#       define R300_MEM_PWRUP_COMPL_D       (1 <<  3)
+#       define RADEON_MEM_PWRUP_COMPLETE    0x03
+#       define R300_MEM_PWRUP_COMPLETE      0x0f
+#define RADEON_MC_STATUS                    0x0150
+#       define RADEON_MC_IDLE               (1 << 2)
+#       define R300_MC_IDLE                 (1 << 4)
+#define RADEON_MEM_VGA_RP_SEL               0x003c
+#define RADEON_MEM_VGA_WP_SEL               0x0038
+#define RADEON_MIN_GRANT                    0x0f3e /* PCI */
+#define RADEON_MM_DATA                      0x0004
+#define RADEON_MM_INDEX                     0x0000
+#      define RADEON_MM_APER           (1 << 31)
+#define RADEON_MPLL_CNTL                    0x000e /* PLL */
+#define RADEON_MPP_TB_CONFIG                0x01c0 /* ? */
+#define RADEON_MPP_GP_CONFIG                0x01c8 /* ? */
+#define RADEON_SEPROM_CNTL1                 0x01c0
+#       define RADEON_SCK_PRESCALE_SHIFT    24
+#       define RADEON_SCK_PRESCALE_MASK     (0xff << 24)
+#define R300_MC_IND_INDEX                   0x01f8
+#       define R300_MC_IND_ADDR_MASK        0x3f
+#       define R300_MC_IND_WR_EN            (1 << 8)
+#define R300_MC_IND_DATA                    0x01fc
+#define R300_MC_READ_CNTL_AB                0x017c
+#       define R300_MEM_RBS_POSITION_A_MASK 0x03
+#define R300_MC_READ_CNTL_CD_mcind         0x24
+#       define R300_MEM_RBS_POSITION_C_MASK 0x03
+
+#define RADEON_N_VIF_COUNT                  0x0248
+
+#define RADEON_OV0_AUTO_FLIP_CNTL           0x0470
+#       define  RADEON_OV0_AUTO_FLIP_CNTL_SOFT_BUF_NUM        0x00000007
+#       define  RADEON_OV0_AUTO_FLIP_CNTL_SOFT_REPEAT_FIELD   0x00000008
+#       define  RADEON_OV0_AUTO_FLIP_CNTL_SOFT_BUF_ODD        0x00000010
+#       define  RADEON_OV0_AUTO_FLIP_CNTL_IGNORE_REPEAT_FIELD 0x00000020
+#       define  RADEON_OV0_AUTO_FLIP_CNTL_SOFT_EOF_TOGGLE     0x00000040
+#       define  RADEON_OV0_AUTO_FLIP_CNTL_VID_PORT_SELECT     0x00000300
+#       define  RADEON_OV0_AUTO_FLIP_CNTL_P1_FIRST_LINE_EVEN  0x00010000
+#       define  RADEON_OV0_AUTO_FLIP_CNTL_SHIFT_EVEN_DOWN     0x00040000
+#       define  RADEON_OV0_AUTO_FLIP_CNTL_SHIFT_ODD_DOWN      0x00080000
+#       define  RADEON_OV0_AUTO_FLIP_CNTL_FIELD_POL_SOURCE    0x00800000
+
+#define RADEON_OV0_COLOUR_CNTL              0x04E0
+#define RADEON_OV0_DEINTERLACE_PATTERN      0x0474
+#define RADEON_OV0_EXCLUSIVE_HORZ           0x0408
+#       define  RADEON_EXCL_HORZ_START_MASK        0x000000ff
+#       define  RADEON_EXCL_HORZ_END_MASK          0x0000ff00
+#       define  RADEON_EXCL_HORZ_BACK_PORCH_MASK   0x00ff0000
+#       define  RADEON_EXCL_HORZ_EXCLUSIVE_EN      0x80000000
+#define RADEON_OV0_EXCLUSIVE_VERT           0x040C
+#       define  RADEON_EXCL_VERT_START_MASK        0x000003ff
+#       define  RADEON_EXCL_VERT_END_MASK          0x03ff0000
+#define RADEON_OV0_FILTER_CNTL              0x04A0
+#       define RADEON_FILTER_PROGRAMMABLE_COEF            0x0
+#       define RADEON_FILTER_HC_COEF_HORZ_Y               0x1
+#       define RADEON_FILTER_HC_COEF_HORZ_UV              0x2
+#       define RADEON_FILTER_HC_COEF_VERT_Y               0x4
+#       define RADEON_FILTER_HC_COEF_VERT_UV              0x8
+#       define RADEON_FILTER_HARDCODED_COEF               0xf
+#       define RADEON_FILTER_COEF_MASK                    0xf
+
+#define RADEON_OV0_FOUR_TAP_COEF_0          0x04B0
+#define RADEON_OV0_FOUR_TAP_COEF_1          0x04B4
+#define RADEON_OV0_FOUR_TAP_COEF_2          0x04B8
+#define RADEON_OV0_FOUR_TAP_COEF_3          0x04BC
+#define RADEON_OV0_FOUR_TAP_COEF_4          0x04C0
+#define RADEON_OV0_FLAG_CNTL                0x04DC
+#define RADEON_OV0_GAMMA_000_00F            0x0d40
+#define RADEON_OV0_GAMMA_010_01F            0x0d44
+#define RADEON_OV0_GAMMA_020_03F            0x0d48
+#define RADEON_OV0_GAMMA_040_07F            0x0d4c
+#define RADEON_OV0_GAMMA_080_0BF            0x0e00
+#define RADEON_OV0_GAMMA_0C0_0FF            0x0e04
+#define RADEON_OV0_GAMMA_100_13F            0x0e08
+#define RADEON_OV0_GAMMA_140_17F            0x0e0c
+#define RADEON_OV0_GAMMA_180_1BF            0x0e10
+#define RADEON_OV0_GAMMA_1C0_1FF            0x0e14
+#define RADEON_OV0_GAMMA_200_23F            0x0e18
+#define RADEON_OV0_GAMMA_240_27F            0x0e1c
+#define RADEON_OV0_GAMMA_280_2BF            0x0e20
+#define RADEON_OV0_GAMMA_2C0_2FF            0x0e24
+#define RADEON_OV0_GAMMA_300_33F            0x0e28
+#define RADEON_OV0_GAMMA_340_37F            0x0e2c
+#define RADEON_OV0_GAMMA_380_3BF            0x0d50
+#define RADEON_OV0_GAMMA_3C0_3FF            0x0d54
+#define RADEON_OV0_GRAPHICS_KEY_CLR_LOW     0x04EC
+#define RADEON_OV0_GRAPHICS_KEY_CLR_HIGH    0x04F0
+#define RADEON_OV0_H_INC                    0x0480
+#define RADEON_OV0_KEY_CNTL                 0x04F4
+#       define  RADEON_VIDEO_KEY_FN_MASK    0x00000003L
+#       define  RADEON_VIDEO_KEY_FN_FALSE   0x00000000L
+#       define  RADEON_VIDEO_KEY_FN_TRUE    0x00000001L
+#       define  RADEON_VIDEO_KEY_FN_EQ      0x00000002L
+#       define  RADEON_VIDEO_KEY_FN_NE      0x00000003L
+#       define  RADEON_GRAPHIC_KEY_FN_MASK  0x00000030L
+#       define  RADEON_GRAPHIC_KEY_FN_FALSE 0x00000000L
+#       define  RADEON_GRAPHIC_KEY_FN_TRUE  0x00000010L
+#       define  RADEON_GRAPHIC_KEY_FN_EQ    0x00000020L
+#       define  RADEON_GRAPHIC_KEY_FN_NE    0x00000030L
+#       define  RADEON_CMP_MIX_MASK         0x00000100L
+#       define  RADEON_CMP_MIX_OR           0x00000000L
+#       define  RADEON_CMP_MIX_AND          0x00000100L
+#define RADEON_OV0_LIN_TRANS_A              0x0d20
+#define RADEON_OV0_LIN_TRANS_B              0x0d24
+#define RADEON_OV0_LIN_TRANS_C              0x0d28
+#define RADEON_OV0_LIN_TRANS_D              0x0d2c
+#define RADEON_OV0_LIN_TRANS_E              0x0d30
+#define RADEON_OV0_LIN_TRANS_F              0x0d34
+#define RADEON_OV0_P1_BLANK_LINES_AT_TOP    0x0430
+#       define  RADEON_P1_BLNK_LN_AT_TOP_M1_MASK   0x00000fffL
+#       define  RADEON_P1_ACTIVE_LINES_M1          0x0fff0000L
+#define RADEON_OV0_P1_H_ACCUM_INIT          0x0488
+#define RADEON_OV0_P1_V_ACCUM_INIT          0x0428
+#       define  RADEON_OV0_P1_MAX_LN_IN_PER_LN_OUT 0x00000003L
+#       define  RADEON_OV0_P1_V_ACCUM_INIT_MASK    0x01ff8000L
+#define RADEON_OV0_P1_X_START_END           0x0494
+#define RADEON_OV0_P2_X_START_END           0x0498
+#define RADEON_OV0_P23_BLANK_LINES_AT_TOP   0x0434
+#       define  RADEON_P23_BLNK_LN_AT_TOP_M1_MASK  0x000007ffL
+#       define  RADEON_P23_ACTIVE_LINES_M1         0x07ff0000L
+#define RADEON_OV0_P23_H_ACCUM_INIT         0x048C
+#define RADEON_OV0_P23_V_ACCUM_INIT         0x042C
+#define RADEON_OV0_P3_X_START_END           0x049C
+#define RADEON_OV0_REG_LOAD_CNTL            0x0410
+#       define  RADEON_REG_LD_CTL_LOCK                 0x00000001L
+#       define  RADEON_REG_LD_CTL_VBLANK_DURING_LOCK   0x00000002L
+#       define  RADEON_REG_LD_CTL_STALL_GUI_UNTIL_FLIP 0x00000004L
+#       define  RADEON_REG_LD_CTL_LOCK_READBACK        0x00000008L
+#       define  RADEON_REG_LD_CTL_FLIP_READBACK        0x00000010L
+#define RADEON_OV0_SCALE_CNTL               0x0420
+#       define  RADEON_SCALER_HORZ_PICK_NEAREST    0x00000004L
+#       define  RADEON_SCALER_VERT_PICK_NEAREST    0x00000008L
+#       define  RADEON_SCALER_SIGNED_UV            0x00000010L
+#       define  RADEON_SCALER_GAMMA_SEL_MASK       0x00000060L
+#       define  RADEON_SCALER_GAMMA_SEL_BRIGHT     0x00000000L
+#       define  RADEON_SCALER_GAMMA_SEL_G22        0x00000020L
+#       define  RADEON_SCALER_GAMMA_SEL_G18        0x00000040L
+#       define  RADEON_SCALER_GAMMA_SEL_G14        0x00000060L
+#       define  RADEON_SCALER_COMCORE_SHIFT_UP_ONE 0x00000080L
+#       define  RADEON_SCALER_SURFAC_FORMAT        0x00000f00L
+#       define  RADEON_SCALER_SOURCE_15BPP         0x00000300L
+#       define  RADEON_SCALER_SOURCE_16BPP         0x00000400L
+#       define  RADEON_SCALER_SOURCE_32BPP         0x00000600L
+#       define  RADEON_SCALER_SOURCE_YUV9          0x00000900L
+#       define  RADEON_SCALER_SOURCE_YUV12         0x00000A00L
+#       define  RADEON_SCALER_SOURCE_VYUY422       0x00000B00L
+#       define  RADEON_SCALER_SOURCE_YVYU422       0x00000C00L
+#       define  RADEON_SCALER_ADAPTIVE_DEINT       0x00001000L
+#       define  RADEON_SCALER_TEMPORAL_DEINT       0x00002000L
+#       define  RADEON_SCALER_CRTC_SEL             0x00004000L
+#       define  RADEON_SCALER_SMART_SWITCH         0x00008000L
+#       define  RADEON_SCALER_BURST_PER_PLANE      0x007F0000L
+#       define  RADEON_SCALER_DOUBLE_BUFFER        0x01000000L
+#       define  RADEON_SCALER_DIS_LIMIT            0x08000000L
+#       define  RADEON_SCALER_LIN_TRANS_BYPASS     0x10000000L
+#       define  RADEON_SCALER_INT_EMU              0x20000000L
+#       define  RADEON_SCALER_ENABLE               0x40000000L
+#       define  RADEON_SCALER_SOFT_RESET           0x80000000L
+#define RADEON_OV0_STEP_BY                  0x0484
+#define RADEON_OV0_TEST                     0x04F8
+#define RADEON_OV0_V_INC                    0x0424
+#define RADEON_OV0_VID_BUF_PITCH0_VALUE     0x0460
+#define RADEON_OV0_VID_BUF_PITCH1_VALUE     0x0464
+#define RADEON_OV0_VID_BUF0_BASE_ADRS       0x0440
+#       define  RADEON_VIF_BUF0_PITCH_SEL          0x00000001L
+#       define  RADEON_VIF_BUF0_TILE_ADRS          0x00000002L
+#       define  RADEON_VIF_BUF0_BASE_ADRS_MASK     0x03fffff0L
+#       define  RADEON_VIF_BUF0_1ST_LINE_LSBS_MASK 0x48000000L
+#define RADEON_OV0_VID_BUF1_BASE_ADRS       0x0444
+#       define  RADEON_VIF_BUF1_PITCH_SEL          0x00000001L
+#       define  RADEON_VIF_BUF1_TILE_ADRS          0x00000002L
+#       define  RADEON_VIF_BUF1_BASE_ADRS_MASK     0x03fffff0L
+#       define  RADEON_VIF_BUF1_1ST_LINE_LSBS_MASK 0x48000000L
+#define RADEON_OV0_VID_BUF2_BASE_ADRS       0x0448
+#       define  RADEON_VIF_BUF2_PITCH_SEL          0x00000001L
+#       define  RADEON_VIF_BUF2_TILE_ADRS          0x00000002L
+#       define  RADEON_VIF_BUF2_BASE_ADRS_MASK     0x03fffff0L
+#       define  RADEON_VIF_BUF2_1ST_LINE_LSBS_MASK 0x48000000L
+#define RADEON_OV0_VID_BUF3_BASE_ADRS       0x044C
+#define RADEON_OV0_VID_BUF4_BASE_ADRS       0x0450
+#define RADEON_OV0_VID_BUF5_BASE_ADRS       0x0454
+#define RADEON_OV0_VIDEO_KEY_CLR_HIGH       0x04E8
+#define RADEON_OV0_VIDEO_KEY_CLR_LOW        0x04E4
+#define RADEON_OV0_Y_X_START                0x0400
+#define RADEON_OV0_Y_X_END                  0x0404
+#define RADEON_OV1_Y_X_START                0x0600
+#define RADEON_OV1_Y_X_END                  0x0604
+#define RADEON_OVR_CLR                      0x0230
+#define RADEON_OVR_WID_LEFT_RIGHT           0x0234
+#define RADEON_OVR_WID_TOP_BOTTOM           0x0238
+
+/* first capture unit */
+
+#define RADEON_CAP0_BUF0_OFFSET           0x0920
+#define RADEON_CAP0_BUF1_OFFSET           0x0924
+#define RADEON_CAP0_BUF0_EVEN_OFFSET      0x0928
+#define RADEON_CAP0_BUF1_EVEN_OFFSET      0x092C
+
+#define RADEON_CAP0_BUF_PITCH             0x0930
+#define RADEON_CAP0_V_WINDOW              0x0934
+#define RADEON_CAP0_H_WINDOW              0x0938
+#define RADEON_CAP0_VBI0_OFFSET           0x093C
+#define RADEON_CAP0_VBI1_OFFSET           0x0940
+#define RADEON_CAP0_VBI_V_WINDOW          0x0944
+#define RADEON_CAP0_VBI_H_WINDOW          0x0948
+#define RADEON_CAP0_PORT_MODE_CNTL        0x094C
+#define RADEON_CAP0_TRIG_CNTL             0x0950
+#define RADEON_CAP0_DEBUG                 0x0954
+#define RADEON_CAP0_CONFIG                0x0958
+#       define RADEON_CAP0_CONFIG_CONTINUOS          0x00000001
+#       define RADEON_CAP0_CONFIG_START_FIELD_EVEN   0x00000002
+#       define RADEON_CAP0_CONFIG_START_BUF_GET      0x00000004
+#       define RADEON_CAP0_CONFIG_START_BUF_SET      0x00000008
+#       define RADEON_CAP0_CONFIG_BUF_TYPE_ALT       0x00000010
+#       define RADEON_CAP0_CONFIG_BUF_TYPE_FRAME     0x00000020
+#       define RADEON_CAP0_CONFIG_ONESHOT_MODE_FRAME 0x00000040
+#       define RADEON_CAP0_CONFIG_BUF_MODE_DOUBLE    0x00000080
+#       define RADEON_CAP0_CONFIG_BUF_MODE_TRIPLE    0x00000100
+#       define RADEON_CAP0_CONFIG_MIRROR_EN          0x00000200
+#       define RADEON_CAP0_CONFIG_ONESHOT_MIRROR_EN  0x00000400
+#       define RADEON_CAP0_CONFIG_VIDEO_SIGNED_UV    0x00000800
+#       define RADEON_CAP0_CONFIG_ANC_DECODE_EN      0x00001000
+#       define RADEON_CAP0_CONFIG_VBI_EN             0x00002000
+#       define RADEON_CAP0_CONFIG_SOFT_PULL_DOWN_EN  0x00004000
+#       define RADEON_CAP0_CONFIG_VIP_EXTEND_FLAG_EN 0x00008000
+#       define RADEON_CAP0_CONFIG_FAKE_FIELD_EN      0x00010000
+#       define RADEON_CAP0_CONFIG_ODD_ONE_MORE_LINE  0x00020000
+#       define RADEON_CAP0_CONFIG_EVEN_ONE_MORE_LINE 0x00040000
+#       define RADEON_CAP0_CONFIG_HORZ_DIVIDE_2      0x00080000
+#       define RADEON_CAP0_CONFIG_HORZ_DIVIDE_4      0x00100000
+#       define RADEON_CAP0_CONFIG_VERT_DIVIDE_2      0x00200000
+#       define RADEON_CAP0_CONFIG_VERT_DIVIDE_4      0x00400000
+#       define RADEON_CAP0_CONFIG_FORMAT_BROOKTREE   0x00000000
+#       define RADEON_CAP0_CONFIG_FORMAT_CCIR656     0x00800000
+#       define RADEON_CAP0_CONFIG_FORMAT_ZV          0x01000000
+#       define RADEON_CAP0_CONFIG_FORMAT_VIP         0x01800000
+#       define RADEON_CAP0_CONFIG_FORMAT_TRANSPORT   0x02000000
+#       define RADEON_CAP0_CONFIG_HORZ_DECIMATOR     0x04000000
+#       define RADEON_CAP0_CONFIG_VIDEO_IN_YVYU422   0x00000000
+#       define RADEON_CAP0_CONFIG_VIDEO_IN_VYUY422   0x20000000
+#       define RADEON_CAP0_CONFIG_VBI_DIVIDE_2       0x40000000
+#       define RADEON_CAP0_CONFIG_VBI_DIVIDE_4       0x80000000
+#define RADEON_CAP0_ANC_ODD_OFFSET        0x095C
+#define RADEON_CAP0_ANC_EVEN_OFFSET       0x0960
+#define RADEON_CAP0_ANC_H_WINDOW          0x0964
+#define RADEON_CAP0_VIDEO_SYNC_TEST       0x0968
+#define RADEON_CAP0_ONESHOT_BUF_OFFSET    0x096C
+#define RADEON_CAP0_BUF_STATUS            0x0970
+/* #define RADEON_CAP0_DWNSC_XRATIO       0x0978 */
+/* #define RADEON_CAP0_XSHARPNESS                 0x097C */
+#define RADEON_CAP0_VBI2_OFFSET           0x0980
+#define RADEON_CAP0_VBI3_OFFSET           0x0984
+#define RADEON_CAP0_ANC2_OFFSET           0x0988
+#define RADEON_CAP0_ANC3_OFFSET           0x098C
+#define RADEON_VID_BUFFER_CONTROL         0x0900
+
+/* second capture unit */
+
+#define RADEON_CAP1_BUF0_OFFSET           0x0990
+#define RADEON_CAP1_BUF1_OFFSET           0x0994
+#define RADEON_CAP1_BUF0_EVEN_OFFSET      0x0998
+#define RADEON_CAP1_BUF1_EVEN_OFFSET      0x099C
+
+#define RADEON_CAP1_BUF_PITCH             0x09A0
+#define RADEON_CAP1_V_WINDOW              0x09A4
+#define RADEON_CAP1_H_WINDOW              0x09A8
+#define RADEON_CAP1_VBI_ODD_OFFSET        0x09AC
+#define RADEON_CAP1_VBI_EVEN_OFFSET       0x09B0
+#define RADEON_CAP1_VBI_V_WINDOW                  0x09B4
+#define RADEON_CAP1_VBI_H_WINDOW                  0x09B8
+#define RADEON_CAP1_PORT_MODE_CNTL        0x09BC
+#define RADEON_CAP1_TRIG_CNTL             0x09C0
+#define RADEON_CAP1_DEBUG                         0x09C4
+#define RADEON_CAP1_CONFIG                0x09C8
+#define RADEON_CAP1_ANC_ODD_OFFSET        0x09CC
+#define RADEON_CAP1_ANC_EVEN_OFFSET       0x09D0
+#define RADEON_CAP1_ANC_H_WINDOW                  0x09D4
+#define RADEON_CAP1_VIDEO_SYNC_TEST       0x09D8
+#define RADEON_CAP1_ONESHOT_BUF_OFFSET    0x09DC
+#define RADEON_CAP1_BUF_STATUS            0x09E0
+#define RADEON_CAP1_DWNSC_XRATIO                  0x09E8
+#define RADEON_CAP1_XSHARPNESS            0x09EC
+
+/* misc multimedia registers */
+
+#define RADEON_IDCT_RUNS                  0x1F80
+#define RADEON_IDCT_LEVELS                0x1F84
+#define RADEON_IDCT_CONTROL               0x1FBC
+#define RADEON_IDCT_AUTH_CONTROL          0x1F88
+#define RADEON_IDCT_AUTH                  0x1F8C
+
+#define RADEON_P2PLL_CNTL                   0x002a /* P2PLL */
+#       define RADEON_P2PLL_RESET                (1 <<  0)
+#       define RADEON_P2PLL_SLEEP                (1 <<  1)
+#       define RADEON_P2PLL_PVG_MASK             (7 << 11)
+#       define RADEON_P2PLL_PVG_SHIFT            11
+#       define RADEON_P2PLL_ATOMIC_UPDATE_EN     (1 << 16)
+#       define RADEON_P2PLL_VGA_ATOMIC_UPDATE_EN (1 << 17)
+#       define RADEON_P2PLL_ATOMIC_UPDATE_VSYNC  (1 << 18)
+#define RADEON_P2PLL_DIV_0                  0x002c
+#       define RADEON_P2PLL_FB0_DIV_MASK    0x07ff
+#       define RADEON_P2PLL_POST0_DIV_MASK  0x00070000
+#define RADEON_P2PLL_REF_DIV                0x002B /* PLL */
+#       define RADEON_P2PLL_REF_DIV_MASK    0x03ff
+#       define RADEON_P2PLL_ATOMIC_UPDATE_R (1 << 15) /* same as _W */
+#       define RADEON_P2PLL_ATOMIC_UPDATE_W (1 << 15) /* same as _R */
+#       define R300_PPLL_REF_DIV_ACC_MASK   (0x3ff << 18)
+#       define R300_PPLL_REF_DIV_ACC_SHIFT  18
+#define RADEON_PALETTE_DATA                 0x00b4
+#define RADEON_PALETTE_30_DATA              0x00b8
+#define RADEON_PALETTE_INDEX                0x00b0
+#define RADEON_PCI_GART_PAGE                0x017c
+#define RADEON_PIXCLKS_CNTL                 0x002d
+#       define RADEON_PIX2CLK_SRC_SEL_MASK     0x03
+#       define RADEON_PIX2CLK_SRC_SEL_CPUCLK   0x00
+#       define RADEON_PIX2CLK_SRC_SEL_PSCANCLK 0x01
+#       define RADEON_PIX2CLK_SRC_SEL_BYTECLK  0x02
+#       define RADEON_PIX2CLK_SRC_SEL_P2PLLCLK 0x03
+#       define RADEON_PIX2CLK_ALWAYS_ONb       (1<<6)
+#       define RADEON_PIX2CLK_DAC_ALWAYS_ONb   (1<<7)
+#       define RADEON_PIXCLK_TV_SRC_SEL        (1 << 8)
+#       define RADEON_DISP_TVOUT_PIXCLK_TV_ALWAYS_ONb (1 << 9)
+#       define R300_DVOCLK_ALWAYS_ONb          (1 << 10)
+#       define RADEON_PIXCLK_BLEND_ALWAYS_ONb  (1 << 11)
+#       define RADEON_PIXCLK_GV_ALWAYS_ONb     (1 << 12)
+#       define RADEON_PIXCLK_DIG_TMDS_ALWAYS_ONb (1 << 13)
+#       define R300_PIXCLK_DVO_ALWAYS_ONb      (1 << 13)
+#       define RADEON_PIXCLK_LVDS_ALWAYS_ONb   (1 << 14)
+#       define RADEON_PIXCLK_TMDS_ALWAYS_ONb   (1 << 15)
+#       define R300_PIXCLK_TRANS_ALWAYS_ONb    (1 << 16)
+#       define R300_PIXCLK_TVO_ALWAYS_ONb      (1 << 17)
+#       define R300_P2G2CLK_ALWAYS_ONb         (1 << 18)
+#       define R300_P2G2CLK_DAC_ALWAYS_ONb     (1 << 19)
+#       define R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF (1 << 23)
+#define RADEON_PLANE_3D_MASK_C              0x1d44
+#define RADEON_PLL_TEST_CNTL                0x0013 /* PLL */
+#       define RADEON_PLL_MASK_READ_B          (1 << 9)
+#define RADEON_PMI_CAP_ID                   0x0f5c /* PCI */
+#define RADEON_PMI_DATA                     0x0f63 /* PCI */
+#define RADEON_PMI_NXT_CAP_PTR              0x0f5d /* PCI */
+#define RADEON_PMI_PMC_REG                  0x0f5e /* PCI */
+#define RADEON_PMI_PMCSR_REG                0x0f60 /* PCI */
+#define RADEON_PMI_REGISTER                 0x0f5c /* PCI */
+#define RADEON_PPLL_CNTL                    0x0002 /* PLL */
+#       define RADEON_PPLL_RESET                (1 <<  0)
+#       define RADEON_PPLL_SLEEP                (1 <<  1)
+#       define RADEON_PPLL_PVG_MASK             (7 << 11)
+#       define RADEON_PPLL_PVG_SHIFT            11
+#       define RADEON_PPLL_ATOMIC_UPDATE_EN     (1 << 16)
+#       define RADEON_PPLL_VGA_ATOMIC_UPDATE_EN (1 << 17)
+#       define RADEON_PPLL_ATOMIC_UPDATE_VSYNC  (1 << 18)
+#define RADEON_PPLL_DIV_0                   0x0004 /* PLL */
+#define RADEON_PPLL_DIV_1                   0x0005 /* PLL */
+#define RADEON_PPLL_DIV_2                   0x0006 /* PLL */
+#define RADEON_PPLL_DIV_3                   0x0007 /* PLL */
+#       define RADEON_PPLL_FB3_DIV_MASK     0x07ff
+#       define RADEON_PPLL_POST3_DIV_MASK   0x00070000
+#define RADEON_PPLL_REF_DIV                 0x0003 /* PLL */
+#       define RADEON_PPLL_REF_DIV_MASK     0x03ff
+#       define RADEON_PPLL_ATOMIC_UPDATE_R  (1 << 15) /* same as _W */
+#       define RADEON_PPLL_ATOMIC_UPDATE_W  (1 << 15) /* same as _R */
+#define RADEON_PWR_MNGMT_CNTL_STATUS        0x0f60 /* PCI */
+
+#define RADEON_RBBM_GUICNTL                 0x172c
+#       define RADEON_HOST_DATA_SWAP_NONE   (0 << 0)
+#       define RADEON_HOST_DATA_SWAP_16BIT  (1 << 0)
+#       define RADEON_HOST_DATA_SWAP_32BIT  (2 << 0)
+#       define RADEON_HOST_DATA_SWAP_HDW    (3 << 0)
+#define RADEON_RBBM_SOFT_RESET              0x00f0
+#       define RADEON_SOFT_RESET_CP         (1 <<  0)
+#       define RADEON_SOFT_RESET_HI         (1 <<  1)
+#       define RADEON_SOFT_RESET_SE         (1 <<  2)
+#       define RADEON_SOFT_RESET_RE         (1 <<  3)
+#       define RADEON_SOFT_RESET_PP         (1 <<  4)
+#       define RADEON_SOFT_RESET_E2         (1 <<  5)
+#       define RADEON_SOFT_RESET_RB         (1 <<  6)
+#       define RADEON_SOFT_RESET_HDP        (1 <<  7)
+#define RADEON_RBBM_STATUS                  0x0e40
+#       define RADEON_RBBM_FIFOCNT_MASK     0x007f
+#       define RADEON_RBBM_ACTIVE           (1 << 31)
+#define RADEON_RB2D_DSTCACHE_CTLSTAT        0x342c
+#       define RADEON_RB2D_DC_FLUSH         (3 << 0)
+#       define RADEON_RB2D_DC_FREE          (3 << 2)
+#       define RADEON_RB2D_DC_FLUSH_ALL     0xf
+#       define RADEON_RB2D_DC_BUSY          (1 << 31)
+#define RADEON_RB2D_DSTCACHE_MODE           0x3428
+#define RADEON_DSTCACHE_CTLSTAT             0x1714
+
+#define RADEON_RB3D_ZCACHE_MODE             0x3250
+#define RADEON_RB3D_ZCACHE_CTLSTAT          0x3254
+#       define RADEON_RB3D_ZC_FLUSH_ALL     0x5
+#define RADEON_RB3D_DSTCACHE_MODE           0x3258
+# define RADEON_RB3D_DC_CACHE_ENABLE            (0)
+# define RADEON_RB3D_DC_2D_CACHE_DISABLE        (1)
+# define RADEON_RB3D_DC_3D_CACHE_DISABLE        (2)
+# define RADEON_RB3D_DC_CACHE_DISABLE           (3)
+# define RADEON_RB3D_DC_2D_CACHE_LINESIZE_128   (1 << 2)
+# define RADEON_RB3D_DC_3D_CACHE_LINESIZE_128   (2 << 2)
+# define RADEON_RB3D_DC_2D_CACHE_AUTOFLUSH      (1 << 8)
+# define RADEON_RB3D_DC_3D_CACHE_AUTOFLUSH      (2 << 8)
+# define R200_RB3D_DC_2D_CACHE_AUTOFREE         (1 << 10)
+# define R200_RB3D_DC_3D_CACHE_AUTOFREE         (2 << 10)
+# define RADEON_RB3D_DC_FORCE_RMW               (1 << 16)
+# define RADEON_RB3D_DC_DISABLE_RI_FILL         (1 << 24)
+# define RADEON_RB3D_DC_DISABLE_RI_READ         (1 << 25)
+
+#define RADEON_RB3D_DSTCACHE_CTLSTAT            0x325C
+# define RADEON_RB3D_DC_FLUSH                   (3 << 0)
+# define RADEON_RB3D_DC_FREE                    (3 << 2)
+# define RADEON_RB3D_DC_FLUSH_ALL               0xf
+# define RADEON_RB3D_DC_BUSY                    (1 << 31)
+
+#define RADEON_REG_BASE                     0x0f18 /* PCI */
+#define RADEON_REGPROG_INF                  0x0f09 /* PCI */
+#define RADEON_REVISION_ID                  0x0f08 /* PCI */
+
+#define RADEON_SC_BOTTOM                    0x164c
+#define RADEON_SC_BOTTOM_RIGHT              0x16f0
+#define RADEON_SC_BOTTOM_RIGHT_C            0x1c8c
+#define RADEON_SC_LEFT                      0x1640
+#define RADEON_SC_RIGHT                     0x1644
+#define RADEON_SC_TOP                       0x1648
+#define RADEON_SC_TOP_LEFT                  0x16ec
+#define RADEON_SC_TOP_LEFT_C                0x1c88
+#       define RADEON_SC_SIGN_MASK_LO       0x8000
+#       define RADEON_SC_SIGN_MASK_HI       0x80000000
+#define RADEON_M_SPLL_REF_FB_DIV            0x000a /* PLL */
+#      define RADEON_M_SPLL_REF_DIV_SHIFT  0
+#      define RADEON_M_SPLL_REF_DIV_MASK   0xff
+#      define RADEON_MPLL_FB_DIV_SHIFT     8
+#      define RADEON_MPLL_FB_DIV_MASK      0xff
+#      define RADEON_SPLL_FB_DIV_SHIFT     16
+#      define RADEON_SPLL_FB_DIV_MASK      0xff
+#define RADEON_SPLL_CNTL                    0x000c /* PLL */
+#       define RADEON_SPLL_SLEEP            (1 << 0)
+#       define RADEON_SPLL_RESET            (1 << 1)
+#       define RADEON_SPLL_PCP_MASK         0x7
+#       define RADEON_SPLL_PCP_SHIFT        8
+#       define RADEON_SPLL_PVG_MASK         0x7
+#       define RADEON_SPLL_PVG_SHIFT        11
+#       define RADEON_SPLL_PDC_MASK         0x3
+#       define RADEON_SPLL_PDC_SHIFT        14
+#define RADEON_SCLK_CNTL                    0x000d /* PLL */
+#       define RADEON_SCLK_SRC_SEL_MASK     0x0007
+#       define RADEON_DYN_STOP_LAT_MASK     0x00007ff8
+#       define RADEON_CP_MAX_DYN_STOP_LAT   0x0008
+#       define RADEON_SCLK_FORCEON_MASK     0xffff8000
+#       define RADEON_SCLK_FORCE_DISP2      (1<<15)
+#       define RADEON_SCLK_FORCE_CP         (1<<16)
+#       define RADEON_SCLK_FORCE_HDP        (1<<17)
+#       define RADEON_SCLK_FORCE_DISP1      (1<<18)
+#       define RADEON_SCLK_FORCE_TOP        (1<<19)
+#       define RADEON_SCLK_FORCE_E2         (1<<20)
+#       define RADEON_SCLK_FORCE_SE         (1<<21)
+#       define RADEON_SCLK_FORCE_IDCT       (1<<22)
+#       define RADEON_SCLK_FORCE_VIP        (1<<23)
+#       define RADEON_SCLK_FORCE_RE         (1<<24)
+#       define RADEON_SCLK_FORCE_PB         (1<<25)
+#       define RADEON_SCLK_FORCE_TAM        (1<<26)
+#       define RADEON_SCLK_FORCE_TDM        (1<<27)
+#       define RADEON_SCLK_FORCE_RB         (1<<28)
+#       define RADEON_SCLK_FORCE_TV_SCLK    (1<<29)
+#       define RADEON_SCLK_FORCE_SUBPIC     (1<<30)
+#       define RADEON_SCLK_FORCE_OV0        (1<<31)
+#       define R300_SCLK_FORCE_VAP          (1<<21)
+#       define R300_SCLK_FORCE_SR           (1<<25)
+#       define R300_SCLK_FORCE_PX           (1<<26)
+#       define R300_SCLK_FORCE_TX           (1<<27)
+#       define R300_SCLK_FORCE_US           (1<<28)
+#       define R300_SCLK_FORCE_SU           (1<<30)
+#define R300_SCLK_CNTL2                     0x1e   /* PLL */
+#       define R300_SCLK_TCL_MAX_DYN_STOP_LAT (1<<10)
+#       define R300_SCLK_GA_MAX_DYN_STOP_LAT  (1<<11)
+#       define R300_SCLK_CBA_MAX_DYN_STOP_LAT (1<<12)
+#       define R300_SCLK_FORCE_TCL          (1<<13)
+#       define R300_SCLK_FORCE_CBA          (1<<14)
+#       define R300_SCLK_FORCE_GA           (1<<15)
+#define RADEON_SCLK_MORE_CNTL               0x0035 /* PLL */
+#       define RADEON_SCLK_MORE_MAX_DYN_STOP_LAT 0x0007
+#       define RADEON_SCLK_MORE_FORCEON     0x0700
+#define RADEON_SDRAM_MODE_REG               0x0158
+#define RADEON_SEQ8_DATA                    0x03c5 /* VGA */
+#define RADEON_SEQ8_IDX                     0x03c4 /* VGA */
+#define RADEON_SNAPSHOT_F_COUNT             0x0244
+#define RADEON_SNAPSHOT_VH_COUNTS           0x0240
+#define RADEON_SNAPSHOT_VIF_COUNT           0x024c
+#define RADEON_SRC_OFFSET                   0x15ac
+#define RADEON_SRC_PITCH                    0x15b0
+#define RADEON_SRC_PITCH_OFFSET             0x1428
+#define RADEON_SRC_SC_BOTTOM                0x165c
+#define RADEON_SRC_SC_BOTTOM_RIGHT          0x16f4
+#define RADEON_SRC_SC_RIGHT                 0x1654
+#define RADEON_SRC_X                        0x1414
+#define RADEON_SRC_X_Y                      0x1590
+#define RADEON_SRC_Y                        0x1418
+#define RADEON_SRC_Y_X                      0x1434
+#define RADEON_STATUS                       0x0f06 /* PCI */
+#define RADEON_SUBPIC_CNTL                  0x0540 /* ? */
+#define RADEON_SUB_CLASS                    0x0f0a /* PCI */
+#define RADEON_SURFACE_CNTL                 0x0b00
+#       define RADEON_SURF_TRANSLATION_DIS  (1 << 8)
+#       define RADEON_NONSURF_AP0_SWP_16BPP (1 << 20)
+#       define RADEON_NONSURF_AP0_SWP_32BPP (1 << 21)
+#       define RADEON_NONSURF_AP1_SWP_16BPP (1 << 22)
+#       define RADEON_NONSURF_AP1_SWP_32BPP (1 << 23)
+#define RADEON_SURFACE0_INFO                0x0b0c
+#       define RADEON_SURF_TILE_COLOR_MACRO (0 << 16)
+#       define RADEON_SURF_TILE_COLOR_BOTH  (1 << 16)
+#       define RADEON_SURF_TILE_DEPTH_32BPP (2 << 16)
+#       define RADEON_SURF_TILE_DEPTH_16BPP (3 << 16)
+#       define R200_SURF_TILE_NONE          (0 << 16)
+#       define R200_SURF_TILE_COLOR_MACRO   (1 << 16)
+#       define R200_SURF_TILE_COLOR_MICRO   (2 << 16)
+#       define R200_SURF_TILE_COLOR_BOTH    (3 << 16)
+#       define R200_SURF_TILE_DEPTH_32BPP   (4 << 16)
+#       define R200_SURF_TILE_DEPTH_16BPP   (5 << 16)
+#       define R300_SURF_TILE_NONE          (0 << 16)
+#       define R300_SURF_TILE_COLOR_MACRO   (1 << 16)
+#       define R300_SURF_TILE_DEPTH_32BPP   (2 << 16)
+#       define RADEON_SURF_AP0_SWP_16BPP    (1 << 20)
+#       define RADEON_SURF_AP0_SWP_32BPP    (1 << 21)
+#       define RADEON_SURF_AP1_SWP_16BPP    (1 << 22)
+#       define RADEON_SURF_AP1_SWP_32BPP    (1 << 23)
+#define RADEON_SURFACE0_LOWER_BOUND         0x0b04
+#define RADEON_SURFACE0_UPPER_BOUND         0x0b08
+#define RADEON_SURFACE1_INFO                0x0b1c
+#define RADEON_SURFACE1_LOWER_BOUND         0x0b14
+#define RADEON_SURFACE1_UPPER_BOUND         0x0b18
+#define RADEON_SURFACE2_INFO                0x0b2c
+#define RADEON_SURFACE2_LOWER_BOUND         0x0b24
+#define RADEON_SURFACE2_UPPER_BOUND         0x0b28
+#define RADEON_SURFACE3_INFO                0x0b3c
+#define RADEON_SURFACE3_LOWER_BOUND         0x0b34
+#define RADEON_SURFACE3_UPPER_BOUND         0x0b38
+#define RADEON_SURFACE4_INFO                0x0b4c
+#define RADEON_SURFACE4_LOWER_BOUND         0x0b44
+#define RADEON_SURFACE4_UPPER_BOUND         0x0b48
+#define RADEON_SURFACE5_INFO                0x0b5c
+#define RADEON_SURFACE5_LOWER_BOUND         0x0b54
+#define RADEON_SURFACE5_UPPER_BOUND         0x0b58
+#define RADEON_SURFACE6_INFO                0x0b6c
+#define RADEON_SURFACE6_LOWER_BOUND         0x0b64
+#define RADEON_SURFACE6_UPPER_BOUND         0x0b68
+#define RADEON_SURFACE7_INFO                0x0b7c
+#define RADEON_SURFACE7_LOWER_BOUND         0x0b74
+#define RADEON_SURFACE7_UPPER_BOUND         0x0b78
+#define RADEON_SW_SEMAPHORE                 0x013c
+
+#define RADEON_TEST_DEBUG_CNTL              0x0120
+#define RADEON_TEST_DEBUG_CNTL__TEST_DEBUG_OUT_EN 0x00000001
+
+#define RADEON_TEST_DEBUG_MUX               0x0124
+#define RADEON_TEST_DEBUG_OUT               0x012c
+#define RADEON_TMDS_PLL_CNTL                0x02a8
+#define RADEON_TMDS_TRANSMITTER_CNTL        0x02a4
+#       define RADEON_TMDS_TRANSMITTER_PLLEN  1
+#       define RADEON_TMDS_TRANSMITTER_PLLRST 2
+#define RADEON_TRAIL_BRES_DEC               0x1614
+#define RADEON_TRAIL_BRES_ERR               0x160c
+#define RADEON_TRAIL_BRES_INC               0x1610
+#define RADEON_TRAIL_X                      0x1618
+#define RADEON_TRAIL_X_SUB                  0x1620
+
+#define RADEON_VCLK_ECP_CNTL                0x0008 /* PLL */
+#       define RADEON_VCLK_SRC_SEL_MASK     0x03
+#       define RADEON_VCLK_SRC_SEL_CPUCLK   0x00
+#       define RADEON_VCLK_SRC_SEL_PSCANCLK 0x01
+#       define RADEON_VCLK_SRC_SEL_BYTECLK  0x02
+#       define RADEON_VCLK_SRC_SEL_PPLLCLK  0x03
+#       define RADEON_PIXCLK_ALWAYS_ONb     (1<<6)
+#       define RADEON_PIXCLK_DAC_ALWAYS_ONb (1<<7)
+#       define R300_DISP_DAC_PIXCLK_DAC_BLANK_OFF (1<<23)
+
+#define RADEON_VENDOR_ID                    0x0f00 /* PCI */
+#define RADEON_VGA_DDA_CONFIG               0x02e8
+#define RADEON_VGA_DDA_ON_OFF               0x02ec
+#define RADEON_VID_BUFFER_CONTROL           0x0900
+#define RADEON_VIDEOMUX_CNTL                0x0190
+
+/* VIP bus */
+#define RADEON_VIPH_CH0_DATA                0x0c00
+#define RADEON_VIPH_CH1_DATA                0x0c04
+#define RADEON_VIPH_CH2_DATA                0x0c08
+#define RADEON_VIPH_CH3_DATA                0x0c0c
+#define RADEON_VIPH_CH0_ADDR                0x0c10
+#define RADEON_VIPH_CH1_ADDR                0x0c14
+#define RADEON_VIPH_CH2_ADDR                0x0c18
+#define RADEON_VIPH_CH3_ADDR                0x0c1c
+#define RADEON_VIPH_CH0_SBCNT               0x0c20
+#define RADEON_VIPH_CH1_SBCNT               0x0c24
+#define RADEON_VIPH_CH2_SBCNT               0x0c28
+#define RADEON_VIPH_CH3_SBCNT               0x0c2c
+#define RADEON_VIPH_CH0_ABCNT               0x0c30
+#define RADEON_VIPH_CH1_ABCNT               0x0c34
+#define RADEON_VIPH_CH2_ABCNT               0x0c38
+#define RADEON_VIPH_CH3_ABCNT               0x0c3c
+#define RADEON_VIPH_CONTROL                 0x0c40
+#       define RADEON_VIP_BUSY 0
+#       define RADEON_VIP_IDLE 1
+#       define RADEON_VIP_RESET 2
+#       define RADEON_VIPH_EN               (1 << 21)
+#define RADEON_VIPH_DV_LAT                  0x0c44
+#define RADEON_VIPH_BM_CHUNK                0x0c48
+#define RADEON_VIPH_DV_INT                  0x0c4c
+#define RADEON_VIPH_TIMEOUT_STAT            0x0c50
+#define RADEON_VIPH_TIMEOUT_STAT__VIPH_REG_STAT 0x00000010
+#define RADEON_VIPH_TIMEOUT_STAT__VIPH_REG_AK   0x00000010
+#define RADEON_VIPH_TIMEOUT_STAT__VIPH_REGR_DIS 0x01000000
+
+#define RADEON_VIPH_REG_DATA                0x0084
+#define RADEON_VIPH_REG_ADDR                0x0080
+
+
+#define RADEON_WAIT_UNTIL                   0x1720
+#       define RADEON_WAIT_CRTC_PFLIP       (1 << 0)
+#       define RADEON_WAIT_RE_CRTC_VLINE    (1 << 1)
+#       define RADEON_WAIT_FE_CRTC_VLINE    (1 << 2)
+#       define RADEON_WAIT_CRTC_VLINE       (1 << 3)
+#       define RADEON_WAIT_DMA_VID_IDLE     (1 << 8)
+#       define RADEON_WAIT_DMA_GUI_IDLE     (1 << 9)
+#       define RADEON_WAIT_CMDFIFO          (1 << 10) /* wait for CMDFIFO_ENTRIES */
+#       define RADEON_WAIT_OV0_FLIP         (1 << 11)
+#       define RADEON_WAIT_AGP_FLUSH        (1 << 13)
+#       define RADEON_WAIT_2D_IDLE          (1 << 14)
+#       define RADEON_WAIT_3D_IDLE          (1 << 15)
+#       define RADEON_WAIT_2D_IDLECLEAN     (1 << 16)
+#       define RADEON_WAIT_3D_IDLECLEAN     (1 << 17)
+#       define RADEON_WAIT_HOST_IDLECLEAN   (1 << 18)
+#       define RADEON_CMDFIFO_ENTRIES_SHIFT 10
+#       define RADEON_CMDFIFO_ENTRIES_MASK  0x7f
+#       define RADEON_WAIT_VAP_IDLE         (1 << 28)
+#       define RADEON_WAIT_BOTH_CRTC_PFLIP  (1 << 30)
+#       define RADEON_ENG_DISPLAY_SELECT_CRTC0    (0 << 31)
+#       define RADEON_ENG_DISPLAY_SELECT_CRTC1    (1 << 31)
+
+#define RADEON_X_MPLL_REF_FB_DIV            0x000a /* PLL */
+#define RADEON_XCLK_CNTL                    0x000d /* PLL */
+#define RADEON_XDLL_CNTL                    0x000c /* PLL */
+#define RADEON_XPLL_CNTL                    0x000b /* PLL */
+
+
+
+                               /* Registers for 3D/TCL */
+#define RADEON_PP_BORDER_COLOR_0            0x1d40
+#define RADEON_PP_BORDER_COLOR_1            0x1d44
+#define RADEON_PP_BORDER_COLOR_2            0x1d48
+#define RADEON_PP_CNTL                      0x1c38
+#       define RADEON_STIPPLE_ENABLE        (1 <<  0)
+#       define RADEON_SCISSOR_ENABLE        (1 <<  1)
+#       define RADEON_PATTERN_ENABLE        (1 <<  2)
+#       define RADEON_SHADOW_ENABLE         (1 <<  3)
+#       define RADEON_TEX_ENABLE_MASK       (0xf << 4)
+#       define RADEON_TEX_0_ENABLE          (1 <<  4)
+#       define RADEON_TEX_1_ENABLE          (1 <<  5)
+#       define RADEON_TEX_2_ENABLE          (1 <<  6)
+#       define RADEON_TEX_3_ENABLE          (1 <<  7)
+#       define RADEON_TEX_BLEND_ENABLE_MASK (0xf << 12)
+#       define RADEON_TEX_BLEND_0_ENABLE    (1 << 12)
+#       define RADEON_TEX_BLEND_1_ENABLE    (1 << 13)
+#       define RADEON_TEX_BLEND_2_ENABLE    (1 << 14)
+#       define RADEON_TEX_BLEND_3_ENABLE    (1 << 15)
+#       define RADEON_PLANAR_YUV_ENABLE     (1 << 20)
+#       define RADEON_SPECULAR_ENABLE       (1 << 21)
+#       define RADEON_FOG_ENABLE            (1 << 22)
+#       define RADEON_ALPHA_TEST_ENABLE     (1 << 23)
+#       define RADEON_ANTI_ALIAS_NONE       (0 << 24)
+#       define RADEON_ANTI_ALIAS_LINE       (1 << 24)
+#       define RADEON_ANTI_ALIAS_POLY       (2 << 24)
+#       define RADEON_ANTI_ALIAS_LINE_POLY  (3 << 24)
+#       define RADEON_BUMP_MAP_ENABLE       (1 << 26)
+#       define RADEON_BUMPED_MAP_T0         (0 << 27)
+#       define RADEON_BUMPED_MAP_T1         (1 << 27)
+#       define RADEON_BUMPED_MAP_T2         (2 << 27)
+#       define RADEON_TEX_3D_ENABLE_0       (1 << 29)
+#       define RADEON_TEX_3D_ENABLE_1       (1 << 30)
+#       define RADEON_MC_ENABLE             (1 << 31)
+#define RADEON_PP_FOG_COLOR                 0x1c18
+#       define RADEON_FOG_COLOR_MASK        0x00ffffff
+#       define RADEON_FOG_VERTEX            (0 << 24)
+#       define RADEON_FOG_TABLE             (1 << 24)
+#       define RADEON_FOG_USE_DEPTH         (0 << 25)
+#       define RADEON_FOG_USE_DIFFUSE_ALPHA (2 << 25)
+#       define RADEON_FOG_USE_SPEC_ALPHA    (3 << 25)
+#define RADEON_PP_LUM_MATRIX                0x1d00
+#define RADEON_PP_MISC                      0x1c14
+#       define RADEON_REF_ALPHA_MASK        0x000000ff
+#       define RADEON_ALPHA_TEST_FAIL       (0 << 8)
+#       define RADEON_ALPHA_TEST_LESS       (1 << 8)
+#       define RADEON_ALPHA_TEST_LEQUAL     (2 << 8)
+#       define RADEON_ALPHA_TEST_EQUAL      (3 << 8)
+#       define RADEON_ALPHA_TEST_GEQUAL     (4 << 8)
+#       define RADEON_ALPHA_TEST_GREATER    (5 << 8)
+#       define RADEON_ALPHA_TEST_NEQUAL     (6 << 8)
+#       define RADEON_ALPHA_TEST_PASS       (7 << 8)
+#       define RADEON_ALPHA_TEST_OP_MASK    (7 << 8)
+#       define RADEON_CHROMA_FUNC_FAIL      (0 << 16)
+#       define RADEON_CHROMA_FUNC_PASS      (1 << 16)
+#       define RADEON_CHROMA_FUNC_NEQUAL    (2 << 16)
+#       define RADEON_CHROMA_FUNC_EQUAL     (3 << 16)
+#       define RADEON_CHROMA_KEY_NEAREST    (0 << 18)
+#       define RADEON_CHROMA_KEY_ZERO       (1 << 18)
+#       define RADEON_SHADOW_ID_AUTO_INC    (1 << 20)
+#       define RADEON_SHADOW_FUNC_EQUAL     (0 << 21)
+#       define RADEON_SHADOW_FUNC_NEQUAL    (1 << 21)
+#       define RADEON_SHADOW_PASS_1         (0 << 22)
+#       define RADEON_SHADOW_PASS_2         (1 << 22)
+#       define RADEON_RIGHT_HAND_CUBE_D3D   (0 << 24)
+#       define RADEON_RIGHT_HAND_CUBE_OGL   (1 << 24)
+#define RADEON_PP_ROT_MATRIX_0              0x1d58
+#define RADEON_PP_ROT_MATRIX_1              0x1d5c
+#define RADEON_PP_TXFILTER_0                0x1c54
+#define RADEON_PP_TXFILTER_1                0x1c6c
+#define RADEON_PP_TXFILTER_2                0x1c84
+#       define RADEON_MAG_FILTER_NEAREST                   (0  <<  0)
+#       define RADEON_MAG_FILTER_LINEAR                    (1  <<  0)
+#       define RADEON_MAG_FILTER_MASK                      (1  <<  0)
+#       define RADEON_MIN_FILTER_NEAREST                   (0  <<  1)
+#       define RADEON_MIN_FILTER_LINEAR                    (1  <<  1)
+#       define RADEON_MIN_FILTER_NEAREST_MIP_NEAREST       (2  <<  1)
+#       define RADEON_MIN_FILTER_NEAREST_MIP_LINEAR        (3  <<  1)
+#       define RADEON_MIN_FILTER_LINEAR_MIP_NEAREST        (6  <<  1)
+#       define RADEON_MIN_FILTER_LINEAR_MIP_LINEAR         (7  <<  1)
+#       define RADEON_MIN_FILTER_ANISO_NEAREST             (8  <<  1)
+#       define RADEON_MIN_FILTER_ANISO_LINEAR              (9  <<  1)
+#       define RADEON_MIN_FILTER_ANISO_NEAREST_MIP_NEAREST (10 <<  1)
+#       define RADEON_MIN_FILTER_ANISO_NEAREST_MIP_LINEAR  (11 <<  1)
+#       define RADEON_MIN_FILTER_MASK                      (15 <<  1)
+#       define RADEON_MAX_ANISO_1_TO_1                     (0  <<  5)
+#       define RADEON_MAX_ANISO_2_TO_1                     (1  <<  5)
+#       define RADEON_MAX_ANISO_4_TO_1                     (2  <<  5)
+#       define RADEON_MAX_ANISO_8_TO_1                     (3  <<  5)
+#       define RADEON_MAX_ANISO_16_TO_1                    (4  <<  5)
+#       define RADEON_MAX_ANISO_MASK                       (7  <<  5)
+#       define RADEON_LOD_BIAS_MASK                        (0xff <<  8)
+#       define RADEON_LOD_BIAS_SHIFT                       8
+#       define RADEON_MAX_MIP_LEVEL_MASK                   (0x0f << 16)
+#       define RADEON_MAX_MIP_LEVEL_SHIFT                  16
+#       define RADEON_YUV_TO_RGB                           (1  << 20)
+#       define RADEON_YUV_TEMPERATURE_COOL                 (0  << 21)
+#       define RADEON_YUV_TEMPERATURE_HOT                  (1  << 21)
+#       define RADEON_YUV_TEMPERATURE_MASK                 (1  << 21)
+#       define RADEON_WRAPEN_S                             (1  << 22)
+#       define RADEON_CLAMP_S_WRAP                         (0  << 23)
+#       define RADEON_CLAMP_S_MIRROR                       (1  << 23)
+#       define RADEON_CLAMP_S_CLAMP_LAST                   (2  << 23)
+#       define RADEON_CLAMP_S_MIRROR_CLAMP_LAST            (3  << 23)
+#       define RADEON_CLAMP_S_CLAMP_BORDER                 (4  << 23)
+#       define RADEON_CLAMP_S_MIRROR_CLAMP_BORDER          (5  << 23)
+#       define RADEON_CLAMP_S_CLAMP_GL                     (6  << 23)
+#       define RADEON_CLAMP_S_MIRROR_CLAMP_GL              (7  << 23)
+#       define RADEON_CLAMP_S_MASK                         (7  << 23)
+#       define RADEON_WRAPEN_T                             (1  << 26)
+#       define RADEON_CLAMP_T_WRAP                         (0  << 27)
+#       define RADEON_CLAMP_T_MIRROR                       (1  << 27)
+#       define RADEON_CLAMP_T_CLAMP_LAST                   (2  << 27)
+#       define RADEON_CLAMP_T_MIRROR_CLAMP_LAST            (3  << 27)
+#       define RADEON_CLAMP_T_CLAMP_BORDER                 (4  << 27)
+#       define RADEON_CLAMP_T_MIRROR_CLAMP_BORDER          (5  << 27)
+#       define RADEON_CLAMP_T_CLAMP_GL                     (6  << 27)
+#       define RADEON_CLAMP_T_MIRROR_CLAMP_GL              (7  << 27)
+#       define RADEON_CLAMP_T_MASK                         (7  << 27)
+#       define RADEON_BORDER_MODE_OGL                      (0  << 31)
+#       define RADEON_BORDER_MODE_D3D                      (1  << 31)
+#define RADEON_PP_TXFORMAT_0                0x1c58
+#define RADEON_PP_TXFORMAT_1                0x1c70
+#define RADEON_PP_TXFORMAT_2                0x1c88
+#       define RADEON_TXFORMAT_I8                 (0  <<  0)
+#       define RADEON_TXFORMAT_AI88               (1  <<  0)
+#       define RADEON_TXFORMAT_RGB332             (2  <<  0)
+#       define RADEON_TXFORMAT_ARGB1555           (3  <<  0)
+#       define RADEON_TXFORMAT_RGB565             (4  <<  0)
+#       define RADEON_TXFORMAT_ARGB4444           (5  <<  0)
+#       define RADEON_TXFORMAT_ARGB8888           (6  <<  0)
+#       define RADEON_TXFORMAT_RGBA8888           (7  <<  0)
+#       define RADEON_TXFORMAT_Y8                 (8  <<  0)
+#       define RADEON_TXFORMAT_VYUY422            (10 <<  0)
+#       define RADEON_TXFORMAT_YVYU422            (11 <<  0)
+#       define RADEON_TXFORMAT_DXT1               (12 <<  0)
+#       define RADEON_TXFORMAT_DXT23              (14 <<  0)
+#       define RADEON_TXFORMAT_DXT45              (15 <<  0)
+#       define RADEON_TXFORMAT_FORMAT_MASK        (31 <<  0)
+#       define RADEON_TXFORMAT_FORMAT_SHIFT       0
+#       define RADEON_TXFORMAT_APPLE_YUV_MODE     (1  <<  5)
+#       define RADEON_TXFORMAT_ALPHA_IN_MAP       (1  <<  6)
+#       define RADEON_TXFORMAT_NON_POWER2         (1  <<  7)
+#       define RADEON_TXFORMAT_WIDTH_MASK         (15 <<  8)
+#       define RADEON_TXFORMAT_WIDTH_SHIFT        8
+#       define RADEON_TXFORMAT_HEIGHT_MASK        (15 << 12)
+#       define RADEON_TXFORMAT_HEIGHT_SHIFT       12
+#       define RADEON_TXFORMAT_F5_WIDTH_MASK      (15 << 16)
+#       define RADEON_TXFORMAT_F5_WIDTH_SHIFT     16
+#       define RADEON_TXFORMAT_F5_HEIGHT_MASK     (15 << 20)
+#       define RADEON_TXFORMAT_F5_HEIGHT_SHIFT    20
+#       define RADEON_TXFORMAT_ST_ROUTE_STQ0      (0  << 24)
+#       define RADEON_TXFORMAT_ST_ROUTE_MASK      (3  << 24)
+#       define RADEON_TXFORMAT_ST_ROUTE_STQ1      (1  << 24)
+#       define RADEON_TXFORMAT_ST_ROUTE_STQ2      (2  << 24)
+#       define RADEON_TXFORMAT_ENDIAN_NO_SWAP     (0  << 26)
+#       define RADEON_TXFORMAT_ENDIAN_16BPP_SWAP  (1  << 26)
+#       define RADEON_TXFORMAT_ENDIAN_32BPP_SWAP  (2  << 26)
+#       define RADEON_TXFORMAT_ENDIAN_HALFDW_SWAP (3  << 26)
+#       define RADEON_TXFORMAT_ALPHA_MASK_ENABLE  (1  << 28)
+#       define RADEON_TXFORMAT_CHROMA_KEY_ENABLE  (1  << 29)
+#       define RADEON_TXFORMAT_CUBIC_MAP_ENABLE   (1  << 30)
+#       define RADEON_TXFORMAT_PERSPECTIVE_ENABLE (1  << 31)
+#define RADEON_PP_CUBIC_FACES_0             0x1d24
+#define RADEON_PP_CUBIC_FACES_1             0x1d28
+#define RADEON_PP_CUBIC_FACES_2             0x1d2c
+#       define RADEON_FACE_WIDTH_1_SHIFT          0
+#       define RADEON_FACE_HEIGHT_1_SHIFT         4
+#       define RADEON_FACE_WIDTH_1_MASK           (0xf << 0)
+#       define RADEON_FACE_HEIGHT_1_MASK          (0xf << 4)
+#       define RADEON_FACE_WIDTH_2_SHIFT          8
+#       define RADEON_FACE_HEIGHT_2_SHIFT         12
+#       define RADEON_FACE_WIDTH_2_MASK           (0xf << 8)
+#       define RADEON_FACE_HEIGHT_2_MASK          (0xf << 12)
+#       define RADEON_FACE_WIDTH_3_SHIFT          16
+#       define RADEON_FACE_HEIGHT_3_SHIFT         20
+#       define RADEON_FACE_WIDTH_3_MASK           (0xf << 16)
+#       define RADEON_FACE_HEIGHT_3_MASK          (0xf << 20)
+#       define RADEON_FACE_WIDTH_4_SHIFT          24
+#       define RADEON_FACE_HEIGHT_4_SHIFT         28
+#       define RADEON_FACE_WIDTH_4_MASK           (0xf << 24)
+#       define RADEON_FACE_HEIGHT_4_MASK          (0xf << 28)
+
+#define RADEON_PP_TXOFFSET_0                0x1c5c
+#define RADEON_PP_TXOFFSET_1                0x1c74
+#define RADEON_PP_TXOFFSET_2                0x1c8c
+#       define RADEON_TXO_ENDIAN_NO_SWAP     (0 << 0)
+#       define RADEON_TXO_ENDIAN_BYTE_SWAP   (1 << 0)
+#       define RADEON_TXO_ENDIAN_WORD_SWAP   (2 << 0)
+#       define RADEON_TXO_ENDIAN_HALFDW_SWAP (3 << 0)
+#       define RADEON_TXO_MACRO_LINEAR       (0 << 2)
+#       define RADEON_TXO_MACRO_TILE         (1 << 2)
+#       define RADEON_TXO_MICRO_LINEAR       (0 << 3)
+#       define RADEON_TXO_MICRO_TILE_X2      (1 << 3)
+#       define RADEON_TXO_MICRO_TILE_OPT     (2 << 3)
+#       define RADEON_TXO_OFFSET_MASK        0xffffffe0
+#       define RADEON_TXO_OFFSET_SHIFT       5
+
+#define RADEON_PP_CUBIC_OFFSET_T0_0         0x1dd0  /* bits [31:5] */
+#define RADEON_PP_CUBIC_OFFSET_T0_1         0x1dd4
+#define RADEON_PP_CUBIC_OFFSET_T0_2         0x1dd8
+#define RADEON_PP_CUBIC_OFFSET_T0_3         0x1ddc
+#define RADEON_PP_CUBIC_OFFSET_T0_4         0x1de0
+#define RADEON_PP_CUBIC_OFFSET_T1_0         0x1e00
+#define RADEON_PP_CUBIC_OFFSET_T1_1         0x1e04
+#define RADEON_PP_CUBIC_OFFSET_T1_2         0x1e08
+#define RADEON_PP_CUBIC_OFFSET_T1_3         0x1e0c
+#define RADEON_PP_CUBIC_OFFSET_T1_4         0x1e10
+#define RADEON_PP_CUBIC_OFFSET_T2_0         0x1e14
+#define RADEON_PP_CUBIC_OFFSET_T2_1         0x1e18
+#define RADEON_PP_CUBIC_OFFSET_T2_2         0x1e1c
+#define RADEON_PP_CUBIC_OFFSET_T2_3         0x1e20
+#define RADEON_PP_CUBIC_OFFSET_T2_4         0x1e24
+
+#define RADEON_PP_TEX_SIZE_0                0x1d04  /* NPOT */
+#define RADEON_PP_TEX_SIZE_1                0x1d0c
+#define RADEON_PP_TEX_SIZE_2                0x1d14
+#       define RADEON_TEX_USIZE_MASK        (0x7ff << 0)
+#       define RADEON_TEX_USIZE_SHIFT       0
+#       define RADEON_TEX_VSIZE_MASK        (0x7ff << 16)
+#       define RADEON_TEX_VSIZE_SHIFT       16
+#       define RADEON_SIGNED_RGB_MASK       (1 << 30)
+#       define RADEON_SIGNED_RGB_SHIFT      30
+#       define RADEON_SIGNED_ALPHA_MASK     (1 << 31)
+#       define RADEON_SIGNED_ALPHA_SHIFT    31
+#define RADEON_PP_TEX_PITCH_0               0x1d08  /* NPOT */
+#define RADEON_PP_TEX_PITCH_1               0x1d10  /* NPOT */
+#define RADEON_PP_TEX_PITCH_2               0x1d18  /* NPOT */
+/* note: bits 13-5: 32 byte aligned stride of texture map */
+
+#define RADEON_PP_TXCBLEND_0                0x1c60
+#define RADEON_PP_TXCBLEND_1                0x1c78
+#define RADEON_PP_TXCBLEND_2                0x1c90
+#       define RADEON_COLOR_ARG_A_SHIFT          0
+#       define RADEON_COLOR_ARG_A_MASK           (0x1f << 0)
+#       define RADEON_COLOR_ARG_A_ZERO           (0    << 0)
+#       define RADEON_COLOR_ARG_A_CURRENT_COLOR  (2    << 0)
+#       define RADEON_COLOR_ARG_A_CURRENT_ALPHA  (3    << 0)
+#       define RADEON_COLOR_ARG_A_DIFFUSE_COLOR  (4    << 0)
+#       define RADEON_COLOR_ARG_A_DIFFUSE_ALPHA  (5    << 0)
+#       define RADEON_COLOR_ARG_A_SPECULAR_COLOR (6    << 0)
+#       define RADEON_COLOR_ARG_A_SPECULAR_ALPHA (7    << 0)
+#       define RADEON_COLOR_ARG_A_TFACTOR_COLOR  (8    << 0)
+#       define RADEON_COLOR_ARG_A_TFACTOR_ALPHA  (9    << 0)
+#       define RADEON_COLOR_ARG_A_T0_COLOR       (10   << 0)
+#       define RADEON_COLOR_ARG_A_T0_ALPHA       (11   << 0)
+#       define RADEON_COLOR_ARG_A_T1_COLOR       (12   << 0)
+#       define RADEON_COLOR_ARG_A_T1_ALPHA       (13   << 0)
+#       define RADEON_COLOR_ARG_A_T2_COLOR       (14   << 0)
+#       define RADEON_COLOR_ARG_A_T2_ALPHA       (15   << 0)
+#       define RADEON_COLOR_ARG_A_T3_COLOR       (16   << 0)
+#       define RADEON_COLOR_ARG_A_T3_ALPHA       (17   << 0)
+#       define RADEON_COLOR_ARG_B_SHIFT          5
+#       define RADEON_COLOR_ARG_B_MASK           (0x1f << 5)
+#       define RADEON_COLOR_ARG_B_ZERO           (0    << 5)
+#       define RADEON_COLOR_ARG_B_CURRENT_COLOR  (2    << 5)
+#       define RADEON_COLOR_ARG_B_CURRENT_ALPHA  (3    << 5)
+#       define RADEON_COLOR_ARG_B_DIFFUSE_COLOR  (4    << 5)
+#       define RADEON_COLOR_ARG_B_DIFFUSE_ALPHA  (5    << 5)
+#       define RADEON_COLOR_ARG_B_SPECULAR_COLOR (6    << 5)
+#       define RADEON_COLOR_ARG_B_SPECULAR_ALPHA (7    << 5)
+#       define RADEON_COLOR_ARG_B_TFACTOR_COLOR  (8    << 5)
+#       define RADEON_COLOR_ARG_B_TFACTOR_ALPHA  (9    << 5)
+#       define RADEON_COLOR_ARG_B_T0_COLOR       (10   << 5)
+#       define RADEON_COLOR_ARG_B_T0_ALPHA       (11   << 5)
+#       define RADEON_COLOR_ARG_B_T1_COLOR       (12   << 5)
+#       define RADEON_COLOR_ARG_B_T1_ALPHA       (13   << 5)
+#       define RADEON_COLOR_ARG_B_T2_COLOR       (14   << 5)
+#       define RADEON_COLOR_ARG_B_T2_ALPHA       (15   << 5)
+#       define RADEON_COLOR_ARG_B_T3_COLOR       (16   << 5)
+#       define RADEON_COLOR_ARG_B_T3_ALPHA       (17   << 5)
+#       define RADEON_COLOR_ARG_C_SHIFT          10
+#       define RADEON_COLOR_ARG_C_MASK           (0x1f << 10)
+#       define RADEON_COLOR_ARG_C_ZERO           (0    << 10)
+#       define RADEON_COLOR_ARG_C_CURRENT_COLOR  (2    << 10)
+#       define RADEON_COLOR_ARG_C_CURRENT_ALPHA  (3    << 10)
+#       define RADEON_COLOR_ARG_C_DIFFUSE_COLOR  (4    << 10)
+#       define RADEON_COLOR_ARG_C_DIFFUSE_ALPHA  (5    << 10)
+#       define RADEON_COLOR_ARG_C_SPECULAR_COLOR (6    << 10)
+#       define RADEON_COLOR_ARG_C_SPECULAR_ALPHA (7    << 10)
+#       define RADEON_COLOR_ARG_C_TFACTOR_COLOR  (8    << 10)
+#       define RADEON_COLOR_ARG_C_TFACTOR_ALPHA  (9    << 10)
+#       define RADEON_COLOR_ARG_C_T0_COLOR       (10   << 10)
+#       define RADEON_COLOR_ARG_C_T0_ALPHA       (11   << 10)
+#       define RADEON_COLOR_ARG_C_T1_COLOR       (12   << 10)
+#       define RADEON_COLOR_ARG_C_T1_ALPHA       (13   << 10)
+#       define RADEON_COLOR_ARG_C_T2_COLOR       (14   << 10)
+#       define RADEON_COLOR_ARG_C_T2_ALPHA       (15   << 10)
+#       define RADEON_COLOR_ARG_C_T3_COLOR       (16   << 10)
+#       define RADEON_COLOR_ARG_C_T3_ALPHA       (17   << 10)
+#       define RADEON_COMP_ARG_A                 (1 << 15)
+#       define RADEON_COMP_ARG_A_SHIFT           15
+#       define RADEON_COMP_ARG_B                 (1 << 16)
+#       define RADEON_COMP_ARG_B_SHIFT           16
+#       define RADEON_COMP_ARG_C                 (1 << 17)
+#       define RADEON_COMP_ARG_C_SHIFT           17
+#       define RADEON_BLEND_CTL_MASK             (7 << 18)
+#       define RADEON_BLEND_CTL_ADD              (0 << 18)
+#       define RADEON_BLEND_CTL_SUBTRACT         (1 << 18)
+#       define RADEON_BLEND_CTL_ADDSIGNED        (2 << 18)
+#       define RADEON_BLEND_CTL_BLEND            (3 << 18)
+#       define RADEON_BLEND_CTL_DOT3             (4 << 18)
+#       define RADEON_SCALE_SHIFT                21
+#       define RADEON_SCALE_MASK                 (3 << 21)
+#       define RADEON_SCALE_1X                   (0 << 21)
+#       define RADEON_SCALE_2X                   (1 << 21)
+#       define RADEON_SCALE_4X                   (2 << 21)
+#       define RADEON_CLAMP_TX                   (1 << 23)
+#       define RADEON_T0_EQ_TCUR                 (1 << 24)
+#       define RADEON_T1_EQ_TCUR                 (1 << 25)
+#       define RADEON_T2_EQ_TCUR                 (1 << 26)
+#       define RADEON_T3_EQ_TCUR                 (1 << 27)
+#       define RADEON_COLOR_ARG_MASK             0x1f
+#       define RADEON_COMP_ARG_SHIFT             15
+#define RADEON_PP_TXABLEND_0                0x1c64
+#define RADEON_PP_TXABLEND_1                0x1c7c
+#define RADEON_PP_TXABLEND_2                0x1c94
+#       define RADEON_ALPHA_ARG_A_SHIFT          0
+#       define RADEON_ALPHA_ARG_A_MASK           (0xf << 0)
+#       define RADEON_ALPHA_ARG_A_ZERO           (0   << 0)
+#       define RADEON_ALPHA_ARG_A_CURRENT_ALPHA  (1   << 0)
+#       define RADEON_ALPHA_ARG_A_DIFFUSE_ALPHA  (2   << 0)
+#       define RADEON_ALPHA_ARG_A_SPECULAR_ALPHA (3   << 0)
+#       define RADEON_ALPHA_ARG_A_TFACTOR_ALPHA  (4   << 0)
+#       define RADEON_ALPHA_ARG_A_T0_ALPHA       (5   << 0)
+#       define RADEON_ALPHA_ARG_A_T1_ALPHA       (6   << 0)
+#       define RADEON_ALPHA_ARG_A_T2_ALPHA       (7   << 0)
+#       define RADEON_ALPHA_ARG_A_T3_ALPHA       (8   << 0)
+#       define RADEON_ALPHA_ARG_B_SHIFT          4
+#       define RADEON_ALPHA_ARG_B_MASK           (0xf << 4)
+#       define RADEON_ALPHA_ARG_B_ZERO           (0   << 4)
+#       define RADEON_ALPHA_ARG_B_CURRENT_ALPHA  (1   << 4)
+#       define RADEON_ALPHA_ARG_B_DIFFUSE_ALPHA  (2   << 4)
+#       define RADEON_ALPHA_ARG_B_SPECULAR_ALPHA (3   << 4)
+#       define RADEON_ALPHA_ARG_B_TFACTOR_ALPHA  (4   << 4)
+#       define RADEON_ALPHA_ARG_B_T0_ALPHA       (5   << 4)
+#       define RADEON_ALPHA_ARG_B_T1_ALPHA       (6   << 4)
+#       define RADEON_ALPHA_ARG_B_T2_ALPHA       (7   << 4)
+#       define RADEON_ALPHA_ARG_B_T3_ALPHA       (8   << 4)
+#       define RADEON_ALPHA_ARG_C_SHIFT          8
+#       define RADEON_ALPHA_ARG_C_MASK           (0xf << 8)
+#       define RADEON_ALPHA_ARG_C_ZERO           (0   << 8)
+#       define RADEON_ALPHA_ARG_C_CURRENT_ALPHA  (1   << 8)
+#       define RADEON_ALPHA_ARG_C_DIFFUSE_ALPHA  (2   << 8)
+#       define RADEON_ALPHA_ARG_C_SPECULAR_ALPHA (3   << 8)
+#       define RADEON_ALPHA_ARG_C_TFACTOR_ALPHA  (4   << 8)
+#       define RADEON_ALPHA_ARG_C_T0_ALPHA       (5   << 8)
+#       define RADEON_ALPHA_ARG_C_T1_ALPHA       (6   << 8)
+#       define RADEON_ALPHA_ARG_C_T2_ALPHA       (7   << 8)
+#       define RADEON_ALPHA_ARG_C_T3_ALPHA       (8   << 8)
+#       define RADEON_DOT_ALPHA_DONT_REPLICATE   (1   << 9)
+#       define RADEON_ALPHA_ARG_MASK             0xf
+
+#define RADEON_PP_TFACTOR_0                 0x1c68
+#define RADEON_PP_TFACTOR_1                 0x1c80
+#define RADEON_PP_TFACTOR_2                 0x1c98
+
+#define RADEON_RB3D_BLENDCNTL               0x1c20
+#       define RADEON_COMB_FCN_MASK                    (3  << 12)
+#       define RADEON_COMB_FCN_ADD_CLAMP               (0  << 12)
+#       define RADEON_COMB_FCN_ADD_NOCLAMP             (1  << 12)
+#       define RADEON_COMB_FCN_SUB_CLAMP               (2  << 12)
+#       define RADEON_COMB_FCN_SUB_NOCLAMP             (3  << 12)
+#       define RADEON_SRC_BLEND_GL_ZERO                (32 << 16)
+#       define RADEON_SRC_BLEND_GL_ONE                 (33 << 16)
+#       define RADEON_SRC_BLEND_GL_SRC_COLOR           (34 << 16)
+#       define RADEON_SRC_BLEND_GL_ONE_MINUS_SRC_COLOR (35 << 16)
+#       define RADEON_SRC_BLEND_GL_DST_COLOR           (36 << 16)
+#       define RADEON_SRC_BLEND_GL_ONE_MINUS_DST_COLOR (37 << 16)
+#       define RADEON_SRC_BLEND_GL_SRC_ALPHA           (38 << 16)
+#       define RADEON_SRC_BLEND_GL_ONE_MINUS_SRC_ALPHA (39 << 16)
+#       define RADEON_SRC_BLEND_GL_DST_ALPHA           (40 << 16)
+#       define RADEON_SRC_BLEND_GL_ONE_MINUS_DST_ALPHA (41 << 16)
+#       define RADEON_SRC_BLEND_GL_SRC_ALPHA_SATURATE  (42 << 16)
+#       define RADEON_SRC_BLEND_MASK                   (63 << 16)
+#       define RADEON_DST_BLEND_GL_ZERO                (32 << 24)
+#       define RADEON_DST_BLEND_GL_ONE                 (33 << 24)
+#       define RADEON_DST_BLEND_GL_SRC_COLOR           (34 << 24)
+#       define RADEON_DST_BLEND_GL_ONE_MINUS_SRC_COLOR (35 << 24)
+#       define RADEON_DST_BLEND_GL_DST_COLOR           (36 << 24)
+#       define RADEON_DST_BLEND_GL_ONE_MINUS_DST_COLOR (37 << 24)
+#       define RADEON_DST_BLEND_GL_SRC_ALPHA           (38 << 24)
+#       define RADEON_DST_BLEND_GL_ONE_MINUS_SRC_ALPHA (39 << 24)
+#       define RADEON_DST_BLEND_GL_DST_ALPHA           (40 << 24)
+#       define RADEON_DST_BLEND_GL_ONE_MINUS_DST_ALPHA (41 << 24)
+#       define RADEON_DST_BLEND_MASK                   (63 << 24)
+#define RADEON_RB3D_CNTL                    0x1c3c
+#       define RADEON_ALPHA_BLEND_ENABLE       (1  <<  0)
+#       define RADEON_PLANE_MASK_ENABLE        (1  <<  1)
+#       define RADEON_DITHER_ENABLE            (1  <<  2)
+#       define RADEON_ROUND_ENABLE             (1  <<  3)
+#       define RADEON_SCALE_DITHER_ENABLE      (1  <<  4)
+#       define RADEON_DITHER_INIT              (1  <<  5)
+#       define RADEON_ROP_ENABLE               (1  <<  6)
+#       define RADEON_STENCIL_ENABLE           (1  <<  7)
+#       define RADEON_Z_ENABLE                 (1  <<  8)
+#       define RADEON_DEPTH_XZ_OFFEST_ENABLE   (1  <<  9)
+#       define RADEON_RB3D_COLOR_FORMAT_SHIFT  10
+
+#       define RADEON_COLOR_FORMAT_ARGB1555    3
+#       define RADEON_COLOR_FORMAT_RGB565      4
+#       define RADEON_COLOR_FORMAT_ARGB8888    6
+#       define RADEON_COLOR_FORMAT_RGB332      7
+#       define RADEON_COLOR_FORMAT_Y8          8
+#       define RADEON_COLOR_FORMAT_RGB8        9
+#       define RADEON_COLOR_FORMAT_YUV422_VYUY 11
+#       define RADEON_COLOR_FORMAT_YUV422_YVYU 12
+#       define RADEON_COLOR_FORMAT_aYUV444     14
+#       define RADEON_COLOR_FORMAT_ARGB4444    15
+
+#       define RADEON_CLRCMP_FLIP_ENABLE       (1  << 14)
+#define RADEON_RB3D_COLOROFFSET             0x1c40
+#       define RADEON_COLOROFFSET_MASK      0xfffffff0
+#define RADEON_RB3D_COLORPITCH              0x1c48
+#       define RADEON_COLORPITCH_MASK         0x000001ff8
+#       define RADEON_COLOR_TILE_ENABLE       (1 << 16)
+#       define RADEON_COLOR_MICROTILE_ENABLE  (1 << 17)
+#       define RADEON_COLOR_ENDIAN_NO_SWAP    (0 << 18)
+#       define RADEON_COLOR_ENDIAN_WORD_SWAP  (1 << 18)
+#       define RADEON_COLOR_ENDIAN_DWORD_SWAP (2 << 18)
+#define RADEON_RB3D_DEPTHOFFSET             0x1c24
+#define RADEON_RB3D_DEPTHPITCH              0x1c28
+#       define RADEON_DEPTHPITCH_MASK         0x00001ff8
+#       define RADEON_DEPTH_ENDIAN_NO_SWAP    (0 << 18)
+#       define RADEON_DEPTH_ENDIAN_WORD_SWAP  (1 << 18)
+#       define RADEON_DEPTH_ENDIAN_DWORD_SWAP (2 << 18)
+#define RADEON_RB3D_PLANEMASK               0x1d84
+#define RADEON_RB3D_ROPCNTL                 0x1d80
+#       define RADEON_ROP_MASK              (15 << 8)
+#       define RADEON_ROP_CLEAR             (0  << 8)
+#       define RADEON_ROP_NOR               (1  << 8)
+#       define RADEON_ROP_AND_INVERTED      (2  << 8)
+#       define RADEON_ROP_COPY_INVERTED     (3  << 8)
+#       define RADEON_ROP_AND_REVERSE       (4  << 8)
+#       define RADEON_ROP_INVERT            (5  << 8)
+#       define RADEON_ROP_XOR               (6  << 8)
+#       define RADEON_ROP_NAND              (7  << 8)
+#       define RADEON_ROP_AND               (8  << 8)
+#       define RADEON_ROP_EQUIV             (9  << 8)
+#       define RADEON_ROP_NOOP              (10 << 8)
+#       define RADEON_ROP_OR_INVERTED       (11 << 8)
+#       define RADEON_ROP_COPY              (12 << 8)
+#       define RADEON_ROP_OR_REVERSE        (13 << 8)
+#       define RADEON_ROP_OR                (14 << 8)
+#       define RADEON_ROP_SET               (15 << 8)
+#define RADEON_RB3D_STENCILREFMASK          0x1d7c
+#       define RADEON_STENCIL_REF_SHIFT       0
+#       define RADEON_STENCIL_REF_MASK        (0xff << 0)
+#       define RADEON_STENCIL_MASK_SHIFT      16
+#       define RADEON_STENCIL_VALUE_MASK      (0xff << 16)
+#       define RADEON_STENCIL_WRITEMASK_SHIFT 24
+#       define RADEON_STENCIL_WRITE_MASK      (0xff << 24)
+#define RADEON_RB3D_ZSTENCILCNTL            0x1c2c
+#       define RADEON_DEPTH_FORMAT_MASK          (0xf << 0)
+#       define RADEON_DEPTH_FORMAT_16BIT_INT_Z   (0  <<  0)
+#       define RADEON_DEPTH_FORMAT_24BIT_INT_Z   (2  <<  0)
+#       define RADEON_DEPTH_FORMAT_24BIT_FLOAT_Z (3  <<  0)
+#       define RADEON_DEPTH_FORMAT_32BIT_INT_Z   (4  <<  0)
+#       define RADEON_DEPTH_FORMAT_32BIT_FLOAT_Z (5  <<  0)
+#       define RADEON_DEPTH_FORMAT_16BIT_FLOAT_W (7  <<  0)
+#       define RADEON_DEPTH_FORMAT_24BIT_FLOAT_W (9  <<  0)
+#       define RADEON_DEPTH_FORMAT_32BIT_FLOAT_W (11 <<  0)
+#       define RADEON_Z_TEST_NEVER               (0  <<  4)
+#       define RADEON_Z_TEST_LESS                (1  <<  4)
+#       define RADEON_Z_TEST_LEQUAL              (2  <<  4)
+#       define RADEON_Z_TEST_EQUAL               (3  <<  4)
+#       define RADEON_Z_TEST_GEQUAL              (4  <<  4)
+#       define RADEON_Z_TEST_GREATER             (5  <<  4)
+#       define RADEON_Z_TEST_NEQUAL              (6  <<  4)
+#       define RADEON_Z_TEST_ALWAYS              (7  <<  4)
+#       define RADEON_Z_TEST_MASK                (7  <<  4)
+#       define RADEON_STENCIL_TEST_NEVER         (0  << 12)
+#       define RADEON_STENCIL_TEST_LESS          (1  << 12)
+#       define RADEON_STENCIL_TEST_LEQUAL        (2  << 12)
+#       define RADEON_STENCIL_TEST_EQUAL         (3  << 12)
+#       define RADEON_STENCIL_TEST_GEQUAL        (4  << 12)
+#       define RADEON_STENCIL_TEST_GREATER       (5  << 12)
+#       define RADEON_STENCIL_TEST_NEQUAL        (6  << 12)
+#       define RADEON_STENCIL_TEST_ALWAYS        (7  << 12)
+#       define RADEON_STENCIL_TEST_MASK          (0x7 << 12)
+#       define RADEON_STENCIL_FAIL_KEEP          (0  << 16)
+#       define RADEON_STENCIL_FAIL_ZERO          (1  << 16)
+#       define RADEON_STENCIL_FAIL_REPLACE       (2  << 16)
+#       define RADEON_STENCIL_FAIL_INC           (3  << 16)
+#       define RADEON_STENCIL_FAIL_DEC           (4  << 16)
+#       define RADEON_STENCIL_FAIL_INVERT        (5  << 16)
+#       define RADEON_STENCIL_FAIL_MASK          (0x7 << 16)
+#       define RADEON_STENCIL_ZPASS_KEEP         (0  << 20)
+#       define RADEON_STENCIL_ZPASS_ZERO         (1  << 20)
+#       define RADEON_STENCIL_ZPASS_REPLACE      (2  << 20)
+#       define RADEON_STENCIL_ZPASS_INC          (3  << 20)
+#       define RADEON_STENCIL_ZPASS_DEC          (4  << 20)
+#       define RADEON_STENCIL_ZPASS_INVERT       (5  << 20)
+#       define RADEON_STENCIL_ZPASS_MASK         (0x7 << 20)
+#       define RADEON_STENCIL_ZFAIL_KEEP         (0  << 24)
+#       define RADEON_STENCIL_ZFAIL_ZERO         (1  << 24)
+#       define RADEON_STENCIL_ZFAIL_REPLACE      (2  << 24)
+#       define RADEON_STENCIL_ZFAIL_INC          (3  << 24)
+#       define RADEON_STENCIL_ZFAIL_DEC          (4  << 24)
+#       define RADEON_STENCIL_ZFAIL_INVERT       (5  << 24)
+#       define RADEON_STENCIL_ZFAIL_MASK         (0x7 << 24)
+#       define RADEON_Z_COMPRESSION_ENABLE       (1  << 28)
+#       define RADEON_FORCE_Z_DIRTY              (1  << 29)
+#       define RADEON_Z_WRITE_ENABLE             (1  << 30)
+#define RADEON_RE_LINE_PATTERN              0x1cd0
+#       define RADEON_LINE_PATTERN_MASK             0x0000ffff
+#       define RADEON_LINE_REPEAT_COUNT_SHIFT       16
+#       define RADEON_LINE_PATTERN_START_SHIFT      24
+#       define RADEON_LINE_PATTERN_LITTLE_BIT_ORDER (0 << 28)
+#       define RADEON_LINE_PATTERN_BIG_BIT_ORDER    (1 << 28)
+#       define RADEON_LINE_PATTERN_AUTO_RESET       (1 << 29)
+#define RADEON_RE_LINE_STATE                0x1cd4
+#       define RADEON_LINE_CURRENT_PTR_SHIFT   0
+#       define RADEON_LINE_CURRENT_COUNT_SHIFT 8
+#define RADEON_RE_MISC                      0x26c4
+#       define RADEON_STIPPLE_COORD_MASK       0x1f
+#       define RADEON_STIPPLE_X_OFFSET_SHIFT   0
+#       define RADEON_STIPPLE_X_OFFSET_MASK    (0x1f << 0)
+#       define RADEON_STIPPLE_Y_OFFSET_SHIFT   8
+#       define RADEON_STIPPLE_Y_OFFSET_MASK    (0x1f << 8)
+#       define RADEON_STIPPLE_LITTLE_BIT_ORDER (0 << 16)
+#       define RADEON_STIPPLE_BIG_BIT_ORDER    (1 << 16)
+#define RADEON_RE_SOLID_COLOR               0x1c1c
+#define RADEON_RE_TOP_LEFT                  0x26c0
+#       define RADEON_RE_LEFT_SHIFT         0
+#       define RADEON_RE_TOP_SHIFT          16
+#define RADEON_RE_WIDTH_HEIGHT              0x1c44
+#       define RADEON_RE_WIDTH_SHIFT        0
+#       define RADEON_RE_HEIGHT_SHIFT       16
+
+#define RADEON_SE_CNTL                      0x1c4c
+#       define RADEON_FFACE_CULL_CW          (0 <<  0)
+#       define RADEON_FFACE_CULL_CCW         (1 <<  0)
+#       define RADEON_FFACE_CULL_DIR_MASK    (1 <<  0)
+#       define RADEON_BFACE_CULL             (0 <<  1)
+#       define RADEON_BFACE_SOLID            (3 <<  1)
+#       define RADEON_FFACE_CULL             (0 <<  3)
+#       define RADEON_FFACE_SOLID            (3 <<  3)
+#       define RADEON_FFACE_CULL_MASK        (3 <<  3)
+#       define RADEON_BADVTX_CULL_DISABLE    (1 <<  5)
+#       define RADEON_FLAT_SHADE_VTX_0       (0 <<  6)
+#       define RADEON_FLAT_SHADE_VTX_1       (1 <<  6)
+#       define RADEON_FLAT_SHADE_VTX_2       (2 <<  6)
+#       define RADEON_FLAT_SHADE_VTX_LAST    (3 <<  6)
+#       define RADEON_DIFFUSE_SHADE_SOLID    (0 <<  8)
+#       define RADEON_DIFFUSE_SHADE_FLAT     (1 <<  8)
+#       define RADEON_DIFFUSE_SHADE_GOURAUD  (2 <<  8)
+#       define RADEON_DIFFUSE_SHADE_MASK     (3 <<  8)
+#       define RADEON_ALPHA_SHADE_SOLID      (0 << 10)
+#       define RADEON_ALPHA_SHADE_FLAT       (1 << 10)
+#       define RADEON_ALPHA_SHADE_GOURAUD    (2 << 10)
+#       define RADEON_ALPHA_SHADE_MASK       (3 << 10)
+#       define RADEON_SPECULAR_SHADE_SOLID   (0 << 12)
+#       define RADEON_SPECULAR_SHADE_FLAT    (1 << 12)
+#       define RADEON_SPECULAR_SHADE_GOURAUD (2 << 12)
+#       define RADEON_SPECULAR_SHADE_MASK    (3 << 12)
+#       define RADEON_FOG_SHADE_SOLID        (0 << 14)
+#       define RADEON_FOG_SHADE_FLAT         (1 << 14)
+#       define RADEON_FOG_SHADE_GOURAUD      (2 << 14)
+#       define RADEON_FOG_SHADE_MASK         (3 << 14)
+#       define RADEON_ZBIAS_ENABLE_POINT     (1 << 16)
+#       define RADEON_ZBIAS_ENABLE_LINE      (1 << 17)
+#       define RADEON_ZBIAS_ENABLE_TRI       (1 << 18)
+#       define RADEON_WIDELINE_ENABLE        (1 << 20)
+#       define RADEON_VPORT_XY_XFORM_ENABLE  (1 << 24)
+#       define RADEON_VPORT_Z_XFORM_ENABLE   (1 << 25)
+#       define RADEON_VTX_PIX_CENTER_D3D     (0 << 27)
+#       define RADEON_VTX_PIX_CENTER_OGL     (1 << 27)
+#       define RADEON_ROUND_MODE_TRUNC       (0 << 28)
+#       define RADEON_ROUND_MODE_ROUND       (1 << 28)
+#       define RADEON_ROUND_MODE_ROUND_EVEN  (2 << 28)
+#       define RADEON_ROUND_MODE_ROUND_ODD   (3 << 28)
+#       define RADEON_ROUND_PREC_16TH_PIX    (0 << 30)
+#       define RADEON_ROUND_PREC_8TH_PIX     (1 << 30)
+#       define RADEON_ROUND_PREC_4TH_PIX     (2 << 30)
+#       define RADEON_ROUND_PREC_HALF_PIX    (3 << 30)
+#define R200_RE_CNTL                           0x1c50
+#       define R200_STIPPLE_ENABLE             0x1
+#       define R200_SCISSOR_ENABLE             0x2
+#       define R200_PATTERN_ENABLE             0x4
+#       define R200_PERSPECTIVE_ENABLE         0x8
+#       define R200_POINT_SMOOTH               0x20
+#       define R200_VTX_STQ0_D3D               0x00010000
+#       define R200_VTX_STQ1_D3D               0x00040000
+#       define R200_VTX_STQ2_D3D               0x00100000
+#       define R200_VTX_STQ3_D3D               0x00400000
+#       define R200_VTX_STQ4_D3D               0x01000000
+#       define R200_VTX_STQ5_D3D               0x04000000
+#define RADEON_SE_CNTL_STATUS               0x2140
+#       define RADEON_VC_NO_SWAP            (0 << 0)
+#       define RADEON_VC_16BIT_SWAP         (1 << 0)
+#       define RADEON_VC_32BIT_SWAP         (2 << 0)
+#       define RADEON_VC_HALF_DWORD_SWAP    (3 << 0)
+#       define RADEON_TCL_BYPASS            (1 << 8)
+#define RADEON_SE_COORD_FMT                 0x1c50
+#       define RADEON_VTX_XY_PRE_MULT_1_OVER_W0  (1 <<  0)
+#       define RADEON_VTX_Z_PRE_MULT_1_OVER_W0   (1 <<  1)
+#       define RADEON_VTX_ST0_NONPARAMETRIC      (1 <<  8)
+#       define RADEON_VTX_ST1_NONPARAMETRIC      (1 <<  9)
+#       define RADEON_VTX_ST2_NONPARAMETRIC      (1 << 10)
+#       define RADEON_VTX_ST3_NONPARAMETRIC      (1 << 11)
+#       define RADEON_VTX_W0_NORMALIZE           (1 << 12)
+#       define RADEON_VTX_W0_IS_NOT_1_OVER_W0    (1 << 16)
+#       define RADEON_VTX_ST0_PRE_MULT_1_OVER_W0 (1 << 17)
+#       define RADEON_VTX_ST1_PRE_MULT_1_OVER_W0 (1 << 19)
+#       define RADEON_VTX_ST2_PRE_MULT_1_OVER_W0 (1 << 21)
+#       define RADEON_VTX_ST3_PRE_MULT_1_OVER_W0 (1 << 23)
+#       define RADEON_TEX1_W_ROUTING_USE_W0      (0 << 26)
+#       define RADEON_TEX1_W_ROUTING_USE_Q1      (1 << 26)
+#define RADEON_SE_LINE_WIDTH                0x1db8
+#define RADEON_SE_TCL_LIGHT_MODEL_CTL       0x226c
+#       define RADEON_LIGHTING_ENABLE              (1 << 0)
+#       define RADEON_LIGHT_IN_MODELSPACE          (1 << 1)
+#       define RADEON_LOCAL_VIEWER                 (1 << 2)
+#       define RADEON_NORMALIZE_NORMALS            (1 << 3)
+#       define RADEON_RESCALE_NORMALS              (1 << 4)
+#       define RADEON_SPECULAR_LIGHTS              (1 << 5)
+#       define RADEON_DIFFUSE_SPECULAR_COMBINE     (1 << 6)
+#       define RADEON_LIGHT_ALPHA                  (1 << 7)
+#       define RADEON_LOCAL_LIGHT_VEC_GL           (1 << 8)
+#       define RADEON_LIGHT_NO_NORMAL_AMBIENT_ONLY (1 << 9)
+#       define RADEON_LM_SOURCE_STATE_PREMULT      0
+#       define RADEON_LM_SOURCE_STATE_MULT         1
+#       define RADEON_LM_SOURCE_VERTEX_DIFFUSE     2
+#       define RADEON_LM_SOURCE_VERTEX_SPECULAR    3
+#       define RADEON_EMISSIVE_SOURCE_SHIFT        16
+#       define RADEON_AMBIENT_SOURCE_SHIFT         18
+#       define RADEON_DIFFUSE_SOURCE_SHIFT         20
+#       define RADEON_SPECULAR_SOURCE_SHIFT        22
+#define RADEON_SE_TCL_MATERIAL_AMBIENT_RED     0x2220
+#define RADEON_SE_TCL_MATERIAL_AMBIENT_GREEN   0x2224
+#define RADEON_SE_TCL_MATERIAL_AMBIENT_BLUE    0x2228
+#define RADEON_SE_TCL_MATERIAL_AMBIENT_ALPHA   0x222c
+#define RADEON_SE_TCL_MATERIAL_DIFFUSE_RED     0x2230
+#define RADEON_SE_TCL_MATERIAL_DIFFUSE_GREEN   0x2234
+#define RADEON_SE_TCL_MATERIAL_DIFFUSE_BLUE    0x2238
+#define RADEON_SE_TCL_MATERIAL_DIFFUSE_ALPHA   0x223c
+#define RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED   0x2210
+#define RADEON_SE_TCL_MATERIAL_EMMISSIVE_GREEN 0x2214
+#define RADEON_SE_TCL_MATERIAL_EMMISSIVE_BLUE  0x2218
+#define RADEON_SE_TCL_MATERIAL_EMMISSIVE_ALPHA 0x221c
+#define RADEON_SE_TCL_MATERIAL_SPECULAR_RED    0x2240
+#define RADEON_SE_TCL_MATERIAL_SPECULAR_GREEN  0x2244
+#define RADEON_SE_TCL_MATERIAL_SPECULAR_BLUE   0x2248
+#define RADEON_SE_TCL_MATERIAL_SPECULAR_ALPHA  0x224c
+#define RADEON_SE_TCL_MATRIX_SELECT_0       0x225c
+#       define RADEON_MODELVIEW_0_SHIFT        0
+#       define RADEON_MODELVIEW_1_SHIFT        4
+#       define RADEON_MODELVIEW_2_SHIFT        8
+#       define RADEON_MODELVIEW_3_SHIFT        12
+#       define RADEON_IT_MODELVIEW_0_SHIFT     16
+#       define RADEON_IT_MODELVIEW_1_SHIFT     20
+#       define RADEON_IT_MODELVIEW_2_SHIFT     24
+#       define RADEON_IT_MODELVIEW_3_SHIFT     28
+#define RADEON_SE_TCL_MATRIX_SELECT_1       0x2260
+#       define RADEON_MODELPROJECT_0_SHIFT     0
+#       define RADEON_MODELPROJECT_1_SHIFT     4
+#       define RADEON_MODELPROJECT_2_SHIFT     8
+#       define RADEON_MODELPROJECT_3_SHIFT     12
+#       define RADEON_TEXMAT_0_SHIFT           16
+#       define RADEON_TEXMAT_1_SHIFT           20
+#       define RADEON_TEXMAT_2_SHIFT           24
+#       define RADEON_TEXMAT_3_SHIFT           28
+
+
+#define RADEON_SE_TCL_OUTPUT_VTX_FMT        0x2254
+#       define RADEON_TCL_VTX_W0                 (1 <<  0)
+#       define RADEON_TCL_VTX_FP_DIFFUSE         (1 <<  1)
+#       define RADEON_TCL_VTX_FP_ALPHA           (1 <<  2)
+#       define RADEON_TCL_VTX_PK_DIFFUSE         (1 <<  3)
+#       define RADEON_TCL_VTX_FP_SPEC            (1 <<  4)
+#       define RADEON_TCL_VTX_FP_FOG             (1 <<  5)
+#       define RADEON_TCL_VTX_PK_SPEC            (1 <<  6)
+#       define RADEON_TCL_VTX_ST0                (1 <<  7)
+#       define RADEON_TCL_VTX_ST1                (1 <<  8)
+#       define RADEON_TCL_VTX_Q1                 (1 <<  9)
+#       define RADEON_TCL_VTX_ST2                (1 << 10)
+#       define RADEON_TCL_VTX_Q2                 (1 << 11)
+#       define RADEON_TCL_VTX_ST3                (1 << 12)
+#       define RADEON_TCL_VTX_Q3                 (1 << 13)
+#       define RADEON_TCL_VTX_Q0                 (1 << 14)
+#       define RADEON_TCL_VTX_WEIGHT_COUNT_SHIFT 15
+#       define RADEON_TCL_VTX_NORM0              (1 << 18)
+#       define RADEON_TCL_VTX_XY1                (1 << 27)
+#       define RADEON_TCL_VTX_Z1                 (1 << 28)
+#       define RADEON_TCL_VTX_W1                 (1 << 29)
+#       define RADEON_TCL_VTX_NORM1              (1 << 30)
+#       define RADEON_TCL_VTX_Z0                 (1 << 31)
+
+#define RADEON_SE_TCL_OUTPUT_VTX_SEL        0x2258
+#       define RADEON_TCL_COMPUTE_XYZW           (1 << 0)
+#       define RADEON_TCL_COMPUTE_DIFFUSE        (1 << 1)
+#       define RADEON_TCL_COMPUTE_SPECULAR       (1 << 2)
+#       define RADEON_TCL_FORCE_NAN_IF_COLOR_NAN (1 << 3)
+#       define RADEON_TCL_FORCE_INORDER_PROC     (1 << 4)
+#       define RADEON_TCL_TEX_INPUT_TEX_0        0
+#       define RADEON_TCL_TEX_INPUT_TEX_1        1
+#       define RADEON_TCL_TEX_INPUT_TEX_2        2
+#       define RADEON_TCL_TEX_INPUT_TEX_3        3
+#       define RADEON_TCL_TEX_COMPUTED_TEX_0     8
+#       define RADEON_TCL_TEX_COMPUTED_TEX_1     9
+#       define RADEON_TCL_TEX_COMPUTED_TEX_2     10
+#       define RADEON_TCL_TEX_COMPUTED_TEX_3     11
+#       define RADEON_TCL_TEX_0_OUTPUT_SHIFT     16
+#       define RADEON_TCL_TEX_1_OUTPUT_SHIFT     20
+#       define RADEON_TCL_TEX_2_OUTPUT_SHIFT     24
+#       define RADEON_TCL_TEX_3_OUTPUT_SHIFT     28
+
+#define RADEON_SE_TCL_PER_LIGHT_CTL_0       0x2270
+#       define RADEON_LIGHT_0_ENABLE               (1 <<  0)
+#       define RADEON_LIGHT_0_ENABLE_AMBIENT       (1 <<  1)
+#       define RADEON_LIGHT_0_ENABLE_SPECULAR      (1 <<  2)
+#       define RADEON_LIGHT_0_IS_LOCAL             (1 <<  3)
+#       define RADEON_LIGHT_0_IS_SPOT              (1 <<  4)
+#       define RADEON_LIGHT_0_DUAL_CONE            (1 <<  5)
+#       define RADEON_LIGHT_0_ENABLE_RANGE_ATTEN   (1 <<  6)
+#       define RADEON_LIGHT_0_CONSTANT_RANGE_ATTEN (1 <<  7)
+#       define RADEON_LIGHT_0_SHIFT                0
+#       define RADEON_LIGHT_1_ENABLE               (1 << 16)
+#       define RADEON_LIGHT_1_ENABLE_AMBIENT       (1 << 17)
+#       define RADEON_LIGHT_1_ENABLE_SPECULAR      (1 << 18)
+#       define RADEON_LIGHT_1_IS_LOCAL             (1 << 19)
+#       define RADEON_LIGHT_1_IS_SPOT              (1 << 20)
+#       define RADEON_LIGHT_1_DUAL_CONE            (1 << 21)
+#       define RADEON_LIGHT_1_ENABLE_RANGE_ATTEN   (1 << 22)
+#       define RADEON_LIGHT_1_CONSTANT_RANGE_ATTEN (1 << 23)
+#       define RADEON_LIGHT_1_SHIFT                16
+#define RADEON_SE_TCL_PER_LIGHT_CTL_1       0x2274
+#       define RADEON_LIGHT_2_SHIFT            0
+#       define RADEON_LIGHT_3_SHIFT            16
+#define RADEON_SE_TCL_PER_LIGHT_CTL_2       0x2278
+#       define RADEON_LIGHT_4_SHIFT            0
+#       define RADEON_LIGHT_5_SHIFT            16
+#define RADEON_SE_TCL_PER_LIGHT_CTL_3       0x227c
+#       define RADEON_LIGHT_6_SHIFT            0
+#       define RADEON_LIGHT_7_SHIFT            16
+
+#define RADEON_SE_TCL_SHININESS             0x2250
+
+#define RADEON_SE_TCL_TEXTURE_PROC_CTL      0x2268
+#       define RADEON_TEXGEN_TEXMAT_0_ENABLE      (1 << 0)
+#       define RADEON_TEXGEN_TEXMAT_1_ENABLE      (1 << 1)
+#       define RADEON_TEXGEN_TEXMAT_2_ENABLE      (1 << 2)
+#       define RADEON_TEXGEN_TEXMAT_3_ENABLE      (1 << 3)
+#       define RADEON_TEXMAT_0_ENABLE             (1 << 4)
+#       define RADEON_TEXMAT_1_ENABLE             (1 << 5)
+#       define RADEON_TEXMAT_2_ENABLE             (1 << 6)
+#       define RADEON_TEXMAT_3_ENABLE             (1 << 7)
+#       define RADEON_TEXGEN_INPUT_MASK           0xf
+#       define RADEON_TEXGEN_INPUT_TEXCOORD_0     0
+#       define RADEON_TEXGEN_INPUT_TEXCOORD_1     1
+#       define RADEON_TEXGEN_INPUT_TEXCOORD_2     2
+#       define RADEON_TEXGEN_INPUT_TEXCOORD_3     3
+#       define RADEON_TEXGEN_INPUT_OBJ            4
+#       define RADEON_TEXGEN_INPUT_EYE            5
+#       define RADEON_TEXGEN_INPUT_EYE_NORMAL     6
+#       define RADEON_TEXGEN_INPUT_EYE_REFLECT    7
+#       define RADEON_TEXGEN_INPUT_EYE_NORMALIZED 8
+#       define RADEON_TEXGEN_0_INPUT_SHIFT        16
+#       define RADEON_TEXGEN_1_INPUT_SHIFT        20
+#       define RADEON_TEXGEN_2_INPUT_SHIFT        24
+#       define RADEON_TEXGEN_3_INPUT_SHIFT        28
+
+#define RADEON_SE_TCL_UCP_VERT_BLEND_CTL    0x2264
+#       define RADEON_UCP_IN_CLIP_SPACE            (1 <<  0)
+#       define RADEON_UCP_IN_MODEL_SPACE           (1 <<  1)
+#       define RADEON_UCP_ENABLE_0                 (1 <<  2)
+#       define RADEON_UCP_ENABLE_1                 (1 <<  3)
+#       define RADEON_UCP_ENABLE_2                 (1 <<  4)
+#       define RADEON_UCP_ENABLE_3                 (1 <<  5)
+#       define RADEON_UCP_ENABLE_4                 (1 <<  6)
+#       define RADEON_UCP_ENABLE_5                 (1 <<  7)
+#       define RADEON_TCL_FOG_MASK                 (3 <<  8)
+#       define RADEON_TCL_FOG_DISABLE              (0 <<  8)
+#       define RADEON_TCL_FOG_EXP                  (1 <<  8)
+#       define RADEON_TCL_FOG_EXP2                 (2 <<  8)
+#       define RADEON_TCL_FOG_LINEAR               (3 <<  8)
+#       define RADEON_RNG_BASED_FOG                (1 << 10)
+#       define RADEON_LIGHT_TWOSIDE                (1 << 11)
+#       define RADEON_BLEND_OP_COUNT_MASK          (7 << 12)
+#       define RADEON_BLEND_OP_COUNT_SHIFT         12
+#       define RADEON_POSITION_BLEND_OP_ENABLE     (1 << 16)
+#       define RADEON_NORMAL_BLEND_OP_ENABLE       (1 << 17)
+#       define RADEON_VERTEX_BLEND_SRC_0_PRIMARY   (1 << 18)
+#       define RADEON_VERTEX_BLEND_SRC_0_SECONDARY (1 << 18)
+#       define RADEON_VERTEX_BLEND_SRC_1_PRIMARY   (1 << 19)
+#       define RADEON_VERTEX_BLEND_SRC_1_SECONDARY (1 << 19)
+#       define RADEON_VERTEX_BLEND_SRC_2_PRIMARY   (1 << 20)
+#       define RADEON_VERTEX_BLEND_SRC_2_SECONDARY (1 << 20)
+#       define RADEON_VERTEX_BLEND_SRC_3_PRIMARY   (1 << 21)
+#       define RADEON_VERTEX_BLEND_SRC_3_SECONDARY (1 << 21)
+#       define RADEON_VERTEX_BLEND_WGT_MINUS_ONE   (1 << 22)
+#       define RADEON_CULL_FRONT_IS_CW             (0 << 28)
+#       define RADEON_CULL_FRONT_IS_CCW            (1 << 28)
+#       define RADEON_CULL_FRONT                   (1 << 29)
+#       define RADEON_CULL_BACK                    (1 << 30)
+#       define RADEON_FORCE_W_TO_ONE               (1 << 31)
+
+#define RADEON_SE_VPORT_XSCALE              0x1d98
+#define RADEON_SE_VPORT_XOFFSET             0x1d9c
+#define RADEON_SE_VPORT_YSCALE              0x1da0
+#define RADEON_SE_VPORT_YOFFSET             0x1da4
+#define RADEON_SE_VPORT_ZSCALE              0x1da8
+#define RADEON_SE_VPORT_ZOFFSET             0x1dac
+#define RADEON_SE_ZBIAS_FACTOR              0x1db0
+#define RADEON_SE_ZBIAS_CONSTANT            0x1db4
+
+#define RADEON_SE_VTX_FMT                   0x2080
+#       define RADEON_SE_VTX_FMT_XY         0x00000000
+#       define RADEON_SE_VTX_FMT_W0         0x00000001
+#       define RADEON_SE_VTX_FMT_FPCOLOR    0x00000002
+#       define RADEON_SE_VTX_FMT_FPALPHA    0x00000004
+#       define RADEON_SE_VTX_FMT_PKCOLOR    0x00000008
+#       define RADEON_SE_VTX_FMT_FPSPEC     0x00000010
+#       define RADEON_SE_VTX_FMT_FPFOG      0x00000020
+#       define RADEON_SE_VTX_FMT_PKSPEC     0x00000040
+#       define RADEON_SE_VTX_FMT_ST0        0x00000080
+#       define RADEON_SE_VTX_FMT_ST1        0x00000100
+#       define RADEON_SE_VTX_FMT_Q1         0x00000200
+#       define RADEON_SE_VTX_FMT_ST2        0x00000400
+#       define RADEON_SE_VTX_FMT_Q2         0x00000800
+#       define RADEON_SE_VTX_FMT_ST3        0x00001000
+#       define RADEON_SE_VTX_FMT_Q3         0x00002000
+#       define RADEON_SE_VTX_FMT_Q0         0x00004000
+#       define RADEON_SE_VTX_FMT_BLND_WEIGHT_CNT_MASK  0x00038000
+#       define RADEON_SE_VTX_FMT_N0         0x00040000
+#       define RADEON_SE_VTX_FMT_XY1        0x08000000
+#       define RADEON_SE_VTX_FMT_Z1         0x10000000
+#       define RADEON_SE_VTX_FMT_W1         0x20000000
+#       define RADEON_SE_VTX_FMT_N1         0x40000000
+#       define RADEON_SE_VTX_FMT_Z          0x80000000
+
+#define RADEON_SE_VF_CNTL                             0x2084
+#       define RADEON_VF_PRIM_TYPE_POINT_LIST         1
+#       define RADEON_VF_PRIM_TYPE_LINE_LIST          2
+#       define RADEON_VF_PRIM_TYPE_LINE_STRIP         3
+#       define RADEON_VF_PRIM_TYPE_TRIANGLE_LIST      4
+#       define RADEON_VF_PRIM_TYPE_TRIANGLE_FAN       5
+#       define RADEON_VF_PRIM_TYPE_TRIANGLE_STRIP     6
+#       define RADEON_VF_PRIM_TYPE_TRIANGLE_FLAG      7
+#       define RADEON_VF_PRIM_TYPE_RECTANGLE_LIST     8
+#       define RADEON_VF_PRIM_TYPE_POINT_LIST_3       9
+#       define RADEON_VF_PRIM_TYPE_LINE_LIST_3        10
+#       define RADEON_VF_PRIM_TYPE_SPIRIT_LIST        11
+#       define RADEON_VF_PRIM_TYPE_LINE_LOOP          12
+#       define RADEON_VF_PRIM_TYPE_QUAD_LIST          13
+#       define RADEON_VF_PRIM_TYPE_QUAD_STRIP         14
+#       define RADEON_VF_PRIM_TYPE_POLYGON            15
+#       define RADEON_VF_PRIM_WALK_STATE              (0<<4)
+#       define RADEON_VF_PRIM_WALK_INDEX              (1<<4)
+#       define RADEON_VF_PRIM_WALK_LIST               (2<<4)
+#       define RADEON_VF_PRIM_WALK_DATA               (3<<4)
+#       define RADEON_VF_COLOR_ORDER_RGBA             (1<<6)
+#       define RADEON_VF_RADEON_MODE                  (1<<8)
+#       define RADEON_VF_TCL_OUTPUT_CTL_ENA           (1<<9)
+#       define RADEON_VF_PROG_STREAM_ENA              (1<<10)
+#       define RADEON_VF_INDEX_SIZE_SHIFT             11
+#       define RADEON_VF_NUM_VERTICES_SHIFT           16
+
+#define RADEON_SE_PORT_DATA0                   0x2000
+
+#define R200_SE_VAP_CNTL                       0x2080
+#       define R200_VAP_TCL_ENABLE             0x00000001
+#       define R200_VAP_SINGLE_BUF_STATE_ENABLE        0x00000010
+#       define R200_VAP_FORCE_W_TO_ONE         0x00010000
+#       define R200_VAP_D3D_TEX_DEFAULT                0x00020000
+#       define R200_VAP_VF_MAX_VTX_NUM__SHIFT  18
+#       define R200_VAP_VF_MAX_VTX_NUM         (9 << 18)
+#       define R200_VAP_DX_CLIP_SPACE_DEF      0x00400000
+#define R200_VF_MAX_VTX_INDX                   0x210c
+#define R200_VF_MIN_VTX_INDX                   0x2110
+#define R200_SE_VTE_CNTL                       0x20b0
+#       define R200_VPORT_X_SCALE_ENA                  0x00000001
+#       define R200_VPORT_X_OFFSET_ENA                 0x00000002
+#       define R200_VPORT_Y_SCALE_ENA                  0x00000004
+#       define R200_VPORT_Y_OFFSET_ENA                 0x00000008
+#       define R200_VPORT_Z_SCALE_ENA                  0x00000010
+#       define R200_VPORT_Z_OFFSET_ENA                 0x00000020
+#       define R200_VTX_XY_FMT                         0x00000100
+#       define R200_VTX_Z_FMT                          0x00000200
+#       define R200_VTX_W0_FMT                         0x00000400
+#       define R200_VTX_W0_NORMALIZE                   0x00000800
+#       define R200_VTX_ST_DENORMALIZED                0x00001000
+#define R200_SE_VAP_CNTL_STATUS                        0x2140
+#       define R200_VC_NO_SWAP                 (0 << 0)
+#       define R200_VC_16BIT_SWAP              (1 << 0)
+#       define R200_VC_32BIT_SWAP              (2 << 0)
+#define R200_PP_TXFILTER_0                     0x2c00
+#define R200_PP_TXFILTER_1                     0x2c20
+#define R200_PP_TXFILTER_2                     0x2c40
+#define R200_PP_TXFILTER_3                     0x2c60
+#define R200_PP_TXFILTER_4                     0x2c80
+#define R200_PP_TXFILTER_5                     0x2ca0
+#       define R200_MAG_FILTER_NEAREST         (0  <<  0)
+#       define R200_MAG_FILTER_LINEAR          (1  <<  0)
+#       define R200_MAG_FILTER_MASK            (1  <<  0)
+#       define R200_MIN_FILTER_NEAREST         (0  <<  1)
+#       define R200_MIN_FILTER_LINEAR          (1  <<  1)
+#       define R200_MIN_FILTER_NEAREST_MIP_NEAREST (2  <<  1)
+#       define R200_MIN_FILTER_NEAREST_MIP_LINEAR (3  <<  1)
+#       define R200_MIN_FILTER_LINEAR_MIP_NEAREST (6  <<  1)
+#       define R200_MIN_FILTER_LINEAR_MIP_LINEAR (7  <<  1)
+#       define R200_MIN_FILTER_ANISO_NEAREST   (8  <<  1)
+#       define R200_MIN_FILTER_ANISO_LINEAR    (9  <<  1)
+#       define R200_MIN_FILTER_ANISO_NEAREST_MIP_NEAREST (10 <<  1)
+#       define R200_MIN_FILTER_ANISO_NEAREST_MIP_LINEAR (11 <<  1)
+#       define R200_MIN_FILTER_MASK            (15 <<  1)
+#       define R200_MAX_ANISO_1_TO_1           (0  <<  5)
+#       define R200_MAX_ANISO_2_TO_1           (1  <<  5)
+#       define R200_MAX_ANISO_4_TO_1           (2  <<  5)
+#       define R200_MAX_ANISO_8_TO_1           (3  <<  5)
+#       define R200_MAX_ANISO_16_TO_1          (4  <<  5)
+#       define R200_MAX_ANISO_MASK             (7  <<  5)
+#       define R200_MAX_MIP_LEVEL_MASK         (0x0f << 16)
+#       define R200_MAX_MIP_LEVEL_SHIFT                16
+#       define R200_YUV_TO_RGB                 (1  << 20)
+#       define R200_YUV_TEMPERATURE_COOL       (0  << 21)
+#       define R200_YUV_TEMPERATURE_HOT                (1  << 21)
+#       define R200_YUV_TEMPERATURE_MASK       (1  << 21)
+#       define R200_WRAPEN_S                   (1  << 22)
+#       define R200_CLAMP_S_WRAP               (0  << 23)
+#       define R200_CLAMP_S_MIRROR             (1  << 23)
+#       define R200_CLAMP_S_CLAMP_LAST         (2  << 23)
+#       define R200_CLAMP_S_MIRROR_CLAMP_LAST  (3  << 23)
+#       define R200_CLAMP_S_CLAMP_BORDER       (4  << 23)
+#       define R200_CLAMP_S_MIRROR_CLAMP_BORDER        (5  << 23)
+#       define R200_CLAMP_S_CLAMP_GL           (6  << 23)
+#       define R200_CLAMP_S_MIRROR_CLAMP_GL    (7  << 23)
+#       define R200_CLAMP_S_MASK               (7  << 23)
+#       define R200_WRAPEN_T                   (1  << 26)
+#       define R200_CLAMP_T_WRAP               (0  << 27)
+#       define R200_CLAMP_T_MIRROR             (1  << 27)
+#       define R200_CLAMP_T_CLAMP_LAST         (2  << 27)
+#       define R200_CLAMP_T_MIRROR_CLAMP_LAST  (3  << 27)
+#       define R200_CLAMP_T_CLAMP_BORDER       (4  << 27)
+#       define R200_CLAMP_T_MIRROR_CLAMP_BORDER        (5  << 27)
+#       define R200_CLAMP_T_CLAMP_GL           (6  << 27)
+#       define R200_CLAMP_T_MIRROR_CLAMP_GL    (7  << 27)
+#       define R200_CLAMP_T_MASK               (7  << 27)
+#       define R200_KILL_LT_ZERO               (1  << 30)
+#       define R200_BORDER_MODE_OGL            (0  << 31)
+#       define R200_BORDER_MODE_D3D            (1  << 31)
+#define R200_PP_TXFORMAT_0                     0x2c04
+#define R200_PP_TXFORMAT_1                     0x2c24
+#define R200_PP_TXFORMAT_2                     0x2c44
+#define R200_PP_TXFORMAT_3                     0x2c64
+#define R200_PP_TXFORMAT_4                     0x2c84
+#define R200_PP_TXFORMAT_5                     0x2ca4
+#       define R200_TXFORMAT_I8                        (0 << 0)
+#       define R200_TXFORMAT_AI88              (1 << 0)
+#       define R200_TXFORMAT_RGB332            (2 << 0)
+#       define R200_TXFORMAT_ARGB1555          (3 << 0)
+#       define R200_TXFORMAT_RGB565            (4 << 0)
+#       define R200_TXFORMAT_ARGB4444          (5 << 0)
+#       define R200_TXFORMAT_ARGB8888          (6 << 0)
+#       define R200_TXFORMAT_RGBA8888          (7 << 0)
+#       define R200_TXFORMAT_Y8                        (8 << 0)
+#       define R200_TXFORMAT_AVYU4444          (9 << 0)
+#       define R200_TXFORMAT_VYUY422           (10 << 0)
+#       define R200_TXFORMAT_YVYU422           (11 << 0)
+#       define R200_TXFORMAT_DXT1              (12 << 0)
+#       define R200_TXFORMAT_DXT23             (14 << 0)
+#       define R200_TXFORMAT_DXT45             (15 << 0)
+#       define R200_TXFORMAT_ABGR8888          (22 << 0)
+#       define R200_TXFORMAT_FORMAT_MASK       (31 <<  0)
+#       define R200_TXFORMAT_FORMAT_SHIFT      0
+#       define R200_TXFORMAT_ALPHA_IN_MAP      (1 << 6)
+#       define R200_TXFORMAT_NON_POWER2                (1 << 7)
+#       define R200_TXFORMAT_WIDTH_MASK                (15 <<  8)
+#       define R200_TXFORMAT_WIDTH_SHIFT       8
+#       define R200_TXFORMAT_HEIGHT_MASK       (15 << 12)
+#       define R200_TXFORMAT_HEIGHT_SHIFT      12
+#       define R200_TXFORMAT_F5_WIDTH_MASK     (15 << 16)      /* cube face 5 */
+#       define R200_TXFORMAT_F5_WIDTH_SHIFT    16
+#       define R200_TXFORMAT_F5_HEIGHT_MASK    (15 << 20)
+#       define R200_TXFORMAT_F5_HEIGHT_SHIFT   20
+#       define R200_TXFORMAT_ST_ROUTE_STQ0     (0 << 24)
+#       define R200_TXFORMAT_ST_ROUTE_STQ1     (1 << 24)
+#       define R200_TXFORMAT_ST_ROUTE_STQ2     (2 << 24)
+#       define R200_TXFORMAT_ST_ROUTE_STQ3     (3 << 24)
+#       define R200_TXFORMAT_ST_ROUTE_STQ4     (4 << 24)
+#       define R200_TXFORMAT_ST_ROUTE_STQ5     (5 << 24)
+#       define R200_TXFORMAT_ST_ROUTE_MASK     (7 << 24)
+#       define R200_TXFORMAT_ST_ROUTE_SHIFT    24
+#       define R200_TXFORMAT_ALPHA_MASK_ENABLE (1 << 28)
+#       define R200_TXFORMAT_CHROMA_KEY_ENABLE (1 << 29)
+#       define R200_TXFORMAT_CUBIC_MAP_ENABLE          (1 << 30)
+#define R200_PP_TXFORMAT_X_0                    0x2c08
+#define R200_PP_TXFORMAT_X_1                    0x2c28
+#define R200_PP_TXFORMAT_X_2                    0x2c48
+#define R200_PP_TXFORMAT_X_3                    0x2c68
+#define R200_PP_TXFORMAT_X_4                    0x2c88
+#define R200_PP_TXFORMAT_X_5                    0x2ca8
+
+#define R200_PP_TXSIZE_0                       0x2c0c /* NPOT only */
+#define R200_PP_TXSIZE_1                       0x2c2c /* NPOT only */
+#define R200_PP_TXSIZE_2                       0x2c4c /* NPOT only */
+#define R200_PP_TXSIZE_3                       0x2c6c /* NPOT only */
+#define R200_PP_TXSIZE_4                       0x2c8c /* NPOT only */
+#define R200_PP_TXSIZE_5                       0x2cac /* NPOT only */
+
+#define R200_PP_TXPITCH_0                       0x2c10 /* NPOT only */
+#define R200_PP_TXPITCH_1                      0x2c30 /* NPOT only */
+#define R200_PP_TXPITCH_2                      0x2c50 /* NPOT only */
+#define R200_PP_TXPITCH_3                      0x2c70 /* NPOT only */
+#define R200_PP_TXPITCH_4                      0x2c90 /* NPOT only */
+#define R200_PP_TXPITCH_5                      0x2cb0 /* NPOT only */
+
+#define R200_PP_TXOFFSET_0                     0x2d00
+#       define R200_TXO_ENDIAN_NO_SWAP         (0 << 0)
+#       define R200_TXO_ENDIAN_BYTE_SWAP       (1 << 0)
+#       define R200_TXO_ENDIAN_WORD_SWAP       (2 << 0)
+#       define R200_TXO_ENDIAN_HALFDW_SWAP     (3 << 0)
+#       define R200_TXO_MACRO_LINEAR           (0 << 2)
+#       define R200_TXO_MACRO_TILE             (1 << 2)
+#       define R200_TXO_MICRO_LINEAR           (0 << 3)
+#       define R200_TXO_MICRO_TILE             (1 << 3)
+#       define R200_TXO_OFFSET_MASK            0xffffffe0
+#       define R200_TXO_OFFSET_SHIFT           5
+#define R200_PP_TXOFFSET_1                     0x2d18
+#define R200_PP_TXOFFSET_2                     0x2d30
+#define R200_PP_TXOFFSET_3                     0x2d48
+#define R200_PP_TXOFFSET_4                     0x2d60
+#define R200_PP_TXOFFSET_5                     0x2d78
+
+#define R200_PP_TFACTOR_0                      0x2ee0
+#define R200_PP_TFACTOR_1                      0x2ee4
+#define R200_PP_TFACTOR_2                      0x2ee8
+#define R200_PP_TFACTOR_3                      0x2eec
+#define R200_PP_TFACTOR_4                      0x2ef0
+#define R200_PP_TFACTOR_5                      0x2ef4
+
+#define R200_PP_TXCBLEND_0                     0x2f00
+#       define R200_TXC_ARG_A_ZERO             (0)
+#       define R200_TXC_ARG_A_CURRENT_COLOR    (2)
+#       define R200_TXC_ARG_A_CURRENT_ALPHA    (3)
+#       define R200_TXC_ARG_A_DIFFUSE_COLOR    (4)
+#       define R200_TXC_ARG_A_DIFFUSE_ALPHA    (5)
+#       define R200_TXC_ARG_A_SPECULAR_COLOR   (6)
+#       define R200_TXC_ARG_A_SPECULAR_ALPHA   (7)
+#       define R200_TXC_ARG_A_TFACTOR_COLOR    (8)
+#       define R200_TXC_ARG_A_TFACTOR_ALPHA    (9)
+#       define R200_TXC_ARG_A_R0_COLOR         (10)
+#       define R200_TXC_ARG_A_R0_ALPHA         (11)
+#       define R200_TXC_ARG_A_R1_COLOR         (12)
+#       define R200_TXC_ARG_A_R1_ALPHA         (13)
+#       define R200_TXC_ARG_A_R2_COLOR         (14)
+#       define R200_TXC_ARG_A_R2_ALPHA         (15)
+#       define R200_TXC_ARG_A_R3_COLOR         (16)
+#       define R200_TXC_ARG_A_R3_ALPHA         (17)
+#       define R200_TXC_ARG_A_R4_COLOR         (18)
+#       define R200_TXC_ARG_A_R4_ALPHA         (19)
+#       define R200_TXC_ARG_A_R5_COLOR         (20)
+#       define R200_TXC_ARG_A_R5_ALPHA         (21)
+#       define R200_TXC_ARG_A_TFACTOR1_COLOR   (26)
+#       define R200_TXC_ARG_A_TFACTOR1_ALPHA   (27)
+#       define R200_TXC_ARG_A_MASK             (31 << 0)
+#       define R200_TXC_ARG_A_SHIFT            0
+#       define R200_TXC_ARG_B_ZERO             (0 << 5)
+#       define R200_TXC_ARG_B_CURRENT_COLOR    (2 << 5)
+#       define R200_TXC_ARG_B_CURRENT_ALPHA    (3 << 5)
+#       define R200_TXC_ARG_B_DIFFUSE_COLOR    (4 << 5)
+#       define R200_TXC_ARG_B_DIFFUSE_ALPHA    (5 << 5)
+#       define R200_TXC_ARG_B_SPECULAR_COLOR   (6 << 5)
+#       define R200_TXC_ARG_B_SPECULAR_ALPHA   (7 << 5)
+#       define R200_TXC_ARG_B_TFACTOR_COLOR    (8 << 5)
+#       define R200_TXC_ARG_B_TFACTOR_ALPHA    (9 << 5)
+#       define R200_TXC_ARG_B_R0_COLOR         (10 << 5)
+#       define R200_TXC_ARG_B_R0_ALPHA         (11 << 5)
+#       define R200_TXC_ARG_B_R1_COLOR         (12 << 5)
+#       define R200_TXC_ARG_B_R1_ALPHA         (13 << 5)
+#       define R200_TXC_ARG_B_R2_COLOR         (14 << 5)
+#       define R200_TXC_ARG_B_R2_ALPHA         (15 << 5)
+#       define R200_TXC_ARG_B_R3_COLOR         (16 << 5)
+#       define R200_TXC_ARG_B_R3_ALPHA         (17 << 5)
+#       define R200_TXC_ARG_B_R4_COLOR         (18 << 5)
+#       define R200_TXC_ARG_B_R4_ALPHA         (19 << 5)
+#       define R200_TXC_ARG_B_R5_COLOR         (20 << 5)
+#       define R200_TXC_ARG_B_R5_ALPHA         (21 << 5)
+#       define R200_TXC_ARG_B_TFACTOR1_COLOR   (26 << 5)
+#       define R200_TXC_ARG_B_TFACTOR1_ALPHA   (27 << 5)
+#       define R200_TXC_ARG_B_MASK             (31 << 5)
+#       define R200_TXC_ARG_B_SHIFT            5
+#       define R200_TXC_ARG_C_ZERO             (0 << 10)
+#       define R200_TXC_ARG_C_CURRENT_COLOR    (2 << 10)
+#       define R200_TXC_ARG_C_CURRENT_ALPHA    (3 << 10)
+#       define R200_TXC_ARG_C_DIFFUSE_COLOR    (4 << 10)
+#       define R200_TXC_ARG_C_DIFFUSE_ALPHA    (5 << 10)
+#       define R200_TXC_ARG_C_SPECULAR_COLOR   (6 << 10)
+#       define R200_TXC_ARG_C_SPECULAR_ALPHA   (7 << 10)
+#       define R200_TXC_ARG_C_TFACTOR_COLOR    (8 << 10)
+#       define R200_TXC_ARG_C_TFACTOR_ALPHA    (9 << 10)
+#       define R200_TXC_ARG_C_R0_COLOR         (10 << 10)
+#       define R200_TXC_ARG_C_R0_ALPHA         (11 << 10)
+#       define R200_TXC_ARG_C_R1_COLOR         (12 << 10)
+#       define R200_TXC_ARG_C_R1_ALPHA         (13 << 10)
+#       define R200_TXC_ARG_C_R2_COLOR         (14 << 10)
+#       define R200_TXC_ARG_C_R2_ALPHA         (15 << 10)
+#       define R200_TXC_ARG_C_R3_COLOR         (16 << 10)
+#       define R200_TXC_ARG_C_R3_ALPHA         (17 << 10)
+#       define R200_TXC_ARG_C_R4_COLOR         (18 << 10)
+#       define R200_TXC_ARG_C_R4_ALPHA         (19 << 10)
+#       define R200_TXC_ARG_C_R5_COLOR         (20 << 10)
+#       define R200_TXC_ARG_C_R5_ALPHA         (21 << 10)
+#       define R200_TXC_ARG_C_TFACTOR1_COLOR   (26 << 10)
+#       define R200_TXC_ARG_C_TFACTOR1_ALPHA   (27 << 10)
+#       define R200_TXC_ARG_C_MASK             (31 << 10)
+#       define R200_TXC_ARG_C_SHIFT            10
+#       define R200_TXC_COMP_ARG_A             (1 << 16)
+#       define R200_TXC_COMP_ARG_A_SHIFT       (16)
+#       define R200_TXC_BIAS_ARG_A             (1 << 17)
+#       define R200_TXC_SCALE_ARG_A            (1 << 18)
+#       define R200_TXC_NEG_ARG_A              (1 << 19)
+#       define R200_TXC_COMP_ARG_B             (1 << 20)
+#       define R200_TXC_COMP_ARG_B_SHIFT       (20)
+#       define R200_TXC_BIAS_ARG_B             (1 << 21)
+#       define R200_TXC_SCALE_ARG_B            (1 << 22)
+#       define R200_TXC_NEG_ARG_B              (1 << 23)
+#       define R200_TXC_COMP_ARG_C             (1 << 24)
+#       define R200_TXC_COMP_ARG_C_SHIFT       (24)
+#       define R200_TXC_BIAS_ARG_C             (1 << 25)
+#       define R200_TXC_SCALE_ARG_C            (1 << 26)
+#       define R200_TXC_NEG_ARG_C              (1 << 27)
+#       define R200_TXC_OP_MADD                        (0 << 28)
+#       define R200_TXC_OP_CND0                        (2 << 28)
+#       define R200_TXC_OP_LERP                        (3 << 28)
+#       define R200_TXC_OP_DOT3                        (4 << 28)
+#       define R200_TXC_OP_DOT4                        (5 << 28)
+#       define R200_TXC_OP_CONDITIONAL         (6 << 28)
+#       define R200_TXC_OP_DOT2_ADD            (7 << 28)
+#       define R200_TXC_OP_MASK                        (7 << 28)
+#define R200_PP_TXCBLEND2_0            0x2f04
+#       define R200_TXC_TFACTOR_SEL_SHIFT      0
+#       define R200_TXC_TFACTOR_SEL_MASK       0x7
+#       define R200_TXC_TFACTOR1_SEL_SHIFT     4
+#       define R200_TXC_TFACTOR1_SEL_MASK      (0x7 << 4)
+#       define R200_TXC_SCALE_SHIFT            8
+#       define R200_TXC_SCALE_MASK             (7 << 8)
+#       define R200_TXC_SCALE_1X               (0 << 8)
+#       define R200_TXC_SCALE_2X               (1 << 8)
+#       define R200_TXC_SCALE_4X               (2 << 8)
+#       define R200_TXC_SCALE_8X               (3 << 8)
+#       define R200_TXC_SCALE_INV2             (5 << 8)
+#       define R200_TXC_SCALE_INV4             (6 << 8)
+#       define R200_TXC_SCALE_INV8             (7 << 8)
+#       define R200_TXC_CLAMP_SHIFT            12
+#       define R200_TXC_CLAMP_MASK             (3 << 12)
+#       define R200_TXC_CLAMP_WRAP             (0 << 12)
+#       define R200_TXC_CLAMP_0_1              (1 << 12)
+#       define R200_TXC_CLAMP_8_8              (2 << 12)
+#       define R200_TXC_OUTPUT_REG_MASK                (7 << 16)
+#       define R200_TXC_OUTPUT_REG_NONE                (0 << 16)
+#       define R200_TXC_OUTPUT_REG_R0          (1 << 16)
+#       define R200_TXC_OUTPUT_REG_R1          (2 << 16)
+#       define R200_TXC_OUTPUT_REG_R2          (3 << 16)
+#       define R200_TXC_OUTPUT_REG_R3          (4 << 16)
+#       define R200_TXC_OUTPUT_REG_R4          (5 << 16)
+#       define R200_TXC_OUTPUT_REG_R5          (6 << 16)
+#       define R200_TXC_OUTPUT_MASK_MASK       (7 << 20)
+#       define R200_TXC_OUTPUT_MASK_RGB                (0 << 20)
+#       define R200_TXC_OUTPUT_MASK_RG         (1 << 20)
+#       define R200_TXC_OUTPUT_MASK_RB         (2 << 20)
+#       define R200_TXC_OUTPUT_MASK_R          (3 << 20)
+#       define R200_TXC_OUTPUT_MASK_GB         (4 << 20)
+#       define R200_TXC_OUTPUT_MASK_G          (5 << 20)
+#       define R200_TXC_OUTPUT_MASK_B          (6 << 20)
+#       define R200_TXC_OUTPUT_MASK_NONE       (7 << 20)
+#       define R200_TXC_REPL_NORMAL            0
+#       define R200_TXC_REPL_RED               1
+#       define R200_TXC_REPL_GREEN             2
+#       define R200_TXC_REPL_BLUE              3
+#       define R200_TXC_REPL_ARG_A_SHIFT       26
+#       define R200_TXC_REPL_ARG_A_MASK                (3 << 26)
+#       define R200_TXC_REPL_ARG_B_SHIFT       28
+#       define R200_TXC_REPL_ARG_B_MASK                (3 << 28)
+#       define R200_TXC_REPL_ARG_C_SHIFT       30
+#       define R200_TXC_REPL_ARG_C_MASK                (3 << 30)
+#define R200_PP_TXABLEND_0                     0x2f08
+#       define R200_TXA_ARG_A_ZERO             (0)
+#       define R200_TXA_ARG_A_CURRENT_ALPHA    (2) /* guess */
+#       define R200_TXA_ARG_A_CURRENT_BLUE     (3) /* guess */
+#       define R200_TXA_ARG_A_DIFFUSE_ALPHA    (4)
+#       define R200_TXA_ARG_A_DIFFUSE_BLUE     (5)
+#       define R200_TXA_ARG_A_SPECULAR_ALPHA   (6)
+#       define R200_TXA_ARG_A_SPECULAR_BLUE    (7)
+#       define R200_TXA_ARG_A_TFACTOR_ALPHA    (8)
+#       define R200_TXA_ARG_A_TFACTOR_BLUE     (9)
+#       define R200_TXA_ARG_A_R0_ALPHA         (10)
+#       define R200_TXA_ARG_A_R0_BLUE          (11)
+#       define R200_TXA_ARG_A_R1_ALPHA         (12)
+#       define R200_TXA_ARG_A_R1_BLUE          (13)
+#       define R200_TXA_ARG_A_R2_ALPHA         (14)
+#       define R200_TXA_ARG_A_R2_BLUE          (15)
+#       define R200_TXA_ARG_A_R3_ALPHA         (16)
+#       define R200_TXA_ARG_A_R3_BLUE          (17)
+#       define R200_TXA_ARG_A_R4_ALPHA         (18)
+#       define R200_TXA_ARG_A_R4_BLUE          (19)
+#       define R200_TXA_ARG_A_R5_ALPHA         (20)
+#       define R200_TXA_ARG_A_R5_BLUE          (21)
+#       define R200_TXA_ARG_A_TFACTOR1_ALPHA   (26)
+#       define R200_TXA_ARG_A_TFACTOR1_BLUE    (27)
+#       define R200_TXA_ARG_A_MASK             (31 << 0)
+#       define R200_TXA_ARG_A_SHIFT            0
+#       define R200_TXA_ARG_B_ZERO             (0 << 5)
+#       define R200_TXA_ARG_B_CURRENT_ALPHA    (2 << 5) /* guess */
+#       define R200_TXA_ARG_B_CURRENT_BLUE     (3 << 5) /* guess */
+#       define R200_TXA_ARG_B_DIFFUSE_ALPHA    (4 << 5)
+#       define R200_TXA_ARG_B_DIFFUSE_BLUE     (5 << 5)
+#       define R200_TXA_ARG_B_SPECULAR_ALPHA   (6 << 5)
+#       define R200_TXA_ARG_B_SPECULAR_BLUE    (7 << 5)
+#       define R200_TXA_ARG_B_TFACTOR_ALPHA    (8 << 5)
+#       define R200_TXA_ARG_B_TFACTOR_BLUE     (9 << 5)
+#       define R200_TXA_ARG_B_R0_ALPHA         (10 << 5)
+#       define R200_TXA_ARG_B_R0_BLUE          (11 << 5)
+#       define R200_TXA_ARG_B_R1_ALPHA         (12 << 5)
+#       define R200_TXA_ARG_B_R1_BLUE          (13 << 5)
+#       define R200_TXA_ARG_B_R2_ALPHA         (14 << 5)
+#       define R200_TXA_ARG_B_R2_BLUE          (15 << 5)
+#       define R200_TXA_ARG_B_R3_ALPHA         (16 << 5)
+#       define R200_TXA_ARG_B_R3_BLUE          (17 << 5)
+#       define R200_TXA_ARG_B_R4_ALPHA         (18 << 5)
+#       define R200_TXA_ARG_B_R4_BLUE          (19 << 5)
+#       define R200_TXA_ARG_B_R5_ALPHA         (20 << 5)
+#       define R200_TXA_ARG_B_R5_BLUE          (21 << 5)
+#       define R200_TXA_ARG_B_TFACTOR1_ALPHA   (26 << 5)
+#       define R200_TXA_ARG_B_TFACTOR1_BLUE    (27 << 5)
+#       define R200_TXA_ARG_B_MASK             (31 << 5)
+#       define R200_TXA_ARG_B_SHIFT                    5
+#       define R200_TXA_ARG_C_ZERO             (0 << 10)
+#       define R200_TXA_ARG_C_CURRENT_ALPHA    (2 << 10) /* guess */
+#       define R200_TXA_ARG_C_CURRENT_BLUE     (3 << 10) /* guess */
+#       define R200_TXA_ARG_C_DIFFUSE_ALPHA    (4 << 10)
+#       define R200_TXA_ARG_C_DIFFUSE_BLUE     (5 << 10)
+#       define R200_TXA_ARG_C_SPECULAR_ALPHA   (6 << 10)
+#       define R200_TXA_ARG_C_SPECULAR_BLUE    (7 << 10)
+#       define R200_TXA_ARG_C_TFACTOR_ALPHA    (8 << 10)
+#       define R200_TXA_ARG_C_TFACTOR_BLUE     (9 << 10)
+#       define R200_TXA_ARG_C_R0_ALPHA         (10 << 10)
+#       define R200_TXA_ARG_C_R0_BLUE          (11 << 10)
+#       define R200_TXA_ARG_C_R1_ALPHA         (12 << 10)
+#       define R200_TXA_ARG_C_R1_BLUE          (13 << 10)
+#       define R200_TXA_ARG_C_R2_ALPHA         (14 << 10)
+#       define R200_TXA_ARG_C_R2_BLUE          (15 << 10)
+#       define R200_TXA_ARG_C_R3_ALPHA         (16 << 10)
+#       define R200_TXA_ARG_C_R3_BLUE          (17 << 10)
+#       define R200_TXA_ARG_C_R4_ALPHA         (18 << 10)
+#       define R200_TXA_ARG_C_R4_BLUE          (19 << 10)
+#       define R200_TXA_ARG_C_R5_ALPHA         (20 << 10)
+#       define R200_TXA_ARG_C_R5_BLUE          (21 << 10)
+#       define R200_TXA_ARG_C_TFACTOR1_ALPHA   (26 << 10)
+#       define R200_TXA_ARG_C_TFACTOR1_BLUE    (27 << 10)
+#       define R200_TXA_ARG_C_MASK             (31 << 10)
+#       define R200_TXA_ARG_C_SHIFT            10
+#       define R200_TXA_COMP_ARG_A             (1 << 16)
+#       define R200_TXA_COMP_ARG_A_SHIFT       (16)
+#       define R200_TXA_BIAS_ARG_A             (1 << 17)
+#       define R200_TXA_SCALE_ARG_A            (1 << 18)
+#       define R200_TXA_NEG_ARG_A              (1 << 19)
+#       define R200_TXA_COMP_ARG_B             (1 << 20)
+#       define R200_TXA_COMP_ARG_B_SHIFT       (20)
+#       define R200_TXA_BIAS_ARG_B             (1 << 21)
+#       define R200_TXA_SCALE_ARG_B            (1 << 22)
+#       define R200_TXA_NEG_ARG_B              (1 << 23)
+#       define R200_TXA_COMP_ARG_C             (1 << 24)
+#       define R200_TXA_COMP_ARG_C_SHIFT       (24)
+#       define R200_TXA_BIAS_ARG_C             (1 << 25)
+#       define R200_TXA_SCALE_ARG_C            (1 << 26)
+#       define R200_TXA_NEG_ARG_C              (1 << 27)
+#       define R200_TXA_OP_MADD                        (0 << 28)
+#       define R200_TXA_OP_CND0                        (2 << 28)
+#       define R200_TXA_OP_LERP                        (3 << 28)
+#       define R200_TXA_OP_CONDITIONAL         (6 << 28)
+#       define R200_TXA_OP_MASK                        (7 << 28)
+#define R200_PP_TXABLEND2_0                    0x2f0c
+#       define R200_TXA_TFACTOR_SEL_SHIFT      0
+#       define R200_TXA_TFACTOR_SEL_MASK       0x7
+#       define R200_TXA_TFACTOR1_SEL_SHIFT     4
+#       define R200_TXA_TFACTOR1_SEL_MASK      (0x7 << 4)
+#       define R200_TXA_SCALE_SHIFT            8
+#       define R200_TXA_SCALE_MASK             (7 << 8)
+#       define R200_TXA_SCALE_1X               (0 << 8)
+#       define R200_TXA_SCALE_2X               (1 << 8)
+#       define R200_TXA_SCALE_4X               (2 << 8)
+#       define R200_TXA_SCALE_8X               (3 << 8)
+#       define R200_TXA_SCALE_INV2             (5 << 8)
+#       define R200_TXA_SCALE_INV4             (6 << 8)
+#       define R200_TXA_SCALE_INV8             (7 << 8)
+#       define R200_TXA_CLAMP_SHIFT            12
+#       define R200_TXA_CLAMP_MASK             (3 << 12)
+#       define R200_TXA_CLAMP_WRAP             (0 << 12)
+#       define R200_TXA_CLAMP_0_1              (1 << 12)
+#       define R200_TXA_CLAMP_8_8              (2 << 12)
+#       define R200_TXA_OUTPUT_REG_MASK                (7 << 16)
+#       define R200_TXA_OUTPUT_REG_NONE                (0 << 16)
+#       define R200_TXA_OUTPUT_REG_R0          (1 << 16)
+#       define R200_TXA_OUTPUT_REG_R1          (2 << 16)
+#       define R200_TXA_OUTPUT_REG_R2          (3 << 16)
+#       define R200_TXA_OUTPUT_REG_R3          (4 << 16)
+#       define R200_TXA_OUTPUT_REG_R4          (5 << 16)
+#       define R200_TXA_OUTPUT_REG_R5          (6 << 16)
+#       define R200_TXA_DOT_ALPHA              (1 << 20)
+#       define R200_TXA_REPL_NORMAL            0
+#       define R200_TXA_REPL_RED               1
+#       define R200_TXA_REPL_GREEN             2
+#       define R200_TXA_REPL_ARG_A_SHIFT       26
+#       define R200_TXA_REPL_ARG_A_MASK                (3 << 26)
+#       define R200_TXA_REPL_ARG_B_SHIFT       28
+#       define R200_TXA_REPL_ARG_B_MASK                (3 << 28)
+#       define R200_TXA_REPL_ARG_C_SHIFT       30
+#       define R200_TXA_REPL_ARG_C_MASK                (3 << 30)
+
+#define R200_SE_VTX_FMT_0                      0x2088
+#       define R200_VTX_XY                     0 /* always have xy */
+#       define R200_VTX_Z0                     (1<<0)
+#       define R200_VTX_W0                     (1<<1)
+#       define R200_VTX_WEIGHT_COUNT_SHIFT     (2)
+#       define R200_VTX_PV_MATRIX_SEL          (1<<5)
+#       define R200_VTX_N0                     (1<<6)
+#       define R200_VTX_POINT_SIZE             (1<<7)
+#       define R200_VTX_DISCRETE_FOG           (1<<8)
+#       define R200_VTX_SHININESS_0            (1<<9)
+#       define R200_VTX_SHININESS_1            (1<<10)
+#       define   R200_VTX_COLOR_NOT_PRESENT    0
+#       define   R200_VTX_PK_RGBA              1
+#       define   R200_VTX_FP_RGB               2
+#       define   R200_VTX_FP_RGBA              3
+#       define   R200_VTX_COLOR_MASK           3
+#       define R200_VTX_COLOR_0_SHIFT          11
+#       define R200_VTX_COLOR_1_SHIFT          13
+#       define R200_VTX_COLOR_2_SHIFT          15
+#       define R200_VTX_COLOR_3_SHIFT          17
+#       define R200_VTX_COLOR_4_SHIFT          19
+#       define R200_VTX_COLOR_5_SHIFT          21
+#       define R200_VTX_COLOR_6_SHIFT          23
+#       define R200_VTX_COLOR_7_SHIFT          25
+#       define R200_VTX_XY1                    (1<<28)
+#       define R200_VTX_Z1                     (1<<29)
+#       define R200_VTX_W1                     (1<<30)
+#       define R200_VTX_N1                     (1<<31)
+#define R200_SE_VTX_FMT_1                      0x208c
+#       define R200_VTX_TEX0_COMP_CNT_SHIFT    0
+#       define R200_VTX_TEX1_COMP_CNT_SHIFT    3
+#       define R200_VTX_TEX2_COMP_CNT_SHIFT    6
+#       define R200_VTX_TEX3_COMP_CNT_SHIFT    9
+#       define R200_VTX_TEX4_COMP_CNT_SHIFT    12
+#       define R200_VTX_TEX5_COMP_CNT_SHIFT    15
+
+#define R200_SE_TCL_OUTPUT_VTX_FMT_0           0x2090
+#define R200_SE_TCL_OUTPUT_VTX_FMT_1           0x2094
+#define R200_SE_TCL_OUTPUT_VTX_COMP_SEL                0x2250
+#       define R200_OUTPUT_XYZW                        (1<<0)
+#       define R200_OUTPUT_COLOR_0             (1<<8)
+#       define R200_OUTPUT_COLOR_1             (1<<9)
+#       define R200_OUTPUT_TEX_0               (1<<16)
+#       define R200_OUTPUT_TEX_1               (1<<17)
+#       define R200_OUTPUT_TEX_2               (1<<18)
+#       define R200_OUTPUT_TEX_3               (1<<19)
+#       define R200_OUTPUT_TEX_4               (1<<20)
+#       define R200_OUTPUT_TEX_5               (1<<21)
+#       define R200_OUTPUT_TEX_MASK            (0x3f<<16)
+#       define R200_OUTPUT_DISCRETE_FOG                (1<<24)
+#       define R200_OUTPUT_PT_SIZE             (1<<25)
+#       define R200_FORCE_INORDER_PROC         (1<<31)
+#define R200_PP_CNTL_X                         0x2cc4
+#define R200_PP_TXMULTI_CTL_0                  0x2c1c
+#define R200_SE_VTX_STATE_CNTL                 0x2180
+#       define R200_UPDATE_USER_COLOR_0_ENA_MASK (1<<16)
+
+                               /* Registers for CP and Microcode Engine */
+#define RADEON_CP_ME_RAM_ADDR               0x07d4
+#define RADEON_CP_ME_RAM_RADDR              0x07d8
+#define RADEON_CP_ME_RAM_DATAH              0x07dc
+#define RADEON_CP_ME_RAM_DATAL              0x07e0
+
+#define RADEON_CP_RB_BASE                   0x0700
+#define RADEON_CP_RB_CNTL                   0x0704
+#      define RADEON_RB_BUFSZ_SHIFT            0
+#      define RADEON_RB_BUFSZ_MASK             (0x3f << 0)
+#      define RADEON_RB_BLKSZ_SHIFT            8
+#      define RADEON_RB_BLKSZ_MASK             (0x3f << 8)
+#      define RADEON_MAX_FETCH_SHIFT           18
+#      define RADEON_MAX_FETCH_MASK            (0x3 << 18)
+#      define RADEON_RB_NO_UPDATE              (1 << 27)
+#      define RADEON_RB_RPTR_WR_ENA            (1 << 31)
+#define RADEON_CP_RB_RPTR_ADDR              0x070c
+#define RADEON_CP_RB_RPTR                   0x0710
+#define RADEON_CP_RB_WPTR                   0x0714
+#define RADEON_CP_RB_RPTR_WR                0x071c
+
+#define RADEON_CP_IB_BASE                   0x0738
+#define RADEON_CP_IB_BUFSZ                  0x073c
+
+#define RADEON_CP_CSQ_CNTL                  0x0740
+#       define RADEON_CSQ_CNT_PRIMARY_MASK     (0xff << 0)
+#       define RADEON_CSQ_PRIDIS_INDDIS        (0    << 28)
+#       define RADEON_CSQ_PRIPIO_INDDIS        (1    << 28)
+#       define RADEON_CSQ_PRIBM_INDDIS         (2    << 28)
+#       define RADEON_CSQ_PRIPIO_INDBM         (3    << 28)
+#       define RADEON_CSQ_PRIBM_INDBM          (4    << 28)
+#       define RADEON_CSQ_PRIPIO_INDPIO        (15   << 28)
+
+#define R300_CP_RESYNC_ADDR                 0x778
+#define R300_CP_RESYNC_DATA                 0x77c
+
+#define RADEON_CP_CSQ_STAT                  0x07f8
+#       define RADEON_CSQ_RPTR_PRIMARY_MASK    (0xff <<  0)
+#       define RADEON_CSQ_WPTR_PRIMARY_MASK    (0xff <<  8)
+#       define RADEON_CSQ_RPTR_INDIRECT_MASK   (0xff << 16)
+#       define RADEON_CSQ_WPTR_INDIRECT_MASK   (0xff << 24)
+#define RADEON_CP_CSQ2_STAT                  0x07fc
+#define RADEON_CP_CSQ_ADDR                  0x07f0
+#define RADEON_CP_CSQ_DATA                  0x07f4
+#define RADEON_CP_CSQ_APER_PRIMARY          0x1000
+#define RADEON_CP_CSQ_APER_INDIRECT         0x1300
+
+#define RADEON_CP_RB_WPTR_DELAY             0x0718
+#       define RADEON_PRE_WRITE_TIMER_SHIFT    0
+#       define RADEON_PRE_WRITE_LIMIT_SHIFT    23
+#define RADEON_CP_CSQ_MODE             0x0744
+#      define RADEON_INDIRECT2_START_SHIFT     0
+#      define RADEON_INDIRECT2_START_MASK      (0x7f << 0)
+#      define RADEON_INDIRECT1_START_SHIFT     8
+#      define RADEON_INDIRECT1_START_MASK      (0x7f << 8)
+
+#define RADEON_AIC_CNTL                     0x01d0
+#       define RADEON_PCIGART_TRANSLATE_EN     (1 << 0)
+#       define RADEON_DIS_OUT_OF_PCI_GART_ACCESS     (1 << 1)
+#define RADEON_AIC_LO_ADDR                  0x01dc
+#define RADEON_AIC_PT_BASE             0x01d8
+#define RADEON_AIC_HI_ADDR             0x01e0
+
+
+
+                               /* Constants */
+/* #define RADEON_LAST_FRAME_REG               RADEON_GUI_SCRATCH_REG0 */
+/* efine RADEON_LAST_CLEAR_REG               RADEON_GUI_SCRATCH_REG2 */
+
+
+
+                               /* CP packet types */
+#define RADEON_CP_PACKET0                           0x00000000
+#define RADEON_CP_PACKET1                           0x40000000
+#define RADEON_CP_PACKET2                           0x80000000
+#define RADEON_CP_PACKET3                           0xC0000000
+#       define RADEON_CP_PACKET_MASK                0xC0000000
+#       define RADEON_CP_PACKET_COUNT_MASK          0x3fff0000
+#       define RADEON_CP_PACKET_MAX_DWORDS          (1 << 12)
+#       define RADEON_CP_PACKET0_REG_MASK           0x000007ff
+#       define R300_CP_PACKET0_REG_MASK             0x00001fff
+#       define RADEON_CP_PACKET1_REG0_MASK          0x000007ff
+#       define RADEON_CP_PACKET1_REG1_MASK          0x003ff800
+
+#define RADEON_CP_PACKET0_ONE_REG_WR                0x00008000
+
+#define RADEON_CP_PACKET3_NOP                       0xC0001000
+#define RADEON_CP_PACKET3_NEXT_CHAR                 0xC0001900
+#define RADEON_CP_PACKET3_PLY_NEXTSCAN              0xC0001D00
+#define RADEON_CP_PACKET3_SET_SCISSORS              0xC0001E00
+#define RADEON_CP_PACKET3_3D_RNDR_GEN_INDX_PRIM     0xC0002300
+#define RADEON_CP_PACKET3_LOAD_MICROCODE            0xC0002400
+#define RADEON_CP_PACKET3_WAIT_FOR_IDLE             0xC0002600
+#define RADEON_CP_PACKET3_3D_DRAW_VBUF              0xC0002800
+#define RADEON_CP_PACKET3_3D_DRAW_IMMD              0xC0002900
+#define RADEON_CP_PACKET3_3D_DRAW_INDX              0xC0002A00
+#define RADEON_CP_PACKET3_LOAD_PALETTE              0xC0002C00
+#define R200_CP_PACKET3_3D_DRAW_IMMD_2              0xc0003500
+#define RADEON_CP_PACKET3_3D_LOAD_VBPNTR            0xC0002F00
+#define RADEON_CP_PACKET3_CNTL_PAINT                0xC0009100
+#define RADEON_CP_PACKET3_CNTL_BITBLT               0xC0009200
+#define RADEON_CP_PACKET3_CNTL_SMALLTEXT            0xC0009300
+#define RADEON_CP_PACKET3_CNTL_HOSTDATA_BLT         0xC0009400
+#define RADEON_CP_PACKET3_CNTL_POLYLINE             0xC0009500
+#define RADEON_CP_PACKET3_CNTL_POLYSCANLINES        0xC0009800
+#define RADEON_CP_PACKET3_CNTL_PAINT_MULTI          0xC0009A00
+#define RADEON_CP_PACKET3_CNTL_BITBLT_MULTI         0xC0009B00
+#define RADEON_CP_PACKET3_CNTL_TRANS_BITBLT         0xC0009C00
+
+
+#define RADEON_CP_VC_FRMT_XY                        0x00000000
+#define RADEON_CP_VC_FRMT_W0                        0x00000001
+#define RADEON_CP_VC_FRMT_FPCOLOR                   0x00000002
+#define RADEON_CP_VC_FRMT_FPALPHA                   0x00000004
+#define RADEON_CP_VC_FRMT_PKCOLOR                   0x00000008
+#define RADEON_CP_VC_FRMT_FPSPEC                    0x00000010
+#define RADEON_CP_VC_FRMT_FPFOG                     0x00000020
+#define RADEON_CP_VC_FRMT_PKSPEC                    0x00000040
+#define RADEON_CP_VC_FRMT_ST0                       0x00000080
+#define RADEON_CP_VC_FRMT_ST1                       0x00000100
+#define RADEON_CP_VC_FRMT_Q1                        0x00000200
+#define RADEON_CP_VC_FRMT_ST2                       0x00000400
+#define RADEON_CP_VC_FRMT_Q2                        0x00000800
+#define RADEON_CP_VC_FRMT_ST3                       0x00001000
+#define RADEON_CP_VC_FRMT_Q3                        0x00002000
+#define RADEON_CP_VC_FRMT_Q0                        0x00004000
+#define RADEON_CP_VC_FRMT_BLND_WEIGHT_CNT_MASK      0x00038000
+#define RADEON_CP_VC_FRMT_N0                        0x00040000
+#define RADEON_CP_VC_FRMT_XY1                       0x08000000
+#define RADEON_CP_VC_FRMT_Z1                        0x10000000
+#define RADEON_CP_VC_FRMT_W1                        0x20000000
+#define RADEON_CP_VC_FRMT_N1                        0x40000000
+#define RADEON_CP_VC_FRMT_Z                         0x80000000
+
+#define RADEON_CP_VC_CNTL_PRIM_TYPE_NONE            0x00000000
+#define RADEON_CP_VC_CNTL_PRIM_TYPE_POINT           0x00000001
+#define RADEON_CP_VC_CNTL_PRIM_TYPE_LINE            0x00000002
+#define RADEON_CP_VC_CNTL_PRIM_TYPE_LINE_STRIP      0x00000003
+#define RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST        0x00000004
+#define RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_FAN         0x00000005
+#define RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_STRIP       0x00000006
+#define RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_TYPE_2      0x00000007
+#define RADEON_CP_VC_CNTL_PRIM_TYPE_RECT_LIST       0x00000008
+#define RADEON_CP_VC_CNTL_PRIM_TYPE_3VRT_POINT_LIST 0x00000009
+#define RADEON_CP_VC_CNTL_PRIM_TYPE_3VRT_LINE_LIST  0x0000000a
+#define RADEON_CP_VC_CNTL_PRIM_WALK_IND             0x00000010
+#define RADEON_CP_VC_CNTL_PRIM_WALK_LIST            0x00000020
+#define RADEON_CP_VC_CNTL_PRIM_WALK_RING            0x00000030
+#define RADEON_CP_VC_CNTL_COLOR_ORDER_BGRA          0x00000000
+#define RADEON_CP_VC_CNTL_COLOR_ORDER_RGBA          0x00000040
+#define RADEON_CP_VC_CNTL_MAOS_ENABLE               0x00000080
+#define RADEON_CP_VC_CNTL_VTX_FMT_NON_RADEON_MODE   0x00000000
+#define RADEON_CP_VC_CNTL_VTX_FMT_RADEON_MODE       0x00000100
+#define RADEON_CP_VC_CNTL_TCL_DISABLE               0x00000000
+#define RADEON_CP_VC_CNTL_TCL_ENABLE                0x00000200
+#define RADEON_CP_VC_CNTL_NUM_SHIFT                 16
+
+#define RADEON_VS_MATRIX_0_ADDR                   0
+#define RADEON_VS_MATRIX_1_ADDR                   4
+#define RADEON_VS_MATRIX_2_ADDR                   8
+#define RADEON_VS_MATRIX_3_ADDR                  12
+#define RADEON_VS_MATRIX_4_ADDR                  16
+#define RADEON_VS_MATRIX_5_ADDR                  20
+#define RADEON_VS_MATRIX_6_ADDR                  24
+#define RADEON_VS_MATRIX_7_ADDR                  28
+#define RADEON_VS_MATRIX_8_ADDR                  32
+#define RADEON_VS_MATRIX_9_ADDR                  36
+#define RADEON_VS_MATRIX_10_ADDR                 40
+#define RADEON_VS_MATRIX_11_ADDR                 44
+#define RADEON_VS_MATRIX_12_ADDR                 48
+#define RADEON_VS_MATRIX_13_ADDR                 52
+#define RADEON_VS_MATRIX_14_ADDR                 56
+#define RADEON_VS_MATRIX_15_ADDR                 60
+#define RADEON_VS_LIGHT_AMBIENT_ADDR             64
+#define RADEON_VS_LIGHT_DIFFUSE_ADDR             72
+#define RADEON_VS_LIGHT_SPECULAR_ADDR            80
+#define RADEON_VS_LIGHT_DIRPOS_ADDR              88
+#define RADEON_VS_LIGHT_HWVSPOT_ADDR             96
+#define RADEON_VS_LIGHT_ATTENUATION_ADDR        104
+#define RADEON_VS_MATRIX_EYE2CLIP_ADDR          112
+#define RADEON_VS_UCP_ADDR                      116
+#define RADEON_VS_GLOBAL_AMBIENT_ADDR           122
+#define RADEON_VS_FOG_PARAM_ADDR                123
+#define RADEON_VS_EYE_VECTOR_ADDR               124
+
+#define RADEON_SS_LIGHT_DCD_ADDR                  0
+#define RADEON_SS_LIGHT_SPOT_EXPONENT_ADDR        8
+#define RADEON_SS_LIGHT_SPOT_CUTOFF_ADDR         16
+#define RADEON_SS_LIGHT_SPECULAR_THRESH_ADDR     24
+#define RADEON_SS_LIGHT_RANGE_CUTOFF_ADDR        32
+#define RADEON_SS_VERT_GUARD_CLIP_ADJ_ADDR       48
+#define RADEON_SS_VERT_GUARD_DISCARD_ADJ_ADDR    49
+#define RADEON_SS_HORZ_GUARD_CLIP_ADJ_ADDR       50
+#define RADEON_SS_HORZ_GUARD_DISCARD_ADJ_ADDR    51
+#define RADEON_SS_SHININESS                      60
+
+#define RADEON_TV_MASTER_CNTL                    0x0800
+#       define RADEON_TV_ASYNC_RST               (1 <<  0)
+#       define RADEON_CRT_ASYNC_RST              (1 <<  1)
+#       define RADEON_RESTART_PHASE_FIX          (1 <<  3)
+#      define RADEON_TV_FIFO_ASYNC_RST          (1 <<  4)
+#      define RADEON_VIN_ASYNC_RST              (1 <<  5)
+#      define RADEON_AUD_ASYNC_RST              (1 <<  6)
+#      define RADEON_DVS_ASYNC_RST              (1 <<  7)
+#       define RADEON_CRT_FIFO_CE_EN             (1 <<  9)
+#       define RADEON_TV_FIFO_CE_EN              (1 << 10)
+#       define RADEON_RE_SYNC_NOW_SEL_MASK       (3 << 14)
+#       define RADEON_TVCLK_ALWAYS_ONb           (1 << 30)
+#      define RADEON_TV_ON                      (1 << 31)
+#define RADEON_TV_PRE_DAC_MUX_CNTL               0x0888
+#       define RADEON_Y_RED_EN                   (1 << 0)
+#       define RADEON_C_GRN_EN                   (1 << 1)
+#       define RADEON_CMP_BLU_EN                 (1 << 2)
+#       define RADEON_DAC_DITHER_EN              (1 << 3)
+#       define RADEON_RED_MX_FORCE_DAC_DATA      (6 << 4)
+#       define RADEON_GRN_MX_FORCE_DAC_DATA      (6 << 8)
+#       define RADEON_BLU_MX_FORCE_DAC_DATA      (6 << 12)
+#       define RADEON_TV_FORCE_DAC_DATA_SHIFT    16
+#define RADEON_TV_RGB_CNTL                           0x0804
+#       define RADEON_SWITCH_TO_BLUE             (1 <<  4)
+#       define RADEON_RGB_DITHER_EN              (1 <<  5)
+#       define RADEON_RGB_SRC_SEL_MASK           (3 <<  8)
+#       define RADEON_RGB_SRC_SEL_CRTC1                  (0 <<  8)
+#       define RADEON_RGB_SRC_SEL_RMX            (1 <<  8)
+#       define RADEON_RGB_SRC_SEL_CRTC2                  (2 <<  8)
+#       define RADEON_RGB_CONVERT_BY_PASS        (1 << 10)
+#       define RADEON_UVRAM_READ_MARGIN_SHIFT    16
+#       define RADEON_FIFORAM_FFMACRO_READ_MARGIN_SHIFT          20
+#      define RADEON_TVOUT_SCALE_EN              (1 << 26)
+#define RADEON_TV_SYNC_CNTL                          0x0808
+#       define RADEON_SYNC_OE                     (1 <<  0)
+#       define RADEON_SYNC_OUT                    (1 <<  1)
+#       define RADEON_SYNC_IN                     (1 <<  2)
+#       define RADEON_SYNC_PUB                    (1 <<  3)
+#       define RADEON_SYNC_PD                     (1 <<  4)
+#       define RADEON_TV_SYNC_IO_DRIVE            (1 <<  5)
+#define RADEON_TV_HTOTAL                             0x080c
+#define RADEON_TV_HDISP                              0x0810
+#define RADEON_TV_HSTART                             0x0818
+#define RADEON_TV_HCOUNT                             0x081C
+#define RADEON_TV_VTOTAL                             0x0820
+#define RADEON_TV_VDISP                              0x0824
+#define RADEON_TV_VCOUNT                             0x0828
+#define RADEON_TV_FTOTAL                             0x082c
+#define RADEON_TV_FCOUNT                             0x0830
+#define RADEON_TV_FRESTART                           0x0834
+#define RADEON_TV_HRESTART                           0x0838
+#define RADEON_TV_VRESTART                           0x083c
+#define RADEON_TV_HOST_READ_DATA                     0x0840
+#define RADEON_TV_HOST_WRITE_DATA                    0x0844
+#define RADEON_TV_HOST_RD_WT_CNTL                    0x0848
+#      define RADEON_HOST_FIFO_RD               (1 << 12)
+#      define RADEON_HOST_FIFO_RD_ACK           (1 << 13)
+#      define RADEON_HOST_FIFO_WT               (1 << 14)
+#      define RADEON_HOST_FIFO_WT_ACK           (1 << 15)
+#define RADEON_TV_VSCALER_CNTL1                      0x084c
+#       define RADEON_UV_INC_MASK                0xffff
+#       define RADEON_UV_INC_SHIFT               0
+#       define RADEON_Y_W_EN                    (1 << 24)
+#       define RADEON_RESTART_FIELD              (1 << 29) /* restart on field 0 */
+#       define RADEON_Y_DEL_W_SIG_SHIFT          26
+#define RADEON_TV_TIMING_CNTL                        0x0850
+#       define RADEON_H_INC_MASK                 0xfff
+#       define RADEON_H_INC_SHIFT                0
+#       define RADEON_REQ_Y_FIRST                (1 << 19)
+#       define RADEON_FORCE_BURST_ALWAYS         (1 << 21)
+#       define RADEON_UV_POST_SCALE_BYPASS       (1 << 23)
+#       define RADEON_UV_OUTPUT_POST_SCALE_SHIFT 24
+#define RADEON_TV_VSCALER_CNTL2                      0x0854
+#       define RADEON_DITHER_MODE                (1 <<  0)
+#       define RADEON_Y_OUTPUT_DITHER_EN         (1 <<  1)
+#       define RADEON_UV_OUTPUT_DITHER_EN        (1 <<  2)
+#       define RADEON_UV_TO_BUF_DITHER_EN        (1 <<  3)
+#define RADEON_TV_Y_FALL_CNTL                        0x0858
+#       define RADEON_Y_FALL_PING_PONG           (1 << 16)
+#       define RADEON_Y_COEF_EN                  (1 << 17)
+#define RADEON_TV_Y_RISE_CNTL                        0x085c
+#       define RADEON_Y_RISE_PING_PONG           (1 << 16)
+#define RADEON_TV_Y_SAW_TOOTH_CNTL                   0x0860
+#define RADEON_TV_UPSAMP_AND_GAIN_CNTL               0x0864
+#      define RADEON_YUPSAMP_EN                 (1 <<  0)
+#      define RADEON_UVUPSAMP_EN                (1 <<  2)
+#define RADEON_TV_GAIN_LIMIT_SETTINGS                0x0868
+#       define RADEON_Y_GAIN_LIMIT_SHIFT         0
+#       define RADEON_UV_GAIN_LIMIT_SHIFT        16
+#define RADEON_TV_LINEAR_GAIN_SETTINGS               0x086c
+#       define RADEON_Y_GAIN_SHIFT               0
+#       define RADEON_UV_GAIN_SHIFT              16
+#define RADEON_TV_MODULATOR_CNTL1                    0x0870
+#      define RADEON_YFLT_EN                    (1 <<  2)
+#      define RADEON_UVFLT_EN                   (1 <<  3)
+#       define RADEON_ALT_PHASE_EN               (1 <<  6)
+#       define RADEON_SYNC_TIP_LEVEL             (1 <<  7)
+#       define RADEON_BLANK_LEVEL_SHIFT          8
+#       define RADEON_SET_UP_LEVEL_SHIFT         16
+#      define RADEON_SLEW_RATE_LIMIT            (1 << 23)
+#       define RADEON_CY_FILT_BLEND_SHIFT        28
+#define RADEON_TV_MODULATOR_CNTL2                    0x0874
+#       define RADEON_TV_U_BURST_LEVEL_MASK     0x1ff
+#       define RADEON_TV_V_BURST_LEVEL_MASK     0x1ff
+#       define RADEON_TV_V_BURST_LEVEL_SHIFT    16
+#define RADEON_TV_CRC_CNTL                           0x0890
+#define RADEON_TV_UV_ADR                             0x08ac
+#      define RADEON_MAX_UV_ADR_MASK            0x000000ff
+#      define RADEON_MAX_UV_ADR_SHIFT           0
+#      define RADEON_TABLE1_BOT_ADR_MASK        0x0000ff00
+#      define RADEON_TABLE1_BOT_ADR_SHIFT       8
+#      define RADEON_TABLE3_TOP_ADR_MASK        0x00ff0000
+#      define RADEON_TABLE3_TOP_ADR_SHIFT       16
+#      define RADEON_HCODE_TABLE_SEL_MASK       0x06000000
+#      define RADEON_HCODE_TABLE_SEL_SHIFT      25
+#      define RADEON_VCODE_TABLE_SEL_MASK       0x18000000
+#      define RADEON_VCODE_TABLE_SEL_SHIFT      27
+#      define RADEON_TV_MAX_FIFO_ADDR           0x1a7
+#      define RADEON_TV_MAX_FIFO_ADDR_INTERNAL  0x1ff
+#define RADEON_TV_PLL_FINE_CNTL                             0x0020     /* PLL */
+#define RADEON_TV_PLL_CNTL                           0x0021    /* PLL */
+#       define RADEON_TV_M0LO_MASK               0xff
+#       define RADEON_TV_M0HI_MASK               0x7
+#       define RADEON_TV_M0HI_SHIFT              18
+#       define RADEON_TV_N0LO_MASK               0x1ff
+#       define RADEON_TV_N0LO_SHIFT              8
+#       define RADEON_TV_N0HI_MASK               0x3
+#       define RADEON_TV_N0HI_SHIFT              21
+#       define RADEON_TV_P_MASK                  0xf
+#       define RADEON_TV_P_SHIFT                 24
+#       define RADEON_TV_SLIP_EN                 (1 << 23)
+#       define RADEON_TV_DTO_EN                  (1 << 28)
+#define RADEON_TV_PLL_CNTL1                          0x0022    /* PLL */
+#       define RADEON_TVPLL_RESET                (1 <<  1)
+#       define RADEON_TVPLL_SLEEP                (1 <<  3)
+#       define RADEON_TVPLL_REFCLK_SEL           (1 <<  4)
+#       define RADEON_TVPCP_SHIFT                8
+#       define RADEON_TVPCP_MASK                 (7 << 8)
+#       define RADEON_TVPVG_SHIFT                11
+#       define RADEON_TVPVG_MASK                 (7 << 11)
+#       define RADEON_TVPDC_SHIFT                14
+#       define RADEON_TVPDC_MASK                 (3 << 14)
+#       define RADEON_TVPLL_TEST_DIS             (1 << 31)
+#       define RADEON_TVCLK_SRC_SEL_TVPLL        (1 << 30)
+
+#define RS400_DISP2_REQ_CNTL1                  0xe30
+#       define RS400_DISP2_START_REQ_LEVEL_SHIFT   0
+#       define RS400_DISP2_START_REQ_LEVEL_MASK    0x3ff
+#       define RS400_DISP2_STOP_REQ_LEVEL_SHIFT    12
+#       define RS400_DISP2_STOP_REQ_LEVEL_MASK     0x3ff
+#       define RS400_DISP2_ALLOW_FID_LEVEL_SHIFT   22
+#       define RS400_DISP2_ALLOW_FID_LEVEL_MASK    0x3ff
+#define RS400_DISP2_REQ_CNTL2                  0xe34
+#       define RS400_DISP2_CRITICAL_POINT_START_SHIFT    12
+#       define RS400_DISP2_CRITICAL_POINT_START_MASK     0x3ff
+#       define RS400_DISP2_CRITICAL_POINT_STOP_SHIFT     22
+#       define RS400_DISP2_CRITICAL_POINT_STOP_MASK      0x3ff
+#define RS400_DMIF_MEM_CNTL1                   0xe38
+#       define RS400_DISP2_START_ADR_SHIFT      0
+#       define RS400_DISP2_START_ADR_MASK       0x3ff
+#       define RS400_DISP1_CRITICAL_POINT_START_SHIFT    12
+#       define RS400_DISP1_CRITICAL_POINT_START_MASK     0x3ff
+#       define RS400_DISP1_CRITICAL_POINT_STOP_SHIFT     22
+#       define RS400_DISP1_CRITICAL_POINT_STOP_MASK      0x3ff
+#define RS400_DISP1_REQ_CNTL1                  0xe3c
+#       define RS400_DISP1_START_REQ_LEVEL_SHIFT   0
+#       define RS400_DISP1_START_REQ_LEVEL_MASK    0x3ff
+#       define RS400_DISP1_STOP_REQ_LEVEL_SHIFT    12
+#       define RS400_DISP1_STOP_REQ_LEVEL_MASK     0x3ff
+#       define RS400_DISP1_ALLOW_FID_LEVEL_SHIFT   22
+#       define RS400_DISP1_ALLOW_FID_LEVEL_MASK    0x3ff
+
+#define RADEON_PCIE_INDEX               0x0030
+#define RADEON_PCIE_DATA                0x0034
+#define RADEON_PCIE_TX_GART_CNTL       0x10
+#      define RADEON_PCIE_TX_GART_EN           (1 << 0)
+#      define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_PASS_THRU (0 << 1)
+#      define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_CLAMP_LO  (1 << 1)
+#      define RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD   (3 << 1)
+#      define RADEON_PCIE_TX_GART_MODE_32_128_CACHE    (0 << 3)
+#      define RADEON_PCIE_TX_GART_MODE_8_4_128_CACHE   (1 << 3)
+#      define RADEON_PCIE_TX_GART_CHK_RW_VALID_EN      (1 << 5)
+#      define RADEON_PCIE_TX_GART_INVALIDATE_TLB       (1 << 8)
+#define RADEON_PCIE_TX_DISCARD_RD_ADDR_LO 0x11
+#define RADEON_PCIE_TX_DISCARD_RD_ADDR_HI 0x12
+#define RADEON_PCIE_TX_GART_BASE       0x13
+#define RADEON_PCIE_TX_GART_START_LO   0x14
+#define RADEON_PCIE_TX_GART_START_HI   0x15
+#define RADEON_PCIE_TX_GART_END_LO     0x16
+#define RADEON_PCIE_TX_GART_END_HI     0x17
+#define RADEON_PCIE_TX_GART_ERROR      0x18
+
+#define RADEON_SCRATCH_REG0            0x15e0
+#define RADEON_SCRATCH_REG1            0x15e4
+#define RADEON_SCRATCH_REG2            0x15e8
+#define RADEON_SCRATCH_REG3            0x15ec
+#define RADEON_SCRATCH_REG4            0x15f0
+#define RADEON_SCRATCH_REG5            0x15f4
+
+#endif
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c
new file mode 100644 (file)
index 0000000..a853261
--- /dev/null
@@ -0,0 +1,485 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ *          Jerome Glisse
+ */
+#include <linux/seq_file.h>
+#include "drmP.h"
+#include "radeon_drm.h"
+#include "radeon_reg.h"
+#include "radeon.h"
+#include "atom.h"
+
+int radeon_debugfs_ib_init(struct radeon_device *rdev);
+
+/*
+ * IB.
+ */
+int radeon_ib_get(struct radeon_device *rdev, struct radeon_ib **ib)
+{
+       struct radeon_fence *fence;
+       struct radeon_ib *nib;
+       unsigned long i;
+       int r = 0;
+
+       *ib = NULL;
+       r = radeon_fence_create(rdev, &fence);
+       if (r) {
+               DRM_ERROR("failed to create fence for new IB\n");
+               return r;
+       }
+       mutex_lock(&rdev->ib_pool.mutex);
+       i = find_first_zero_bit(rdev->ib_pool.alloc_bm, RADEON_IB_POOL_SIZE);
+       if (i < RADEON_IB_POOL_SIZE) {
+               set_bit(i, rdev->ib_pool.alloc_bm);
+               rdev->ib_pool.ibs[i].length_dw = 0;
+               *ib = &rdev->ib_pool.ibs[i];
+               goto out;
+       }
+       if (list_empty(&rdev->ib_pool.scheduled_ibs)) {
+               /* we go do nothings here */
+               DRM_ERROR("all IB allocated none scheduled.\n");
+               r = -EINVAL;
+               goto out;
+       }
+       /* get the first ib on the scheduled list */
+       nib = list_entry(rdev->ib_pool.scheduled_ibs.next,
+                        struct radeon_ib, list);
+       if (nib->fence == NULL) {
+               /* we go do nothings here */
+               DRM_ERROR("IB %lu scheduled without a fence.\n", nib->idx);
+               r = -EINVAL;
+               goto out;
+       }
+       r = radeon_fence_wait(nib->fence, false);
+       if (r) {
+               DRM_ERROR("radeon: IB(%lu:0x%016lX:%u)\n", nib->idx,
+                         (unsigned long)nib->gpu_addr, nib->length_dw);
+               DRM_ERROR("radeon: GPU lockup detected, fail to get a IB\n");
+               goto out;
+       }
+       radeon_fence_unref(&nib->fence);
+       nib->length_dw = 0;
+       list_del(&nib->list);
+       INIT_LIST_HEAD(&nib->list);
+       *ib = nib;
+out:
+       mutex_unlock(&rdev->ib_pool.mutex);
+       if (r) {
+               radeon_fence_unref(&fence);
+       } else {
+               (*ib)->fence = fence;
+       }
+       return r;
+}
+
+void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib **ib)
+{
+       struct radeon_ib *tmp = *ib;
+
+       *ib = NULL;
+       if (tmp == NULL) {
+               return;
+       }
+       mutex_lock(&rdev->ib_pool.mutex);
+       if (!list_empty(&tmp->list) && !radeon_fence_signaled(tmp->fence)) {
+               /* IB is scheduled & not signaled don't do anythings */
+               mutex_unlock(&rdev->ib_pool.mutex);
+               return;
+       }
+       list_del(&tmp->list);
+       INIT_LIST_HEAD(&tmp->list);
+       if (tmp->fence) {
+               radeon_fence_unref(&tmp->fence);
+       }
+       tmp->length_dw = 0;
+       clear_bit(tmp->idx, rdev->ib_pool.alloc_bm);
+       mutex_unlock(&rdev->ib_pool.mutex);
+}
+
+static void radeon_ib_align(struct radeon_device *rdev, struct radeon_ib *ib)
+{
+       while ((ib->length_dw & rdev->cp.align_mask)) {
+               ib->ptr[ib->length_dw++] = PACKET2(0);
+       }
+}
+
+static void radeon_ib_cpu_flush(struct radeon_device *rdev,
+                               struct radeon_ib *ib)
+{
+       unsigned long tmp;
+       unsigned i;
+
+       /* To force CPU cache flush ugly but seems reliable */
+       for (i = 0; i < ib->length_dw; i += (rdev->cp.align_mask + 1)) {
+               tmp = readl(&ib->ptr[i]);
+       }
+}
+
+int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib)
+{
+       int r = 0;
+
+       mutex_lock(&rdev->ib_pool.mutex);
+       radeon_ib_align(rdev, ib);
+       radeon_ib_cpu_flush(rdev, ib);
+       if (!ib->length_dw || !rdev->cp.ready) {
+               /* TODO: Nothings in the ib we should report. */
+               mutex_unlock(&rdev->ib_pool.mutex);
+               DRM_ERROR("radeon: couldn't schedule IB(%lu).\n", ib->idx);
+               return -EINVAL;
+       }
+       /* 64 dwords should be enought for fence too */
+       r = radeon_ring_lock(rdev, 64);
+       if (r) {
+               DRM_ERROR("radeon: scheduling IB failled (%d).\n", r);
+               mutex_unlock(&rdev->ib_pool.mutex);
+               return r;
+       }
+       radeon_ring_write(rdev, PACKET0(RADEON_CP_IB_BASE, 1));
+       radeon_ring_write(rdev, ib->gpu_addr);
+       radeon_ring_write(rdev, ib->length_dw);
+       radeon_fence_emit(rdev, ib->fence);
+       radeon_ring_unlock_commit(rdev);
+       list_add_tail(&ib->list, &rdev->ib_pool.scheduled_ibs);
+       mutex_unlock(&rdev->ib_pool.mutex);
+       return 0;
+}
+
+int radeon_ib_pool_init(struct radeon_device *rdev)
+{
+       void *ptr;
+       uint64_t gpu_addr;
+       int i;
+       int r = 0;
+
+       /* Allocate 1M object buffer */
+       INIT_LIST_HEAD(&rdev->ib_pool.scheduled_ibs);
+       r = radeon_object_create(rdev, NULL,  RADEON_IB_POOL_SIZE*64*1024,
+                                true, RADEON_GEM_DOMAIN_GTT,
+                                false, &rdev->ib_pool.robj);
+       if (r) {
+               DRM_ERROR("radeon: failed to ib pool (%d).\n", r);
+               return r;
+       }
+       r = radeon_object_pin(rdev->ib_pool.robj, RADEON_GEM_DOMAIN_GTT, &gpu_addr);
+       if (r) {
+               DRM_ERROR("radeon: failed to pin ib pool (%d).\n", r);
+               return r;
+       }
+       r = radeon_object_kmap(rdev->ib_pool.robj, &ptr);
+       if (r) {
+               DRM_ERROR("radeon: failed to map ib poll (%d).\n", r);
+               return r;
+       }
+       for (i = 0; i < RADEON_IB_POOL_SIZE; i++) {
+               unsigned offset;
+
+               offset = i * 64 * 1024;
+               rdev->ib_pool.ibs[i].gpu_addr = gpu_addr + offset;
+               rdev->ib_pool.ibs[i].ptr = ptr + offset;
+               rdev->ib_pool.ibs[i].idx = i;
+               rdev->ib_pool.ibs[i].length_dw = 0;
+               INIT_LIST_HEAD(&rdev->ib_pool.ibs[i].list);
+       }
+       bitmap_zero(rdev->ib_pool.alloc_bm, RADEON_IB_POOL_SIZE);
+       rdev->ib_pool.ready = true;
+       DRM_INFO("radeon: ib pool ready.\n");
+       if (radeon_debugfs_ib_init(rdev)) {
+               DRM_ERROR("Failed to register debugfs file for IB !\n");
+       }
+       return r;
+}
+
+void radeon_ib_pool_fini(struct radeon_device *rdev)
+{
+       if (!rdev->ib_pool.ready) {
+               return;
+       }
+       mutex_lock(&rdev->ib_pool.mutex);
+       bitmap_zero(rdev->ib_pool.alloc_bm, RADEON_IB_POOL_SIZE);
+       if (rdev->ib_pool.robj) {
+               radeon_object_kunmap(rdev->ib_pool.robj);
+               radeon_object_unref(&rdev->ib_pool.robj);
+               rdev->ib_pool.robj = NULL;
+       }
+       mutex_unlock(&rdev->ib_pool.mutex);
+}
+
+int radeon_ib_test(struct radeon_device *rdev)
+{
+       struct radeon_ib *ib;
+       uint32_t scratch;
+       uint32_t tmp = 0;
+       unsigned i;
+       int r;
+
+       r = radeon_scratch_get(rdev, &scratch);
+       if (r) {
+               DRM_ERROR("radeon: failed to get scratch reg (%d).\n", r);
+               return r;
+       }
+       WREG32(scratch, 0xCAFEDEAD);
+       r = radeon_ib_get(rdev, &ib);
+       if (r) {
+               return r;
+       }
+       ib->ptr[0] = PACKET0(scratch, 0);
+       ib->ptr[1] = 0xDEADBEEF;
+       ib->ptr[2] = PACKET2(0);
+       ib->ptr[3] = PACKET2(0);
+       ib->ptr[4] = PACKET2(0);
+       ib->ptr[5] = PACKET2(0);
+       ib->ptr[6] = PACKET2(0);
+       ib->ptr[7] = PACKET2(0);
+       ib->length_dw = 8;
+       r = radeon_ib_schedule(rdev, ib);
+       if (r) {
+               radeon_scratch_free(rdev, scratch);
+               radeon_ib_free(rdev, &ib);
+               return r;
+       }
+       r = radeon_fence_wait(ib->fence, false);
+       if (r) {
+               return r;
+       }
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               tmp = RREG32(scratch);
+               if (tmp == 0xDEADBEEF) {
+                       break;
+               }
+               DRM_UDELAY(1);
+       }
+       if (i < rdev->usec_timeout) {
+               DRM_INFO("ib test succeeded in %u usecs\n", i);
+       } else {
+               DRM_ERROR("radeon: ib test failed (sracth(0x%04X)=0x%08X)\n",
+                         scratch, tmp);
+               r = -EINVAL;
+       }
+       radeon_scratch_free(rdev, scratch);
+       radeon_ib_free(rdev, &ib);
+       return r;
+}
+
+
+/*
+ * Ring.
+ */
+void radeon_ring_free_size(struct radeon_device *rdev)
+{
+       rdev->cp.rptr = RREG32(RADEON_CP_RB_RPTR);
+       /* This works because ring_size is a power of 2 */
+       rdev->cp.ring_free_dw = (rdev->cp.rptr + (rdev->cp.ring_size / 4));
+       rdev->cp.ring_free_dw -= rdev->cp.wptr;
+       rdev->cp.ring_free_dw &= rdev->cp.ptr_mask;
+       if (!rdev->cp.ring_free_dw) {
+               rdev->cp.ring_free_dw = rdev->cp.ring_size / 4;
+       }
+}
+
+int radeon_ring_lock(struct radeon_device *rdev, unsigned ndw)
+{
+       int r;
+
+       /* Align requested size with padding so unlock_commit can
+        * pad safely */
+       ndw = (ndw + rdev->cp.align_mask) & ~rdev->cp.align_mask;
+       mutex_lock(&rdev->cp.mutex);
+       while (ndw > (rdev->cp.ring_free_dw - 1)) {
+               radeon_ring_free_size(rdev);
+               if (ndw < rdev->cp.ring_free_dw) {
+                       break;
+               }
+               r = radeon_fence_wait_next(rdev);
+               if (r) {
+                       mutex_unlock(&rdev->cp.mutex);
+                       return r;
+               }
+       }
+       rdev->cp.count_dw = ndw;
+       rdev->cp.wptr_old = rdev->cp.wptr;
+       return 0;
+}
+
+void radeon_ring_unlock_commit(struct radeon_device *rdev)
+{
+       unsigned count_dw_pad;
+       unsigned i;
+
+       /* We pad to match fetch size */
+       count_dw_pad = (rdev->cp.align_mask + 1) -
+                      (rdev->cp.wptr & rdev->cp.align_mask);
+       for (i = 0; i < count_dw_pad; i++) {
+               radeon_ring_write(rdev, PACKET2(0));
+       }
+       DRM_MEMORYBARRIER();
+       WREG32(RADEON_CP_RB_WPTR, rdev->cp.wptr);
+       (void)RREG32(RADEON_CP_RB_WPTR);
+       mutex_unlock(&rdev->cp.mutex);
+}
+
+void radeon_ring_unlock_undo(struct radeon_device *rdev)
+{
+       rdev->cp.wptr = rdev->cp.wptr_old;
+       mutex_unlock(&rdev->cp.mutex);
+}
+
+int radeon_ring_test(struct radeon_device *rdev)
+{
+       uint32_t scratch;
+       uint32_t tmp = 0;
+       unsigned i;
+       int r;
+
+       r = radeon_scratch_get(rdev, &scratch);
+       if (r) {
+               DRM_ERROR("radeon: cp failed to get scratch reg (%d).\n", r);
+               return r;
+       }
+       WREG32(scratch, 0xCAFEDEAD);
+       r = radeon_ring_lock(rdev, 2);
+       if (r) {
+               DRM_ERROR("radeon: cp failed to lock ring (%d).\n", r);
+               radeon_scratch_free(rdev, scratch);
+               return r;
+       }
+       radeon_ring_write(rdev, PACKET0(scratch, 0));
+       radeon_ring_write(rdev, 0xDEADBEEF);
+       radeon_ring_unlock_commit(rdev);
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               tmp = RREG32(scratch);
+               if (tmp == 0xDEADBEEF) {
+                       break;
+               }
+               DRM_UDELAY(1);
+       }
+       if (i < rdev->usec_timeout) {
+               DRM_INFO("ring test succeeded in %d usecs\n", i);
+       } else {
+               DRM_ERROR("radeon: ring test failed (sracth(0x%04X)=0x%08X)\n",
+                         scratch, tmp);
+               r = -EINVAL;
+       }
+       radeon_scratch_free(rdev, scratch);
+       return r;
+}
+
+int radeon_ring_init(struct radeon_device *rdev, unsigned ring_size)
+{
+       int r;
+
+       rdev->cp.ring_size = ring_size;
+       /* Allocate ring buffer */
+       if (rdev->cp.ring_obj == NULL) {
+               r = radeon_object_create(rdev, NULL, rdev->cp.ring_size,
+                                        true,
+                                        RADEON_GEM_DOMAIN_GTT,
+                                        false,
+                                        &rdev->cp.ring_obj);
+               if (r) {
+                       DRM_ERROR("radeon: failed to create ring buffer (%d).\n", r);
+                       mutex_unlock(&rdev->cp.mutex);
+                       return r;
+               }
+               r = radeon_object_pin(rdev->cp.ring_obj,
+                                     RADEON_GEM_DOMAIN_GTT,
+                                     &rdev->cp.gpu_addr);
+               if (r) {
+                       DRM_ERROR("radeon: failed to pin ring buffer (%d).\n", r);
+                       mutex_unlock(&rdev->cp.mutex);
+                       return r;
+               }
+               r = radeon_object_kmap(rdev->cp.ring_obj,
+                                      (void **)&rdev->cp.ring);
+               if (r) {
+                       DRM_ERROR("radeon: failed to map ring buffer (%d).\n", r);
+                       mutex_unlock(&rdev->cp.mutex);
+                       return r;
+               }
+       }
+       rdev->cp.ptr_mask = (rdev->cp.ring_size / 4) - 1;
+       rdev->cp.ring_free_dw = rdev->cp.ring_size / 4;
+       return 0;
+}
+
+void radeon_ring_fini(struct radeon_device *rdev)
+{
+       mutex_lock(&rdev->cp.mutex);
+       if (rdev->cp.ring_obj) {
+               radeon_object_kunmap(rdev->cp.ring_obj);
+               radeon_object_unpin(rdev->cp.ring_obj);
+               radeon_object_unref(&rdev->cp.ring_obj);
+               rdev->cp.ring = NULL;
+               rdev->cp.ring_obj = NULL;
+       }
+       mutex_unlock(&rdev->cp.mutex);
+}
+
+
+/*
+ * Debugfs info
+ */
+#if defined(CONFIG_DEBUG_FS)
+static int radeon_debugfs_ib_info(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct radeon_ib *ib = node->info_ent->data;
+       unsigned i;
+
+       if (ib == NULL) {
+               return 0;
+       }
+       seq_printf(m, "IB %04lu\n", ib->idx);
+       seq_printf(m, "IB fence %p\n", ib->fence);
+       seq_printf(m, "IB size %05u dwords\n", ib->length_dw);
+       for (i = 0; i < ib->length_dw; i++) {
+               seq_printf(m, "[%05u]=0x%08X\n", i, ib->ptr[i]);
+       }
+       return 0;
+}
+
+static struct drm_info_list radeon_debugfs_ib_list[RADEON_IB_POOL_SIZE];
+static char radeon_debugfs_ib_names[RADEON_IB_POOL_SIZE][32];
+#endif
+
+int radeon_debugfs_ib_init(struct radeon_device *rdev)
+{
+#if defined(CONFIG_DEBUG_FS)
+       unsigned i;
+
+       for (i = 0; i < RADEON_IB_POOL_SIZE; i++) {
+               sprintf(radeon_debugfs_ib_names[i], "radeon_ib_%04u", i);
+               radeon_debugfs_ib_list[i].name = radeon_debugfs_ib_names[i];
+               radeon_debugfs_ib_list[i].show = &radeon_debugfs_ib_info;
+               radeon_debugfs_ib_list[i].driver_features = 0;
+               radeon_debugfs_ib_list[i].data = &rdev->ib_pool.ibs[i];
+       }
+       return radeon_debugfs_add_files(rdev, radeon_debugfs_ib_list,
+                                       RADEON_IB_POOL_SIZE);
+#else
+       return 0;
+#endif
+}
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
new file mode 100644 (file)
index 0000000..4c087c1
--- /dev/null
@@ -0,0 +1,653 @@
+/*
+ * Copyright 2009 Jerome Glisse.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors:
+ *    Jerome Glisse <glisse@freedesktop.org>
+ *    Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
+ *    Dave Airlie
+ */
+#include <ttm/ttm_bo_api.h>
+#include <ttm/ttm_bo_driver.h>
+#include <ttm/ttm_placement.h>
+#include <ttm/ttm_module.h>
+#include <drm/drmP.h>
+#include <drm/radeon_drm.h>
+#include "radeon_reg.h"
+#include "radeon.h"
+
+#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
+
+static struct radeon_device *radeon_get_rdev(struct ttm_bo_device *bdev)
+{
+       struct radeon_mman *mman;
+       struct radeon_device *rdev;
+
+       mman = container_of(bdev, struct radeon_mman, bdev);
+       rdev = container_of(mman, struct radeon_device, mman);
+       return rdev;
+}
+
+
+/*
+ * Global memory.
+ */
+static int radeon_ttm_mem_global_init(struct ttm_global_reference *ref)
+{
+       return ttm_mem_global_init(ref->object);
+}
+
+static void radeon_ttm_mem_global_release(struct ttm_global_reference *ref)
+{
+       ttm_mem_global_release(ref->object);
+}
+
+static int radeon_ttm_global_init(struct radeon_device *rdev)
+{
+       struct ttm_global_reference *global_ref;
+       int r;
+
+       rdev->mman.mem_global_referenced = false;
+       global_ref = &rdev->mman.mem_global_ref;
+       global_ref->global_type = TTM_GLOBAL_TTM_MEM;
+       global_ref->size = sizeof(struct ttm_mem_global);
+       global_ref->init = &radeon_ttm_mem_global_init;
+       global_ref->release = &radeon_ttm_mem_global_release;
+       r = ttm_global_item_ref(global_ref);
+       if (r != 0) {
+               DRM_ERROR("Failed referencing a global TTM memory object.\n");
+               return r;
+       }
+       rdev->mman.mem_global_referenced = true;
+       return 0;
+}
+
+static void radeon_ttm_global_fini(struct radeon_device *rdev)
+{
+       if (rdev->mman.mem_global_referenced) {
+               ttm_global_item_unref(&rdev->mman.mem_global_ref);
+               rdev->mman.mem_global_referenced = false;
+       }
+}
+
+struct ttm_backend *radeon_ttm_backend_create(struct radeon_device *rdev);
+
+static struct ttm_backend*
+radeon_create_ttm_backend_entry(struct ttm_bo_device *bdev)
+{
+       struct radeon_device *rdev;
+
+       rdev = radeon_get_rdev(bdev);
+#if __OS_HAS_AGP
+       if (rdev->flags & RADEON_IS_AGP) {
+               return ttm_agp_backend_init(bdev, rdev->ddev->agp->bridge);
+       } else
+#endif
+       {
+               return radeon_ttm_backend_create(rdev);
+       }
+}
+
+static int radeon_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags)
+{
+       return 0;
+}
+
+static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
+                               struct ttm_mem_type_manager *man)
+{
+       struct radeon_device *rdev;
+
+       rdev = radeon_get_rdev(bdev);
+
+       switch (type) {
+       case TTM_PL_SYSTEM:
+               /* System memory */
+               man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
+               man->available_caching = TTM_PL_MASK_CACHING;
+               man->default_caching = TTM_PL_FLAG_CACHED;
+               break;
+       case TTM_PL_TT:
+               man->gpu_offset = 0;
+               man->available_caching = TTM_PL_MASK_CACHING;
+               man->default_caching = TTM_PL_FLAG_CACHED;
+#if __OS_HAS_AGP
+               if (rdev->flags & RADEON_IS_AGP) {
+                       if (!(drm_core_has_AGP(rdev->ddev) && rdev->ddev->agp)) {
+                               DRM_ERROR("AGP is not enabled for memory type %u\n",
+                                         (unsigned)type);
+                               return -EINVAL;
+                       }
+                       man->io_offset = rdev->mc.agp_base;
+                       man->io_size = rdev->mc.gtt_size;
+                       man->io_addr = NULL;
+                       man->flags = TTM_MEMTYPE_FLAG_NEEDS_IOREMAP |
+                                    TTM_MEMTYPE_FLAG_MAPPABLE;
+                       man->available_caching = TTM_PL_FLAG_UNCACHED |
+                                                TTM_PL_FLAG_WC;
+                       man->default_caching = TTM_PL_FLAG_WC;
+               } else
+#endif
+               {
+                       man->io_offset = 0;
+                       man->io_size = 0;
+                       man->io_addr = NULL;
+                       man->flags = TTM_MEMTYPE_FLAG_MAPPABLE |
+                                    TTM_MEMTYPE_FLAG_CMA;
+               }
+               break;
+       case TTM_PL_VRAM:
+               /* "On-card" video ram */
+               man->gpu_offset = 0;
+               man->flags = TTM_MEMTYPE_FLAG_FIXED |
+                            TTM_MEMTYPE_FLAG_NEEDS_IOREMAP |
+                            TTM_MEMTYPE_FLAG_MAPPABLE;
+               man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC;
+               man->default_caching = TTM_PL_FLAG_WC;
+               man->io_addr = NULL;
+               man->io_offset = rdev->mc.aper_base;
+               man->io_size = rdev->mc.aper_size;
+               break;
+       default:
+               DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static uint32_t radeon_evict_flags(struct ttm_buffer_object *bo)
+{
+       uint32_t cur_placement = bo->mem.placement & ~TTM_PL_MASK_MEMTYPE;
+
+       switch (bo->mem.mem_type) {
+       default:
+               return (cur_placement & ~TTM_PL_MASK_CACHING) |
+                       TTM_PL_FLAG_SYSTEM |
+                       TTM_PL_FLAG_CACHED;
+       }
+}
+
+static int radeon_verify_access(struct ttm_buffer_object *bo, struct file *filp)
+{
+       return 0;
+}
+
+static void radeon_move_null(struct ttm_buffer_object *bo,
+                            struct ttm_mem_reg *new_mem)
+{
+       struct ttm_mem_reg *old_mem = &bo->mem;
+
+       BUG_ON(old_mem->mm_node != NULL);
+       *old_mem = *new_mem;
+       new_mem->mm_node = NULL;
+}
+
+static int radeon_move_blit(struct ttm_buffer_object *bo,
+                           bool evict, int no_wait,
+                           struct ttm_mem_reg *new_mem,
+                           struct ttm_mem_reg *old_mem)
+{
+       struct radeon_device *rdev;
+       uint64_t old_start, new_start;
+       struct radeon_fence *fence;
+       int r;
+
+       rdev = radeon_get_rdev(bo->bdev);
+       r = radeon_fence_create(rdev, &fence);
+       if (unlikely(r)) {
+               return r;
+       }
+       old_start = old_mem->mm_node->start << PAGE_SHIFT;
+       new_start = new_mem->mm_node->start << PAGE_SHIFT;
+
+       switch (old_mem->mem_type) {
+       case TTM_PL_VRAM:
+               old_start += rdev->mc.vram_location;
+               break;
+       case TTM_PL_TT:
+               old_start += rdev->mc.gtt_location;
+               break;
+       default:
+               DRM_ERROR("Unknown placement %d\n", old_mem->mem_type);
+               return -EINVAL;
+       }
+       switch (new_mem->mem_type) {
+       case TTM_PL_VRAM:
+               new_start += rdev->mc.vram_location;
+               break;
+       case TTM_PL_TT:
+               new_start += rdev->mc.gtt_location;
+               break;
+       default:
+               DRM_ERROR("Unknown placement %d\n", old_mem->mem_type);
+               return -EINVAL;
+       }
+       if (!rdev->cp.ready) {
+               DRM_ERROR("Trying to move memory with CP turned off.\n");
+               return -EINVAL;
+       }
+       r = radeon_copy(rdev, old_start, new_start, new_mem->num_pages, fence);
+       /* FIXME: handle copy error */
+       r = ttm_bo_move_accel_cleanup(bo, (void *)fence, NULL,
+                                     evict, no_wait, new_mem);
+       radeon_fence_unref(&fence);
+       return r;
+}
+
+static int radeon_move_vram_ram(struct ttm_buffer_object *bo,
+                               bool evict, bool interruptible, bool no_wait,
+                               struct ttm_mem_reg *new_mem)
+{
+       struct radeon_device *rdev;
+       struct ttm_mem_reg *old_mem = &bo->mem;
+       struct ttm_mem_reg tmp_mem;
+       uint32_t proposed_placement;
+       int r;
+
+       rdev = radeon_get_rdev(bo->bdev);
+       tmp_mem = *new_mem;
+       tmp_mem.mm_node = NULL;
+       proposed_placement = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING;
+       r = ttm_bo_mem_space(bo, proposed_placement, &tmp_mem,
+                            interruptible, no_wait);
+       if (unlikely(r)) {
+               return r;
+       }
+       r = ttm_tt_bind(bo->ttm, &tmp_mem);
+       if (unlikely(r)) {
+               goto out_cleanup;
+       }
+       r = radeon_move_blit(bo, true, no_wait, &tmp_mem, old_mem);
+       if (unlikely(r)) {
+               goto out_cleanup;
+       }
+       r = ttm_bo_move_ttm(bo, true, no_wait, new_mem);
+out_cleanup:
+       if (tmp_mem.mm_node) {
+               spin_lock(&rdev->mman.bdev.lru_lock);
+               drm_mm_put_block(tmp_mem.mm_node);
+               spin_unlock(&rdev->mman.bdev.lru_lock);
+               return r;
+       }
+       return r;
+}
+
+static int radeon_move_ram_vram(struct ttm_buffer_object *bo,
+                               bool evict, bool interruptible, bool no_wait,
+                               struct ttm_mem_reg *new_mem)
+{
+       struct radeon_device *rdev;
+       struct ttm_mem_reg *old_mem = &bo->mem;
+       struct ttm_mem_reg tmp_mem;
+       uint32_t proposed_flags;
+       int r;
+
+       rdev = radeon_get_rdev(bo->bdev);
+       tmp_mem = *new_mem;
+       tmp_mem.mm_node = NULL;
+       proposed_flags = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING;
+       r = ttm_bo_mem_space(bo, proposed_flags, &tmp_mem,
+                            interruptible, no_wait);
+       if (unlikely(r)) {
+               return r;
+       }
+       r = ttm_bo_move_ttm(bo, true, no_wait, &tmp_mem);
+       if (unlikely(r)) {
+               goto out_cleanup;
+       }
+       r = radeon_move_blit(bo, true, no_wait, new_mem, old_mem);
+       if (unlikely(r)) {
+               goto out_cleanup;
+       }
+out_cleanup:
+       if (tmp_mem.mm_node) {
+               spin_lock(&rdev->mman.bdev.lru_lock);
+               drm_mm_put_block(tmp_mem.mm_node);
+               spin_unlock(&rdev->mman.bdev.lru_lock);
+               return r;
+       }
+       return r;
+}
+
+static int radeon_bo_move(struct ttm_buffer_object *bo,
+                         bool evict, bool interruptible, bool no_wait,
+                         struct ttm_mem_reg *new_mem)
+{
+       struct radeon_device *rdev;
+       struct ttm_mem_reg *old_mem = &bo->mem;
+       int r;
+
+       rdev = radeon_get_rdev(bo->bdev);
+       if (old_mem->mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) {
+               radeon_move_null(bo, new_mem);
+               return 0;
+       }
+       if ((old_mem->mem_type == TTM_PL_TT &&
+            new_mem->mem_type == TTM_PL_SYSTEM) ||
+           (old_mem->mem_type == TTM_PL_SYSTEM &&
+            new_mem->mem_type == TTM_PL_TT)) {
+               /* bind is enought */
+               radeon_move_null(bo, new_mem);
+               return 0;
+       }
+       if (!rdev->cp.ready) {
+               /* use memcpy */
+               DRM_ERROR("CP is not ready use memcpy.\n");
+               return ttm_bo_move_memcpy(bo, evict, no_wait, new_mem);
+       }
+
+       if (old_mem->mem_type == TTM_PL_VRAM &&
+           new_mem->mem_type == TTM_PL_SYSTEM) {
+               return radeon_move_vram_ram(bo, evict, interruptible,
+                                           no_wait, new_mem);
+       } else if (old_mem->mem_type == TTM_PL_SYSTEM &&
+                  new_mem->mem_type == TTM_PL_VRAM) {
+               return radeon_move_ram_vram(bo, evict, interruptible,
+                                           no_wait, new_mem);
+       } else {
+               r = radeon_move_blit(bo, evict, no_wait, new_mem, old_mem);
+               if (unlikely(r)) {
+                       return r;
+               }
+       }
+       return r;
+}
+
+const uint32_t radeon_mem_prios[] = {
+       TTM_PL_VRAM,
+       TTM_PL_TT,
+       TTM_PL_SYSTEM,
+};
+
+const uint32_t radeon_busy_prios[] = {
+       TTM_PL_TT,
+       TTM_PL_VRAM,
+       TTM_PL_SYSTEM,
+};
+
+static int radeon_sync_obj_wait(void *sync_obj, void *sync_arg,
+                               bool lazy, bool interruptible)
+{
+       return radeon_fence_wait((struct radeon_fence *)sync_obj, interruptible);
+}
+
+static int radeon_sync_obj_flush(void *sync_obj, void *sync_arg)
+{
+       return 0;
+}
+
+static void radeon_sync_obj_unref(void **sync_obj)
+{
+       radeon_fence_unref((struct radeon_fence **)sync_obj);
+}
+
+static void *radeon_sync_obj_ref(void *sync_obj)
+{
+       return radeon_fence_ref((struct radeon_fence *)sync_obj);
+}
+
+static bool radeon_sync_obj_signaled(void *sync_obj, void *sync_arg)
+{
+       return radeon_fence_signaled((struct radeon_fence *)sync_obj);
+}
+
+static struct ttm_bo_driver radeon_bo_driver = {
+       .mem_type_prio = radeon_mem_prios,
+       .mem_busy_prio = radeon_busy_prios,
+       .num_mem_type_prio = ARRAY_SIZE(radeon_mem_prios),
+       .num_mem_busy_prio = ARRAY_SIZE(radeon_busy_prios),
+       .create_ttm_backend_entry = &radeon_create_ttm_backend_entry,
+       .invalidate_caches = &radeon_invalidate_caches,
+       .init_mem_type = &radeon_init_mem_type,
+       .evict_flags = &radeon_evict_flags,
+       .move = &radeon_bo_move,
+       .verify_access = &radeon_verify_access,
+       .sync_obj_signaled = &radeon_sync_obj_signaled,
+       .sync_obj_wait = &radeon_sync_obj_wait,
+       .sync_obj_flush = &radeon_sync_obj_flush,
+       .sync_obj_unref = &radeon_sync_obj_unref,
+       .sync_obj_ref = &radeon_sync_obj_ref,
+};
+
+int radeon_ttm_init(struct radeon_device *rdev)
+{
+       int r;
+
+       r = radeon_ttm_global_init(rdev);
+       if (r) {
+               return r;
+       }
+       /* No others user of address space so set it to 0 */
+       r = ttm_bo_device_init(&rdev->mman.bdev,
+                              rdev->mman.mem_global_ref.object,
+                              &radeon_bo_driver, DRM_FILE_PAGE_OFFSET);
+       if (r) {
+               DRM_ERROR("failed initializing buffer object driver(%d).\n", r);
+               return r;
+       }
+       r = ttm_bo_init_mm(&rdev->mman.bdev, TTM_PL_VRAM, 0,
+                          ((rdev->mc.aper_size) >> PAGE_SHIFT));
+       if (r) {
+               DRM_ERROR("Failed initializing VRAM heap.\n");
+               return r;
+       }
+       r = radeon_object_create(rdev, NULL, 256 * 1024, true,
+                                RADEON_GEM_DOMAIN_VRAM, false,
+                                &rdev->stollen_vga_memory);
+       if (r) {
+               return r;
+       }
+       r = radeon_object_pin(rdev->stollen_vga_memory, RADEON_GEM_DOMAIN_VRAM, NULL);
+       if (r) {
+               radeon_object_unref(&rdev->stollen_vga_memory);
+               return r;
+       }
+       DRM_INFO("radeon: %uM of VRAM memory ready\n",
+                rdev->mc.vram_size / (1024 * 1024));
+       r = ttm_bo_init_mm(&rdev->mman.bdev, TTM_PL_TT, 0,
+                          ((rdev->mc.gtt_size) >> PAGE_SHIFT));
+       if (r) {
+               DRM_ERROR("Failed initializing GTT heap.\n");
+               return r;
+       }
+       DRM_INFO("radeon: %uM of GTT memory ready.\n",
+                rdev->mc.gtt_size / (1024 * 1024));
+       if (unlikely(rdev->mman.bdev.dev_mapping == NULL)) {
+               rdev->mman.bdev.dev_mapping = rdev->ddev->dev_mapping;
+       }
+       return 0;
+}
+
+void radeon_ttm_fini(struct radeon_device *rdev)
+{
+       if (rdev->stollen_vga_memory) {
+               radeon_object_unpin(rdev->stollen_vga_memory);
+               radeon_object_unref(&rdev->stollen_vga_memory);
+       }
+       ttm_bo_clean_mm(&rdev->mman.bdev, TTM_PL_VRAM);
+       ttm_bo_clean_mm(&rdev->mman.bdev, TTM_PL_TT);
+       ttm_bo_device_release(&rdev->mman.bdev);
+       radeon_gart_fini(rdev);
+       radeon_ttm_global_fini(rdev);
+       DRM_INFO("radeon: ttm finalized\n");
+}
+
+static struct vm_operations_struct radeon_ttm_vm_ops;
+static struct vm_operations_struct *ttm_vm_ops = NULL;
+
+static int radeon_ttm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+       struct ttm_buffer_object *bo;
+       int r;
+
+       bo = (struct ttm_buffer_object *)vma->vm_private_data;
+       if (bo == NULL) {
+               return VM_FAULT_NOPAGE;
+       }
+       r = ttm_vm_ops->fault(vma, vmf);
+       return r;
+}
+
+int radeon_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct drm_file *file_priv;
+       struct radeon_device *rdev;
+       int r;
+
+       if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) {
+               return drm_mmap(filp, vma);
+       }
+
+       file_priv = (struct drm_file *)filp->private_data;
+       rdev = file_priv->minor->dev->dev_private;
+       if (rdev == NULL) {
+               return -EINVAL;
+       }
+       r = ttm_bo_mmap(filp, vma, &rdev->mman.bdev);
+       if (unlikely(r != 0)) {
+               return r;
+       }
+       if (unlikely(ttm_vm_ops == NULL)) {
+               ttm_vm_ops = vma->vm_ops;
+               radeon_ttm_vm_ops = *ttm_vm_ops;
+               radeon_ttm_vm_ops.fault = &radeon_ttm_fault;
+       }
+       vma->vm_ops = &radeon_ttm_vm_ops;
+       return 0;
+}
+
+
+/*
+ * TTM backend functions.
+ */
+struct radeon_ttm_backend {
+       struct ttm_backend              backend;
+       struct radeon_device            *rdev;
+       unsigned long                   num_pages;
+       struct page                     **pages;
+       struct page                     *dummy_read_page;
+       bool                            populated;
+       bool                            bound;
+       unsigned                        offset;
+};
+
+static int radeon_ttm_backend_populate(struct ttm_backend *backend,
+                                      unsigned long num_pages,
+                                      struct page **pages,
+                                      struct page *dummy_read_page)
+{
+       struct radeon_ttm_backend *gtt;
+
+       gtt = container_of(backend, struct radeon_ttm_backend, backend);
+       gtt->pages = pages;
+       gtt->num_pages = num_pages;
+       gtt->dummy_read_page = dummy_read_page;
+       gtt->populated = true;
+       return 0;
+}
+
+static void radeon_ttm_backend_clear(struct ttm_backend *backend)
+{
+       struct radeon_ttm_backend *gtt;
+
+       gtt = container_of(backend, struct radeon_ttm_backend, backend);
+       gtt->pages = NULL;
+       gtt->num_pages = 0;
+       gtt->dummy_read_page = NULL;
+       gtt->populated = false;
+       gtt->bound = false;
+}
+
+
+static int radeon_ttm_backend_bind(struct ttm_backend *backend,
+                                  struct ttm_mem_reg *bo_mem)
+{
+       struct radeon_ttm_backend *gtt;
+       int r;
+
+       gtt = container_of(backend, struct radeon_ttm_backend, backend);
+       gtt->offset = bo_mem->mm_node->start << PAGE_SHIFT;
+       if (!gtt->num_pages) {
+               WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n", gtt->num_pages, bo_mem, backend);
+       }
+       r = radeon_gart_bind(gtt->rdev, gtt->offset,
+                            gtt->num_pages, gtt->pages);
+       if (r) {
+               DRM_ERROR("failed to bind %lu pages at 0x%08X\n",
+                         gtt->num_pages, gtt->offset);
+               return r;
+       }
+       gtt->bound = true;
+       return 0;
+}
+
+static int radeon_ttm_backend_unbind(struct ttm_backend *backend)
+{
+       struct radeon_ttm_backend *gtt;
+
+       gtt = container_of(backend, struct radeon_ttm_backend, backend);
+       radeon_gart_unbind(gtt->rdev, gtt->offset, gtt->num_pages);
+       gtt->bound = false;
+       return 0;
+}
+
+static void radeon_ttm_backend_destroy(struct ttm_backend *backend)
+{
+       struct radeon_ttm_backend *gtt;
+
+       gtt = container_of(backend, struct radeon_ttm_backend, backend);
+       if (gtt->bound) {
+               radeon_ttm_backend_unbind(backend);
+       }
+       kfree(gtt);
+}
+
+static struct ttm_backend_func radeon_backend_func = {
+       .populate = &radeon_ttm_backend_populate,
+       .clear = &radeon_ttm_backend_clear,
+       .bind = &radeon_ttm_backend_bind,
+       .unbind = &radeon_ttm_backend_unbind,
+       .destroy = &radeon_ttm_backend_destroy,
+};
+
+struct ttm_backend *radeon_ttm_backend_create(struct radeon_device *rdev)
+{
+       struct radeon_ttm_backend *gtt;
+
+       gtt = kzalloc(sizeof(struct radeon_ttm_backend), GFP_KERNEL);
+       if (gtt == NULL) {
+               return NULL;
+       }
+       gtt->backend.bdev = &rdev->mman.bdev;
+       gtt->backend.flags = 0;
+       gtt->backend.func = &radeon_backend_func;
+       gtt->rdev = rdev;
+       gtt->pages = NULL;
+       gtt->num_pages = 0;
+       gtt->dummy_read_page = NULL;
+       gtt->populated = false;
+       gtt->bound = false;
+       return &gtt->backend;
+}
diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c
new file mode 100644 (file)
index 0000000..cc074b5
--- /dev/null
@@ -0,0 +1,411 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ *          Jerome Glisse
+ */
+#include <linux/seq_file.h>
+#include <drm/drmP.h>
+#include "radeon_reg.h"
+#include "radeon.h"
+
+/* rs400,rs480 depends on : */
+void r100_hdp_reset(struct radeon_device *rdev);
+void r100_mc_disable_clients(struct radeon_device *rdev);
+int r300_mc_wait_for_idle(struct radeon_device *rdev);
+void r420_pipes_init(struct radeon_device *rdev);
+
+/* This files gather functions specifics to :
+ * rs400,rs480
+ *
+ * Some of these functions might be used by newer ASICs.
+ */
+void rs400_gpu_init(struct radeon_device *rdev);
+int rs400_debugfs_pcie_gart_info_init(struct radeon_device *rdev);
+
+
+/*
+ * GART functions.
+ */
+void rs400_gart_adjust_size(struct radeon_device *rdev)
+{
+       /* Check gart size */
+       switch (rdev->mc.gtt_size/(1024*1024)) {
+       case 32:
+       case 64:
+       case 128:
+       case 256:
+       case 512:
+       case 1024:
+       case 2048:
+               break;
+       default:
+               DRM_ERROR("Unable to use IGP GART size %uM\n",
+                         rdev->mc.gtt_size >> 20);
+               DRM_ERROR("Valid GART size for IGP are 32M,64M,128M,256M,512M,1G,2G\n");
+               DRM_ERROR("Forcing to 32M GART size\n");
+               rdev->mc.gtt_size = 32 * 1024 * 1024;
+               return;
+       }
+       if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480) {
+               /* FIXME: RS400 & RS480 seems to have issue with GART size
+                * if 4G of system memory (needs more testing) */
+               rdev->mc.gtt_size = 32 * 1024 * 1024;
+               DRM_ERROR("Forcing to 32M GART size (because of ASIC bug ?)\n");
+       }
+}
+
+void rs400_gart_tlb_flush(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+       unsigned int timeout = rdev->usec_timeout;
+
+       WREG32_MC(RS480_GART_CACHE_CNTRL, RS480_GART_CACHE_INVALIDATE);
+       do {
+               tmp = RREG32_MC(RS480_GART_CACHE_CNTRL);
+               if ((tmp & RS480_GART_CACHE_INVALIDATE) == 0)
+                       break;
+               DRM_UDELAY(1);
+               timeout--;
+       } while (timeout > 0);
+       WREG32_MC(RS480_GART_CACHE_CNTRL, 0);
+}
+
+int rs400_gart_enable(struct radeon_device *rdev)
+{
+       uint32_t size_reg;
+       uint32_t tmp;
+       int r;
+
+       /* Initialize common gart structure */
+       r = radeon_gart_init(rdev);
+       if (r) {
+               return r;
+       }
+       if (rs400_debugfs_pcie_gart_info_init(rdev)) {
+               DRM_ERROR("Failed to register debugfs file for RS400 GART !\n");
+       }
+
+       tmp = RREG32_MC(RS690_AIC_CTRL_SCRATCH);
+       tmp |= RS690_DIS_OUT_OF_PCI_GART_ACCESS;
+       WREG32_MC(RS690_AIC_CTRL_SCRATCH, tmp);
+       /* Check gart size */
+       switch(rdev->mc.gtt_size / (1024 * 1024)) {
+       case 32:
+               size_reg = RS480_VA_SIZE_32MB;
+               break;
+       case 64:
+               size_reg = RS480_VA_SIZE_64MB;
+               break;
+       case 128:
+               size_reg = RS480_VA_SIZE_128MB;
+               break;
+       case 256:
+               size_reg = RS480_VA_SIZE_256MB;
+               break;
+       case 512:
+               size_reg = RS480_VA_SIZE_512MB;
+               break;
+       case 1024:
+               size_reg = RS480_VA_SIZE_1GB;
+               break;
+       case 2048:
+               size_reg = RS480_VA_SIZE_2GB;
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (rdev->gart.table.ram.ptr == NULL) {
+               rdev->gart.table_size = rdev->gart.num_gpu_pages * 4;
+               r = radeon_gart_table_ram_alloc(rdev);
+               if (r) {
+                       return r;
+               }
+       }
+       /* It should be fine to program it to max value */
+       if (rdev->family == CHIP_RS690 || (rdev->family == CHIP_RS740)) {
+               WREG32_MC(RS690_MCCFG_AGP_BASE, 0xFFFFFFFF);
+               WREG32_MC(RS690_MCCFG_AGP_BASE_2, 0);
+       } else {
+               WREG32(RADEON_AGP_BASE, 0xFFFFFFFF);
+               WREG32(RS480_AGP_BASE_2, 0);
+       }
+       tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1;
+       tmp = REG_SET(RS690_MC_AGP_TOP, tmp >> 16);
+       tmp |= REG_SET(RS690_MC_AGP_START, rdev->mc.gtt_location >> 16);
+       if ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740)) {
+               WREG32_MC(RS690_MCCFG_AGP_LOCATION, tmp);
+               tmp = RREG32(RADEON_BUS_CNTL) & ~RS600_BUS_MASTER_DIS;
+               WREG32(RADEON_BUS_CNTL, tmp);
+       } else {
+               WREG32(RADEON_MC_AGP_LOCATION, tmp);
+               tmp = RREG32(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
+               WREG32(RADEON_BUS_CNTL, tmp);
+       }
+       /* Table should be in 32bits address space so ignore bits above. */
+       tmp = rdev->gart.table_addr & 0xfffff000;
+       WREG32_MC(RS480_GART_BASE, tmp);
+       /* TODO: more tweaking here */
+       WREG32_MC(RS480_GART_FEATURE_ID,
+                 (RS480_TLB_ENABLE |
+                  RS480_GTW_LAC_EN | RS480_1LEVEL_GART));
+       /* Disable snooping */
+       WREG32_MC(RS480_AGP_MODE_CNTL,
+                 (1 << RS480_REQ_TYPE_SNOOP_SHIFT) | RS480_REQ_TYPE_SNOOP_DIS);
+       /* Disable AGP mode */
+       /* FIXME: according to doc we should set HIDE_MMCFG_BAR=0,
+        * AGPMODE30=0 & AGP30ENHANCED=0 in NB_CNTL */
+       if ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740)) {
+               WREG32_MC(RS480_MC_MISC_CNTL,
+                         (RS480_GART_INDEX_REG_EN | RS690_BLOCK_GFX_D3_EN));
+       } else {
+               WREG32_MC(RS480_MC_MISC_CNTL, RS480_GART_INDEX_REG_EN);
+       }
+       /* Enable gart */
+       WREG32_MC(RS480_AGP_ADDRESS_SPACE_SIZE, (RS480_GART_EN | size_reg));
+       rs400_gart_tlb_flush(rdev);
+       rdev->gart.ready = true;
+       return 0;
+}
+
+void rs400_gart_disable(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+
+       tmp = RREG32_MC(RS690_AIC_CTRL_SCRATCH);
+       tmp |= RS690_DIS_OUT_OF_PCI_GART_ACCESS;
+       WREG32_MC(RS690_AIC_CTRL_SCRATCH, tmp);
+       WREG32_MC(RS480_AGP_ADDRESS_SPACE_SIZE, 0);
+}
+
+int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)
+{
+       if (i < 0 || i > rdev->gart.num_gpu_pages) {
+               return -EINVAL;
+       }
+       rdev->gart.table.ram.ptr[i] = cpu_to_le32(((uint32_t)addr) | 0xC);
+       return 0;
+}
+
+
+/*
+ * MC functions.
+ */
+int rs400_mc_init(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+       int r;
+
+       if (r100_debugfs_rbbm_init(rdev)) {
+               DRM_ERROR("Failed to register debugfs file for RBBM !\n");
+       }
+
+       rs400_gpu_init(rdev);
+       rs400_gart_disable(rdev);
+       rdev->mc.gtt_location = rdev->mc.vram_size;
+       rdev->mc.gtt_location += (rdev->mc.gtt_size - 1);
+       rdev->mc.gtt_location &= ~(rdev->mc.gtt_size - 1);
+       rdev->mc.vram_location = 0xFFFFFFFFUL;
+       r = radeon_mc_setup(rdev);
+       if (r) {
+               return r;
+       }
+
+       r100_mc_disable_clients(rdev);
+       if (r300_mc_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait MC idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+
+       tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1;
+       tmp = REG_SET(RADEON_MC_FB_TOP, tmp >> 16);
+       tmp |= REG_SET(RADEON_MC_FB_START, rdev->mc.vram_location >> 16);
+       WREG32(RADEON_MC_FB_LOCATION, tmp);
+       tmp = RREG32(RADEON_HOST_PATH_CNTL) | RADEON_HP_LIN_RD_CACHE_DIS;
+       WREG32(RADEON_HOST_PATH_CNTL, tmp | RADEON_HDP_SOFT_RESET | RADEON_HDP_READ_BUFFER_INVALIDATE);
+       (void)RREG32(RADEON_HOST_PATH_CNTL);
+       WREG32(RADEON_HOST_PATH_CNTL, tmp);
+       (void)RREG32(RADEON_HOST_PATH_CNTL);
+       return 0;
+}
+
+void rs400_mc_fini(struct radeon_device *rdev)
+{
+       rs400_gart_disable(rdev);
+       radeon_gart_table_ram_free(rdev);
+       radeon_gart_fini(rdev);
+}
+
+
+/*
+ * Global GPU functions
+ */
+void rs400_errata(struct radeon_device *rdev)
+{
+       rdev->pll_errata = 0;
+}
+
+void rs400_gpu_init(struct radeon_device *rdev)
+{
+       /* FIXME: HDP same place on rs400 ? */
+       r100_hdp_reset(rdev);
+       /* FIXME: is this correct ? */
+       r420_pipes_init(rdev);
+       if (r300_mc_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait MC idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+}
+
+
+/*
+ * VRAM info.
+ */
+void rs400_vram_info(struct radeon_device *rdev)
+{
+       uint32_t tom;
+
+       rs400_gart_adjust_size(rdev);
+       /* DDR for all card after R300 & IGP */
+       rdev->mc.vram_is_ddr = true;
+       rdev->mc.vram_width = 128;
+
+       /* read NB_TOM to get the amount of ram stolen for the GPU */
+       tom = RREG32(RADEON_NB_TOM);
+       rdev->mc.vram_size = (((tom >> 16) - (tom & 0xffff) + 1) << 16);
+       WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size);
+
+       /* Could aper size report 0 ? */
+       rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
+       rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
+}
+
+
+/*
+ * Indirect registers accessor
+ */
+uint32_t rs400_mc_rreg(struct radeon_device *rdev, uint32_t reg)
+{
+       uint32_t r;
+
+       WREG32(RS480_NB_MC_INDEX, reg & 0xff);
+       r = RREG32(RS480_NB_MC_DATA);
+       WREG32(RS480_NB_MC_INDEX, 0xff);
+       return r;
+}
+
+void rs400_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
+{
+       WREG32(RS480_NB_MC_INDEX, ((reg) & 0xff) | RS480_NB_MC_IND_WR_EN);
+       WREG32(RS480_NB_MC_DATA, (v));
+       WREG32(RS480_NB_MC_INDEX, 0xff);
+}
+
+
+/*
+ * Debugfs info
+ */
+#if defined(CONFIG_DEBUG_FS)
+static int rs400_debugfs_gart_info(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t tmp;
+
+       tmp = RREG32(RADEON_HOST_PATH_CNTL);
+       seq_printf(m, "HOST_PATH_CNTL 0x%08x\n", tmp);
+       tmp = RREG32(RADEON_BUS_CNTL);
+       seq_printf(m, "BUS_CNTL 0x%08x\n", tmp);
+       tmp = RREG32_MC(RS690_AIC_CTRL_SCRATCH);
+       seq_printf(m, "AIC_CTRL_SCRATCH 0x%08x\n", tmp);
+       if (rdev->family == CHIP_RS690 || (rdev->family == CHIP_RS740)) {
+               tmp = RREG32_MC(RS690_MCCFG_AGP_BASE);
+               seq_printf(m, "MCCFG_AGP_BASE 0x%08x\n", tmp);
+               tmp = RREG32_MC(RS690_MCCFG_AGP_BASE_2);
+               seq_printf(m, "MCCFG_AGP_BASE_2 0x%08x\n", tmp);
+               tmp = RREG32_MC(RS690_MCCFG_AGP_LOCATION);
+               seq_printf(m, "MCCFG_AGP_LOCATION 0x%08x\n", tmp);
+               tmp = RREG32_MC(0x100);
+               seq_printf(m, "MCCFG_FB_LOCATION 0x%08x\n", tmp);
+               tmp = RREG32(0x134);
+               seq_printf(m, "HDP_FB_LOCATION 0x%08x\n", tmp);
+       } else {
+               tmp = RREG32(RADEON_AGP_BASE);
+               seq_printf(m, "AGP_BASE 0x%08x\n", tmp);
+               tmp = RREG32(RS480_AGP_BASE_2);
+               seq_printf(m, "AGP_BASE_2 0x%08x\n", tmp);
+               tmp = RREG32(RADEON_MC_AGP_LOCATION);
+               seq_printf(m, "MC_AGP_LOCATION 0x%08x\n", tmp);
+       }
+       tmp = RREG32_MC(RS480_GART_BASE);
+       seq_printf(m, "GART_BASE 0x%08x\n", tmp);
+       tmp = RREG32_MC(RS480_GART_FEATURE_ID);
+       seq_printf(m, "GART_FEATURE_ID 0x%08x\n", tmp);
+       tmp = RREG32_MC(RS480_AGP_MODE_CNTL);
+       seq_printf(m, "AGP_MODE_CONTROL 0x%08x\n", tmp);
+       tmp = RREG32_MC(RS480_MC_MISC_CNTL);
+       seq_printf(m, "MC_MISC_CNTL 0x%08x\n", tmp);
+       tmp = RREG32_MC(0x5F);
+       seq_printf(m, "MC_MISC_UMA_CNTL 0x%08x\n", tmp);
+       tmp = RREG32_MC(RS480_AGP_ADDRESS_SPACE_SIZE);
+       seq_printf(m, "AGP_ADDRESS_SPACE_SIZE 0x%08x\n", tmp);
+       tmp = RREG32_MC(RS480_GART_CACHE_CNTRL);
+       seq_printf(m, "GART_CACHE_CNTRL 0x%08x\n", tmp);
+       tmp = RREG32_MC(0x3B);
+       seq_printf(m, "MC_GART_ERROR_ADDRESS 0x%08x\n", tmp);
+       tmp = RREG32_MC(0x3C);
+       seq_printf(m, "MC_GART_ERROR_ADDRESS_HI 0x%08x\n", tmp);
+       tmp = RREG32_MC(0x30);
+       seq_printf(m, "GART_ERROR_0 0x%08x\n", tmp);
+       tmp = RREG32_MC(0x31);
+       seq_printf(m, "GART_ERROR_1 0x%08x\n", tmp);
+       tmp = RREG32_MC(0x32);
+       seq_printf(m, "GART_ERROR_2 0x%08x\n", tmp);
+       tmp = RREG32_MC(0x33);
+       seq_printf(m, "GART_ERROR_3 0x%08x\n", tmp);
+       tmp = RREG32_MC(0x34);
+       seq_printf(m, "GART_ERROR_4 0x%08x\n", tmp);
+       tmp = RREG32_MC(0x35);
+       seq_printf(m, "GART_ERROR_5 0x%08x\n", tmp);
+       tmp = RREG32_MC(0x36);
+       seq_printf(m, "GART_ERROR_6 0x%08x\n", tmp);
+       tmp = RREG32_MC(0x37);
+       seq_printf(m, "GART_ERROR_7 0x%08x\n", tmp);
+       return 0;
+}
+
+static struct drm_info_list rs400_gart_info_list[] = {
+       {"rs400_gart_info", rs400_debugfs_gart_info, 0, NULL},
+};
+#endif
+
+int rs400_debugfs_pcie_gart_info_init(struct radeon_device *rdev)
+{
+#if defined(CONFIG_DEBUG_FS)
+       return radeon_debugfs_add_files(rdev, rs400_gart_info_list, 1);
+#else
+       return 0;
+#endif
+}
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
new file mode 100644 (file)
index 0000000..ab0c967
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ *          Jerome Glisse
+ */
+#include "drmP.h"
+#include "radeon_reg.h"
+#include "radeon.h"
+
+/* rs600 depends on : */
+void r100_hdp_reset(struct radeon_device *rdev);
+int r100_gui_wait_for_idle(struct radeon_device *rdev);
+int r300_mc_wait_for_idle(struct radeon_device *rdev);
+void r420_pipes_init(struct radeon_device *rdev);
+
+/* This files gather functions specifics to :
+ * rs600
+ *
+ * Some of these functions might be used by newer ASICs.
+ */
+void rs600_gpu_init(struct radeon_device *rdev);
+int rs600_mc_wait_for_idle(struct radeon_device *rdev);
+void rs600_disable_vga(struct radeon_device *rdev);
+
+
+/*
+ * GART.
+ */
+void rs600_gart_tlb_flush(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+
+       tmp = RREG32_MC(RS600_MC_PT0_CNTL);
+       tmp &= ~(RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE);
+       WREG32_MC(RS600_MC_PT0_CNTL, tmp);
+
+       tmp = RREG32_MC(RS600_MC_PT0_CNTL);
+       tmp |= RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE;
+       WREG32_MC(RS600_MC_PT0_CNTL, tmp);
+
+       tmp = RREG32_MC(RS600_MC_PT0_CNTL);
+       tmp &= ~(RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE);
+       WREG32_MC(RS600_MC_PT0_CNTL, tmp);
+       tmp = RREG32_MC(RS600_MC_PT0_CNTL);
+}
+
+int rs600_gart_enable(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+       int i;
+       int r;
+
+       /* Initialize common gart structure */
+       r = radeon_gart_init(rdev);
+       if (r) {
+               return r;
+       }
+       rdev->gart.table_size = rdev->gart.num_gpu_pages * 8;
+       r = radeon_gart_table_vram_alloc(rdev);
+       if (r) {
+               return r;
+       }
+       /* FIXME: setup default page */
+       WREG32_MC(RS600_MC_PT0_CNTL,
+                (RS600_EFFECTIVE_L2_CACHE_SIZE(6) |
+                 RS600_EFFECTIVE_L2_QUEUE_SIZE(6)));
+       for (i = 0; i < 19; i++) {
+               WREG32_MC(RS600_MC_PT0_CLIENT0_CNTL + i,
+                        (RS600_ENABLE_TRANSLATION_MODE_OVERRIDE |
+                         RS600_SYSTEM_ACCESS_MODE_IN_SYS |
+                         RS600_SYSTEM_APERTURE_UNMAPPED_ACCESS_DEFAULT_PAGE |
+                         RS600_EFFECTIVE_L1_CACHE_SIZE(3) |
+                         RS600_ENABLE_FRAGMENT_PROCESSING |
+                         RS600_EFFECTIVE_L1_QUEUE_SIZE(3)));
+       }
+
+       /* System context map to GART space */
+       WREG32_MC(RS600_MC_PT0_SYSTEM_APERTURE_LOW_ADDR, rdev->mc.gtt_location);
+       tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1;
+       WREG32_MC(RS600_MC_PT0_SYSTEM_APERTURE_HIGH_ADDR, tmp);
+
+       /* enable first context */
+       WREG32_MC(RS600_MC_PT0_CONTEXT0_FLAT_START_ADDR, rdev->mc.gtt_location);
+       tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1;
+       WREG32_MC(RS600_MC_PT0_CONTEXT0_FLAT_END_ADDR, tmp);
+       WREG32_MC(RS600_MC_PT0_CONTEXT0_CNTL,
+                (RS600_ENABLE_PAGE_TABLE | RS600_PAGE_TABLE_TYPE_FLAT));
+       /* disable all other contexts */
+       for (i = 1; i < 8; i++) {
+               WREG32_MC(RS600_MC_PT0_CONTEXT0_CNTL + i, 0);
+       }
+
+       /* setup the page table */
+       WREG32_MC(RS600_MC_PT0_CONTEXT0_FLAT_BASE_ADDR,
+                rdev->gart.table_addr);
+       WREG32_MC(RS600_MC_PT0_CONTEXT0_DEFAULT_READ_ADDR, 0);
+
+       /* enable page tables */
+       tmp = RREG32_MC(RS600_MC_PT0_CNTL);
+       WREG32_MC(RS600_MC_PT0_CNTL, (tmp | RS600_ENABLE_PT));
+       tmp = RREG32_MC(RS600_MC_CNTL1);
+       WREG32_MC(RS600_MC_CNTL1, (tmp | RS600_ENABLE_PAGE_TABLES));
+       rs600_gart_tlb_flush(rdev);
+       rdev->gart.ready = true;
+       return 0;
+}
+
+void rs600_gart_disable(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+
+       /* FIXME: disable out of gart access */
+       WREG32_MC(RS600_MC_PT0_CNTL, 0);
+       tmp = RREG32_MC(RS600_MC_CNTL1);
+       tmp &= ~RS600_ENABLE_PAGE_TABLES;
+       WREG32_MC(RS600_MC_CNTL1, tmp);
+       radeon_object_kunmap(rdev->gart.table.vram.robj);
+       radeon_object_unpin(rdev->gart.table.vram.robj);
+}
+
+#define R600_PTE_VALID     (1 << 0)
+#define R600_PTE_SYSTEM    (1 << 1)
+#define R600_PTE_SNOOPED   (1 << 2)
+#define R600_PTE_READABLE  (1 << 5)
+#define R600_PTE_WRITEABLE (1 << 6)
+
+int rs600_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)
+{
+       void __iomem *ptr = (void *)rdev->gart.table.vram.ptr;
+
+       if (i < 0 || i > rdev->gart.num_gpu_pages) {
+               return -EINVAL;
+       }
+       addr = addr & 0xFFFFFFFFFFFFF000ULL;
+       addr |= R600_PTE_VALID | R600_PTE_SYSTEM | R600_PTE_SNOOPED;
+       addr |= R600_PTE_READABLE | R600_PTE_WRITEABLE;
+       writeq(addr, ((void __iomem *)ptr) + (i * 8));
+       return 0;
+}
+
+
+/*
+ * MC.
+ */
+void rs600_mc_disable_clients(struct radeon_device *rdev)
+{
+       unsigned tmp;
+
+       if (r100_gui_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait GUI idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+
+       tmp = RREG32(AVIVO_D1VGA_CONTROL);
+       WREG32(AVIVO_D1VGA_CONTROL, tmp & ~AVIVO_DVGA_CONTROL_MODE_ENABLE);
+       tmp = RREG32(AVIVO_D2VGA_CONTROL);
+       WREG32(AVIVO_D2VGA_CONTROL, tmp & ~AVIVO_DVGA_CONTROL_MODE_ENABLE);
+
+       tmp = RREG32(AVIVO_D1CRTC_CONTROL);
+       WREG32(AVIVO_D1CRTC_CONTROL, tmp & ~AVIVO_CRTC_EN);
+       tmp = RREG32(AVIVO_D2CRTC_CONTROL);
+       WREG32(AVIVO_D2CRTC_CONTROL, tmp & ~AVIVO_CRTC_EN);
+
+       /* make sure all previous write got through */
+       tmp = RREG32(AVIVO_D2CRTC_CONTROL);
+
+       mdelay(1);
+}
+
+int rs600_mc_init(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+       int r;
+
+       if (r100_debugfs_rbbm_init(rdev)) {
+               DRM_ERROR("Failed to register debugfs file for RBBM !\n");
+       }
+
+       rs600_gpu_init(rdev);
+       rs600_gart_disable(rdev);
+
+       /* Setup GPU memory space */
+       rdev->mc.vram_location = 0xFFFFFFFFUL;
+       rdev->mc.gtt_location = 0xFFFFFFFFUL;
+       r = radeon_mc_setup(rdev);
+       if (r) {
+               return r;
+       }
+
+       /* Program GPU memory space */
+       /* Enable bus master */
+       tmp = RREG32(RADEON_BUS_CNTL) & ~RS600_BUS_MASTER_DIS;
+       WREG32(RADEON_BUS_CNTL, tmp);
+       /* FIXME: What does AGP means for such chipset ? */
+       WREG32_MC(RS600_MC_AGP_LOCATION, 0x0FFFFFFF);
+       /* FIXME: are this AGP reg in indirect MC range ? */
+       WREG32_MC(RS600_MC_AGP_BASE, 0);
+       WREG32_MC(RS600_MC_AGP_BASE_2, 0);
+       rs600_mc_disable_clients(rdev);
+       if (rs600_mc_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait MC idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+       tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1;
+       tmp = REG_SET(RS600_MC_FB_TOP, tmp >> 16);
+       tmp |= REG_SET(RS600_MC_FB_START, rdev->mc.vram_location >> 16);
+       WREG32_MC(RS600_MC_FB_LOCATION, tmp);
+       WREG32(RS690_HDP_FB_LOCATION, rdev->mc.vram_location >> 16);
+       return 0;
+}
+
+void rs600_mc_fini(struct radeon_device *rdev)
+{
+       rs600_gart_disable(rdev);
+       radeon_gart_table_vram_free(rdev);
+       radeon_gart_fini(rdev);
+}
+
+
+/*
+ * Global GPU functions
+ */
+void rs600_disable_vga(struct radeon_device *rdev)
+{
+       unsigned tmp;
+
+       WREG32(0x330, 0);
+       WREG32(0x338, 0);
+       tmp = RREG32(0x300);
+       tmp &= ~(3 << 16);
+       WREG32(0x300, tmp);
+       WREG32(0x308, (1 << 8));
+       WREG32(0x310, rdev->mc.vram_location);
+       WREG32(0x594, 0);
+}
+
+int rs600_mc_wait_for_idle(struct radeon_device *rdev)
+{
+       unsigned i;
+       uint32_t tmp;
+
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               /* read MC_STATUS */
+               tmp = RREG32_MC(RS600_MC_STATUS);
+               if (tmp & RS600_MC_STATUS_IDLE) {
+                       return 0;
+               }
+               DRM_UDELAY(1);
+       }
+       return -1;
+}
+
+void rs600_errata(struct radeon_device *rdev)
+{
+       rdev->pll_errata = 0;
+}
+
+void rs600_gpu_init(struct radeon_device *rdev)
+{
+       /* FIXME: HDP same place on rs600 ? */
+       r100_hdp_reset(rdev);
+       rs600_disable_vga(rdev);
+       /* FIXME: is this correct ? */
+       r420_pipes_init(rdev);
+       if (rs600_mc_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait MC idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+}
+
+
+/*
+ * VRAM info.
+ */
+void rs600_vram_info(struct radeon_device *rdev)
+{
+       /* FIXME: to do or is these values sane ? */
+       rdev->mc.vram_is_ddr = true;
+       rdev->mc.vram_width = 128;
+}
+
+
+/*
+ * Indirect registers accessor
+ */
+uint32_t rs600_mc_rreg(struct radeon_device *rdev, uint32_t reg)
+{
+       uint32_t r;
+
+       WREG32(RS600_MC_INDEX,
+              ((reg & RS600_MC_ADDR_MASK) | RS600_MC_IND_CITF_ARB0));
+       r = RREG32(RS600_MC_DATA);
+       return r;
+}
+
+void rs600_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
+{
+       WREG32(RS600_MC_INDEX,
+               RS600_MC_IND_WR_EN | RS600_MC_IND_CITF_ARB0 |
+               ((reg) & RS600_MC_ADDR_MASK));
+       WREG32(RS600_MC_DATA, v);
+}
diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c
new file mode 100644 (file)
index 0000000..79ba850
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ *          Jerome Glisse
+ */
+#include "drmP.h"
+#include "radeon_reg.h"
+#include "radeon.h"
+
+/* rs690,rs740 depends on : */
+void r100_hdp_reset(struct radeon_device *rdev);
+int r300_mc_wait_for_idle(struct radeon_device *rdev);
+void r420_pipes_init(struct radeon_device *rdev);
+void rs400_gart_disable(struct radeon_device *rdev);
+int rs400_gart_enable(struct radeon_device *rdev);
+void rs400_gart_adjust_size(struct radeon_device *rdev);
+void rs600_mc_disable_clients(struct radeon_device *rdev);
+void rs600_disable_vga(struct radeon_device *rdev);
+
+/* This files gather functions specifics to :
+ * rs690,rs740
+ *
+ * Some of these functions might be used by newer ASICs.
+ */
+void rs690_gpu_init(struct radeon_device *rdev);
+int rs690_mc_wait_for_idle(struct radeon_device *rdev);
+
+
+/*
+ * MC functions.
+ */
+int rs690_mc_init(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+       int r;
+
+       if (r100_debugfs_rbbm_init(rdev)) {
+               DRM_ERROR("Failed to register debugfs file for RBBM !\n");
+       }
+
+       rs690_gpu_init(rdev);
+       rs400_gart_disable(rdev);
+
+       /* Setup GPU memory space */
+       rdev->mc.gtt_location = rdev->mc.vram_size;
+       rdev->mc.gtt_location += (rdev->mc.gtt_size - 1);
+       rdev->mc.gtt_location &= ~(rdev->mc.gtt_size - 1);
+       rdev->mc.vram_location = 0xFFFFFFFFUL;
+       r = radeon_mc_setup(rdev);
+       if (r) {
+               return r;
+       }
+
+       /* Program GPU memory space */
+       rs600_mc_disable_clients(rdev);
+       if (rs690_mc_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait MC idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+       tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1;
+       tmp = REG_SET(RS690_MC_FB_TOP, tmp >> 16);
+       tmp |= REG_SET(RS690_MC_FB_START, rdev->mc.vram_location >> 16);
+       WREG32_MC(RS690_MCCFG_FB_LOCATION, tmp);
+       /* FIXME: Does this reg exist on RS480,RS740 ? */
+       WREG32(0x310, rdev->mc.vram_location);
+       WREG32(RS690_HDP_FB_LOCATION, rdev->mc.vram_location >> 16);
+       return 0;
+}
+
+void rs690_mc_fini(struct radeon_device *rdev)
+{
+       rs400_gart_disable(rdev);
+       radeon_gart_table_ram_free(rdev);
+       radeon_gart_fini(rdev);
+}
+
+
+/*
+ * Global GPU functions
+ */
+int rs690_mc_wait_for_idle(struct radeon_device *rdev)
+{
+       unsigned i;
+       uint32_t tmp;
+
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               /* read MC_STATUS */
+               tmp = RREG32_MC(RS690_MC_STATUS);
+               if (tmp & RS690_MC_STATUS_IDLE) {
+                       return 0;
+               }
+               DRM_UDELAY(1);
+       }
+       return -1;
+}
+
+void rs690_errata(struct radeon_device *rdev)
+{
+       rdev->pll_errata = 0;
+}
+
+void rs690_gpu_init(struct radeon_device *rdev)
+{
+       /* FIXME: HDP same place on rs690 ? */
+       r100_hdp_reset(rdev);
+       rs600_disable_vga(rdev);
+       /* FIXME: is this correct ? */
+       r420_pipes_init(rdev);
+       if (rs690_mc_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait MC idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+}
+
+
+/*
+ * VRAM info.
+ */
+void rs690_vram_info(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+
+       rs400_gart_adjust_size(rdev);
+       /* DDR for all card after R300 & IGP */
+       rdev->mc.vram_is_ddr = true;
+       /* FIXME: is this correct for RS690/RS740 ? */
+       tmp = RREG32(RADEON_MEM_CNTL);
+       if (tmp & R300_MEM_NUM_CHANNELS_MASK) {
+               rdev->mc.vram_width = 128;
+       } else {
+               rdev->mc.vram_width = 64;
+       }
+       rdev->mc.vram_size = RREG32(RADEON_CONFIG_MEMSIZE);
+
+       rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
+       rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
+}
+
+
+/*
+ * Indirect registers accessor
+ */
+uint32_t rs690_mc_rreg(struct radeon_device *rdev, uint32_t reg)
+{
+       uint32_t r;
+
+       WREG32(RS690_MC_INDEX, (reg & RS690_MC_INDEX_MASK));
+       r = RREG32(RS690_MC_DATA);
+       WREG32(RS690_MC_INDEX, RS690_MC_INDEX_MASK);
+       return r;
+}
+
+void rs690_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
+{
+       WREG32(RS690_MC_INDEX,
+              RS690_MC_INDEX_WR_EN | ((reg) & RS690_MC_INDEX_MASK));
+       WREG32(RS690_MC_DATA, v);
+       WREG32(RS690_MC_INDEX, RS690_MC_INDEX_WR_ACK);
+}
diff --git a/drivers/gpu/drm/radeon/rs780.c b/drivers/gpu/drm/radeon/rs780.c
new file mode 100644 (file)
index 0000000..0affcff
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ *          Jerome Glisse
+ */
+#include "drmP.h"
+#include "radeon_reg.h"
+#include "radeon.h"
+
+/* rs780  depends on : */
+void rs600_mc_disable_clients(struct radeon_device *rdev);
+
+/* This files gather functions specifics to:
+ * rs780
+ *
+ * Some of these functions might be used by newer ASICs.
+ */
+int rs780_mc_wait_for_idle(struct radeon_device *rdev);
+void rs780_gpu_init(struct radeon_device *rdev);
+
+
+/*
+ * MC
+ */
+int rs780_mc_init(struct radeon_device *rdev)
+{
+       rs780_gpu_init(rdev);
+       /* FIXME: implement */
+
+       rs600_mc_disable_clients(rdev);
+       if (rs780_mc_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait MC idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+       return 0;
+}
+
+void rs780_mc_fini(struct radeon_device *rdev)
+{
+       /* FIXME: implement */
+}
+
+
+/*
+ * Global GPU functions
+ */
+void rs780_errata(struct radeon_device *rdev)
+{
+       rdev->pll_errata = 0;
+}
+
+int rs780_mc_wait_for_idle(struct radeon_device *rdev)
+{
+       /* FIXME: implement */
+       return 0;
+}
+
+void rs780_gpu_init(struct radeon_device *rdev)
+{
+       /* FIXME: implement */
+}
+
+
+/*
+ * VRAM info
+ */
+void rs780_vram_get_type(struct radeon_device *rdev)
+{
+       /* FIXME: implement */
+}
+
+void rs780_vram_info(struct radeon_device *rdev)
+{
+       rs780_vram_get_type(rdev);
+
+       /* FIXME: implement */
+       /* Could aper size report 0 ? */
+       rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
+       rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
+}
diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c
new file mode 100644 (file)
index 0000000..7eab95d
--- /dev/null
@@ -0,0 +1,504 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ *          Jerome Glisse
+ */
+#include <linux/seq_file.h>
+#include "drmP.h"
+#include "radeon_reg.h"
+#include "radeon.h"
+
+/* rv515 depends on : */
+void r100_hdp_reset(struct radeon_device *rdev);
+int r100_cp_reset(struct radeon_device *rdev);
+int r100_rb2d_reset(struct radeon_device *rdev);
+int r100_gui_wait_for_idle(struct radeon_device *rdev);
+int r100_cp_init(struct radeon_device *rdev, unsigned ring_size);
+int rv370_pcie_gart_enable(struct radeon_device *rdev);
+void rv370_pcie_gart_disable(struct radeon_device *rdev);
+void r420_pipes_init(struct radeon_device *rdev);
+void rs600_mc_disable_clients(struct radeon_device *rdev);
+void rs600_disable_vga(struct radeon_device *rdev);
+
+/* This files gather functions specifics to:
+ * rv515
+ *
+ * Some of these functions might be used by newer ASICs.
+ */
+int rv515_debugfs_pipes_info_init(struct radeon_device *rdev);
+int rv515_debugfs_ga_info_init(struct radeon_device *rdev);
+void rv515_gpu_init(struct radeon_device *rdev);
+int rv515_mc_wait_for_idle(struct radeon_device *rdev);
+
+
+/*
+ * MC
+ */
+int rv515_mc_init(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+       int r;
+
+       if (r100_debugfs_rbbm_init(rdev)) {
+               DRM_ERROR("Failed to register debugfs file for RBBM !\n");
+       }
+       if (rv515_debugfs_pipes_info_init(rdev)) {
+               DRM_ERROR("Failed to register debugfs file for pipes !\n");
+       }
+       if (rv515_debugfs_ga_info_init(rdev)) {
+               DRM_ERROR("Failed to register debugfs file for pipes !\n");
+       }
+
+       rv515_gpu_init(rdev);
+       rv370_pcie_gart_disable(rdev);
+
+       /* Setup GPU memory space */
+       rdev->mc.vram_location = 0xFFFFFFFFUL;
+       rdev->mc.gtt_location = 0xFFFFFFFFUL;
+       if (rdev->flags & RADEON_IS_AGP) {
+               r = radeon_agp_init(rdev);
+               if (r) {
+                       printk(KERN_WARNING "[drm] Disabling AGP\n");
+                       rdev->flags &= ~RADEON_IS_AGP;
+                       rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024;
+               } else {
+                       rdev->mc.gtt_location = rdev->mc.agp_base;
+               }
+       }
+       r = radeon_mc_setup(rdev);
+       if (r) {
+               return r;
+       }
+
+       /* Program GPU memory space */
+       rs600_mc_disable_clients(rdev);
+       if (rv515_mc_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait MC idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+       /* Write VRAM size in case we are limiting it */
+       WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size);
+       tmp = REG_SET(RV515_MC_FB_START, rdev->mc.vram_location >> 16);
+       WREG32(0x134, tmp);
+       tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1;
+       tmp = REG_SET(RV515_MC_FB_TOP, tmp >> 16);
+       tmp |= REG_SET(RV515_MC_FB_START, rdev->mc.vram_location >> 16);
+       WREG32_MC(RV515_MC_FB_LOCATION, tmp);
+       WREG32(RS690_HDP_FB_LOCATION, rdev->mc.vram_location >> 16);
+       WREG32(0x310, rdev->mc.vram_location);
+       if (rdev->flags & RADEON_IS_AGP) {
+               tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1;
+               tmp = REG_SET(RV515_MC_AGP_TOP, tmp >> 16);
+               tmp |= REG_SET(RV515_MC_AGP_START, rdev->mc.gtt_location >> 16);
+               WREG32_MC(RV515_MC_AGP_LOCATION, tmp);
+               WREG32_MC(RV515_MC_AGP_BASE, rdev->mc.agp_base);
+               WREG32_MC(RV515_MC_AGP_BASE_2, 0);
+       } else {
+               WREG32_MC(RV515_MC_AGP_LOCATION, 0x0FFFFFFF);
+               WREG32_MC(RV515_MC_AGP_BASE, 0);
+               WREG32_MC(RV515_MC_AGP_BASE_2, 0);
+       }
+       return 0;
+}
+
+void rv515_mc_fini(struct radeon_device *rdev)
+{
+       rv370_pcie_gart_disable(rdev);
+       radeon_gart_table_vram_free(rdev);
+       radeon_gart_fini(rdev);
+}
+
+
+/*
+ * Global GPU functions
+ */
+void rv515_ring_start(struct radeon_device *rdev)
+{
+       unsigned gb_tile_config;
+       int r;
+
+       /* Sub pixel 1/12 so we can have 4K rendering according to doc */
+       gb_tile_config = R300_ENABLE_TILING | R300_TILE_SIZE_16;
+       switch (rdev->num_gb_pipes) {
+       case 2:
+               gb_tile_config |= R300_PIPE_COUNT_R300;
+               break;
+       case 3:
+               gb_tile_config |= R300_PIPE_COUNT_R420_3P;
+               break;
+       case 4:
+               gb_tile_config |= R300_PIPE_COUNT_R420;
+               break;
+       case 1:
+       default:
+               gb_tile_config |= R300_PIPE_COUNT_RV350;
+               break;
+       }
+
+       r = radeon_ring_lock(rdev, 64);
+       if (r) {
+               return;
+       }
+       radeon_ring_write(rdev, PACKET0(RADEON_ISYNC_CNTL, 0));
+       radeon_ring_write(rdev,
+                         RADEON_ISYNC_ANY2D_IDLE3D |
+                         RADEON_ISYNC_ANY3D_IDLE2D |
+                         RADEON_ISYNC_WAIT_IDLEGUI |
+                         RADEON_ISYNC_CPSCRATCH_IDLEGUI);
+       radeon_ring_write(rdev, PACKET0(R300_GB_TILE_CONFIG, 0));
+       radeon_ring_write(rdev, gb_tile_config);
+       radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0));
+       radeon_ring_write(rdev,
+                         RADEON_WAIT_2D_IDLECLEAN |
+                         RADEON_WAIT_3D_IDLECLEAN);
+       radeon_ring_write(rdev, PACKET0(0x170C, 0));
+       radeon_ring_write(rdev, 1 << 31);
+       radeon_ring_write(rdev, PACKET0(R300_GB_SELECT, 0));
+       radeon_ring_write(rdev, 0);
+       radeon_ring_write(rdev, PACKET0(R300_GB_ENABLE, 0));
+       radeon_ring_write(rdev, 0);
+       radeon_ring_write(rdev, PACKET0(0x42C8, 0));
+       radeon_ring_write(rdev, (1 << rdev->num_gb_pipes) - 1);
+       radeon_ring_write(rdev, PACKET0(R500_VAP_INDEX_OFFSET, 0));
+       radeon_ring_write(rdev, 0);
+       radeon_ring_write(rdev, PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0));
+       radeon_ring_write(rdev, R300_RB3D_DC_FLUSH | R300_RB3D_DC_FREE);
+       radeon_ring_write(rdev, PACKET0(R300_RB3D_ZCACHE_CTLSTAT, 0));
+       radeon_ring_write(rdev, R300_ZC_FLUSH | R300_ZC_FREE);
+       radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0));
+       radeon_ring_write(rdev,
+                         RADEON_WAIT_2D_IDLECLEAN |
+                         RADEON_WAIT_3D_IDLECLEAN);
+       radeon_ring_write(rdev, PACKET0(R300_GB_AA_CONFIG, 0));
+       radeon_ring_write(rdev, 0);
+       radeon_ring_write(rdev, PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0));
+       radeon_ring_write(rdev, R300_RB3D_DC_FLUSH | R300_RB3D_DC_FREE);
+       radeon_ring_write(rdev, PACKET0(R300_RB3D_ZCACHE_CTLSTAT, 0));
+       radeon_ring_write(rdev, R300_ZC_FLUSH | R300_ZC_FREE);
+       radeon_ring_write(rdev, PACKET0(R300_GB_MSPOS0, 0));
+       radeon_ring_write(rdev,
+                         ((6 << R300_MS_X0_SHIFT) |
+                          (6 << R300_MS_Y0_SHIFT) |
+                          (6 << R300_MS_X1_SHIFT) |
+                          (6 << R300_MS_Y1_SHIFT) |
+                          (6 << R300_MS_X2_SHIFT) |
+                          (6 << R300_MS_Y2_SHIFT) |
+                          (6 << R300_MSBD0_Y_SHIFT) |
+                          (6 << R300_MSBD0_X_SHIFT)));
+       radeon_ring_write(rdev, PACKET0(R300_GB_MSPOS1, 0));
+       radeon_ring_write(rdev,
+                         ((6 << R300_MS_X3_SHIFT) |
+                          (6 << R300_MS_Y3_SHIFT) |
+                          (6 << R300_MS_X4_SHIFT) |
+                          (6 << R300_MS_Y4_SHIFT) |
+                          (6 << R300_MS_X5_SHIFT) |
+                          (6 << R300_MS_Y5_SHIFT) |
+                          (6 << R300_MSBD1_SHIFT)));
+       radeon_ring_write(rdev, PACKET0(R300_GA_ENHANCE, 0));
+       radeon_ring_write(rdev, R300_GA_DEADLOCK_CNTL | R300_GA_FASTSYNC_CNTL);
+       radeon_ring_write(rdev, PACKET0(R300_GA_POLY_MODE, 0));
+       radeon_ring_write(rdev,
+                         R300_FRONT_PTYPE_TRIANGE | R300_BACK_PTYPE_TRIANGE);
+       radeon_ring_write(rdev, PACKET0(R300_GA_ROUND_MODE, 0));
+       radeon_ring_write(rdev,
+                         R300_GEOMETRY_ROUND_NEAREST |
+                         R300_COLOR_ROUND_NEAREST);
+       radeon_ring_unlock_commit(rdev);
+}
+
+void rv515_errata(struct radeon_device *rdev)
+{
+       rdev->pll_errata = 0;
+}
+
+int rv515_mc_wait_for_idle(struct radeon_device *rdev)
+{
+       unsigned i;
+       uint32_t tmp;
+
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               /* read MC_STATUS */
+               tmp = RREG32_MC(RV515_MC_STATUS);
+               if (tmp & RV515_MC_STATUS_IDLE) {
+                       return 0;
+               }
+               DRM_UDELAY(1);
+       }
+       return -1;
+}
+
+void rv515_gpu_init(struct radeon_device *rdev)
+{
+       unsigned pipe_select_current, gb_pipe_select, tmp;
+
+       r100_hdp_reset(rdev);
+       r100_rb2d_reset(rdev);
+
+       if (r100_gui_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait GUI idle while "
+                      "reseting GPU. Bad things might happen.\n");
+       }
+
+       rs600_disable_vga(rdev);
+
+       r420_pipes_init(rdev);
+       gb_pipe_select = RREG32(0x402C);
+       tmp = RREG32(0x170C);
+       pipe_select_current = (tmp >> 2) & 3;
+       tmp = (1 << pipe_select_current) |
+             (((gb_pipe_select >> 8) & 0xF) << 4);
+       WREG32_PLL(0x000D, tmp);
+       if (r100_gui_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait GUI idle while "
+                      "reseting GPU. Bad things might happen.\n");
+       }
+       if (rv515_mc_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait MC idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+}
+
+int rv515_ga_reset(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+       bool reinit_cp;
+       int i;
+
+       reinit_cp = rdev->cp.ready;
+       rdev->cp.ready = false;
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               WREG32(RADEON_CP_CSQ_MODE, 0);
+               WREG32(RADEON_CP_CSQ_CNTL, 0);
+               WREG32(RADEON_RBBM_SOFT_RESET, 0x32005);
+               (void)RREG32(RADEON_RBBM_SOFT_RESET);
+               udelay(200);
+               WREG32(RADEON_RBBM_SOFT_RESET, 0);
+               /* Wait to prevent race in RBBM_STATUS */
+               mdelay(1);
+               tmp = RREG32(RADEON_RBBM_STATUS);
+               if (tmp & ((1 << 20) | (1 << 26))) {
+                       DRM_ERROR("VAP & CP still busy (RBBM_STATUS=0x%08X)\n", tmp);
+                       /* GA still busy soft reset it */
+                       WREG32(0x429C, 0x200);
+                       WREG32(R300_VAP_PVS_STATE_FLUSH_REG, 0);
+                       WREG32(0x43E0, 0);
+                       WREG32(0x43E4, 0);
+                       WREG32(0x24AC, 0);
+               }
+               /* Wait to prevent race in RBBM_STATUS */
+               mdelay(1);
+               tmp = RREG32(RADEON_RBBM_STATUS);
+               if (!(tmp & ((1 << 20) | (1 << 26)))) {
+                       break;
+               }
+       }
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               tmp = RREG32(RADEON_RBBM_STATUS);
+               if (!(tmp & ((1 << 20) | (1 << 26)))) {
+                       DRM_INFO("GA reset succeed (RBBM_STATUS=0x%08X)\n",
+                                tmp);
+                       DRM_INFO("GA_IDLE=0x%08X\n", RREG32(0x425C));
+                       DRM_INFO("RB3D_RESET_STATUS=0x%08X\n", RREG32(0x46f0));
+                       DRM_INFO("ISYNC_CNTL=0x%08X\n", RREG32(0x1724));
+                       if (reinit_cp) {
+                               return r100_cp_init(rdev, rdev->cp.ring_size);
+                       }
+                       return 0;
+               }
+               DRM_UDELAY(1);
+       }
+       tmp = RREG32(RADEON_RBBM_STATUS);
+       DRM_ERROR("Failed to reset GA ! (RBBM_STATUS=0x%08X)\n", tmp);
+       return -1;
+}
+
+int rv515_gpu_reset(struct radeon_device *rdev)
+{
+       uint32_t status;
+
+       /* reset order likely matter */
+       status = RREG32(RADEON_RBBM_STATUS);
+       /* reset HDP */
+       r100_hdp_reset(rdev);
+       /* reset rb2d */
+       if (status & ((1 << 17) | (1 << 18) | (1 << 27))) {
+               r100_rb2d_reset(rdev);
+       }
+       /* reset GA */
+       if (status & ((1 << 20) | (1 << 26))) {
+               rv515_ga_reset(rdev);
+       }
+       /* reset CP */
+       status = RREG32(RADEON_RBBM_STATUS);
+       if (status & (1 << 16)) {
+               r100_cp_reset(rdev);
+       }
+       /* Check if GPU is idle */
+       status = RREG32(RADEON_RBBM_STATUS);
+       if (status & (1 << 31)) {
+               DRM_ERROR("Failed to reset GPU (RBBM_STATUS=0x%08X)\n", status);
+               return -1;
+       }
+       DRM_INFO("GPU reset succeed (RBBM_STATUS=0x%08X)\n", status);
+       return 0;
+}
+
+
+/*
+ * VRAM info
+ */
+static void rv515_vram_get_type(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+
+       rdev->mc.vram_width = 128;
+       rdev->mc.vram_is_ddr = true;
+       tmp = RREG32_MC(RV515_MC_CNTL);
+       tmp &= RV515_MEM_NUM_CHANNELS_MASK;
+       switch (tmp) {
+       case 0:
+               rdev->mc.vram_width = 64;
+               break;
+       case 1:
+               rdev->mc.vram_width = 128;
+               break;
+       default:
+               rdev->mc.vram_width = 128;
+               break;
+       }
+}
+
+void rv515_vram_info(struct radeon_device *rdev)
+{
+       rv515_vram_get_type(rdev);
+       rdev->mc.vram_size = RREG32(RADEON_CONFIG_MEMSIZE);
+
+       rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
+       rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
+}
+
+
+/*
+ * Indirect registers accessor
+ */
+uint32_t rv515_mc_rreg(struct radeon_device *rdev, uint32_t reg)
+{
+       uint32_t r;
+
+       WREG32(R520_MC_IND_INDEX, 0x7f0000 | (reg & 0xffff));
+       r = RREG32(R520_MC_IND_DATA);
+       WREG32(R520_MC_IND_INDEX, 0);
+       return r;
+}
+
+void rv515_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
+{
+       WREG32(R520_MC_IND_INDEX, 0xff0000 | ((reg) & 0xffff));
+       WREG32(R520_MC_IND_DATA, (v));
+       WREG32(R520_MC_IND_INDEX, 0);
+}
+
+uint32_t rv515_pcie_rreg(struct radeon_device *rdev, uint32_t reg)
+{
+       uint32_t r;
+
+       WREG32(RADEON_PCIE_INDEX, ((reg) & 0x7ff));
+       (void)RREG32(RADEON_PCIE_INDEX);
+       r = RREG32(RADEON_PCIE_DATA);
+       return r;
+}
+
+void rv515_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
+{
+       WREG32(RADEON_PCIE_INDEX, ((reg) & 0x7ff));
+       (void)RREG32(RADEON_PCIE_INDEX);
+       WREG32(RADEON_PCIE_DATA, (v));
+       (void)RREG32(RADEON_PCIE_DATA);
+}
+
+
+/*
+ * Debugfs info
+ */
+#if defined(CONFIG_DEBUG_FS)
+static int rv515_debugfs_pipes_info(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t tmp;
+
+       tmp = RREG32(R400_GB_PIPE_SELECT);
+       seq_printf(m, "GB_PIPE_SELECT 0x%08x\n", tmp);
+       tmp = RREG32(R500_SU_REG_DEST);
+       seq_printf(m, "SU_REG_DEST 0x%08x\n", tmp);
+       tmp = RREG32(R300_GB_TILE_CONFIG);
+       seq_printf(m, "GB_TILE_CONFIG 0x%08x\n", tmp);
+       tmp = RREG32(R300_DST_PIPE_CONFIG);
+       seq_printf(m, "DST_PIPE_CONFIG 0x%08x\n", tmp);
+       return 0;
+}
+
+static int rv515_debugfs_ga_info(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct radeon_device *rdev = dev->dev_private;
+       uint32_t tmp;
+
+       tmp = RREG32(0x2140);
+       seq_printf(m, "VAP_CNTL_STATUS 0x%08x\n", tmp);
+       radeon_gpu_reset(rdev);
+       tmp = RREG32(0x425C);
+       seq_printf(m, "GA_IDLE 0x%08x\n", tmp);
+       return 0;
+}
+
+static struct drm_info_list rv515_pipes_info_list[] = {
+       {"rv515_pipes_info", rv515_debugfs_pipes_info, 0, NULL},
+};
+
+static struct drm_info_list rv515_ga_info_list[] = {
+       {"rv515_ga_info", rv515_debugfs_ga_info, 0, NULL},
+};
+#endif
+
+int rv515_debugfs_pipes_info_init(struct radeon_device *rdev)
+{
+#if defined(CONFIG_DEBUG_FS)
+       return radeon_debugfs_add_files(rdev, rv515_pipes_info_list, 1);
+#else
+       return 0;
+#endif
+}
+
+int rv515_debugfs_ga_info_init(struct radeon_device *rdev)
+{
+#if defined(CONFIG_DEBUG_FS)
+       return radeon_debugfs_add_files(rdev, rv515_ga_info_list, 1);
+#else
+       return 0;
+#endif
+}
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
new file mode 100644 (file)
index 0000000..da50cc5
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ *          Jerome Glisse
+ */
+#include "drmP.h"
+#include "radeon_reg.h"
+#include "radeon.h"
+
+/* rv770,rv730,rv710  depends on : */
+void rs600_mc_disable_clients(struct radeon_device *rdev);
+
+/* This files gather functions specifics to:
+ * rv770,rv730,rv710
+ *
+ * Some of these functions might be used by newer ASICs.
+ */
+int rv770_mc_wait_for_idle(struct radeon_device *rdev);
+void rv770_gpu_init(struct radeon_device *rdev);
+
+
+/*
+ * MC
+ */
+int rv770_mc_init(struct radeon_device *rdev)
+{
+       uint32_t tmp;
+
+       rv770_gpu_init(rdev);
+
+       /* setup the gart before changing location so we can ask to
+        * discard unmapped mc request
+        */
+       /* FIXME: disable out of gart access */
+       tmp = rdev->mc.gtt_location / 4096;
+       tmp = REG_SET(R700_LOGICAL_PAGE_NUMBER, tmp);
+       WREG32(R700_MC_VM_SYSTEM_APERTURE_LOW_ADDR, tmp);
+       tmp = (rdev->mc.gtt_location + rdev->mc.gtt_size) / 4096;
+       tmp = REG_SET(R700_LOGICAL_PAGE_NUMBER, tmp);
+       WREG32(R700_MC_VM_SYSTEM_APERTURE_HIGH_ADDR, tmp);
+
+       rs600_mc_disable_clients(rdev);
+       if (rv770_mc_wait_for_idle(rdev)) {
+               printk(KERN_WARNING "Failed to wait MC idle while "
+                      "programming pipes. Bad things might happen.\n");
+       }
+
+       tmp = rdev->mc.vram_location + rdev->mc.vram_size - 1;
+       tmp = REG_SET(R700_MC_FB_TOP, tmp >> 24);
+       tmp |= REG_SET(R700_MC_FB_BASE, rdev->mc.vram_location >> 24);
+       WREG32(R700_MC_VM_FB_LOCATION, tmp);
+       tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1;
+       tmp = REG_SET(R700_MC_AGP_TOP, tmp >> 22);
+       WREG32(R700_MC_VM_AGP_TOP, tmp);
+       tmp = REG_SET(R700_MC_AGP_BOT, rdev->mc.gtt_location >> 22);
+       WREG32(R700_MC_VM_AGP_BOT, tmp);
+       return 0;
+}
+
+void rv770_mc_fini(struct radeon_device *rdev)
+{
+       /* FIXME: implement */
+}
+
+
+/*
+ * Global GPU functions
+ */
+void rv770_errata(struct radeon_device *rdev)
+{
+       rdev->pll_errata = 0;
+}
+
+int rv770_mc_wait_for_idle(struct radeon_device *rdev)
+{
+       /* FIXME: implement */
+       return 0;
+}
+
+void rv770_gpu_init(struct radeon_device *rdev)
+{
+       /* FIXME: implement */
+}
+
+
+/*
+ * VRAM info
+ */
+void rv770_vram_get_type(struct radeon_device *rdev)
+{
+       /* FIXME: implement */
+}
+
+void rv770_vram_info(struct radeon_device *rdev)
+{
+       rv770_vram_get_type(rdev);
+
+       /* FIXME: implement */
+       /* Could aper size report 0 ? */
+       rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0);
+       rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0);
+}
diff --git a/drivers/gpu/drm/ttm/Makefile b/drivers/gpu/drm/ttm/Makefile
new file mode 100644 (file)
index 0000000..b0a9de7
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Makefile for the drm device driver.  This driver provides support for the
+
+ccflags-y := -Iinclude/drm
+ttm-y := ttm_agp_backend.o ttm_memory.o ttm_tt.o ttm_bo.o \
+       ttm_bo_util.o ttm_bo_vm.o ttm_module.o ttm_global.o
+
+obj-$(CONFIG_DRM_TTM) += ttm.o
diff --git a/drivers/gpu/drm/ttm/ttm_agp_backend.c b/drivers/gpu/drm/ttm/ttm_agp_backend.c
new file mode 100644 (file)
index 0000000..e8f6d22
--- /dev/null
@@ -0,0 +1,150 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+/*
+ * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
+ *          Keith Packard.
+ */
+
+#include "ttm/ttm_module.h"
+#include "ttm/ttm_bo_driver.h"
+#ifdef TTM_HAS_AGP
+#include "ttm/ttm_placement.h"
+#include <linux/agp_backend.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <asm/agp.h>
+
+struct ttm_agp_backend {
+       struct ttm_backend backend;
+       struct agp_memory *mem;
+       struct agp_bridge_data *bridge;
+};
+
+static int ttm_agp_populate(struct ttm_backend *backend,
+                           unsigned long num_pages, struct page **pages,
+                           struct page *dummy_read_page)
+{
+       struct ttm_agp_backend *agp_be =
+           container_of(backend, struct ttm_agp_backend, backend);
+       struct page **cur_page, **last_page = pages + num_pages;
+       struct agp_memory *mem;
+
+       mem = agp_allocate_memory(agp_be->bridge, num_pages, AGP_USER_MEMORY);
+       if (unlikely(mem == NULL))
+               return -ENOMEM;
+
+       mem->page_count = 0;
+       for (cur_page = pages; cur_page < last_page; ++cur_page) {
+               struct page *page = *cur_page;
+               if (!page)
+                       page = dummy_read_page;
+
+               mem->memory[mem->page_count++] =
+                   phys_to_gart(page_to_phys(page));
+       }
+       agp_be->mem = mem;
+       return 0;
+}
+
+static int ttm_agp_bind(struct ttm_backend *backend, struct ttm_mem_reg *bo_mem)
+{
+       struct ttm_agp_backend *agp_be =
+           container_of(backend, struct ttm_agp_backend, backend);
+       struct agp_memory *mem = agp_be->mem;
+       int cached = (bo_mem->placement & TTM_PL_FLAG_CACHED);
+       int ret;
+
+       mem->is_flushed = 1;
+       mem->type = (cached) ? AGP_USER_CACHED_MEMORY : AGP_USER_MEMORY;
+
+       ret = agp_bind_memory(mem, bo_mem->mm_node->start);
+       if (ret)
+               printk(KERN_ERR TTM_PFX "AGP Bind memory failed.\n");
+
+       return ret;
+}
+
+static int ttm_agp_unbind(struct ttm_backend *backend)
+{
+       struct ttm_agp_backend *agp_be =
+           container_of(backend, struct ttm_agp_backend, backend);
+
+       if (agp_be->mem->is_bound)
+               return agp_unbind_memory(agp_be->mem);
+       else
+               return 0;
+}
+
+static void ttm_agp_clear(struct ttm_backend *backend)
+{
+       struct ttm_agp_backend *agp_be =
+           container_of(backend, struct ttm_agp_backend, backend);
+       struct agp_memory *mem = agp_be->mem;
+
+       if (mem) {
+               ttm_agp_unbind(backend);
+               agp_free_memory(mem);
+       }
+       agp_be->mem = NULL;
+}
+
+static void ttm_agp_destroy(struct ttm_backend *backend)
+{
+       struct ttm_agp_backend *agp_be =
+           container_of(backend, struct ttm_agp_backend, backend);
+
+       if (agp_be->mem)
+               ttm_agp_clear(backend);
+       kfree(agp_be);
+}
+
+static struct ttm_backend_func ttm_agp_func = {
+       .populate = ttm_agp_populate,
+       .clear = ttm_agp_clear,
+       .bind = ttm_agp_bind,
+       .unbind = ttm_agp_unbind,
+       .destroy = ttm_agp_destroy,
+};
+
+struct ttm_backend *ttm_agp_backend_init(struct ttm_bo_device *bdev,
+                                        struct agp_bridge_data *bridge)
+{
+       struct ttm_agp_backend *agp_be;
+
+       agp_be = kmalloc(sizeof(*agp_be), GFP_KERNEL);
+       if (!agp_be)
+               return NULL;
+
+       agp_be->mem = NULL;
+       agp_be->bridge = bridge;
+       agp_be->backend.func = &ttm_agp_func;
+       agp_be->backend.bdev = bdev;
+       return &agp_be->backend;
+}
+EXPORT_SYMBOL(ttm_agp_backend_init);
+
+#endif
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
new file mode 100644 (file)
index 0000000..1587aec
--- /dev/null
@@ -0,0 +1,1698 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+/*
+ * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
+ */
+
+#include "ttm/ttm_module.h"
+#include "ttm/ttm_bo_driver.h"
+#include "ttm/ttm_placement.h"
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/file.h>
+#include <linux/module.h>
+
+#define TTM_ASSERT_LOCKED(param)
+#define TTM_DEBUG(fmt, arg...)
+#define TTM_BO_HASH_ORDER 13
+
+static int ttm_bo_setup_vm(struct ttm_buffer_object *bo);
+static void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo);
+static int ttm_bo_swapout(struct ttm_mem_shrink *shrink);
+
+static inline uint32_t ttm_bo_type_flags(unsigned type)
+{
+       return 1 << (type);
+}
+
+static void ttm_bo_release_list(struct kref *list_kref)
+{
+       struct ttm_buffer_object *bo =
+           container_of(list_kref, struct ttm_buffer_object, list_kref);
+       struct ttm_bo_device *bdev = bo->bdev;
+
+       BUG_ON(atomic_read(&bo->list_kref.refcount));
+       BUG_ON(atomic_read(&bo->kref.refcount));
+       BUG_ON(atomic_read(&bo->cpu_writers));
+       BUG_ON(bo->sync_obj != NULL);
+       BUG_ON(bo->mem.mm_node != NULL);
+       BUG_ON(!list_empty(&bo->lru));
+       BUG_ON(!list_empty(&bo->ddestroy));
+
+       if (bo->ttm)
+               ttm_tt_destroy(bo->ttm);
+       if (bo->destroy)
+               bo->destroy(bo);
+       else {
+               ttm_mem_global_free(bdev->mem_glob, bo->acc_size, false);
+               kfree(bo);
+       }
+}
+
+int ttm_bo_wait_unreserved(struct ttm_buffer_object *bo, bool interruptible)
+{
+
+       if (interruptible) {
+               int ret = 0;
+
+               ret = wait_event_interruptible(bo->event_queue,
+                                              atomic_read(&bo->reserved) == 0);
+               if (unlikely(ret != 0))
+                       return -ERESTART;
+       } else {
+               wait_event(bo->event_queue, atomic_read(&bo->reserved) == 0);
+       }
+       return 0;
+}
+
+static void ttm_bo_add_to_lru(struct ttm_buffer_object *bo)
+{
+       struct ttm_bo_device *bdev = bo->bdev;
+       struct ttm_mem_type_manager *man;
+
+       BUG_ON(!atomic_read(&bo->reserved));
+
+       if (!(bo->mem.placement & TTM_PL_FLAG_NO_EVICT)) {
+
+               BUG_ON(!list_empty(&bo->lru));
+
+               man = &bdev->man[bo->mem.mem_type];
+               list_add_tail(&bo->lru, &man->lru);
+               kref_get(&bo->list_kref);
+
+               if (bo->ttm != NULL) {
+                       list_add_tail(&bo->swap, &bdev->swap_lru);
+                       kref_get(&bo->list_kref);
+               }
+       }
+}
+
+/**
+ * Call with the lru_lock held.
+ */
+
+static int ttm_bo_del_from_lru(struct ttm_buffer_object *bo)
+{
+       int put_count = 0;
+
+       if (!list_empty(&bo->swap)) {
+               list_del_init(&bo->swap);
+               ++put_count;
+       }
+       if (!list_empty(&bo->lru)) {
+               list_del_init(&bo->lru);
+               ++put_count;
+       }
+
+       /*
+        * TODO: Add a driver hook to delete from
+        * driver-specific LRU's here.
+        */
+
+       return put_count;
+}
+
+int ttm_bo_reserve_locked(struct ttm_buffer_object *bo,
+                         bool interruptible,
+                         bool no_wait, bool use_sequence, uint32_t sequence)
+{
+       struct ttm_bo_device *bdev = bo->bdev;
+       int ret;
+
+       while (unlikely(atomic_cmpxchg(&bo->reserved, 0, 1) != 0)) {
+               if (use_sequence && bo->seq_valid &&
+                       (sequence - bo->val_seq < (1 << 31))) {
+                       return -EAGAIN;
+               }
+
+               if (no_wait)
+                       return -EBUSY;
+
+               spin_unlock(&bdev->lru_lock);
+               ret = ttm_bo_wait_unreserved(bo, interruptible);
+               spin_lock(&bdev->lru_lock);
+
+               if (unlikely(ret))
+                       return ret;
+       }
+
+       if (use_sequence) {
+               bo->val_seq = sequence;
+               bo->seq_valid = true;
+       } else {
+               bo->seq_valid = false;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(ttm_bo_reserve);
+
+static void ttm_bo_ref_bug(struct kref *list_kref)
+{
+       BUG();
+}
+
+int ttm_bo_reserve(struct ttm_buffer_object *bo,
+                  bool interruptible,
+                  bool no_wait, bool use_sequence, uint32_t sequence)
+{
+       struct ttm_bo_device *bdev = bo->bdev;
+       int put_count = 0;
+       int ret;
+
+       spin_lock(&bdev->lru_lock);
+       ret = ttm_bo_reserve_locked(bo, interruptible, no_wait, use_sequence,
+                                   sequence);
+       if (likely(ret == 0))
+               put_count = ttm_bo_del_from_lru(bo);
+       spin_unlock(&bdev->lru_lock);
+
+       while (put_count--)
+               kref_put(&bo->list_kref, ttm_bo_ref_bug);
+
+       return ret;
+}
+
+void ttm_bo_unreserve(struct ttm_buffer_object *bo)
+{
+       struct ttm_bo_device *bdev = bo->bdev;
+
+       spin_lock(&bdev->lru_lock);
+       ttm_bo_add_to_lru(bo);
+       atomic_set(&bo->reserved, 0);
+       wake_up_all(&bo->event_queue);
+       spin_unlock(&bdev->lru_lock);
+}
+EXPORT_SYMBOL(ttm_bo_unreserve);
+
+/*
+ * Call bo->mutex locked.
+ */
+
+static int ttm_bo_add_ttm(struct ttm_buffer_object *bo, bool zero_alloc)
+{
+       struct ttm_bo_device *bdev = bo->bdev;
+       int ret = 0;
+       uint32_t page_flags = 0;
+
+       TTM_ASSERT_LOCKED(&bo->mutex);
+       bo->ttm = NULL;
+
+       switch (bo->type) {
+       case ttm_bo_type_device:
+               if (zero_alloc)
+                       page_flags |= TTM_PAGE_FLAG_ZERO_ALLOC;
+       case ttm_bo_type_kernel:
+               bo->ttm = ttm_tt_create(bdev, bo->num_pages << PAGE_SHIFT,
+                                       page_flags, bdev->dummy_read_page);
+               if (unlikely(bo->ttm == NULL))
+                       ret = -ENOMEM;
+               break;
+       case ttm_bo_type_user:
+               bo->ttm = ttm_tt_create(bdev, bo->num_pages << PAGE_SHIFT,
+                                       page_flags | TTM_PAGE_FLAG_USER,
+                                       bdev->dummy_read_page);
+               if (unlikely(bo->ttm == NULL))
+                       ret = -ENOMEM;
+               break;
+
+               ret = ttm_tt_set_user(bo->ttm, current,
+                                     bo->buffer_start, bo->num_pages);
+               if (unlikely(ret != 0))
+                       ttm_tt_destroy(bo->ttm);
+               break;
+       default:
+               printk(KERN_ERR TTM_PFX "Illegal buffer object type\n");
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo,
+                                 struct ttm_mem_reg *mem,
+                                 bool evict, bool interruptible, bool no_wait)
+{
+       struct ttm_bo_device *bdev = bo->bdev;
+       bool old_is_pci = ttm_mem_reg_is_pci(bdev, &bo->mem);
+       bool new_is_pci = ttm_mem_reg_is_pci(bdev, mem);
+       struct ttm_mem_type_manager *old_man = &bdev->man[bo->mem.mem_type];
+       struct ttm_mem_type_manager *new_man = &bdev->man[mem->mem_type];
+       int ret = 0;
+
+       if (old_is_pci || new_is_pci ||
+           ((mem->placement & bo->mem.placement & TTM_PL_MASK_CACHING) == 0))
+               ttm_bo_unmap_virtual(bo);
+
+       /*
+        * Create and bind a ttm if required.
+        */
+
+       if (!(new_man->flags & TTM_MEMTYPE_FLAG_FIXED) && (bo->ttm == NULL)) {
+               ret = ttm_bo_add_ttm(bo, false);
+               if (ret)
+                       goto out_err;
+
+               ret = ttm_tt_set_placement_caching(bo->ttm, mem->placement);
+               if (ret)
+                       return ret;
+
+               if (mem->mem_type != TTM_PL_SYSTEM) {
+                       ret = ttm_tt_bind(bo->ttm, mem);
+                       if (ret)
+                               goto out_err;
+               }
+
+               if (bo->mem.mem_type == TTM_PL_SYSTEM) {
+
+                       struct ttm_mem_reg *old_mem = &bo->mem;
+                       uint32_t save_flags = old_mem->placement;
+
+                       *old_mem = *mem;
+                       mem->mm_node = NULL;
+                       ttm_flag_masked(&save_flags, mem->placement,
+                                       TTM_PL_MASK_MEMTYPE);
+                       goto moved;
+               }
+
+       }
+
+       if (!(old_man->flags & TTM_MEMTYPE_FLAG_FIXED) &&
+           !(new_man->flags & TTM_MEMTYPE_FLAG_FIXED))
+               ret = ttm_bo_move_ttm(bo, evict, no_wait, mem);
+       else if (bdev->driver->move)
+               ret = bdev->driver->move(bo, evict, interruptible,
+                                        no_wait, mem);
+       else
+               ret = ttm_bo_move_memcpy(bo, evict, no_wait, mem);
+
+       if (ret)
+               goto out_err;
+
+moved:
+       if (bo->evicted) {
+               ret = bdev->driver->invalidate_caches(bdev, bo->mem.placement);
+               if (ret)
+                       printk(KERN_ERR TTM_PFX "Can not flush read caches\n");
+               bo->evicted = false;
+       }
+
+       if (bo->mem.mm_node) {
+               spin_lock(&bo->lock);
+               bo->offset = (bo->mem.mm_node->start << PAGE_SHIFT) +
+                   bdev->man[bo->mem.mem_type].gpu_offset;
+               bo->cur_placement = bo->mem.placement;
+               spin_unlock(&bo->lock);
+       }
+
+       return 0;
+
+out_err:
+       new_man = &bdev->man[bo->mem.mem_type];
+       if ((new_man->flags & TTM_MEMTYPE_FLAG_FIXED) && bo->ttm) {
+               ttm_tt_unbind(bo->ttm);
+               ttm_tt_destroy(bo->ttm);
+               bo->ttm = NULL;
+       }
+
+       return ret;
+}
+
+/**
+ * If bo idle, remove from delayed- and lru lists, and unref.
+ * If not idle, and already on delayed list, do nothing.
+ * If not idle, and not on delayed list, put on delayed list,
+ *   up the list_kref and schedule a delayed list check.
+ */
+
+static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo, bool remove_all)
+{
+       struct ttm_bo_device *bdev = bo->bdev;
+       struct ttm_bo_driver *driver = bdev->driver;
+       int ret;
+
+       spin_lock(&bo->lock);
+       (void) ttm_bo_wait(bo, false, false, !remove_all);
+
+       if (!bo->sync_obj) {
+               int put_count;
+
+               spin_unlock(&bo->lock);
+
+               spin_lock(&bdev->lru_lock);
+               ret = ttm_bo_reserve_locked(bo, false, false, false, 0);
+               BUG_ON(ret);
+               if (bo->ttm)
+                       ttm_tt_unbind(bo->ttm);
+
+               if (!list_empty(&bo->ddestroy)) {
+                       list_del_init(&bo->ddestroy);
+                       kref_put(&bo->list_kref, ttm_bo_ref_bug);
+               }
+               if (bo->mem.mm_node) {
+                       drm_mm_put_block(bo->mem.mm_node);
+                       bo->mem.mm_node = NULL;
+               }
+               put_count = ttm_bo_del_from_lru(bo);
+               spin_unlock(&bdev->lru_lock);
+
+               atomic_set(&bo->reserved, 0);
+
+               while (put_count--)
+                       kref_put(&bo->list_kref, ttm_bo_release_list);
+
+               return 0;
+       }
+
+       spin_lock(&bdev->lru_lock);
+       if (list_empty(&bo->ddestroy)) {
+               void *sync_obj = bo->sync_obj;
+               void *sync_obj_arg = bo->sync_obj_arg;
+
+               kref_get(&bo->list_kref);
+               list_add_tail(&bo->ddestroy, &bdev->ddestroy);
+               spin_unlock(&bdev->lru_lock);
+               spin_unlock(&bo->lock);
+
+               if (sync_obj)
+                       driver->sync_obj_flush(sync_obj, sync_obj_arg);
+               schedule_delayed_work(&bdev->wq,
+                                     ((HZ / 100) < 1) ? 1 : HZ / 100);
+               ret = 0;
+
+       } else {
+               spin_unlock(&bdev->lru_lock);
+               spin_unlock(&bo->lock);
+               ret = -EBUSY;
+       }
+
+       return ret;
+}
+
+/**
+ * Traverse the delayed list, and call ttm_bo_cleanup_refs on all
+ * encountered buffers.
+ */
+
+static int ttm_bo_delayed_delete(struct ttm_bo_device *bdev, bool remove_all)
+{
+       struct ttm_buffer_object *entry, *nentry;
+       struct list_head *list, *next;
+       int ret;
+
+       spin_lock(&bdev->lru_lock);
+       list_for_each_safe(list, next, &bdev->ddestroy) {
+               entry = list_entry(list, struct ttm_buffer_object, ddestroy);
+               nentry = NULL;
+
+               /*
+                * Protect the next list entry from destruction while we
+                * unlock the lru_lock.
+                */
+
+               if (next != &bdev->ddestroy) {
+                       nentry = list_entry(next, struct ttm_buffer_object,
+                                           ddestroy);
+                       kref_get(&nentry->list_kref);
+               }
+               kref_get(&entry->list_kref);
+
+               spin_unlock(&bdev->lru_lock);
+               ret = ttm_bo_cleanup_refs(entry, remove_all);
+               kref_put(&entry->list_kref, ttm_bo_release_list);
+
+               spin_lock(&bdev->lru_lock);
+               if (nentry) {
+                       bool next_onlist = !list_empty(next);
+                       spin_unlock(&bdev->lru_lock);
+                       kref_put(&nentry->list_kref, ttm_bo_release_list);
+                       spin_lock(&bdev->lru_lock);
+                       /*
+                        * Someone might have raced us and removed the
+                        * next entry from the list. We don't bother restarting
+                        * list traversal.
+                        */
+
+                       if (!next_onlist)
+                               break;
+               }
+               if (ret)
+                       break;
+       }
+       ret = !list_empty(&bdev->ddestroy);
+       spin_unlock(&bdev->lru_lock);
+
+       return ret;
+}
+
+static void ttm_bo_delayed_workqueue(struct work_struct *work)
+{
+       struct ttm_bo_device *bdev =
+           container_of(work, struct ttm_bo_device, wq.work);
+
+       if (ttm_bo_delayed_delete(bdev, false)) {
+               schedule_delayed_work(&bdev->wq,
+                                     ((HZ / 100) < 1) ? 1 : HZ / 100);
+       }
+}
+
+static void ttm_bo_release(struct kref *kref)
+{
+       struct ttm_buffer_object *bo =
+           container_of(kref, struct ttm_buffer_object, kref);
+       struct ttm_bo_device *bdev = bo->bdev;
+
+       if (likely(bo->vm_node != NULL)) {
+               rb_erase(&bo->vm_rb, &bdev->addr_space_rb);
+               drm_mm_put_block(bo->vm_node);
+               bo->vm_node = NULL;
+       }
+       write_unlock(&bdev->vm_lock);
+       ttm_bo_cleanup_refs(bo, false);
+       kref_put(&bo->list_kref, ttm_bo_release_list);
+       write_lock(&bdev->vm_lock);
+}
+
+void ttm_bo_unref(struct ttm_buffer_object **p_bo)
+{
+       struct ttm_buffer_object *bo = *p_bo;
+       struct ttm_bo_device *bdev = bo->bdev;
+
+       *p_bo = NULL;
+       write_lock(&bdev->vm_lock);
+       kref_put(&bo->kref, ttm_bo_release);
+       write_unlock(&bdev->vm_lock);
+}
+EXPORT_SYMBOL(ttm_bo_unref);
+
+static int ttm_bo_evict(struct ttm_buffer_object *bo, unsigned mem_type,
+                       bool interruptible, bool no_wait)
+{
+       int ret = 0;
+       struct ttm_bo_device *bdev = bo->bdev;
+       struct ttm_mem_reg evict_mem;
+       uint32_t proposed_placement;
+
+       if (bo->mem.mem_type != mem_type)
+               goto out;
+
+       spin_lock(&bo->lock);
+       ret = ttm_bo_wait(bo, false, interruptible, no_wait);
+       spin_unlock(&bo->lock);
+
+       if (ret && ret != -ERESTART) {
+               printk(KERN_ERR TTM_PFX "Failed to expire sync object before "
+                      "buffer eviction.\n");
+               goto out;
+       }
+
+       BUG_ON(!atomic_read(&bo->reserved));
+
+       evict_mem = bo->mem;
+       evict_mem.mm_node = NULL;
+
+       proposed_placement = bdev->driver->evict_flags(bo);
+
+       ret = ttm_bo_mem_space(bo, proposed_placement,
+                              &evict_mem, interruptible, no_wait);
+       if (unlikely(ret != 0 && ret != -ERESTART))
+               ret = ttm_bo_mem_space(bo, TTM_PL_FLAG_SYSTEM,
+                                      &evict_mem, interruptible, no_wait);
+
+       if (ret) {
+               if (ret != -ERESTART)
+                       printk(KERN_ERR TTM_PFX
+                              "Failed to find memory space for "
+                              "buffer 0x%p eviction.\n", bo);
+               goto out;
+       }
+
+       ret = ttm_bo_handle_move_mem(bo, &evict_mem, true, interruptible,
+                                    no_wait);
+       if (ret) {
+               if (ret != -ERESTART)
+                       printk(KERN_ERR TTM_PFX "Buffer eviction failed\n");
+               goto out;
+       }
+
+       spin_lock(&bdev->lru_lock);
+       if (evict_mem.mm_node) {
+               drm_mm_put_block(evict_mem.mm_node);
+               evict_mem.mm_node = NULL;
+       }
+       spin_unlock(&bdev->lru_lock);
+       bo->evicted = true;
+out:
+       return ret;
+}
+
+/**
+ * Repeatedly evict memory from the LRU for @mem_type until we create enough
+ * space, or we've evicted everything and there isn't enough space.
+ */
+static int ttm_bo_mem_force_space(struct ttm_bo_device *bdev,
+                                 struct ttm_mem_reg *mem,
+                                 uint32_t mem_type,
+                                 bool interruptible, bool no_wait)
+{
+       struct drm_mm_node *node;
+       struct ttm_buffer_object *entry;
+       struct ttm_mem_type_manager *man = &bdev->man[mem_type];
+       struct list_head *lru;
+       unsigned long num_pages = mem->num_pages;
+       int put_count = 0;
+       int ret;
+
+retry_pre_get:
+       ret = drm_mm_pre_get(&man->manager);
+       if (unlikely(ret != 0))
+               return ret;
+
+       spin_lock(&bdev->lru_lock);
+       do {
+               node = drm_mm_search_free(&man->manager, num_pages,
+                                         mem->page_alignment, 1);
+               if (node)
+                       break;
+
+               lru = &man->lru;
+               if (list_empty(lru))
+                       break;
+
+               entry = list_first_entry(lru, struct ttm_buffer_object, lru);
+               kref_get(&entry->list_kref);
+
+               ret =
+                   ttm_bo_reserve_locked(entry, interruptible, no_wait,
+                                         false, 0);
+
+               if (likely(ret == 0))
+                       put_count = ttm_bo_del_from_lru(entry);
+
+               spin_unlock(&bdev->lru_lock);
+
+               if (unlikely(ret != 0))
+                       return ret;
+
+               while (put_count--)
+                       kref_put(&entry->list_kref, ttm_bo_ref_bug);
+
+               ret = ttm_bo_evict(entry, mem_type, interruptible, no_wait);
+
+               ttm_bo_unreserve(entry);
+
+               kref_put(&entry->list_kref, ttm_bo_release_list);
+               if (ret)
+                       return ret;
+
+               spin_lock(&bdev->lru_lock);
+       } while (1);
+
+       if (!node) {
+               spin_unlock(&bdev->lru_lock);
+               return -ENOMEM;
+       }
+
+       node = drm_mm_get_block_atomic(node, num_pages, mem->page_alignment);
+       if (unlikely(!node)) {
+               spin_unlock(&bdev->lru_lock);
+               goto retry_pre_get;
+       }
+
+       spin_unlock(&bdev->lru_lock);
+       mem->mm_node = node;
+       mem->mem_type = mem_type;
+       return 0;
+}
+
+static bool ttm_bo_mt_compatible(struct ttm_mem_type_manager *man,
+                                bool disallow_fixed,
+                                uint32_t mem_type,
+                                uint32_t mask, uint32_t *res_mask)
+{
+       uint32_t cur_flags = ttm_bo_type_flags(mem_type);
+
+       if ((man->flags & TTM_MEMTYPE_FLAG_FIXED) && disallow_fixed)
+               return false;
+
+       if ((cur_flags & mask & TTM_PL_MASK_MEM) == 0)
+               return false;
+
+       if ((mask & man->available_caching) == 0)
+               return false;
+       if (mask & man->default_caching)
+               cur_flags |= man->default_caching;
+       else if (mask & TTM_PL_FLAG_CACHED)
+               cur_flags |= TTM_PL_FLAG_CACHED;
+       else if (mask & TTM_PL_FLAG_WC)
+               cur_flags |= TTM_PL_FLAG_WC;
+       else
+               cur_flags |= TTM_PL_FLAG_UNCACHED;
+
+       *res_mask = cur_flags;
+       return true;
+}
+
+/**
+ * Creates space for memory region @mem according to its type.
+ *
+ * This function first searches for free space in compatible memory types in
+ * the priority order defined by the driver.  If free space isn't found, then
+ * ttm_bo_mem_force_space is attempted in priority order to evict and find
+ * space.
+ */
+int ttm_bo_mem_space(struct ttm_buffer_object *bo,
+                    uint32_t proposed_placement,
+                    struct ttm_mem_reg *mem,
+                    bool interruptible, bool no_wait)
+{
+       struct ttm_bo_device *bdev = bo->bdev;
+       struct ttm_mem_type_manager *man;
+
+       uint32_t num_prios = bdev->driver->num_mem_type_prio;
+       const uint32_t *prios = bdev->driver->mem_type_prio;
+       uint32_t i;
+       uint32_t mem_type = TTM_PL_SYSTEM;
+       uint32_t cur_flags = 0;
+       bool type_found = false;
+       bool type_ok = false;
+       bool has_eagain = false;
+       struct drm_mm_node *node = NULL;
+       int ret;
+
+       mem->mm_node = NULL;
+       for (i = 0; i < num_prios; ++i) {
+               mem_type = prios[i];
+               man = &bdev->man[mem_type];
+
+               type_ok = ttm_bo_mt_compatible(man,
+                                              bo->type == ttm_bo_type_user,
+                                              mem_type, proposed_placement,
+                                              &cur_flags);
+
+               if (!type_ok)
+                       continue;
+
+               if (mem_type == TTM_PL_SYSTEM)
+                       break;
+
+               if (man->has_type && man->use_type) {
+                       type_found = true;
+                       do {
+                               ret = drm_mm_pre_get(&man->manager);
+                               if (unlikely(ret))
+                                       return ret;
+
+                               spin_lock(&bdev->lru_lock);
+                               node = drm_mm_search_free(&man->manager,
+                                                         mem->num_pages,
+                                                         mem->page_alignment,
+                                                         1);
+                               if (unlikely(!node)) {
+                                       spin_unlock(&bdev->lru_lock);
+                                       break;
+                               }
+                               node = drm_mm_get_block_atomic(node,
+                                                              mem->num_pages,
+                                                              mem->
+                                                              page_alignment);
+                               spin_unlock(&bdev->lru_lock);
+                       } while (!node);
+               }
+               if (node)
+                       break;
+       }
+
+       if ((type_ok && (mem_type == TTM_PL_SYSTEM)) || node) {
+               mem->mm_node = node;
+               mem->mem_type = mem_type;
+               mem->placement = cur_flags;
+               return 0;
+       }
+
+       if (!type_found)
+               return -EINVAL;
+
+       num_prios = bdev->driver->num_mem_busy_prio;
+       prios = bdev->driver->mem_busy_prio;
+
+       for (i = 0; i < num_prios; ++i) {
+               mem_type = prios[i];
+               man = &bdev->man[mem_type];
+
+               if (!man->has_type)
+                       continue;
+
+               if (!ttm_bo_mt_compatible(man,
+                                         bo->type == ttm_bo_type_user,
+                                         mem_type,
+                                         proposed_placement, &cur_flags))
+                       continue;
+
+               ret = ttm_bo_mem_force_space(bdev, mem, mem_type,
+                                            interruptible, no_wait);
+
+               if (ret == 0 && mem->mm_node) {
+                       mem->placement = cur_flags;
+                       return 0;
+               }
+
+               if (ret == -ERESTART)
+                       has_eagain = true;
+       }
+
+       ret = (has_eagain) ? -ERESTART : -ENOMEM;
+       return ret;
+}
+EXPORT_SYMBOL(ttm_bo_mem_space);
+
+int ttm_bo_wait_cpu(struct ttm_buffer_object *bo, bool no_wait)
+{
+       int ret = 0;
+
+       if ((atomic_read(&bo->cpu_writers) > 0) && no_wait)
+               return -EBUSY;
+
+       ret = wait_event_interruptible(bo->event_queue,
+                                      atomic_read(&bo->cpu_writers) == 0);
+
+       if (ret == -ERESTARTSYS)
+               ret = -ERESTART;
+
+       return ret;
+}
+
+int ttm_bo_move_buffer(struct ttm_buffer_object *bo,
+                      uint32_t proposed_placement,
+                      bool interruptible, bool no_wait)
+{
+       struct ttm_bo_device *bdev = bo->bdev;
+       int ret = 0;
+       struct ttm_mem_reg mem;
+
+       BUG_ON(!atomic_read(&bo->reserved));
+
+       /*
+        * FIXME: It's possible to pipeline buffer moves.
+        * Have the driver move function wait for idle when necessary,
+        * instead of doing it here.
+        */
+
+       spin_lock(&bo->lock);
+       ret = ttm_bo_wait(bo, false, interruptible, no_wait);
+       spin_unlock(&bo->lock);
+
+       if (ret)
+               return ret;
+
+       mem.num_pages = bo->num_pages;
+       mem.size = mem.num_pages << PAGE_SHIFT;
+       mem.page_alignment = bo->mem.page_alignment;
+
+       /*
+        * Determine where to move the buffer.
+        */
+
+       ret = ttm_bo_mem_space(bo, proposed_placement, &mem,
+                              interruptible, no_wait);
+       if (ret)
+               goto out_unlock;
+
+       ret = ttm_bo_handle_move_mem(bo, &mem, false, interruptible, no_wait);
+
+out_unlock:
+       if (ret && mem.mm_node) {
+               spin_lock(&bdev->lru_lock);
+               drm_mm_put_block(mem.mm_node);
+               spin_unlock(&bdev->lru_lock);
+       }
+       return ret;
+}
+
+static int ttm_bo_mem_compat(uint32_t proposed_placement,
+                            struct ttm_mem_reg *mem)
+{
+       if ((proposed_placement & mem->placement & TTM_PL_MASK_MEM) == 0)
+               return 0;
+       if ((proposed_placement & mem->placement & TTM_PL_MASK_CACHING) == 0)
+               return 0;
+
+       return 1;
+}
+
+int ttm_buffer_object_validate(struct ttm_buffer_object *bo,
+                              uint32_t proposed_placement,
+                              bool interruptible, bool no_wait)
+{
+       int ret;
+
+       BUG_ON(!atomic_read(&bo->reserved));
+       bo->proposed_placement = proposed_placement;
+
+       TTM_DEBUG("Proposed placement 0x%08lx, Old flags 0x%08lx\n",
+                 (unsigned long)proposed_placement,
+                 (unsigned long)bo->mem.placement);
+
+       /*
+        * Check whether we need to move buffer.
+        */
+
+       if (!ttm_bo_mem_compat(bo->proposed_placement, &bo->mem)) {
+               ret = ttm_bo_move_buffer(bo, bo->proposed_placement,
+                                        interruptible, no_wait);
+               if (ret) {
+                       if (ret != -ERESTART)
+                               printk(KERN_ERR TTM_PFX
+                                      "Failed moving buffer. "
+                                      "Proposed placement 0x%08x\n",
+                                      bo->proposed_placement);
+                       if (ret == -ENOMEM)
+                               printk(KERN_ERR TTM_PFX
+                                      "Out of aperture space or "
+                                      "DRM memory quota.\n");
+                       return ret;
+               }
+       }
+
+       /*
+        * We might need to add a TTM.
+        */
+
+       if (bo->mem.mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) {
+               ret = ttm_bo_add_ttm(bo, true);
+               if (ret)
+                       return ret;
+       }
+       /*
+        * Validation has succeeded, move the access and other
+        * non-mapping-related flag bits from the proposed flags to
+        * the active flags
+        */
+
+       ttm_flag_masked(&bo->mem.placement, bo->proposed_placement,
+                       ~TTM_PL_MASK_MEMTYPE);
+
+       return 0;
+}
+EXPORT_SYMBOL(ttm_buffer_object_validate);
+
+int
+ttm_bo_check_placement(struct ttm_buffer_object *bo,
+                      uint32_t set_flags, uint32_t clr_flags)
+{
+       uint32_t new_mask = set_flags | clr_flags;
+
+       if ((bo->type == ttm_bo_type_user) &&
+           (clr_flags & TTM_PL_FLAG_CACHED)) {
+               printk(KERN_ERR TTM_PFX
+                      "User buffers require cache-coherent memory.\n");
+               return -EINVAL;
+       }
+
+       if (!capable(CAP_SYS_ADMIN)) {
+               if (new_mask & TTM_PL_FLAG_NO_EVICT) {
+                       printk(KERN_ERR TTM_PFX "Need to be root to modify"
+                              " NO_EVICT status.\n");
+                       return -EINVAL;
+               }
+
+               if ((clr_flags & bo->mem.placement & TTM_PL_MASK_MEMTYPE) &&
+                   (bo->mem.placement & TTM_PL_FLAG_NO_EVICT)) {
+                       printk(KERN_ERR TTM_PFX
+                              "Incompatible memory specification"
+                              " for NO_EVICT buffer.\n");
+                       return -EINVAL;
+               }
+       }
+       return 0;
+}
+
+int ttm_buffer_object_init(struct ttm_bo_device *bdev,
+                          struct ttm_buffer_object *bo,
+                          unsigned long size,
+                          enum ttm_bo_type type,
+                          uint32_t flags,
+                          uint32_t page_alignment,
+                          unsigned long buffer_start,
+                          bool interruptible,
+                          struct file *persistant_swap_storage,
+                          size_t acc_size,
+                          void (*destroy) (struct ttm_buffer_object *))
+{
+       int ret = 0;
+       unsigned long num_pages;
+
+       size += buffer_start & ~PAGE_MASK;
+       num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       if (num_pages == 0) {
+               printk(KERN_ERR TTM_PFX "Illegal buffer object size.\n");
+               return -EINVAL;
+       }
+       bo->destroy = destroy;
+
+       spin_lock_init(&bo->lock);
+       kref_init(&bo->kref);
+       kref_init(&bo->list_kref);
+       atomic_set(&bo->cpu_writers, 0);
+       atomic_set(&bo->reserved, 1);
+       init_waitqueue_head(&bo->event_queue);
+       INIT_LIST_HEAD(&bo->lru);
+       INIT_LIST_HEAD(&bo->ddestroy);
+       INIT_LIST_HEAD(&bo->swap);
+       bo->bdev = bdev;
+       bo->type = type;
+       bo->num_pages = num_pages;
+       bo->mem.mem_type = TTM_PL_SYSTEM;
+       bo->mem.num_pages = bo->num_pages;
+       bo->mem.mm_node = NULL;
+       bo->mem.page_alignment = page_alignment;
+       bo->buffer_start = buffer_start & PAGE_MASK;
+       bo->priv_flags = 0;
+       bo->mem.placement = (TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED);
+       bo->seq_valid = false;
+       bo->persistant_swap_storage = persistant_swap_storage;
+       bo->acc_size = acc_size;
+
+       ret = ttm_bo_check_placement(bo, flags, 0ULL);
+       if (unlikely(ret != 0))
+               goto out_err;
+
+       /*
+        * If no caching attributes are set, accept any form of caching.
+        */
+
+       if ((flags & TTM_PL_MASK_CACHING) == 0)
+               flags |= TTM_PL_MASK_CACHING;
+
+       /*
+        * For ttm_bo_type_device buffers, allocate
+        * address space from the device.
+        */
+
+       if (bo->type == ttm_bo_type_device) {
+               ret = ttm_bo_setup_vm(bo);
+               if (ret)
+                       goto out_err;
+       }
+
+       ret = ttm_buffer_object_validate(bo, flags, interruptible, false);
+       if (ret)
+               goto out_err;
+
+       ttm_bo_unreserve(bo);
+       return 0;
+
+out_err:
+       ttm_bo_unreserve(bo);
+       ttm_bo_unref(&bo);
+
+       return ret;
+}
+EXPORT_SYMBOL(ttm_buffer_object_init);
+
+static inline size_t ttm_bo_size(struct ttm_bo_device *bdev,
+                                unsigned long num_pages)
+{
+       size_t page_array_size = (num_pages * sizeof(void *) + PAGE_SIZE - 1) &
+           PAGE_MASK;
+
+       return bdev->ttm_bo_size + 2 * page_array_size;
+}
+
+int ttm_buffer_object_create(struct ttm_bo_device *bdev,
+                            unsigned long size,
+                            enum ttm_bo_type type,
+                            uint32_t flags,
+                            uint32_t page_alignment,
+                            unsigned long buffer_start,
+                            bool interruptible,
+                            struct file *persistant_swap_storage,
+                            struct ttm_buffer_object **p_bo)
+{
+       struct ttm_buffer_object *bo;
+       int ret;
+       struct ttm_mem_global *mem_glob = bdev->mem_glob;
+
+       size_t acc_size =
+           ttm_bo_size(bdev, (size + PAGE_SIZE - 1) >> PAGE_SHIFT);
+       ret = ttm_mem_global_alloc(mem_glob, acc_size, false, false, false);
+       if (unlikely(ret != 0))
+               return ret;
+
+       bo = kzalloc(sizeof(*bo), GFP_KERNEL);
+
+       if (unlikely(bo == NULL)) {
+               ttm_mem_global_free(mem_glob, acc_size, false);
+               return -ENOMEM;
+       }
+
+       ret = ttm_buffer_object_init(bdev, bo, size, type, flags,
+                                    page_alignment, buffer_start,
+                                    interruptible,
+                                    persistant_swap_storage, acc_size, NULL);
+       if (likely(ret == 0))
+               *p_bo = bo;
+
+       return ret;
+}
+
+static int ttm_bo_leave_list(struct ttm_buffer_object *bo,
+                            uint32_t mem_type, bool allow_errors)
+{
+       int ret;
+
+       spin_lock(&bo->lock);
+       ret = ttm_bo_wait(bo, false, false, false);
+       spin_unlock(&bo->lock);
+
+       if (ret && allow_errors)
+               goto out;
+
+       if (bo->mem.mem_type == mem_type)
+               ret = ttm_bo_evict(bo, mem_type, false, false);
+
+       if (ret) {
+               if (allow_errors) {
+                       goto out;
+               } else {
+                       ret = 0;
+                       printk(KERN_ERR TTM_PFX "Cleanup eviction failed\n");
+               }
+       }
+
+out:
+       return ret;
+}
+
+static int ttm_bo_force_list_clean(struct ttm_bo_device *bdev,
+                                  struct list_head *head,
+                                  unsigned mem_type, bool allow_errors)
+{
+       struct ttm_buffer_object *entry;
+       int ret;
+       int put_count;
+
+       /*
+        * Can't use standard list traversal since we're unlocking.
+        */
+
+       spin_lock(&bdev->lru_lock);
+
+       while (!list_empty(head)) {
+               entry = list_first_entry(head, struct ttm_buffer_object, lru);
+               kref_get(&entry->list_kref);
+               ret = ttm_bo_reserve_locked(entry, false, false, false, 0);
+               put_count = ttm_bo_del_from_lru(entry);
+               spin_unlock(&bdev->lru_lock);
+               while (put_count--)
+                       kref_put(&entry->list_kref, ttm_bo_ref_bug);
+               BUG_ON(ret);
+               ret = ttm_bo_leave_list(entry, mem_type, allow_errors);
+               ttm_bo_unreserve(entry);
+               kref_put(&entry->list_kref, ttm_bo_release_list);
+               spin_lock(&bdev->lru_lock);
+       }
+
+       spin_unlock(&bdev->lru_lock);
+
+       return 0;
+}
+
+int ttm_bo_clean_mm(struct ttm_bo_device *bdev, unsigned mem_type)
+{
+       struct ttm_mem_type_manager *man = &bdev->man[mem_type];
+       int ret = -EINVAL;
+
+       if (mem_type >= TTM_NUM_MEM_TYPES) {
+               printk(KERN_ERR TTM_PFX "Illegal memory type %d\n", mem_type);
+               return ret;
+       }
+
+       if (!man->has_type) {
+               printk(KERN_ERR TTM_PFX "Trying to take down uninitialized "
+                      "memory manager type %u\n", mem_type);
+               return ret;
+       }
+
+       man->use_type = false;
+       man->has_type = false;
+
+       ret = 0;
+       if (mem_type > 0) {
+               ttm_bo_force_list_clean(bdev, &man->lru, mem_type, false);
+
+               spin_lock(&bdev->lru_lock);
+               if (drm_mm_clean(&man->manager))
+                       drm_mm_takedown(&man->manager);
+               else
+                       ret = -EBUSY;
+
+               spin_unlock(&bdev->lru_lock);
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(ttm_bo_clean_mm);
+
+int ttm_bo_evict_mm(struct ttm_bo_device *bdev, unsigned mem_type)
+{
+       struct ttm_mem_type_manager *man = &bdev->man[mem_type];
+
+       if (mem_type == 0 || mem_type >= TTM_NUM_MEM_TYPES) {
+               printk(KERN_ERR TTM_PFX
+                      "Illegal memory manager memory type %u.\n",
+                      mem_type);
+               return -EINVAL;
+       }
+
+       if (!man->has_type) {
+               printk(KERN_ERR TTM_PFX
+                      "Memory type %u has not been initialized.\n",
+                      mem_type);
+               return 0;
+       }
+
+       return ttm_bo_force_list_clean(bdev, &man->lru, mem_type, true);
+}
+EXPORT_SYMBOL(ttm_bo_evict_mm);
+
+int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type,
+                  unsigned long p_offset, unsigned long p_size)
+{
+       int ret = -EINVAL;
+       struct ttm_mem_type_manager *man;
+
+       if (type >= TTM_NUM_MEM_TYPES) {
+               printk(KERN_ERR TTM_PFX "Illegal memory type %d\n", type);
+               return ret;
+       }
+
+       man = &bdev->man[type];
+       if (man->has_type) {
+               printk(KERN_ERR TTM_PFX
+                      "Memory manager already initialized for type %d\n",
+                      type);
+               return ret;
+       }
+
+       ret = bdev->driver->init_mem_type(bdev, type, man);
+       if (ret)
+               return ret;
+
+       ret = 0;
+       if (type != TTM_PL_SYSTEM) {
+               if (!p_size) {
+                       printk(KERN_ERR TTM_PFX
+                              "Zero size memory manager type %d\n",
+                              type);
+                       return ret;
+               }
+               ret = drm_mm_init(&man->manager, p_offset, p_size);
+               if (ret)
+                       return ret;
+       }
+       man->has_type = true;
+       man->use_type = true;
+       man->size = p_size;
+
+       INIT_LIST_HEAD(&man->lru);
+
+       return 0;
+}
+EXPORT_SYMBOL(ttm_bo_init_mm);
+
+int ttm_bo_device_release(struct ttm_bo_device *bdev)
+{
+       int ret = 0;
+       unsigned i = TTM_NUM_MEM_TYPES;
+       struct ttm_mem_type_manager *man;
+
+       while (i--) {
+               man = &bdev->man[i];
+               if (man->has_type) {
+                       man->use_type = false;
+                       if ((i != TTM_PL_SYSTEM) && ttm_bo_clean_mm(bdev, i)) {
+                               ret = -EBUSY;
+                               printk(KERN_ERR TTM_PFX
+                                      "DRM memory manager type %d "
+                                      "is not clean.\n", i);
+                       }
+                       man->has_type = false;
+               }
+       }
+
+       if (!cancel_delayed_work(&bdev->wq))
+               flush_scheduled_work();
+
+       while (ttm_bo_delayed_delete(bdev, true))
+               ;
+
+       spin_lock(&bdev->lru_lock);
+       if (list_empty(&bdev->ddestroy))
+               TTM_DEBUG("Delayed destroy list was clean\n");
+
+       if (list_empty(&bdev->man[0].lru))
+               TTM_DEBUG("Swap list was clean\n");
+       spin_unlock(&bdev->lru_lock);
+
+       ttm_mem_unregister_shrink(bdev->mem_glob, &bdev->shrink);
+       BUG_ON(!drm_mm_clean(&bdev->addr_space_mm));
+       write_lock(&bdev->vm_lock);
+       drm_mm_takedown(&bdev->addr_space_mm);
+       write_unlock(&bdev->vm_lock);
+
+       __free_page(bdev->dummy_read_page);
+       return ret;
+}
+EXPORT_SYMBOL(ttm_bo_device_release);
+
+/*
+ * This function is intended to be called on drm driver load.
+ * If you decide to call it from firstopen, you must protect the call
+ * from a potentially racing ttm_bo_driver_finish in lastclose.
+ * (This may happen on X server restart).
+ */
+
+int ttm_bo_device_init(struct ttm_bo_device *bdev,
+                      struct ttm_mem_global *mem_glob,
+                      struct ttm_bo_driver *driver, uint64_t file_page_offset)
+{
+       int ret = -EINVAL;
+
+       bdev->dummy_read_page = NULL;
+       rwlock_init(&bdev->vm_lock);
+       spin_lock_init(&bdev->lru_lock);
+
+       bdev->driver = driver;
+       bdev->mem_glob = mem_glob;
+
+       memset(bdev->man, 0, sizeof(bdev->man));
+
+       bdev->dummy_read_page = alloc_page(__GFP_ZERO | GFP_DMA32);
+       if (unlikely(bdev->dummy_read_page == NULL)) {
+               ret = -ENOMEM;
+               goto out_err0;
+       }
+
+       /*
+        * Initialize the system memory buffer type.
+        * Other types need to be driver / IOCTL initialized.
+        */
+       ret = ttm_bo_init_mm(bdev, TTM_PL_SYSTEM, 0, 0);
+       if (unlikely(ret != 0))
+               goto out_err1;
+
+       bdev->addr_space_rb = RB_ROOT;
+       ret = drm_mm_init(&bdev->addr_space_mm, file_page_offset, 0x10000000);
+       if (unlikely(ret != 0))
+               goto out_err2;
+
+       INIT_DELAYED_WORK(&bdev->wq, ttm_bo_delayed_workqueue);
+       bdev->nice_mode = true;
+       INIT_LIST_HEAD(&bdev->ddestroy);
+       INIT_LIST_HEAD(&bdev->swap_lru);
+       bdev->dev_mapping = NULL;
+       ttm_mem_init_shrink(&bdev->shrink, ttm_bo_swapout);
+       ret = ttm_mem_register_shrink(mem_glob, &bdev->shrink);
+       if (unlikely(ret != 0)) {
+               printk(KERN_ERR TTM_PFX
+                      "Could not register buffer object swapout.\n");
+               goto out_err2;
+       }
+
+       bdev->ttm_bo_extra_size =
+               ttm_round_pot(sizeof(struct ttm_tt)) +
+               ttm_round_pot(sizeof(struct ttm_backend));
+
+       bdev->ttm_bo_size = bdev->ttm_bo_extra_size +
+               ttm_round_pot(sizeof(struct ttm_buffer_object));
+
+       return 0;
+out_err2:
+       ttm_bo_clean_mm(bdev, 0);
+out_err1:
+       __free_page(bdev->dummy_read_page);
+out_err0:
+       return ret;
+}
+EXPORT_SYMBOL(ttm_bo_device_init);
+
+/*
+ * buffer object vm functions.
+ */
+
+bool ttm_mem_reg_is_pci(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
+{
+       struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
+
+       if (!(man->flags & TTM_MEMTYPE_FLAG_FIXED)) {
+               if (mem->mem_type == TTM_PL_SYSTEM)
+                       return false;
+
+               if (man->flags & TTM_MEMTYPE_FLAG_CMA)
+                       return false;
+
+               if (mem->placement & TTM_PL_FLAG_CACHED)
+                       return false;
+       }
+       return true;
+}
+
+int ttm_bo_pci_offset(struct ttm_bo_device *bdev,
+                     struct ttm_mem_reg *mem,
+                     unsigned long *bus_base,
+                     unsigned long *bus_offset, unsigned long *bus_size)
+{
+       struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
+
+       *bus_size = 0;
+       if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
+               return -EINVAL;
+
+       if (ttm_mem_reg_is_pci(bdev, mem)) {
+               *bus_offset = mem->mm_node->start << PAGE_SHIFT;
+               *bus_size = mem->num_pages << PAGE_SHIFT;
+               *bus_base = man->io_offset;
+       }
+
+       return 0;
+}
+
+void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo)
+{
+       struct ttm_bo_device *bdev = bo->bdev;
+       loff_t offset = (loff_t) bo->addr_space_offset;
+       loff_t holelen = ((loff_t) bo->mem.num_pages) << PAGE_SHIFT;
+
+       if (!bdev->dev_mapping)
+               return;
+
+       unmap_mapping_range(bdev->dev_mapping, offset, holelen, 1);
+}
+
+static void ttm_bo_vm_insert_rb(struct ttm_buffer_object *bo)
+{
+       struct ttm_bo_device *bdev = bo->bdev;
+       struct rb_node **cur = &bdev->addr_space_rb.rb_node;
+       struct rb_node *parent = NULL;
+       struct ttm_buffer_object *cur_bo;
+       unsigned long offset = bo->vm_node->start;
+       unsigned long cur_offset;
+
+       while (*cur) {
+               parent = *cur;
+               cur_bo = rb_entry(parent, struct ttm_buffer_object, vm_rb);
+               cur_offset = cur_bo->vm_node->start;
+               if (offset < cur_offset)
+                       cur = &parent->rb_left;
+               else if (offset > cur_offset)
+                       cur = &parent->rb_right;
+               else
+                       BUG();
+       }
+
+       rb_link_node(&bo->vm_rb, parent, cur);
+       rb_insert_color(&bo->vm_rb, &bdev->addr_space_rb);
+}
+
+/**
+ * ttm_bo_setup_vm:
+ *
+ * @bo: the buffer to allocate address space for
+ *
+ * Allocate address space in the drm device so that applications
+ * can mmap the buffer and access the contents. This only
+ * applies to ttm_bo_type_device objects as others are not
+ * placed in the drm device address space.
+ */
+
+static int ttm_bo_setup_vm(struct ttm_buffer_object *bo)
+{
+       struct ttm_bo_device *bdev = bo->bdev;
+       int ret;
+
+retry_pre_get:
+       ret = drm_mm_pre_get(&bdev->addr_space_mm);
+       if (unlikely(ret != 0))
+               return ret;
+
+       write_lock(&bdev->vm_lock);
+       bo->vm_node = drm_mm_search_free(&bdev->addr_space_mm,
+                                        bo->mem.num_pages, 0, 0);
+
+       if (unlikely(bo->vm_node == NULL)) {
+               ret = -ENOMEM;
+               goto out_unlock;
+       }
+
+       bo->vm_node = drm_mm_get_block_atomic(bo->vm_node,
+                                             bo->mem.num_pages, 0);
+
+       if (unlikely(bo->vm_node == NULL)) {
+               write_unlock(&bdev->vm_lock);
+               goto retry_pre_get;
+       }
+
+       ttm_bo_vm_insert_rb(bo);
+       write_unlock(&bdev->vm_lock);
+       bo->addr_space_offset = ((uint64_t) bo->vm_node->start) << PAGE_SHIFT;
+
+       return 0;
+out_unlock:
+       write_unlock(&bdev->vm_lock);
+       return ret;
+}
+
+int ttm_bo_wait(struct ttm_buffer_object *bo,
+               bool lazy, bool interruptible, bool no_wait)
+{
+       struct ttm_bo_driver *driver = bo->bdev->driver;
+       void *sync_obj;
+       void *sync_obj_arg;
+       int ret = 0;
+
+       if (likely(bo->sync_obj == NULL))
+               return 0;
+
+       while (bo->sync_obj) {
+
+               if (driver->sync_obj_signaled(bo->sync_obj, bo->sync_obj_arg)) {
+                       void *tmp_obj = bo->sync_obj;
+                       bo->sync_obj = NULL;
+                       clear_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags);
+                       spin_unlock(&bo->lock);
+                       driver->sync_obj_unref(&tmp_obj);
+                       spin_lock(&bo->lock);
+                       continue;
+               }
+
+               if (no_wait)
+                       return -EBUSY;
+
+               sync_obj = driver->sync_obj_ref(bo->sync_obj);
+               sync_obj_arg = bo->sync_obj_arg;
+               spin_unlock(&bo->lock);
+               ret = driver->sync_obj_wait(sync_obj, sync_obj_arg,
+                                           lazy, interruptible);
+               if (unlikely(ret != 0)) {
+                       driver->sync_obj_unref(&sync_obj);
+                       spin_lock(&bo->lock);
+                       return ret;
+               }
+               spin_lock(&bo->lock);
+               if (likely(bo->sync_obj == sync_obj &&
+                          bo->sync_obj_arg == sync_obj_arg)) {
+                       void *tmp_obj = bo->sync_obj;
+                       bo->sync_obj = NULL;
+                       clear_bit(TTM_BO_PRIV_FLAG_MOVING,
+                                 &bo->priv_flags);
+                       spin_unlock(&bo->lock);
+                       driver->sync_obj_unref(&sync_obj);
+                       driver->sync_obj_unref(&tmp_obj);
+                       spin_lock(&bo->lock);
+               }
+       }
+       return 0;
+}
+EXPORT_SYMBOL(ttm_bo_wait);
+
+void ttm_bo_unblock_reservation(struct ttm_buffer_object *bo)
+{
+       atomic_set(&bo->reserved, 0);
+       wake_up_all(&bo->event_queue);
+}
+
+int ttm_bo_block_reservation(struct ttm_buffer_object *bo, bool interruptible,
+                            bool no_wait)
+{
+       int ret;
+
+       while (unlikely(atomic_cmpxchg(&bo->reserved, 0, 1) != 0)) {
+               if (no_wait)
+                       return -EBUSY;
+               else if (interruptible) {
+                       ret = wait_event_interruptible
+                           (bo->event_queue, atomic_read(&bo->reserved) == 0);
+                       if (unlikely(ret != 0))
+                               return -ERESTART;
+               } else {
+                       wait_event(bo->event_queue,
+                                  atomic_read(&bo->reserved) == 0);
+               }
+       }
+       return 0;
+}
+
+int ttm_bo_synccpu_write_grab(struct ttm_buffer_object *bo, bool no_wait)
+{
+       int ret = 0;
+
+       /*
+        * Using ttm_bo_reserve instead of ttm_bo_block_reservation
+        * makes sure the lru lists are updated.
+        */
+
+       ret = ttm_bo_reserve(bo, true, no_wait, false, 0);
+       if (unlikely(ret != 0))
+               return ret;
+       spin_lock(&bo->lock);
+       ret = ttm_bo_wait(bo, false, true, no_wait);
+       spin_unlock(&bo->lock);
+       if (likely(ret == 0))
+               atomic_inc(&bo->cpu_writers);
+       ttm_bo_unreserve(bo);
+       return ret;
+}
+
+void ttm_bo_synccpu_write_release(struct ttm_buffer_object *bo)
+{
+       if (atomic_dec_and_test(&bo->cpu_writers))
+               wake_up_all(&bo->event_queue);
+}
+
+/**
+ * A buffer object shrink method that tries to swap out the first
+ * buffer object on the bo_global::swap_lru list.
+ */
+
+static int ttm_bo_swapout(struct ttm_mem_shrink *shrink)
+{
+       struct ttm_bo_device *bdev =
+           container_of(shrink, struct ttm_bo_device, shrink);
+       struct ttm_buffer_object *bo;
+       int ret = -EBUSY;
+       int put_count;
+       uint32_t swap_placement = (TTM_PL_FLAG_CACHED | TTM_PL_FLAG_SYSTEM);
+
+       spin_lock(&bdev->lru_lock);
+       while (ret == -EBUSY) {
+               if (unlikely(list_empty(&bdev->swap_lru))) {
+                       spin_unlock(&bdev->lru_lock);
+                       return -EBUSY;
+               }
+
+               bo = list_first_entry(&bdev->swap_lru,
+                                     struct ttm_buffer_object, swap);
+               kref_get(&bo->list_kref);
+
+               /**
+                * Reserve buffer. Since we unlock while sleeping, we need
+                * to re-check that nobody removed us from the swap-list while
+                * we slept.
+                */
+
+               ret = ttm_bo_reserve_locked(bo, false, true, false, 0);
+               if (unlikely(ret == -EBUSY)) {
+                       spin_unlock(&bdev->lru_lock);
+                       ttm_bo_wait_unreserved(bo, false);
+                       kref_put(&bo->list_kref, ttm_bo_release_list);
+                       spin_lock(&bdev->lru_lock);
+               }
+       }
+
+       BUG_ON(ret != 0);
+       put_count = ttm_bo_del_from_lru(bo);
+       spin_unlock(&bdev->lru_lock);
+
+       while (put_count--)
+               kref_put(&bo->list_kref, ttm_bo_ref_bug);
+
+       /**
+        * Wait for GPU, then move to system cached.
+        */
+
+       spin_lock(&bo->lock);
+       ret = ttm_bo_wait(bo, false, false, false);
+       spin_unlock(&bo->lock);
+
+       if (unlikely(ret != 0))
+               goto out;
+
+       if ((bo->mem.placement & swap_placement) != swap_placement) {
+               struct ttm_mem_reg evict_mem;
+
+               evict_mem = bo->mem;
+               evict_mem.mm_node = NULL;
+               evict_mem.placement = TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED;
+               evict_mem.mem_type = TTM_PL_SYSTEM;
+
+               ret = ttm_bo_handle_move_mem(bo, &evict_mem, true,
+                                            false, false);
+               if (unlikely(ret != 0))
+                       goto out;
+       }
+
+       ttm_bo_unmap_virtual(bo);
+
+       /**
+        * Swap out. Buffer will be swapped in again as soon as
+        * anyone tries to access a ttm page.
+        */
+
+       ret = ttm_tt_swapout(bo->ttm, bo->persistant_swap_storage);
+out:
+
+       /**
+        *
+        * Unreserve without putting on LRU to avoid swapping out an
+        * already swapped buffer.
+        */
+
+       atomic_set(&bo->reserved, 0);
+       wake_up_all(&bo->event_queue);
+       kref_put(&bo->list_kref, ttm_bo_release_list);
+       return ret;
+}
+
+void ttm_bo_swapout_all(struct ttm_bo_device *bdev)
+{
+       while (ttm_bo_swapout(&bdev->shrink) == 0)
+               ;
+}
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
new file mode 100644 (file)
index 0000000..517c845
--- /dev/null
@@ -0,0 +1,561 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2007-2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+/*
+ * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
+ */
+
+#include "ttm/ttm_bo_driver.h"
+#include "ttm/ttm_placement.h"
+#include <linux/io.h>
+#include <linux/highmem.h>
+#include <linux/wait.h>
+#include <linux/vmalloc.h>
+#include <linux/version.h>
+#include <linux/module.h>
+
+void ttm_bo_free_old_node(struct ttm_buffer_object *bo)
+{
+       struct ttm_mem_reg *old_mem = &bo->mem;
+
+       if (old_mem->mm_node) {
+               spin_lock(&bo->bdev->lru_lock);
+               drm_mm_put_block(old_mem->mm_node);
+               spin_unlock(&bo->bdev->lru_lock);
+       }
+       old_mem->mm_node = NULL;
+}
+
+int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
+                   bool evict, bool no_wait, struct ttm_mem_reg *new_mem)
+{
+       struct ttm_tt *ttm = bo->ttm;
+       struct ttm_mem_reg *old_mem = &bo->mem;
+       uint32_t save_flags = old_mem->placement;
+       int ret;
+
+       if (old_mem->mem_type != TTM_PL_SYSTEM) {
+               ttm_tt_unbind(ttm);
+               ttm_bo_free_old_node(bo);
+               ttm_flag_masked(&old_mem->placement, TTM_PL_FLAG_SYSTEM,
+                               TTM_PL_MASK_MEM);
+               old_mem->mem_type = TTM_PL_SYSTEM;
+               save_flags = old_mem->placement;
+       }
+
+       ret = ttm_tt_set_placement_caching(ttm, new_mem->placement);
+       if (unlikely(ret != 0))
+               return ret;
+
+       if (new_mem->mem_type != TTM_PL_SYSTEM) {
+               ret = ttm_tt_bind(ttm, new_mem);
+               if (unlikely(ret != 0))
+                       return ret;
+       }
+
+       *old_mem = *new_mem;
+       new_mem->mm_node = NULL;
+       ttm_flag_masked(&save_flags, new_mem->placement, TTM_PL_MASK_MEMTYPE);
+       return 0;
+}
+EXPORT_SYMBOL(ttm_bo_move_ttm);
+
+int ttm_mem_reg_ioremap(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem,
+                       void **virtual)
+{
+       struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
+       unsigned long bus_offset;
+       unsigned long bus_size;
+       unsigned long bus_base;
+       int ret;
+       void *addr;
+
+       *virtual = NULL;
+       ret = ttm_bo_pci_offset(bdev, mem, &bus_base, &bus_offset, &bus_size);
+       if (ret || bus_size == 0)
+               return ret;
+
+       if (!(man->flags & TTM_MEMTYPE_FLAG_NEEDS_IOREMAP))
+               addr = (void *)(((u8 *) man->io_addr) + bus_offset);
+       else {
+               if (mem->placement & TTM_PL_FLAG_WC)
+                       addr = ioremap_wc(bus_base + bus_offset, bus_size);
+               else
+                       addr = ioremap_nocache(bus_base + bus_offset, bus_size);
+               if (!addr)
+                       return -ENOMEM;
+       }
+       *virtual = addr;
+       return 0;
+}
+
+void ttm_mem_reg_iounmap(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem,
+                        void *virtual)
+{
+       struct ttm_mem_type_manager *man;
+
+       man = &bdev->man[mem->mem_type];
+
+       if (virtual && (man->flags & TTM_MEMTYPE_FLAG_NEEDS_IOREMAP))
+               iounmap(virtual);
+}
+
+static int ttm_copy_io_page(void *dst, void *src, unsigned long page)
+{
+       uint32_t *dstP =
+           (uint32_t *) ((unsigned long)dst + (page << PAGE_SHIFT));
+       uint32_t *srcP =
+           (uint32_t *) ((unsigned long)src + (page << PAGE_SHIFT));
+
+       int i;
+       for (i = 0; i < PAGE_SIZE / sizeof(uint32_t); ++i)
+               iowrite32(ioread32(srcP++), dstP++);
+       return 0;
+}
+
+static int ttm_copy_io_ttm_page(struct ttm_tt *ttm, void *src,
+                               unsigned long page)
+{
+       struct page *d = ttm_tt_get_page(ttm, page);
+       void *dst;
+
+       if (!d)
+               return -ENOMEM;
+
+       src = (void *)((unsigned long)src + (page << PAGE_SHIFT));
+       dst = kmap(d);
+       if (!dst)
+               return -ENOMEM;
+
+       memcpy_fromio(dst, src, PAGE_SIZE);
+       kunmap(d);
+       return 0;
+}
+
+static int ttm_copy_ttm_io_page(struct ttm_tt *ttm, void *dst,
+                               unsigned long page)
+{
+       struct page *s = ttm_tt_get_page(ttm, page);
+       void *src;
+
+       if (!s)
+               return -ENOMEM;
+
+       dst = (void *)((unsigned long)dst + (page << PAGE_SHIFT));
+       src = kmap(s);
+       if (!src)
+               return -ENOMEM;
+
+       memcpy_toio(dst, src, PAGE_SIZE);
+       kunmap(s);
+       return 0;
+}
+
+int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,
+                      bool evict, bool no_wait, struct ttm_mem_reg *new_mem)
+{
+       struct ttm_bo_device *bdev = bo->bdev;
+       struct ttm_mem_type_manager *man = &bdev->man[new_mem->mem_type];
+       struct ttm_tt *ttm = bo->ttm;
+       struct ttm_mem_reg *old_mem = &bo->mem;
+       struct ttm_mem_reg old_copy = *old_mem;
+       void *old_iomap;
+       void *new_iomap;
+       int ret;
+       uint32_t save_flags = old_mem->placement;
+       unsigned long i;
+       unsigned long page;
+       unsigned long add = 0;
+       int dir;
+
+       ret = ttm_mem_reg_ioremap(bdev, old_mem, &old_iomap);
+       if (ret)
+               return ret;
+       ret = ttm_mem_reg_ioremap(bdev, new_mem, &new_iomap);
+       if (ret)
+               goto out;
+
+       if (old_iomap == NULL && new_iomap == NULL)
+               goto out2;
+       if (old_iomap == NULL && ttm == NULL)
+               goto out2;
+
+       add = 0;
+       dir = 1;
+
+       if ((old_mem->mem_type == new_mem->mem_type) &&
+           (new_mem->mm_node->start <
+            old_mem->mm_node->start + old_mem->mm_node->size)) {
+               dir = -1;
+               add = new_mem->num_pages - 1;
+       }
+
+       for (i = 0; i < new_mem->num_pages; ++i) {
+               page = i * dir + add;
+               if (old_iomap == NULL)
+                       ret = ttm_copy_ttm_io_page(ttm, new_iomap, page);
+               else if (new_iomap == NULL)
+                       ret = ttm_copy_io_ttm_page(ttm, old_iomap, page);
+               else
+                       ret = ttm_copy_io_page(new_iomap, old_iomap, page);
+               if (ret)
+                       goto out1;
+       }
+       mb();
+out2:
+       ttm_bo_free_old_node(bo);
+
+       *old_mem = *new_mem;
+       new_mem->mm_node = NULL;
+       ttm_flag_masked(&save_flags, new_mem->placement, TTM_PL_MASK_MEMTYPE);
+
+       if ((man->flags & TTM_MEMTYPE_FLAG_FIXED) && (ttm != NULL)) {
+               ttm_tt_unbind(ttm);
+               ttm_tt_destroy(ttm);
+               bo->ttm = NULL;
+       }
+
+out1:
+       ttm_mem_reg_iounmap(bdev, new_mem, new_iomap);
+out:
+       ttm_mem_reg_iounmap(bdev, &old_copy, old_iomap);
+       return ret;
+}
+EXPORT_SYMBOL(ttm_bo_move_memcpy);
+
+static void ttm_transfered_destroy(struct ttm_buffer_object *bo)
+{
+       kfree(bo);
+}
+
+/**
+ * ttm_buffer_object_transfer
+ *
+ * @bo: A pointer to a struct ttm_buffer_object.
+ * @new_obj: A pointer to a pointer to a newly created ttm_buffer_object,
+ * holding the data of @bo with the old placement.
+ *
+ * This is a utility function that may be called after an accelerated move
+ * has been scheduled. A new buffer object is created as a placeholder for
+ * the old data while it's being copied. When that buffer object is idle,
+ * it can be destroyed, releasing the space of the old placement.
+ * Returns:
+ * !0: Failure.
+ */
+
+static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo,
+                                     struct ttm_buffer_object **new_obj)
+{
+       struct ttm_buffer_object *fbo;
+       struct ttm_bo_device *bdev = bo->bdev;
+       struct ttm_bo_driver *driver = bdev->driver;
+
+       fbo = kzalloc(sizeof(*fbo), GFP_KERNEL);
+       if (!fbo)
+               return -ENOMEM;
+
+       *fbo = *bo;
+
+       /**
+        * Fix up members that we shouldn't copy directly:
+        * TODO: Explicit member copy would probably be better here.
+        */
+
+       spin_lock_init(&fbo->lock);
+       init_waitqueue_head(&fbo->event_queue);
+       INIT_LIST_HEAD(&fbo->ddestroy);
+       INIT_LIST_HEAD(&fbo->lru);
+       INIT_LIST_HEAD(&fbo->swap);
+       fbo->vm_node = NULL;
+
+       fbo->sync_obj = driver->sync_obj_ref(bo->sync_obj);
+       if (fbo->mem.mm_node)
+               fbo->mem.mm_node->private = (void *)fbo;
+       kref_init(&fbo->list_kref);
+       kref_init(&fbo->kref);
+       fbo->destroy = &ttm_transfered_destroy;
+
+       *new_obj = fbo;
+       return 0;
+}
+
+pgprot_t ttm_io_prot(uint32_t caching_flags, pgprot_t tmp)
+{
+#if defined(__i386__) || defined(__x86_64__)
+       if (caching_flags & TTM_PL_FLAG_WC)
+               tmp = pgprot_writecombine(tmp);
+       else if (boot_cpu_data.x86 > 3)
+               tmp = pgprot_noncached(tmp);
+
+#elif defined(__powerpc__)
+       if (!(caching_flags & TTM_PL_FLAG_CACHED)) {
+               pgprot_val(tmp) |= _PAGE_NO_CACHE;
+               if (caching_flags & TTM_PL_FLAG_UNCACHED)
+                       pgprot_val(tmp) |= _PAGE_GUARDED;
+       }
+#endif
+#if defined(__ia64__)
+       if (caching_flags & TTM_PL_FLAG_WC)
+               tmp = pgprot_writecombine(tmp);
+       else
+               tmp = pgprot_noncached(tmp);
+#endif
+#if defined(__sparc__)
+       if (!(caching_flags & TTM_PL_FLAG_CACHED))
+               tmp = pgprot_noncached(tmp);
+#endif
+       return tmp;
+}
+
+static int ttm_bo_ioremap(struct ttm_buffer_object *bo,
+                         unsigned long bus_base,
+                         unsigned long bus_offset,
+                         unsigned long bus_size,
+                         struct ttm_bo_kmap_obj *map)
+{
+       struct ttm_bo_device *bdev = bo->bdev;
+       struct ttm_mem_reg *mem = &bo->mem;
+       struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
+
+       if (!(man->flags & TTM_MEMTYPE_FLAG_NEEDS_IOREMAP)) {
+               map->bo_kmap_type = ttm_bo_map_premapped;
+               map->virtual = (void *)(((u8 *) man->io_addr) + bus_offset);
+       } else {
+               map->bo_kmap_type = ttm_bo_map_iomap;
+               if (mem->placement & TTM_PL_FLAG_WC)
+                       map->virtual = ioremap_wc(bus_base + bus_offset,
+                                                 bus_size);
+               else
+                       map->virtual = ioremap_nocache(bus_base + bus_offset,
+                                                      bus_size);
+       }
+       return (!map->virtual) ? -ENOMEM : 0;
+}
+
+static int ttm_bo_kmap_ttm(struct ttm_buffer_object *bo,
+                          unsigned long start_page,
+                          unsigned long num_pages,
+                          struct ttm_bo_kmap_obj *map)
+{
+       struct ttm_mem_reg *mem = &bo->mem; pgprot_t prot;
+       struct ttm_tt *ttm = bo->ttm;
+       struct page *d;
+       int i;
+
+       BUG_ON(!ttm);
+       if (num_pages == 1 && (mem->placement & TTM_PL_FLAG_CACHED)) {
+               /*
+                * We're mapping a single page, and the desired
+                * page protection is consistent with the bo.
+                */
+
+               map->bo_kmap_type = ttm_bo_map_kmap;
+               map->page = ttm_tt_get_page(ttm, start_page);
+               map->virtual = kmap(map->page);
+       } else {
+           /*
+            * Populate the part we're mapping;
+            */
+               for (i = start_page; i < start_page + num_pages; ++i) {
+                       d = ttm_tt_get_page(ttm, i);
+                       if (!d)
+                               return -ENOMEM;
+               }
+
+               /*
+                * We need to use vmap to get the desired page protection
+                * or to make the buffer object look contigous.
+                */
+               prot = (mem->placement & TTM_PL_FLAG_CACHED) ?
+                       PAGE_KERNEL :
+                       ttm_io_prot(mem->placement, PAGE_KERNEL);
+               map->bo_kmap_type = ttm_bo_map_vmap;
+               map->virtual = vmap(ttm->pages + start_page, num_pages,
+                                   0, prot);
+       }
+       return (!map->virtual) ? -ENOMEM : 0;
+}
+
+int ttm_bo_kmap(struct ttm_buffer_object *bo,
+               unsigned long start_page, unsigned long num_pages,
+               struct ttm_bo_kmap_obj *map)
+{
+       int ret;
+       unsigned long bus_base;
+       unsigned long bus_offset;
+       unsigned long bus_size;
+
+       BUG_ON(!list_empty(&bo->swap));
+       map->virtual = NULL;
+       if (num_pages > bo->num_pages)
+               return -EINVAL;
+       if (start_page > bo->num_pages)
+               return -EINVAL;
+#if 0
+       if (num_pages > 1 && !DRM_SUSER(DRM_CURPROC))
+               return -EPERM;
+#endif
+       ret = ttm_bo_pci_offset(bo->bdev, &bo->mem, &bus_base,
+                               &bus_offset, &bus_size);
+       if (ret)
+               return ret;
+       if (bus_size == 0) {
+               return ttm_bo_kmap_ttm(bo, start_page, num_pages, map);
+       } else {
+               bus_offset += start_page << PAGE_SHIFT;
+               bus_size = num_pages << PAGE_SHIFT;
+               return ttm_bo_ioremap(bo, bus_base, bus_offset, bus_size, map);
+       }
+}
+EXPORT_SYMBOL(ttm_bo_kmap);
+
+void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map)
+{
+       if (!map->virtual)
+               return;
+       switch (map->bo_kmap_type) {
+       case ttm_bo_map_iomap:
+               iounmap(map->virtual);
+               break;
+       case ttm_bo_map_vmap:
+               vunmap(map->virtual);
+               break;
+       case ttm_bo_map_kmap:
+               kunmap(map->page);
+               break;
+       case ttm_bo_map_premapped:
+               break;
+       default:
+               BUG();
+       }
+       map->virtual = NULL;
+       map->page = NULL;
+}
+EXPORT_SYMBOL(ttm_bo_kunmap);
+
+int ttm_bo_pfn_prot(struct ttm_buffer_object *bo,
+                   unsigned long dst_offset,
+                   unsigned long *pfn, pgprot_t *prot)
+{
+       struct ttm_mem_reg *mem = &bo->mem;
+       struct ttm_bo_device *bdev = bo->bdev;
+       unsigned long bus_offset;
+       unsigned long bus_size;
+       unsigned long bus_base;
+       int ret;
+       ret = ttm_bo_pci_offset(bdev, mem, &bus_base, &bus_offset,
+                       &bus_size);
+       if (ret)
+               return -EINVAL;
+       if (bus_size != 0)
+               *pfn = (bus_base + bus_offset + dst_offset) >> PAGE_SHIFT;
+       else
+               if (!bo->ttm)
+                       return -EINVAL;
+               else
+                       *pfn = page_to_pfn(ttm_tt_get_page(bo->ttm,
+                                                          dst_offset >>
+                                                          PAGE_SHIFT));
+       *prot = (mem->placement & TTM_PL_FLAG_CACHED) ?
+               PAGE_KERNEL : ttm_io_prot(mem->placement, PAGE_KERNEL);
+
+       return 0;
+}
+
+int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
+                             void *sync_obj,
+                             void *sync_obj_arg,
+                             bool evict, bool no_wait,
+                             struct ttm_mem_reg *new_mem)
+{
+       struct ttm_bo_device *bdev = bo->bdev;
+       struct ttm_bo_driver *driver = bdev->driver;
+       struct ttm_mem_type_manager *man = &bdev->man[new_mem->mem_type];
+       struct ttm_mem_reg *old_mem = &bo->mem;
+       int ret;
+       uint32_t save_flags = old_mem->placement;
+       struct ttm_buffer_object *ghost_obj;
+       void *tmp_obj = NULL;
+
+       spin_lock(&bo->lock);
+       if (bo->sync_obj) {
+               tmp_obj = bo->sync_obj;
+               bo->sync_obj = NULL;
+       }
+       bo->sync_obj = driver->sync_obj_ref(sync_obj);
+       bo->sync_obj_arg = sync_obj_arg;
+       if (evict) {
+               ret = ttm_bo_wait(bo, false, false, false);
+               spin_unlock(&bo->lock);
+               driver->sync_obj_unref(&bo->sync_obj);
+
+               if (ret)
+                       return ret;
+
+               ttm_bo_free_old_node(bo);
+               if ((man->flags & TTM_MEMTYPE_FLAG_FIXED) &&
+                   (bo->ttm != NULL)) {
+                       ttm_tt_unbind(bo->ttm);
+                       ttm_tt_destroy(bo->ttm);
+                       bo->ttm = NULL;
+               }
+       } else {
+               /**
+                * This should help pipeline ordinary buffer moves.
+                *
+                * Hang old buffer memory on a new buffer object,
+                * and leave it to be released when the GPU
+                * operation has completed.
+                */
+
+               set_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags);
+               spin_unlock(&bo->lock);
+
+               ret = ttm_buffer_object_transfer(bo, &ghost_obj);
+               if (ret)
+                       return ret;
+
+               /**
+                * If we're not moving to fixed memory, the TTM object
+                * needs to stay alive. Otherwhise hang it on the ghost
+                * bo to be unbound and destroyed.
+                */
+
+               if (!(man->flags & TTM_MEMTYPE_FLAG_FIXED))
+                       ghost_obj->ttm = NULL;
+               else
+                       bo->ttm = NULL;
+
+               ttm_bo_unreserve(ghost_obj);
+               ttm_bo_unref(&ghost_obj);
+       }
+
+       *old_mem = *new_mem;
+       new_mem->mm_node = NULL;
+       ttm_flag_masked(&save_flags, new_mem->placement, TTM_PL_MASK_MEMTYPE);
+       return 0;
+}
+EXPORT_SYMBOL(ttm_bo_move_accel_cleanup);
diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c
new file mode 100644 (file)
index 0000000..27b146c
--- /dev/null
@@ -0,0 +1,454 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+/*
+ * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
+ */
+
+#include <ttm/ttm_module.h>
+#include <ttm/ttm_bo_driver.h>
+#include <ttm/ttm_placement.h>
+#include <linux/mm.h>
+#include <linux/version.h>
+#include <linux/rbtree.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+
+#define TTM_BO_VM_NUM_PREFAULT 16
+
+static struct ttm_buffer_object *ttm_bo_vm_lookup_rb(struct ttm_bo_device *bdev,
+                                                    unsigned long page_start,
+                                                    unsigned long num_pages)
+{
+       struct rb_node *cur = bdev->addr_space_rb.rb_node;
+       unsigned long cur_offset;
+       struct ttm_buffer_object *bo;
+       struct ttm_buffer_object *best_bo = NULL;
+
+       while (likely(cur != NULL)) {
+               bo = rb_entry(cur, struct ttm_buffer_object, vm_rb);
+               cur_offset = bo->vm_node->start;
+               if (page_start >= cur_offset) {
+                       cur = cur->rb_right;
+                       best_bo = bo;
+                       if (page_start == cur_offset)
+                               break;
+               } else
+                       cur = cur->rb_left;
+       }
+
+       if (unlikely(best_bo == NULL))
+               return NULL;
+
+       if (unlikely((best_bo->vm_node->start + best_bo->num_pages) <
+                    (page_start + num_pages)))
+               return NULL;
+
+       return best_bo;
+}
+
+static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+       struct ttm_buffer_object *bo = (struct ttm_buffer_object *)
+           vma->vm_private_data;
+       struct ttm_bo_device *bdev = bo->bdev;
+       unsigned long bus_base;
+       unsigned long bus_offset;
+       unsigned long bus_size;
+       unsigned long page_offset;
+       unsigned long page_last;
+       unsigned long pfn;
+       struct ttm_tt *ttm = NULL;
+       struct page *page;
+       int ret;
+       int i;
+       bool is_iomem;
+       unsigned long address = (unsigned long)vmf->virtual_address;
+       int retval = VM_FAULT_NOPAGE;
+
+       /*
+        * Work around locking order reversal in fault / nopfn
+        * between mmap_sem and bo_reserve: Perform a trylock operation
+        * for reserve, and if it fails, retry the fault after scheduling.
+        */
+
+       ret = ttm_bo_reserve(bo, true, true, false, 0);
+       if (unlikely(ret != 0)) {
+               if (ret == -EBUSY)
+                       set_need_resched();
+               return VM_FAULT_NOPAGE;
+       }
+
+       /*
+        * Wait for buffer data in transit, due to a pipelined
+        * move.
+        */
+
+       spin_lock(&bo->lock);
+       if (test_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags)) {
+               ret = ttm_bo_wait(bo, false, true, false);
+               spin_unlock(&bo->lock);
+               if (unlikely(ret != 0)) {
+                       retval = (ret != -ERESTART) ?
+                           VM_FAULT_SIGBUS : VM_FAULT_NOPAGE;
+                       goto out_unlock;
+               }
+       } else
+               spin_unlock(&bo->lock);
+
+
+       ret = ttm_bo_pci_offset(bdev, &bo->mem, &bus_base, &bus_offset,
+                               &bus_size);
+       if (unlikely(ret != 0)) {
+               retval = VM_FAULT_SIGBUS;
+               goto out_unlock;
+       }
+
+       is_iomem = (bus_size != 0);
+
+       page_offset = ((address - vma->vm_start) >> PAGE_SHIFT) +
+           bo->vm_node->start - vma->vm_pgoff;
+       page_last = ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) +
+           bo->vm_node->start - vma->vm_pgoff;
+
+       if (unlikely(page_offset >= bo->num_pages)) {
+               retval = VM_FAULT_SIGBUS;
+               goto out_unlock;
+       }
+
+       /*
+        * Strictly, we're not allowed to modify vma->vm_page_prot here,
+        * since the mmap_sem is only held in read mode. However, we
+        * modify only the caching bits of vma->vm_page_prot and
+        * consider those bits protected by
+        * the bo->mutex, as we should be the only writers.
+        * There shouldn't really be any readers of these bits except
+        * within vm_insert_mixed()? fork?
+        *
+        * TODO: Add a list of vmas to the bo, and change the
+        * vma->vm_page_prot when the object changes caching policy, with
+        * the correct locks held.
+        */
+
+       if (is_iomem) {
+               vma->vm_page_prot = ttm_io_prot(bo->mem.placement,
+                                               vma->vm_page_prot);
+       } else {
+               ttm = bo->ttm;
+               vma->vm_page_prot = (bo->mem.placement & TTM_PL_FLAG_CACHED) ?
+                   vm_get_page_prot(vma->vm_flags) :
+                   ttm_io_prot(bo->mem.placement, vma->vm_page_prot);
+       }
+
+       /*
+        * Speculatively prefault a number of pages. Only error on
+        * first page.
+        */
+
+       for (i = 0; i < TTM_BO_VM_NUM_PREFAULT; ++i) {
+
+               if (is_iomem)
+                       pfn = ((bus_base + bus_offset) >> PAGE_SHIFT) +
+                           page_offset;
+               else {
+                       page = ttm_tt_get_page(ttm, page_offset);
+                       if (unlikely(!page && i == 0)) {
+                               retval = VM_FAULT_OOM;
+                               goto out_unlock;
+                       } else if (unlikely(!page)) {
+                               break;
+                       }
+                       pfn = page_to_pfn(page);
+               }
+
+               ret = vm_insert_mixed(vma, address, pfn);
+               /*
+                * Somebody beat us to this PTE or prefaulting to
+                * an already populated PTE, or prefaulting error.
+                */
+
+               if (unlikely((ret == -EBUSY) || (ret != 0 && i > 0)))
+                       break;
+               else if (unlikely(ret != 0)) {
+                       retval =
+                           (ret == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS;
+                       goto out_unlock;
+
+               }
+
+               address += PAGE_SIZE;
+               if (unlikely(++page_offset >= page_last))
+                       break;
+       }
+
+out_unlock:
+       ttm_bo_unreserve(bo);
+       return retval;
+}
+
+static void ttm_bo_vm_open(struct vm_area_struct *vma)
+{
+       struct ttm_buffer_object *bo =
+           (struct ttm_buffer_object *)vma->vm_private_data;
+
+       (void)ttm_bo_reference(bo);
+}
+
+static void ttm_bo_vm_close(struct vm_area_struct *vma)
+{
+       struct ttm_buffer_object *bo =
+           (struct ttm_buffer_object *)vma->vm_private_data;
+
+       ttm_bo_unref(&bo);
+       vma->vm_private_data = NULL;
+}
+
+static struct vm_operations_struct ttm_bo_vm_ops = {
+       .fault = ttm_bo_vm_fault,
+       .open = ttm_bo_vm_open,
+       .close = ttm_bo_vm_close
+};
+
+int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma,
+               struct ttm_bo_device *bdev)
+{
+       struct ttm_bo_driver *driver;
+       struct ttm_buffer_object *bo;
+       int ret;
+
+       read_lock(&bdev->vm_lock);
+       bo = ttm_bo_vm_lookup_rb(bdev, vma->vm_pgoff,
+                                (vma->vm_end - vma->vm_start) >> PAGE_SHIFT);
+       if (likely(bo != NULL))
+               ttm_bo_reference(bo);
+       read_unlock(&bdev->vm_lock);
+
+       if (unlikely(bo == NULL)) {
+               printk(KERN_ERR TTM_PFX
+                      "Could not find buffer object to map.\n");
+               return -EINVAL;
+       }
+
+       driver = bo->bdev->driver;
+       if (unlikely(!driver->verify_access)) {
+               ret = -EPERM;
+               goto out_unref;
+       }
+       ret = driver->verify_access(bo, filp);
+       if (unlikely(ret != 0))
+               goto out_unref;
+
+       vma->vm_ops = &ttm_bo_vm_ops;
+
+       /*
+        * Note: We're transferring the bo reference to
+        * vma->vm_private_data here.
+        */
+
+       vma->vm_private_data = bo;
+       vma->vm_flags |= VM_RESERVED | VM_IO | VM_MIXEDMAP | VM_DONTEXPAND;
+       return 0;
+out_unref:
+       ttm_bo_unref(&bo);
+       return ret;
+}
+EXPORT_SYMBOL(ttm_bo_mmap);
+
+int ttm_fbdev_mmap(struct vm_area_struct *vma, struct ttm_buffer_object *bo)
+{
+       if (vma->vm_pgoff != 0)
+               return -EACCES;
+
+       vma->vm_ops = &ttm_bo_vm_ops;
+       vma->vm_private_data = ttm_bo_reference(bo);
+       vma->vm_flags |= VM_RESERVED | VM_IO | VM_MIXEDMAP | VM_DONTEXPAND;
+       return 0;
+}
+EXPORT_SYMBOL(ttm_fbdev_mmap);
+
+
+ssize_t ttm_bo_io(struct ttm_bo_device *bdev, struct file *filp,
+                 const char __user *wbuf, char __user *rbuf, size_t count,
+                 loff_t *f_pos, bool write)
+{
+       struct ttm_buffer_object *bo;
+       struct ttm_bo_driver *driver;
+       struct ttm_bo_kmap_obj map;
+       unsigned long dev_offset = (*f_pos >> PAGE_SHIFT);
+       unsigned long kmap_offset;
+       unsigned long kmap_end;
+       unsigned long kmap_num;
+       size_t io_size;
+       unsigned int page_offset;
+       char *virtual;
+       int ret;
+       bool no_wait = false;
+       bool dummy;
+
+       read_lock(&bdev->vm_lock);
+       bo = ttm_bo_vm_lookup_rb(bdev, dev_offset, 1);
+       if (likely(bo != NULL))
+               ttm_bo_reference(bo);
+       read_unlock(&bdev->vm_lock);
+
+       if (unlikely(bo == NULL))
+               return -EFAULT;
+
+       driver = bo->bdev->driver;
+       if (unlikely(driver->verify_access)) {
+               ret = -EPERM;
+               goto out_unref;
+       }
+
+       ret = driver->verify_access(bo, filp);
+       if (unlikely(ret != 0))
+               goto out_unref;
+
+       kmap_offset = dev_offset - bo->vm_node->start;
+       if (unlikely(kmap_offset) >= bo->num_pages) {
+               ret = -EFBIG;
+               goto out_unref;
+       }
+
+       page_offset = *f_pos & ~PAGE_MASK;
+       io_size = bo->num_pages - kmap_offset;
+       io_size = (io_size << PAGE_SHIFT) - page_offset;
+       if (count < io_size)
+               io_size = count;
+
+       kmap_end = (*f_pos + count - 1) >> PAGE_SHIFT;
+       kmap_num = kmap_end - kmap_offset + 1;
+
+       ret = ttm_bo_reserve(bo, true, no_wait, false, 0);
+
+       switch (ret) {
+       case 0:
+               break;
+       case -ERESTART:
+               ret = -EINTR;
+               goto out_unref;
+       case -EBUSY:
+               ret = -EAGAIN;
+               goto out_unref;
+       default:
+               goto out_unref;
+       }
+
+       ret = ttm_bo_kmap(bo, kmap_offset, kmap_num, &map);
+       if (unlikely(ret != 0)) {
+               ttm_bo_unreserve(bo);
+               goto out_unref;
+       }
+
+       virtual = ttm_kmap_obj_virtual(&map, &dummy);
+       virtual += page_offset;
+
+       if (write)
+               ret = copy_from_user(virtual, wbuf, io_size);
+       else
+               ret = copy_to_user(rbuf, virtual, io_size);
+
+       ttm_bo_kunmap(&map);
+       ttm_bo_unreserve(bo);
+       ttm_bo_unref(&bo);
+
+       if (unlikely(ret != 0))
+               return -EFBIG;
+
+       *f_pos += io_size;
+
+       return io_size;
+out_unref:
+       ttm_bo_unref(&bo);
+       return ret;
+}
+
+ssize_t ttm_bo_fbdev_io(struct ttm_buffer_object *bo, const char __user *wbuf,
+                       char __user *rbuf, size_t count, loff_t *f_pos,
+                       bool write)
+{
+       struct ttm_bo_kmap_obj map;
+       unsigned long kmap_offset;
+       unsigned long kmap_end;
+       unsigned long kmap_num;
+       size_t io_size;
+       unsigned int page_offset;
+       char *virtual;
+       int ret;
+       bool no_wait = false;
+       bool dummy;
+
+       kmap_offset = (*f_pos >> PAGE_SHIFT);
+       if (unlikely(kmap_offset) >= bo->num_pages)
+               return -EFBIG;
+
+       page_offset = *f_pos & ~PAGE_MASK;
+       io_size = bo->num_pages - kmap_offset;
+       io_size = (io_size << PAGE_SHIFT) - page_offset;
+       if (count < io_size)
+               io_size = count;
+
+       kmap_end = (*f_pos + count - 1) >> PAGE_SHIFT;
+       kmap_num = kmap_end - kmap_offset + 1;
+
+       ret = ttm_bo_reserve(bo, true, no_wait, false, 0);
+
+       switch (ret) {
+       case 0:
+               break;
+       case -ERESTART:
+               return -EINTR;
+       case -EBUSY:
+               return -EAGAIN;
+       default:
+               return ret;
+       }
+
+       ret = ttm_bo_kmap(bo, kmap_offset, kmap_num, &map);
+       if (unlikely(ret != 0)) {
+               ttm_bo_unreserve(bo);
+               return ret;
+       }
+
+       virtual = ttm_kmap_obj_virtual(&map, &dummy);
+       virtual += page_offset;
+
+       if (write)
+               ret = copy_from_user(virtual, wbuf, io_size);
+       else
+               ret = copy_to_user(rbuf, virtual, io_size);
+
+       ttm_bo_kunmap(&map);
+       ttm_bo_unreserve(bo);
+       ttm_bo_unref(&bo);
+
+       if (unlikely(ret != 0))
+               return ret;
+
+       *f_pos += io_size;
+
+       return io_size;
+}
diff --git a/drivers/gpu/drm/ttm/ttm_global.c b/drivers/gpu/drm/ttm/ttm_global.c
new file mode 100644 (file)
index 0000000..0b14eb1
--- /dev/null
@@ -0,0 +1,114 @@
+/**************************************************************************
+ *
+ * Copyright 2008-2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+/*
+ * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
+ */
+
+#include "ttm/ttm_module.h"
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+struct ttm_global_item {
+       struct mutex mutex;
+       void *object;
+       int refcount;
+};
+
+static struct ttm_global_item glob[TTM_GLOBAL_NUM];
+
+void ttm_global_init(void)
+{
+       int i;
+
+       for (i = 0; i < TTM_GLOBAL_NUM; ++i) {
+               struct ttm_global_item *item = &glob[i];
+               mutex_init(&item->mutex);
+               item->object = NULL;
+               item->refcount = 0;
+       }
+}
+
+void ttm_global_release(void)
+{
+       int i;
+       for (i = 0; i < TTM_GLOBAL_NUM; ++i) {
+               struct ttm_global_item *item = &glob[i];
+               BUG_ON(item->object != NULL);
+               BUG_ON(item->refcount != 0);
+       }
+}
+
+int ttm_global_item_ref(struct ttm_global_reference *ref)
+{
+       int ret;
+       struct ttm_global_item *item = &glob[ref->global_type];
+       void *object;
+
+       mutex_lock(&item->mutex);
+       if (item->refcount == 0) {
+               item->object = kmalloc(ref->size, GFP_KERNEL);
+               if (unlikely(item->object == NULL)) {
+                       ret = -ENOMEM;
+                       goto out_err;
+               }
+
+               ref->object = item->object;
+               ret = ref->init(ref);
+               if (unlikely(ret != 0))
+                       goto out_err;
+
+               ++item->refcount;
+       }
+       ref->object = item->object;
+       object = item->object;
+       mutex_unlock(&item->mutex);
+       return 0;
+out_err:
+       kfree(item->object);
+       mutex_unlock(&item->mutex);
+       item->object = NULL;
+       return ret;
+}
+EXPORT_SYMBOL(ttm_global_item_ref);
+
+void ttm_global_item_unref(struct ttm_global_reference *ref)
+{
+       struct ttm_global_item *item = &glob[ref->global_type];
+
+       mutex_lock(&item->mutex);
+       BUG_ON(item->refcount == 0);
+       BUG_ON(ref->object != item->object);
+       if (--item->refcount == 0) {
+               ref->release(ref);
+               kfree(item->object);
+               item->object = NULL;
+       }
+       mutex_unlock(&item->mutex);
+}
+EXPORT_SYMBOL(ttm_global_item_unref);
+
diff --git a/drivers/gpu/drm/ttm/ttm_memory.c b/drivers/gpu/drm/ttm/ttm_memory.c
new file mode 100644 (file)
index 0000000..87323d4
--- /dev/null
@@ -0,0 +1,234 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "ttm/ttm_memory.h"
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+
+#define TTM_PFX "[TTM] "
+#define TTM_MEMORY_ALLOC_RETRIES 4
+
+/**
+ * At this point we only support a single shrink callback.
+ * Extend this if needed, perhaps using a linked list of callbacks.
+ * Note that this function is reentrant:
+ * many threads may try to swap out at any given time.
+ */
+
+static void ttm_shrink(struct ttm_mem_global *glob, bool from_workqueue,
+                      uint64_t extra)
+{
+       int ret;
+       struct ttm_mem_shrink *shrink;
+       uint64_t target;
+       uint64_t total_target;
+
+       spin_lock(&glob->lock);
+       if (glob->shrink == NULL)
+               goto out;
+
+       if (from_workqueue) {
+               target = glob->swap_limit;
+               total_target = glob->total_memory_swap_limit;
+       } else if (capable(CAP_SYS_ADMIN)) {
+               total_target = glob->emer_total_memory;
+               target = glob->emer_memory;
+       } else {
+               total_target = glob->max_total_memory;
+               target = glob->max_memory;
+       }
+
+       total_target = (extra >= total_target) ? 0 : total_target - extra;
+       target = (extra >= target) ? 0 : target - extra;
+
+       while (glob->used_memory > target ||
+              glob->used_total_memory > total_target) {
+               shrink = glob->shrink;
+               spin_unlock(&glob->lock);
+               ret = shrink->do_shrink(shrink);
+               spin_lock(&glob->lock);
+               if (unlikely(ret != 0))
+                       goto out;
+       }
+out:
+       spin_unlock(&glob->lock);
+}
+
+static void ttm_shrink_work(struct work_struct *work)
+{
+       struct ttm_mem_global *glob =
+           container_of(work, struct ttm_mem_global, work);
+
+       ttm_shrink(glob, true, 0ULL);
+}
+
+int ttm_mem_global_init(struct ttm_mem_global *glob)
+{
+       struct sysinfo si;
+       uint64_t mem;
+
+       spin_lock_init(&glob->lock);
+       glob->swap_queue = create_singlethread_workqueue("ttm_swap");
+       INIT_WORK(&glob->work, ttm_shrink_work);
+       init_waitqueue_head(&glob->queue);
+
+       si_meminfo(&si);
+
+       mem = si.totalram - si.totalhigh;
+       mem *= si.mem_unit;
+
+       glob->max_memory = mem >> 1;
+       glob->emer_memory = (mem >> 1) + (mem >> 2);
+       glob->swap_limit = glob->max_memory - (mem >> 3);
+       glob->used_memory = 0;
+       glob->used_total_memory = 0;
+       glob->shrink = NULL;
+
+       mem = si.totalram;
+       mem *= si.mem_unit;
+
+       glob->max_total_memory = mem >> 1;
+       glob->emer_total_memory = (mem >> 1) + (mem >> 2);
+
+       glob->total_memory_swap_limit = glob->max_total_memory - (mem >> 3);
+
+       printk(KERN_INFO TTM_PFX "TTM available graphics memory: %llu MiB\n",
+              glob->max_total_memory >> 20);
+       printk(KERN_INFO TTM_PFX "TTM available object memory: %llu MiB\n",
+              glob->max_memory >> 20);
+
+       return 0;
+}
+EXPORT_SYMBOL(ttm_mem_global_init);
+
+void ttm_mem_global_release(struct ttm_mem_global *glob)
+{
+       printk(KERN_INFO TTM_PFX "Used total memory is %llu bytes.\n",
+              (unsigned long long)glob->used_total_memory);
+       flush_workqueue(glob->swap_queue);
+       destroy_workqueue(glob->swap_queue);
+       glob->swap_queue = NULL;
+}
+EXPORT_SYMBOL(ttm_mem_global_release);
+
+static inline void ttm_check_swapping(struct ttm_mem_global *glob)
+{
+       bool needs_swapping;
+
+       spin_lock(&glob->lock);
+       needs_swapping = (glob->used_memory > glob->swap_limit ||
+                         glob->used_total_memory >
+                         glob->total_memory_swap_limit);
+       spin_unlock(&glob->lock);
+
+       if (unlikely(needs_swapping))
+               (void)queue_work(glob->swap_queue, &glob->work);
+
+}
+
+void ttm_mem_global_free(struct ttm_mem_global *glob,
+                        uint64_t amount, bool himem)
+{
+       spin_lock(&glob->lock);
+       glob->used_total_memory -= amount;
+       if (!himem)
+               glob->used_memory -= amount;
+       wake_up_all(&glob->queue);
+       spin_unlock(&glob->lock);
+}
+
+static int ttm_mem_global_reserve(struct ttm_mem_global *glob,
+                                 uint64_t amount, bool himem, bool reserve)
+{
+       uint64_t limit;
+       uint64_t lomem_limit;
+       int ret = -ENOMEM;
+
+       spin_lock(&glob->lock);
+
+       if (capable(CAP_SYS_ADMIN)) {
+               limit = glob->emer_total_memory;
+               lomem_limit = glob->emer_memory;
+       } else {
+               limit = glob->max_total_memory;
+               lomem_limit = glob->max_memory;
+       }
+
+       if (unlikely(glob->used_total_memory + amount > limit))
+               goto out_unlock;
+       if (unlikely(!himem && glob->used_memory + amount > lomem_limit))
+               goto out_unlock;
+
+       if (reserve) {
+               glob->used_total_memory += amount;
+               if (!himem)
+                       glob->used_memory += amount;
+       }
+       ret = 0;
+out_unlock:
+       spin_unlock(&glob->lock);
+       ttm_check_swapping(glob);
+
+       return ret;
+}
+
+int ttm_mem_global_alloc(struct ttm_mem_global *glob, uint64_t memory,
+                        bool no_wait, bool interruptible, bool himem)
+{
+       int count = TTM_MEMORY_ALLOC_RETRIES;
+
+       while (unlikely(ttm_mem_global_reserve(glob, memory, himem, true)
+                       != 0)) {
+               if (no_wait)
+                       return -ENOMEM;
+               if (unlikely(count-- == 0))
+                       return -ENOMEM;
+               ttm_shrink(glob, false, memory + (memory >> 2) + 16);
+       }
+
+       return 0;
+}
+
+size_t ttm_round_pot(size_t size)
+{
+       if ((size & (size - 1)) == 0)
+               return size;
+       else if (size > PAGE_SIZE)
+               return PAGE_ALIGN(size);
+       else {
+               size_t tmp_size = 4;
+
+               while (tmp_size < size)
+                       tmp_size <<= 1;
+
+               return tmp_size;
+       }
+       return 0;
+}
diff --git a/drivers/gpu/drm/ttm/ttm_module.c b/drivers/gpu/drm/ttm/ttm_module.c
new file mode 100644 (file)
index 0000000..59ce819
--- /dev/null
@@ -0,0 +1,50 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+/*
+ * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
+ *         Jerome Glisse
+ */
+#include <linux/module.h>
+#include <ttm/ttm_module.h>
+
+static int __init ttm_init(void)
+{
+       ttm_global_init();
+       return 0;
+}
+
+static void __exit ttm_exit(void)
+{
+       ttm_global_release();
+}
+
+module_init(ttm_init);
+module_exit(ttm_exit);
+
+MODULE_AUTHOR("Thomas Hellstrom, Jerome Glisse");
+MODULE_DESCRIPTION("TTM memory manager subsystem (for DRM device)");
+MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
new file mode 100644 (file)
index 0000000..c27ab3a
--- /dev/null
@@ -0,0 +1,635 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+/*
+ * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
+ */
+
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+#include <linux/sched.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/file.h>
+#include <linux/swap.h>
+#include "ttm/ttm_module.h"
+#include "ttm/ttm_bo_driver.h"
+#include "ttm/ttm_placement.h"
+
+static int ttm_tt_swapin(struct ttm_tt *ttm);
+
+#if defined(CONFIG_X86)
+static void ttm_tt_clflush_page(struct page *page)
+{
+       uint8_t *page_virtual;
+       unsigned int i;
+
+       if (unlikely(page == NULL))
+               return;
+
+       page_virtual = kmap_atomic(page, KM_USER0);
+
+       for (i = 0; i < PAGE_SIZE; i += boot_cpu_data.x86_clflush_size)
+               clflush(page_virtual + i);
+
+       kunmap_atomic(page_virtual, KM_USER0);
+}
+
+static void ttm_tt_cache_flush_clflush(struct page *pages[],
+                                      unsigned long num_pages)
+{
+       unsigned long i;
+
+       mb();
+       for (i = 0; i < num_pages; ++i)
+               ttm_tt_clflush_page(*pages++);
+       mb();
+}
+#else
+static void ttm_tt_ipi_handler(void *null)
+{
+       ;
+}
+#endif
+
+void ttm_tt_cache_flush(struct page *pages[], unsigned long num_pages)
+{
+
+#if defined(CONFIG_X86)
+       if (cpu_has_clflush) {
+               ttm_tt_cache_flush_clflush(pages, num_pages);
+               return;
+       }
+#else
+       if (on_each_cpu(ttm_tt_ipi_handler, NULL, 1) != 0)
+               printk(KERN_ERR TTM_PFX
+                      "Timed out waiting for drm cache flush.\n");
+#endif
+}
+
+/**
+ * Allocates storage for pointers to the pages that back the ttm.
+ *
+ * Uses kmalloc if possible. Otherwise falls back to vmalloc.
+ */
+static void ttm_tt_alloc_page_directory(struct ttm_tt *ttm)
+{
+       unsigned long size = ttm->num_pages * sizeof(*ttm->pages);
+       ttm->pages = NULL;
+
+       if (size <= PAGE_SIZE)
+               ttm->pages = kzalloc(size, GFP_KERNEL);
+
+       if (!ttm->pages) {
+               ttm->pages = vmalloc_user(size);
+               if (ttm->pages)
+                       ttm->page_flags |= TTM_PAGE_FLAG_VMALLOC;
+       }
+}
+
+static void ttm_tt_free_page_directory(struct ttm_tt *ttm)
+{
+       if (ttm->page_flags & TTM_PAGE_FLAG_VMALLOC) {
+               vfree(ttm->pages);
+               ttm->page_flags &= ~TTM_PAGE_FLAG_VMALLOC;
+       } else {
+               kfree(ttm->pages);
+       }
+       ttm->pages = NULL;
+}
+
+static struct page *ttm_tt_alloc_page(unsigned page_flags)
+{
+       if (page_flags & TTM_PAGE_FLAG_ZERO_ALLOC)
+               return alloc_page(GFP_HIGHUSER | __GFP_ZERO);
+
+       return alloc_page(GFP_HIGHUSER);
+}
+
+static void ttm_tt_free_user_pages(struct ttm_tt *ttm)
+{
+       int write;
+       int dirty;
+       struct page *page;
+       int i;
+       struct ttm_backend *be = ttm->be;
+
+       BUG_ON(!(ttm->page_flags & TTM_PAGE_FLAG_USER));
+       write = ((ttm->page_flags & TTM_PAGE_FLAG_WRITE) != 0);
+       dirty = ((ttm->page_flags & TTM_PAGE_FLAG_USER_DIRTY) != 0);
+
+       if (be)
+               be->func->clear(be);
+
+       for (i = 0; i < ttm->num_pages; ++i) {
+               page = ttm->pages[i];
+               if (page == NULL)
+                       continue;
+
+               if (page == ttm->dummy_read_page) {
+                       BUG_ON(write);
+                       continue;
+               }
+
+               if (write && dirty && !PageReserved(page))
+                       set_page_dirty_lock(page);
+
+               ttm->pages[i] = NULL;
+               ttm_mem_global_free(ttm->bdev->mem_glob, PAGE_SIZE, false);
+               put_page(page);
+       }
+       ttm->state = tt_unpopulated;
+       ttm->first_himem_page = ttm->num_pages;
+       ttm->last_lomem_page = -1;
+}
+
+static struct page *__ttm_tt_get_page(struct ttm_tt *ttm, int index)
+{
+       struct page *p;
+       struct ttm_bo_device *bdev = ttm->bdev;
+       struct ttm_mem_global *mem_glob = bdev->mem_glob;
+       int ret;
+
+       while (NULL == (p = ttm->pages[index])) {
+               p = ttm_tt_alloc_page(ttm->page_flags);
+
+               if (!p)
+                       return NULL;
+
+               if (PageHighMem(p)) {
+                       ret =
+                           ttm_mem_global_alloc(mem_glob, PAGE_SIZE,
+                                                false, false, true);
+                       if (unlikely(ret != 0))
+                               goto out_err;
+                       ttm->pages[--ttm->first_himem_page] = p;
+               } else {
+                       ret =
+                           ttm_mem_global_alloc(mem_glob, PAGE_SIZE,
+                                                false, false, false);
+                       if (unlikely(ret != 0))
+                               goto out_err;
+                       ttm->pages[++ttm->last_lomem_page] = p;
+               }
+       }
+       return p;
+out_err:
+       put_page(p);
+       return NULL;
+}
+
+struct page *ttm_tt_get_page(struct ttm_tt *ttm, int index)
+{
+       int ret;
+
+       if (unlikely(ttm->page_flags & TTM_PAGE_FLAG_SWAPPED)) {
+               ret = ttm_tt_swapin(ttm);
+               if (unlikely(ret != 0))
+                       return NULL;
+       }
+       return __ttm_tt_get_page(ttm, index);
+}
+
+int ttm_tt_populate(struct ttm_tt *ttm)
+{
+       struct page *page;
+       unsigned long i;
+       struct ttm_backend *be;
+       int ret;
+
+       if (ttm->state != tt_unpopulated)
+               return 0;
+
+       if (unlikely(ttm->page_flags & TTM_PAGE_FLAG_SWAPPED)) {
+               ret = ttm_tt_swapin(ttm);
+               if (unlikely(ret != 0))
+                       return ret;
+       }
+
+       be = ttm->be;
+
+       for (i = 0; i < ttm->num_pages; ++i) {
+               page = __ttm_tt_get_page(ttm, i);
+               if (!page)
+                       return -ENOMEM;
+       }
+
+       be->func->populate(be, ttm->num_pages, ttm->pages,
+                          ttm->dummy_read_page);
+       ttm->state = tt_unbound;
+       return 0;
+}
+
+#ifdef CONFIG_X86
+static inline int ttm_tt_set_page_caching(struct page *p,
+                                         enum ttm_caching_state c_state)
+{
+       if (PageHighMem(p))
+               return 0;
+
+       switch (c_state) {
+       case tt_cached:
+               return set_pages_wb(p, 1);
+       case tt_wc:
+           return set_memory_wc((unsigned long) page_address(p), 1);
+       default:
+               return set_pages_uc(p, 1);
+       }
+}
+#else /* CONFIG_X86 */
+static inline int ttm_tt_set_page_caching(struct page *p,
+                                         enum ttm_caching_state c_state)
+{
+       return 0;
+}
+#endif /* CONFIG_X86 */
+
+/*
+ * Change caching policy for the linear kernel map
+ * for range of pages in a ttm.
+ */
+
+static int ttm_tt_set_caching(struct ttm_tt *ttm,
+                             enum ttm_caching_state c_state)
+{
+       int i, j;
+       struct page *cur_page;
+       int ret;
+
+       if (ttm->caching_state == c_state)
+               return 0;
+
+       if (c_state != tt_cached) {
+               ret = ttm_tt_populate(ttm);
+               if (unlikely(ret != 0))
+                       return ret;
+       }
+
+       if (ttm->caching_state == tt_cached)
+               ttm_tt_cache_flush(ttm->pages, ttm->num_pages);
+
+       for (i = 0; i < ttm->num_pages; ++i) {
+               cur_page = ttm->pages[i];
+               if (likely(cur_page != NULL)) {
+                       ret = ttm_tt_set_page_caching(cur_page, c_state);
+                       if (unlikely(ret != 0))
+                               goto out_err;
+               }
+       }
+
+       ttm->caching_state = c_state;
+
+       return 0;
+
+out_err:
+       for (j = 0; j < i; ++j) {
+               cur_page = ttm->pages[j];
+               if (likely(cur_page != NULL)) {
+                       (void)ttm_tt_set_page_caching(cur_page,
+                                                     ttm->caching_state);
+               }
+       }
+
+       return ret;
+}
+
+int ttm_tt_set_placement_caching(struct ttm_tt *ttm, uint32_t placement)
+{
+       enum ttm_caching_state state;
+
+       if (placement & TTM_PL_FLAG_WC)
+               state = tt_wc;
+       else if (placement & TTM_PL_FLAG_UNCACHED)
+               state = tt_uncached;
+       else
+               state = tt_cached;
+
+       return ttm_tt_set_caching(ttm, state);
+}
+
+static void ttm_tt_free_alloced_pages(struct ttm_tt *ttm)
+{
+       int i;
+       struct page *cur_page;
+       struct ttm_backend *be = ttm->be;
+
+       if (be)
+               be->func->clear(be);
+       (void)ttm_tt_set_caching(ttm, tt_cached);
+       for (i = 0; i < ttm->num_pages; ++i) {
+               cur_page = ttm->pages[i];
+               ttm->pages[i] = NULL;
+               if (cur_page) {
+                       if (page_count(cur_page) != 1)
+                               printk(KERN_ERR TTM_PFX
+                                      "Erroneous page count. "
+                                      "Leaking pages.\n");
+                       ttm_mem_global_free(ttm->bdev->mem_glob, PAGE_SIZE,
+                                           PageHighMem(cur_page));
+                       __free_page(cur_page);
+               }
+       }
+       ttm->state = tt_unpopulated;
+       ttm->first_himem_page = ttm->num_pages;
+       ttm->last_lomem_page = -1;
+}
+
+void ttm_tt_destroy(struct ttm_tt *ttm)
+{
+       struct ttm_backend *be;
+
+       if (unlikely(ttm == NULL))
+               return;
+
+       be = ttm->be;
+       if (likely(be != NULL)) {
+               be->func->destroy(be);
+               ttm->be = NULL;
+       }
+
+       if (likely(ttm->pages != NULL)) {
+               if (ttm->page_flags & TTM_PAGE_FLAG_USER)
+                       ttm_tt_free_user_pages(ttm);
+               else
+                       ttm_tt_free_alloced_pages(ttm);
+
+               ttm_tt_free_page_directory(ttm);
+       }
+
+       if (!(ttm->page_flags & TTM_PAGE_FLAG_PERSISTANT_SWAP) &&
+           ttm->swap_storage)
+               fput(ttm->swap_storage);
+
+       kfree(ttm);
+}
+
+int ttm_tt_set_user(struct ttm_tt *ttm,
+                   struct task_struct *tsk,
+                   unsigned long start, unsigned long num_pages)
+{
+       struct mm_struct *mm = tsk->mm;
+       int ret;
+       int write = (ttm->page_flags & TTM_PAGE_FLAG_WRITE) != 0;
+       struct ttm_mem_global *mem_glob = ttm->bdev->mem_glob;
+
+       BUG_ON(num_pages != ttm->num_pages);
+       BUG_ON((ttm->page_flags & TTM_PAGE_FLAG_USER) == 0);
+
+       /**
+        * Account user pages as lowmem pages for now.
+        */
+
+       ret = ttm_mem_global_alloc(mem_glob, num_pages * PAGE_SIZE,
+                                  false, false, false);
+       if (unlikely(ret != 0))
+               return ret;
+
+       down_read(&mm->mmap_sem);
+       ret = get_user_pages(tsk, mm, start, num_pages,
+                            write, 0, ttm->pages, NULL);
+       up_read(&mm->mmap_sem);
+
+       if (ret != num_pages && write) {
+               ttm_tt_free_user_pages(ttm);
+               ttm_mem_global_free(mem_glob, num_pages * PAGE_SIZE, false);
+               return -ENOMEM;
+       }
+
+       ttm->tsk = tsk;
+       ttm->start = start;
+       ttm->state = tt_unbound;
+
+       return 0;
+}
+
+struct ttm_tt *ttm_tt_create(struct ttm_bo_device *bdev, unsigned long size,
+                            uint32_t page_flags, struct page *dummy_read_page)
+{
+       struct ttm_bo_driver *bo_driver = bdev->driver;
+       struct ttm_tt *ttm;
+
+       if (!bo_driver)
+               return NULL;
+
+       ttm = kzalloc(sizeof(*ttm), GFP_KERNEL);
+       if (!ttm)
+               return NULL;
+
+       ttm->bdev = bdev;
+
+       ttm->num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       ttm->first_himem_page = ttm->num_pages;
+       ttm->last_lomem_page = -1;
+       ttm->caching_state = tt_cached;
+       ttm->page_flags = page_flags;
+
+       ttm->dummy_read_page = dummy_read_page;
+
+       ttm_tt_alloc_page_directory(ttm);
+       if (!ttm->pages) {
+               ttm_tt_destroy(ttm);
+               printk(KERN_ERR TTM_PFX "Failed allocating page table\n");
+               return NULL;
+       }
+       ttm->be = bo_driver->create_ttm_backend_entry(bdev);
+       if (!ttm->be) {
+               ttm_tt_destroy(ttm);
+               printk(KERN_ERR TTM_PFX "Failed creating ttm backend entry\n");
+               return NULL;
+       }
+       ttm->state = tt_unpopulated;
+       return ttm;
+}
+
+void ttm_tt_unbind(struct ttm_tt *ttm)
+{
+       int ret;
+       struct ttm_backend *be = ttm->be;
+
+       if (ttm->state == tt_bound) {
+               ret = be->func->unbind(be);
+               BUG_ON(ret);
+               ttm->state = tt_unbound;
+       }
+}
+
+int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem)
+{
+       int ret = 0;
+       struct ttm_backend *be;
+
+       if (!ttm)
+               return -EINVAL;
+
+       if (ttm->state == tt_bound)
+               return 0;
+
+       be = ttm->be;
+
+       ret = ttm_tt_populate(ttm);
+       if (ret)
+               return ret;
+
+       ret = be->func->bind(be, bo_mem);
+       if (ret) {
+               printk(KERN_ERR TTM_PFX "Couldn't bind backend.\n");
+               return ret;
+       }
+
+       ttm->state = tt_bound;
+
+       if (ttm->page_flags & TTM_PAGE_FLAG_USER)
+               ttm->page_flags |= TTM_PAGE_FLAG_USER_DIRTY;
+       return 0;
+}
+EXPORT_SYMBOL(ttm_tt_bind);
+
+static int ttm_tt_swapin(struct ttm_tt *ttm)
+{
+       struct address_space *swap_space;
+       struct file *swap_storage;
+       struct page *from_page;
+       struct page *to_page;
+       void *from_virtual;
+       void *to_virtual;
+       int i;
+       int ret;
+
+       if (ttm->page_flags & TTM_PAGE_FLAG_USER) {
+               ret = ttm_tt_set_user(ttm, ttm->tsk, ttm->start,
+                                     ttm->num_pages);
+               if (unlikely(ret != 0))
+                       return ret;
+
+               ttm->page_flags &= ~TTM_PAGE_FLAG_SWAPPED;
+               return 0;
+       }
+
+       swap_storage = ttm->swap_storage;
+       BUG_ON(swap_storage == NULL);
+
+       swap_space = swap_storage->f_path.dentry->d_inode->i_mapping;
+
+       for (i = 0; i < ttm->num_pages; ++i) {
+               from_page = read_mapping_page(swap_space, i, NULL);
+               if (IS_ERR(from_page))
+                       goto out_err;
+               to_page = __ttm_tt_get_page(ttm, i);
+               if (unlikely(to_page == NULL))
+                       goto out_err;
+
+               preempt_disable();
+               from_virtual = kmap_atomic(from_page, KM_USER0);
+               to_virtual = kmap_atomic(to_page, KM_USER1);
+               memcpy(to_virtual, from_virtual, PAGE_SIZE);
+               kunmap_atomic(to_virtual, KM_USER1);
+               kunmap_atomic(from_virtual, KM_USER0);
+               preempt_enable();
+               page_cache_release(from_page);
+       }
+
+       if (!(ttm->page_flags & TTM_PAGE_FLAG_PERSISTANT_SWAP))
+               fput(swap_storage);
+       ttm->swap_storage = NULL;
+       ttm->page_flags &= ~TTM_PAGE_FLAG_SWAPPED;
+
+       return 0;
+out_err:
+       ttm_tt_free_alloced_pages(ttm);
+       return -ENOMEM;
+}
+
+int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistant_swap_storage)
+{
+       struct address_space *swap_space;
+       struct file *swap_storage;
+       struct page *from_page;
+       struct page *to_page;
+       void *from_virtual;
+       void *to_virtual;
+       int i;
+
+       BUG_ON(ttm->state != tt_unbound && ttm->state != tt_unpopulated);
+       BUG_ON(ttm->caching_state != tt_cached);
+
+       /*
+        * For user buffers, just unpin the pages, as there should be
+        * vma references.
+        */
+
+       if (ttm->page_flags & TTM_PAGE_FLAG_USER) {
+               ttm_tt_free_user_pages(ttm);
+               ttm->page_flags |= TTM_PAGE_FLAG_SWAPPED;
+               ttm->swap_storage = NULL;
+               return 0;
+       }
+
+       if (!persistant_swap_storage) {
+               swap_storage = shmem_file_setup("ttm swap",
+                                               ttm->num_pages << PAGE_SHIFT,
+                                               0);
+               if (unlikely(IS_ERR(swap_storage))) {
+                       printk(KERN_ERR "Failed allocating swap storage.\n");
+                       return -ENOMEM;
+               }
+       } else
+               swap_storage = persistant_swap_storage;
+
+       swap_space = swap_storage->f_path.dentry->d_inode->i_mapping;
+
+       for (i = 0; i < ttm->num_pages; ++i) {
+               from_page = ttm->pages[i];
+               if (unlikely(from_page == NULL))
+                       continue;
+               to_page = read_mapping_page(swap_space, i, NULL);
+               if (unlikely(to_page == NULL))
+                       goto out_err;
+
+               preempt_disable();
+               from_virtual = kmap_atomic(from_page, KM_USER0);
+               to_virtual = kmap_atomic(to_page, KM_USER1);
+               memcpy(to_virtual, from_virtual, PAGE_SIZE);
+               kunmap_atomic(to_virtual, KM_USER1);
+               kunmap_atomic(from_virtual, KM_USER0);
+               preempt_enable();
+               set_page_dirty(to_page);
+               mark_page_accessed(to_page);
+               page_cache_release(to_page);
+       }
+
+       ttm_tt_free_alloced_pages(ttm);
+       ttm->swap_storage = swap_storage;
+       ttm->page_flags |= TTM_PAGE_FLAG_SWAPPED;
+       if (persistant_swap_storage)
+               ttm->page_flags |= TTM_PAGE_FLAG_PERSISTANT_SWAP;
+
+       return 0;
+out_err:
+       if (!persistant_swap_storage)
+               fput(swap_storage);
+
+       return -ENOMEM;
+}
index e9b436d2d94434c17fb1030d50528341edd71659..9e9421525fb9125fa962c2266550f67545855b39 100644 (file)
@@ -850,8 +850,14 @@ static const struct file_operations hiddev_fops = {
 #endif
 };
 
+static char *hiddev_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev));
+}
+
 static struct usb_class_driver hiddev_class = {
        .name =         "hiddev%d",
+       .nodename =     hiddev_nodename,
        .fops =         &hiddev_fops,
        .minor_base =   HIDDEV_MINOR_BASE,
 };
@@ -955,7 +961,6 @@ static int hiddev_usbd_probe(struct usb_interface *intf,
        return -ENODEV;
 }
 
-
 static /* const */ struct usb_driver hiddev_driver = {
        .name =         "hiddev",
        .probe =        hiddev_usbd_probe,
index d73f5f473e38e09cd92ca4f339b8f3c893de440a..2d5016691d400b9c3d545401d83918e8589ece8b 100644 (file)
@@ -306,11 +306,11 @@ config SENSORS_F71805F
          will be called f71805f.
 
 config SENSORS_F71882FG
-       tristate "Fintek F71862FG, F71882FG and F8000"
+       tristate "Fintek F71858FG, F71862FG, F71882FG and F8000"
        depends on EXPERIMENTAL
        help
          If you say yes here you get support for hardware monitoring
-         features of the Fintek F71882FG/F71883FG, F71862FG/71863FG
+         features of the Fintek F71858FG, F71862FG/71863FG, F71882FG/F71883FG
          and F8000 Super-I/O chips.
 
          This driver can also be built as a module.  If so, the module
@@ -418,7 +418,7 @@ config SENSORS_IBMAEM
          power sensors and capping hardware in various IBM System X
          servers that support Active Energy Manager.  This includes
          the x3350, x3550, x3650, x3655, x3755, x3850 M2, x3950 M2,
-         and certain HS2x/LS2x/QS2x blades.
+         and certain HC10/HS2x/LS2x/QS2x blades.
 
          This driver can also be built as a module.  If so, the module
          will be called ibmaem.
@@ -787,6 +787,16 @@ config SENSORS_THMC50
          This driver can also be built as a module.  If so, the module
          will be called thmc50.
 
+config SENSORS_TMP401
+       tristate "Texas Instruments TMP401 and compatibles"
+       depends on I2C && EXPERIMENTAL
+       help
+         If you say yes here you get support for Texas Instruments TMP401 and
+         TMP411 temperature sensor chips.
+
+         This driver can also be built as a module.  If so, the module
+         will be called tmp401.
+
 config SENSORS_VIA686A
        tristate "VIA686A"
        depends on PCI
@@ -940,6 +950,7 @@ config SENSORS_HDAPS
 config SENSORS_LIS3LV02D
        tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer"
        depends on ACPI && INPUT
+       select INPUT_POLLDEV
        select NEW_LEDS
        select LEDS_CLASS
        default n
@@ -967,6 +978,7 @@ config SENSORS_LIS3LV02D
 config SENSORS_LIS3_SPI
        tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)"
        depends on !ACPI && SPI_MASTER && INPUT
+       select INPUT_POLLDEV
        default n
        help
          This driver provides support for the LIS3LV02Dx accelerometer connected
index 0ae26984ba45b8727deb435f4289ccc71542b3a6..b793dce6bed5b7521ecc929375c51654ea7ca48d 100644 (file)
@@ -82,6 +82,7 @@ obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
 obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
 obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
 obj-$(CONFIG_SENSORS_THMC50)   += thmc50.o
+obj-$(CONFIG_SENSORS_TMP401)   += tmp401.o
 obj-$(CONFIG_SENSORS_VIA686A)  += via686a.o
 obj-$(CONFIG_SENSORS_VT1211)   += vt1211.o
 obj-$(CONFIG_SENSORS_VT8231)   += vt8231.o
index 5f81ddf7150871e67c7fe3ff1647df7e01c6c2c5..4146105f1a5779a5de55006444b9de99e90e8319 100644 (file)
@@ -1,6 +1,6 @@
 /***************************************************************************
  *   Copyright (C) 2006 by Hans Edgington <hans@edgington.nl>              *
- *   Copyright (C) 2007,2008 by Hans de Goede <hdegoede@redhat.com>        *
+ *   Copyright (C) 2007-2009 Hans de Goede <hdegoede@redhat.com>           *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   it under the terms of the GNU General Public License as published by  *
@@ -32,6 +32,7 @@
 
 #define DRVNAME "f71882fg"
 
+#define SIO_F71858FG_LD_HWM    0x02    /* Hardware monitor logical device */
 #define SIO_F71882FG_LD_HWM    0x04    /* Hardware monitor logical device */
 #define SIO_UNLOCK_KEY         0x87    /* Key to enable Super-I/O */
 #define SIO_LOCK_KEY           0xAA    /* Key to diasble Super-I/O */
@@ -44,6 +45,7 @@
 #define SIO_REG_ADDR           0x60    /* Logical device address (2 bytes) */
 
 #define SIO_FINTEK_ID          0x1934  /* Manufacturers ID */
+#define SIO_F71858_ID          0x0507  /* Chipset ID */
 #define SIO_F71862_ID          0x0601  /* Chipset ID */
 #define SIO_F71882_ID          0x0541  /* Chipset ID */
 #define SIO_F8000_ID           0x0581  /* Chipset ID */
@@ -70,6 +72,7 @@
 #define F71882FG_REG_TEMP_HIGH(nr)     (0x81 + 2 * (nr))
 #define F71882FG_REG_TEMP_STATUS       0x62
 #define F71882FG_REG_TEMP_BEEP         0x63
+#define F71882FG_REG_TEMP_CONFIG       0x69
 #define F71882FG_REG_TEMP_HYST(nr)     (0x6C + (nr))
 #define F71882FG_REG_TEMP_TYPE         0x6B
 #define F71882FG_REG_TEMP_DIODE_OPEN   0x6F
@@ -92,9 +95,10 @@ static unsigned short force_id;
 module_param(force_id, ushort, 0);
 MODULE_PARM_DESC(force_id, "Override the detected device ID");
 
-enum chips { f71862fg, f71882fg, f8000 };
+enum chips { f71858fg, f71862fg, f71882fg, f8000 };
 
 static const char *f71882fg_names[] = {
+       "f71858fg",
        "f71862fg",
        "f71882fg",
        "f8000",
@@ -119,6 +123,7 @@ struct f71882fg_data {
        struct device *hwmon_dev;
 
        struct mutex update_lock;
+       int temp_start;                 /* temp numbering start (0 or 1) */
        char valid;                     /* !=0 if following fields are valid */
        unsigned long last_updated;     /* In jiffies */
        unsigned long last_limits;      /* In jiffies */
@@ -136,7 +141,7 @@ struct f71882fg_data {
        /* Note: all models have only 3 temperature channels, but on some
           they are addressed as 0-2 and on others as 1-3, so for coding
           convenience we reserve space for 4 channels */
-       u     temp[4];
+       u16     temp[4];
        u8      temp_ovt[4];
        u8      temp_high[4];
        u8      temp_hyst[2]; /* 2 hysts stored per reg */
@@ -144,6 +149,7 @@ struct f71882fg_data {
        u8      temp_status;
        u8      temp_beep;
        u8      temp_diode_open;
+       u8      temp_config;
        u8      pwm[4];
        u8      pwm_enable;
        u8      pwm_auto_point_hyst[2];
@@ -247,11 +253,55 @@ static struct platform_driver f71882fg_driver = {
                .name   = DRVNAME,
        },
        .probe          = f71882fg_probe,
-       .remove         = __devexit_p(f71882fg_remove),
+       .remove         = f71882fg_remove,
 };
 
 static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 
+/* Temp and in attr for the f71858fg */
+static struct sensor_device_attribute_2 f71858fg_in_temp_attr[] = {
+       SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
+       SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1),
+       SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2),
+       SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0),
+       SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max,
+               store_temp_max, 0, 0),
+       SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+               store_temp_max_hyst, 0, 0),
+       SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0),
+       SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+               store_temp_crit, 0, 0),
+       SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
+               0, 0),
+       SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
+       SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
+       SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
+       SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max,
+               store_temp_max, 0, 1),
+       SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+               store_temp_max_hyst, 0, 1),
+       SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1),
+       SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+               store_temp_crit, 0, 1),
+       SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
+               0, 1),
+       SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
+       SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
+       SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
+       SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
+       SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max,
+               store_temp_max, 0, 2),
+       SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst,
+               store_temp_max_hyst, 0, 2),
+       SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2),
+       SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit,
+               store_temp_crit, 0, 2),
+       SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL,
+               0, 2),
+       SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
+       SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
+};
+
 /* Temp and in attr common to both the f71862fg and f71882fg */
 static struct sensor_device_attribute_2 f718x2fg_in_temp_attr[] = {
        SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0),
@@ -344,6 +394,7 @@ static struct sensor_device_attribute_2 f8000_in_temp_attr[] = {
        SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
                store_temp_max, 0, 0),
        SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4),
+       SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0),
        SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1),
        SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit,
                store_temp_crit, 0, 1),
@@ -351,12 +402,14 @@ static struct sensor_device_attribute_2 f8000_in_temp_attr[] = {
                store_temp_max, 0, 1),
        SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5),
        SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1),
+       SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1),
        SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2),
        SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit,
                store_temp_crit, 0, 2),
        SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max,
                store_temp_max, 0, 2),
        SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6),
+       SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2),
 };
 
 /* Fan / PWM attr common to all models */
@@ -395,6 +448,9 @@ static struct sensor_device_attribute_2 fxxxx_fan_attr[] = {
                      show_pwm_auto_point_channel,
                      store_pwm_auto_point_channel, 0, 1),
 
+       SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
+       SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
+                     store_pwm_enable, 0, 2),
        SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR,
                      show_pwm_interpolate, store_pwm_interpolate, 0, 2),
        SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR,
@@ -450,9 +506,6 @@ static struct sensor_device_attribute_2 f71862fg_fan_attr[] = {
        SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO,
                      show_pwm_auto_point_temp_hyst, NULL, 3, 1),
 
-       SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
-       SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
-                     store_pwm_enable, 0, 2),
        SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
                      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
                      1, 2),
@@ -473,22 +526,8 @@ static struct sensor_device_attribute_2 f71862fg_fan_attr[] = {
                      show_pwm_auto_point_temp_hyst, NULL, 3, 2),
 };
 
-/* Fan / PWM attr for the f71882fg */
-static struct sensor_device_attribute_2 f71882fg_fan_attr[] = {
-       SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
-               store_fan_beep, 0, 0),
-       SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
-               store_fan_beep, 0, 1),
-       SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
-               store_fan_beep, 0, 2),
-       SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
-       SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
-                     show_fan_full_speed,
-                     store_fan_full_speed, 0, 3),
-       SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
-               store_fan_beep, 0, 3),
-       SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
-
+/* Fan / PWM attr common to both the f71882fg and f71858fg */
+static struct sensor_device_attribute_2 f71882fg_f71858fg_fan_attr[] = {
        SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR,
                      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
                      0, 0),
@@ -565,9 +604,6 @@ static struct sensor_device_attribute_2 f71882fg_fan_attr[] = {
        SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO,
                      show_pwm_auto_point_temp_hyst, NULL, 3, 1),
 
-       SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2),
-       SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
-                     store_pwm_enable, 0, 2),
        SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR,
                      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
                      0, 2),
@@ -605,6 +641,24 @@ static struct sensor_device_attribute_2 f71882fg_fan_attr[] = {
                      show_pwm_auto_point_temp_hyst, NULL, 2, 2),
        SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO,
                      show_pwm_auto_point_temp_hyst, NULL, 3, 2),
+};
+
+/* Fan / PWM attr found on the f71882fg but not on the f71858fg */
+static struct sensor_device_attribute_2 f71882fg_fan_attr[] = {
+       SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+               store_fan_beep, 0, 0),
+       SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+               store_fan_beep, 0, 1),
+       SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+               store_fan_beep, 0, 2),
+
+       SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
+       SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR,
+                     show_fan_full_speed,
+                     store_fan_full_speed, 0, 3),
+       SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep,
+               store_fan_beep, 0, 3),
+       SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3),
 
        SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3),
        SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable,
@@ -659,8 +713,6 @@ static struct sensor_device_attribute_2 f71882fg_fan_attr[] = {
 static struct sensor_device_attribute_2 f8000_fan_attr[] = {
        SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3),
 
-       SENSOR_ATTR_2(pwm3, S_IRUGO, show_pwm, NULL, 0, 2),
-
        SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR,
                      show_pwm_auto_point_pwm, store_pwm_auto_point_pwm,
                      0, 2),
@@ -857,13 +909,20 @@ static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val)
        outb(val & 255, data->addr + DATA_REG_OFFSET);
 }
 
+static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr)
+{
+       if (data->type == f71858fg)
+               return f71882fg_read16(data, F71882FG_REG_TEMP(nr));
+       else
+               return f71882fg_read8(data, F71882FG_REG_TEMP(nr));
+}
+
 static struct f71882fg_data *f71882fg_update_device(struct device *dev)
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
        int nr, reg = 0, reg2;
        int nr_fans = (data->type == f71882fg) ? 4 : 3;
-       int nr_ins = (data->type == f8000) ? 3 : 9;
-       int temp_start = (data->type == f8000) ? 0 : 1;
+       int nr_ins = (data->type == f71858fg || data->type == f8000) ? 3 : 9;
 
        mutex_lock(&data->update_lock);
 
@@ -878,7 +937,7 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
                }
 
                /* Get High & boundary temps*/
-               for (nr = temp_start; nr < 3 + temp_start; nr++) {
+               for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) {
                        data->temp_ovt[nr] = f71882fg_read8(data,
                                                F71882FG_REG_TEMP_OVT(nr));
                        data->temp_high[nr] = f71882fg_read8(data,
@@ -886,14 +945,17 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
                }
 
                if (data->type != f8000) {
-                       data->fan_beep = f71882fg_read8(data,
-                                               F71882FG_REG_FAN_BEEP);
-                       data->temp_beep = f71882fg_read8(data,
-                                               F71882FG_REG_TEMP_BEEP);
                        data->temp_hyst[0] = f71882fg_read8(data,
                                                F71882FG_REG_TEMP_HYST(0));
                        data->temp_hyst[1] = f71882fg_read8(data,
                                                F71882FG_REG_TEMP_HYST(1));
+               }
+
+               if (data->type == f71862fg || data->type == f71882fg) {
+                       data->fan_beep = f71882fg_read8(data,
+                                               F71882FG_REG_FAN_BEEP);
+                       data->temp_beep = f71882fg_read8(data,
+                                               F71882FG_REG_TEMP_BEEP);
                        /* Have to hardcode type, because temp1 is special */
                        reg  = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE);
                        data->temp_type[2] = (reg & 0x04) ? 2 : 4;
@@ -904,10 +966,10 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
                        data->temp_type[1] = 6 /* PECI */;
                else if ((reg2 & 0x03) == 0x02)
                        data->temp_type[1] = 5 /* AMDSI */;
-               else if (data->type != f8000)
+               else if (data->type == f71862fg || data->type == f71882fg)
                        data->temp_type[1] = (reg & 0x02) ? 2 : 4;
                else
-                       data->temp_type[1] = 2; /* F8000 only supports BJT */
+                       data->temp_type[1] = 2; /* Only supports BJT */
 
                data->pwm_enable = f71882fg_read8(data,
                                                  F71882FG_REG_PWM_ENABLE);
@@ -963,9 +1025,8 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
                                                F71882FG_REG_TEMP_STATUS);
                data->temp_diode_open = f71882fg_read8(data,
                                                F71882FG_REG_TEMP_DIODE_OPEN);
-               for (nr = temp_start; nr < 3 + temp_start; nr++)
-                       data->temp[nr] = f71882fg_read8(data,
-                                               F71882FG_REG_TEMP(nr));
+               for (nr = data->temp_start; nr < 3 + data->temp_start; nr++)
+                       data->temp[nr] = f71882fg_read_temp(data, nr);
 
                data->fan_status = f71882fg_read8(data,
                                                F71882FG_REG_FAN_STATUS);
@@ -1168,8 +1229,24 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
 {
        struct f71882fg_data *data = f71882fg_update_device(dev);
        int nr = to_sensor_dev_attr_2(devattr)->index;
+       int sign, temp;
+
+       if (data->type == f71858fg) {
+               /* TEMP_TABLE_SEL 1 or 3 ? */
+               if (data->temp_config & 1) {
+                       sign = data->temp[nr] & 0x0001;
+                       temp = (data->temp[nr] >> 5) & 0x7ff;
+               } else {
+                       sign = data->temp[nr] & 0x8000;
+                       temp = (data->temp[nr] >> 5) & 0x3ff;
+               }
+               temp *= 125;
+               if (sign)
+                       temp -= 128000;
+       } else
+               temp = data->temp[nr] * 1000;
 
-       return sprintf(buf, "%d\n", data->temp[nr] * 1000);
+       return sprintf(buf, "%d\n", temp);
 }
 
 static ssize_t show_temp_max(struct device *dev, struct device_attribute
@@ -1440,6 +1517,10 @@ static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
        int nr = to_sensor_dev_attr_2(devattr)->index;
        long val = simple_strtol(buf, NULL, 10);
 
+       /* Special case for F8000 pwm channel 3 which only does auto mode */
+       if (data->type == f8000 && nr == 2 && val != 2)
+               return -EINVAL;
+
        mutex_lock(&data->update_lock);
        data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
        /* Special case for F8000 auto PWM mode / Thermostat mode */
@@ -1458,6 +1539,12 @@ static ssize_t store_pwm_enable(struct device *dev, struct device_attribute
        } else {
                switch (val) {
                case 1:
+                       /* The f71858fg does not support manual RPM mode */
+                       if (data->type == f71858fg &&
+                           ((data->pwm_enable >> (2 * nr)) & 1)) {
+                               count = -EINVAL;
+                               goto leave;
+                       }
                        data->pwm_enable |= 2 << (2 * nr);
                        break;          /* Manual */
                case 2:
@@ -1616,9 +1703,9 @@ static ssize_t show_pwm_auto_point_channel(struct device *dev,
        int result;
        struct f71882fg_data *data = f71882fg_update_device(dev);
        int nr = to_sensor_dev_attr_2(devattr)->index;
-       int temp_start = (data->type == f8000) ? 0 : 1;
 
-       result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) - temp_start);
+       result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) -
+                      data->temp_start);
 
        return sprintf(buf, "%d\n", result);
 }
@@ -1629,7 +1716,6 @@ static ssize_t store_pwm_auto_point_channel(struct device *dev,
 {
        struct f71882fg_data *data = dev_get_drvdata(dev);
        int nr = to_sensor_dev_attr_2(devattr)->index;
-       int temp_start = (data->type == f8000) ? 0 : 1;
        long val = simple_strtol(buf, NULL, 10);
 
        switch (val) {
@@ -1645,7 +1731,7 @@ static ssize_t store_pwm_auto_point_channel(struct device *dev,
        default:
                return -EINVAL;
        }
-       val += temp_start;
+       val += data->temp_start;
        mutex_lock(&data->update_lock);
        data->pwm_auto_point_mapping[nr] =
                f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr));
@@ -1721,6 +1807,8 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
 
        data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
        data->type = sio_data->type;
+       data->temp_start =
+           (data->type == f71858fg || data->type == f8000) ? 0 : 1;
        mutex_init(&data->update_lock);
        platform_set_drvdata(pdev, data);
 
@@ -1736,19 +1824,6 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
                goto exit_free;
        }
 
-       data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
-       /* If it is a 71862 and the fan / pwm part is enabled sanity check
-          the pwm settings */
-       if (data->type == f71862fg && (start_reg & 0x02)) {
-               if ((data->pwm_enable & 0x15) != 0x15) {
-                       dev_err(&pdev->dev,
-                               "Invalid (reserved) pwm settings: 0x%02x\n",
-                               (unsigned int)data->pwm_enable);
-                       err = -ENODEV;
-                       goto exit_free;
-               }
-       }
-
        /* Register sysfs interface files */
        err = device_create_file(&pdev->dev, &dev_attr_name);
        if (err)
@@ -1756,6 +1831,20 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
 
        if (start_reg & 0x01) {
                switch (data->type) {
+               case f71858fg:
+                       data->temp_config =
+                               f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG);
+                       if (data->temp_config & 0x10)
+                               /* The f71858fg temperature alarms behave as
+                                  the f8000 alarms in this mode */
+                               err = f71882fg_create_sysfs_files(pdev,
+                                       f8000_in_temp_attr,
+                                       ARRAY_SIZE(f8000_in_temp_attr));
+                       else
+                               err = f71882fg_create_sysfs_files(pdev,
+                                       f71858fg_in_temp_attr,
+                                       ARRAY_SIZE(f71858fg_in_temp_attr));
+                       break;
                case f71882fg:
                        err = f71882fg_create_sysfs_files(pdev,
                                        f71882fg_in_temp_attr,
@@ -1779,6 +1868,35 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
        }
 
        if (start_reg & 0x02) {
+               data->pwm_enable =
+                       f71882fg_read8(data, F71882FG_REG_PWM_ENABLE);
+
+               /* Sanity check the pwm settings */
+               switch (data->type) {
+               case f71858fg:
+                       err = 0;
+                       for (i = 0; i < nr_fans; i++)
+                               if (((data->pwm_enable >> (i * 2)) & 3) == 3)
+                                       err = 1;
+                       break;
+               case f71862fg:
+                       err = (data->pwm_enable & 0x15) != 0x15;
+                       break;
+               case f71882fg:
+                       err = 0;
+                       break;
+               case f8000:
+                       err = data->pwm_enable & 0x20;
+                       break;
+               }
+               if (err) {
+                       dev_err(&pdev->dev,
+                               "Invalid (reserved) pwm settings: 0x%02x\n",
+                               (unsigned int)data->pwm_enable);
+                       err = -ENODEV;
+                       goto exit_unregister_sysfs;
+               }
+
                err = f71882fg_create_sysfs_files(pdev, fxxxx_fan_attr,
                                        ARRAY_SIZE(fxxxx_fan_attr));
                if (err)
@@ -1794,6 +1912,13 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
                        err = f71882fg_create_sysfs_files(pdev,
                                        f71882fg_fan_attr,
                                        ARRAY_SIZE(f71882fg_fan_attr));
+                       if (err)
+                               goto exit_unregister_sysfs;
+                       /* fall through! */
+               case f71858fg:
+                       err = f71882fg_create_sysfs_files(pdev,
+                                       f71882fg_f71858fg_fan_attr,
+                                       ARRAY_SIZE(f71882fg_f71858fg_fan_attr));
                        break;
                case f8000:
                        err = f71882fg_create_sysfs_files(pdev,
@@ -1878,6 +2003,9 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
 
        devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
        switch (devid) {
+       case SIO_F71858_ID:
+               sio_data->type = f71858fg;
+               break;
        case SIO_F71862_ID:
                sio_data->type = f71862fg;
                break;
@@ -1892,7 +2020,11 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
                goto exit;
        }
 
-       superio_select(sioaddr, SIO_F71882FG_LD_HWM);
+       if (sio_data->type == f71858fg)
+               superio_select(sioaddr, SIO_F71858FG_LD_HWM);
+       else
+               superio_select(sioaddr, SIO_F71882FG_LD_HWM);
+
        if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) {
                printk(KERN_WARNING DRVNAME ": Device not activated\n");
                goto exit;
index abca7e9f953b16aaaf61d0251f5b6f41782afefe..6679854c85b075b82d0a5eea82dbaaf36051853b 100644 (file)
@@ -27,9 +27,6 @@
 #include <linux/types.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
-#include <linux/input.h>
-#include <linux/kthread.h>
-#include <linux/semaphore.h>
 #include <linux/delay.h>
 #include <linux/wait.h>
 #include <linux/poll.h>
@@ -161,6 +158,7 @@ static struct axis_conversion lis3lv02d_axis_normal = {1, 2, 3};
 static struct axis_conversion lis3lv02d_axis_y_inverted = {1, -2, 3};
 static struct axis_conversion lis3lv02d_axis_x_inverted = {-1, 2, 3};
 static struct axis_conversion lis3lv02d_axis_z_inverted = {1, 2, -3};
+static struct axis_conversion lis3lv02d_axis_xy_swap = {2, 1, 3};
 static struct axis_conversion lis3lv02d_axis_xy_rotated_left = {-2, 1, 3};
 static struct axis_conversion lis3lv02d_axis_xy_rotated_left_usd = {-2, 1, -3};
 static struct axis_conversion lis3lv02d_axis_xy_swap_inverted = {-2, -1, 3};
@@ -194,13 +192,16 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = {
        AXIS_DMI_MATCH("NX9420", "HP Compaq nx9420", x_inverted),
        AXIS_DMI_MATCH("NW9440", "HP Compaq nw9440", x_inverted),
        AXIS_DMI_MATCH("NC2510", "HP Compaq 2510", y_inverted),
+       AXIS_DMI_MATCH("NC2710", "HP Compaq 2710", xy_swap),
        AXIS_DMI_MATCH("NC8510", "HP Compaq 8510", xy_swap_inverted),
        AXIS_DMI_MATCH("HP2133", "HP 2133", xy_rotated_left),
        AXIS_DMI_MATCH("HP2140", "HP 2140", xy_swap_inverted),
        AXIS_DMI_MATCH("NC653x", "HP Compaq 653", xy_rotated_left_usd),
        AXIS_DMI_MATCH("NC673x", "HP Compaq 673", xy_rotated_left_usd),
        AXIS_DMI_MATCH("NC651xx", "HP Compaq 651", xy_rotated_right),
-       AXIS_DMI_MATCH("NC671xx", "HP Compaq 671", xy_swap_yz_inverted),
+       AXIS_DMI_MATCH("NC6710x", "HP Compaq 6710", xy_swap_yz_inverted),
+       AXIS_DMI_MATCH("NC6715x", "HP Compaq 6715", y_inverted),
+       AXIS_DMI_MATCH("NC693xx", "HP EliteBook 693", xy_rotated_right),
        /* Intel-based HP Pavilion dv5 */
        AXIS_DMI_MATCH2("HPDV5_I",
                        PRODUCT_NAME, "HP Pavilion dv5",
@@ -216,7 +217,6 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = {
        { NULL, }
 /* Laptop models without axis info (yet):
  * "NC6910" "HP Compaq 6910"
- * HP Compaq 8710x Notebook PC / Mobile Workstation
  * "NC2400" "HP Compaq nc2400"
  * "NX74x0" "HP Compaq nx74"
  * "NX6325" "HP Compaq nx6325"
@@ -324,7 +324,7 @@ static int lis3lv02d_remove(struct acpi_device *device, int type)
        flush_work(&hpled_led.work);
        led_classdev_unregister(&hpled_led.led_classdev);
 
-       return lis3lv02d_remove_fs();
+       return lis3lv02d_remove_fs(&lis3_dev);
 }
 
 
@@ -338,13 +338,7 @@ static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state)
 
 static int lis3lv02d_resume(struct acpi_device *device)
 {
-       /* put back the device in the right state (ACPI might turn it on) */
-       mutex_lock(&lis3_dev.lock);
-       if (lis3_dev.usage > 0)
-               lis3lv02d_poweron(&lis3_dev);
-       else
-               lis3lv02d_poweroff(&lis3_dev);
-       mutex_unlock(&lis3_dev.lock);
+       lis3lv02d_poweron(&lis3_dev);
        return 0;
 }
 #else
index e15c3e7b07e9a1e2314e29090750fd51abadfde7..29ea6753f3bbe54592168dcaa1db07b1a2dbab3d 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/hwmon.h>
 #include <linux/gfp.h>
 #include <linux/spinlock.h>
+#include <linux/pci.h>
 
 #define HWMON_ID_PREFIX "hwmon"
 #define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d"
@@ -86,8 +87,36 @@ void hwmon_device_unregister(struct device *dev)
                        "hwmon_device_unregister() failed: bad class ID!\n");
 }
 
+static void __init hwmon_pci_quirks(void)
+{
+#if defined CONFIG_X86 && defined CONFIG_PCI
+       struct pci_dev *sb;
+       u16 base;
+       u8 enable;
+
+       /* Open access to 0x295-0x296 on MSI MS-7031 */
+       sb = pci_get_device(PCI_VENDOR_ID_ATI, 0x436c, NULL);
+       if (sb &&
+           (sb->subsystem_vendor == 0x1462 &&  /* MSI */
+            sb->subsystem_device == 0x0031)) { /* MS-7031 */
+
+               pci_read_config_byte(sb, 0x48, &enable);
+               pci_read_config_word(sb, 0x64, &base);
+
+               if (base == 0 && !(enable & BIT(2))) {
+                       dev_info(&sb->dev,
+                                "Opening wide generic port at 0x295\n");
+                       pci_write_config_word(sb, 0x64, 0x295);
+                       pci_write_config_byte(sb, 0x48, enable | BIT(2));
+               }
+       }
+#endif
+}
+
 static int __init hwmon_init(void)
 {
+       hwmon_pci_quirks();
+
        hwmon_class = class_create(THIS_MODULE, "hwmon");
        if (IS_ERR(hwmon_class)) {
                printk(KERN_ERR "hwmon.c: couldn't create sysfs class\n");
index fe74609a7feb5f706ab907c5d69be9881c5bc731..405d3fb5d76f9e90aa9115b56eb4676c4e1b03bb 100644 (file)
@@ -1127,3 +1127,4 @@ MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3650-*");
 MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3655-*");
 MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3755-*");
 MODULE_ALIAS("dmi:bvnIBM:*:pnIBM3850M2/x3950M2-*");
+MODULE_ALIAS("dmi:bvnIBM:*:pnIBMBladeHC10-*");
index 778eb77959837eed9c1172cfe4524d0273434b54..271338bdb6be55e5319349ef90fc127388ded3d9 100644 (file)
@@ -27,9 +27,7 @@
 #include <linux/types.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
-#include <linux/input.h>
-#include <linux/kthread.h>
-#include <linux/semaphore.h>
+#include <linux/input-polldev.h>
 #include <linux/delay.h>
 #include <linux/wait.h>
 #include <linux/poll.h>
@@ -105,56 +103,39 @@ static void lis3lv02d_get_xyz(struct lis3lv02d *lis3, int *x, int *y, int *z)
 {
        int position[3];
 
-       position[0] = lis3_dev.read_data(lis3, OUTX);
-       position[1] = lis3_dev.read_data(lis3, OUTY);
-       position[2] = lis3_dev.read_data(lis3, OUTZ);
+       position[0] = lis3->read_data(lis3, OUTX);
+       position[1] = lis3->read_data(lis3, OUTY);
+       position[2] = lis3->read_data(lis3, OUTZ);
 
-       *x = lis3lv02d_get_axis(lis3_dev.ac.x, position);
-       *y = lis3lv02d_get_axis(lis3_dev.ac.y, position);
-       *z = lis3lv02d_get_axis(lis3_dev.ac.z, position);
+       *x = lis3lv02d_get_axis(lis3->ac.x, position);
+       *y = lis3lv02d_get_axis(lis3->ac.y, position);
+       *z = lis3lv02d_get_axis(lis3->ac.z, position);
 }
 
 void lis3lv02d_poweroff(struct lis3lv02d *lis3)
 {
-       lis3_dev.is_on = 0;
+       /* disable X,Y,Z axis and power down */
+       lis3->write(lis3, CTRL_REG1, 0x00);
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_poweroff);
 
 void lis3lv02d_poweron(struct lis3lv02d *lis3)
 {
-       lis3_dev.is_on = 1;
-       lis3_dev.init(lis3);
-}
-EXPORT_SYMBOL_GPL(lis3lv02d_poweron);
+       u8 reg;
 
-/*
- * To be called before starting to use the device. It makes sure that the
- * device will always be on until a call to lis3lv02d_decrease_use(). Not to be
- * used from interrupt context.
- */
-static void lis3lv02d_increase_use(struct lis3lv02d *dev)
-{
-       mutex_lock(&dev->lock);
-       dev->usage++;
-       if (dev->usage == 1) {
-               if (!dev->is_on)
-                       lis3lv02d_poweron(dev);
-       }
-       mutex_unlock(&dev->lock);
-}
+       lis3->init(lis3);
 
-/*
- * To be called whenever a usage of the device is stopped.
- * It will make sure to turn off the device when there is not usage.
- */
-static void lis3lv02d_decrease_use(struct lis3lv02d *dev)
-{
-       mutex_lock(&dev->lock);
-       dev->usage--;
-       if (dev->usage == 0)
-               lis3lv02d_poweroff(dev);
-       mutex_unlock(&dev->lock);
+       /*
+        * Common configuration
+        * BDU: LSB and MSB values are not updated until both have been read.
+        *      So the value read will always be correct.
+        */
+       lis3->read(lis3, CTRL_REG2, &reg);
+       reg |= CTRL2_BDU;
+       lis3->write(lis3, CTRL_REG2, reg);
 }
+EXPORT_SYMBOL_GPL(lis3lv02d_poweron);
+
 
 static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
 {
@@ -198,15 +179,12 @@ static int lis3lv02d_misc_open(struct inode *inode, struct file *file)
                printk(KERN_ERR DRIVER_NAME ": IRQ%d allocation failed\n", lis3_dev.irq);
                return -EBUSY;
        }
-       lis3lv02d_increase_use(&lis3_dev);
-       printk("lis3: registered interrupt %d\n", lis3_dev.irq);
        return 0;
 }
 
 static int lis3lv02d_misc_release(struct inode *inode, struct file *file)
 {
        fasync_helper(-1, file, 0, &lis3_dev.async_queue);
-       lis3lv02d_decrease_use(&lis3_dev);
        free_irq(lis3_dev.irq, &lis3_dev);
        clear_bit(0, &lis3_dev.misc_opened); /* release the device */
        return 0;
@@ -290,46 +268,16 @@ static struct miscdevice lis3lv02d_misc_device = {
        .fops    = &lis3lv02d_misc_fops,
 };
 
-/**
- * lis3lv02d_joystick_kthread - Kthread polling function
- * @data: unused - here to conform to threadfn prototype
- */
-static int lis3lv02d_joystick_kthread(void *data)
+static void lis3lv02d_joystick_poll(struct input_polled_dev *pidev)
 {
        int x, y, z;
 
-       while (!kthread_should_stop()) {
-               lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
-               input_report_abs(lis3_dev.idev, ABS_X, x - lis3_dev.xcalib);
-               input_report_abs(lis3_dev.idev, ABS_Y, y - lis3_dev.ycalib);
-               input_report_abs(lis3_dev.idev, ABS_Z, z - lis3_dev.zcalib);
-
-               input_sync(lis3_dev.idev);
-
-               try_to_freeze();
-               msleep_interruptible(MDPS_POLL_INTERVAL);
-       }
-
-       return 0;
-}
-
-static int lis3lv02d_joystick_open(struct input_dev *input)
-{
-       lis3lv02d_increase_use(&lis3_dev);
-       lis3_dev.kthread = kthread_run(lis3lv02d_joystick_kthread, NULL, "klis3lv02d");
-       if (IS_ERR(lis3_dev.kthread)) {
-               lis3lv02d_decrease_use(&lis3_dev);
-               return PTR_ERR(lis3_dev.kthread);
-       }
-
-       return 0;
+       lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
+       input_report_abs(pidev->input, ABS_X, x - lis3_dev.xcalib);
+       input_report_abs(pidev->input, ABS_Y, y - lis3_dev.ycalib);
+       input_report_abs(pidev->input, ABS_Z, z - lis3_dev.zcalib);
 }
 
-static void lis3lv02d_joystick_close(struct input_dev *input)
-{
-       kthread_stop(lis3_dev.kthread);
-       lis3lv02d_decrease_use(&lis3_dev);
-}
 
 static inline void lis3lv02d_calibrate_joystick(void)
 {
@@ -339,33 +287,36 @@ static inline void lis3lv02d_calibrate_joystick(void)
 
 int lis3lv02d_joystick_enable(void)
 {
+       struct input_dev *input_dev;
        int err;
 
        if (lis3_dev.idev)
                return -EINVAL;
 
-       lis3_dev.idev = input_allocate_device();
+       lis3_dev.idev = input_allocate_polled_device();
        if (!lis3_dev.idev)
                return -ENOMEM;
 
+       lis3_dev.idev->poll = lis3lv02d_joystick_poll;
+       lis3_dev.idev->poll_interval = MDPS_POLL_INTERVAL;
+       input_dev = lis3_dev.idev->input;
+
        lis3lv02d_calibrate_joystick();
 
-       lis3_dev.idev->name       = "ST LIS3LV02DL Accelerometer";
-       lis3_dev.idev->phys       = DRIVER_NAME "/input0";
-       lis3_dev.idev->id.bustype = BUS_HOST;
-       lis3_dev.idev->id.vendor  = 0;
-       lis3_dev.idev->dev.parent = &lis3_dev.pdev->dev;
-       lis3_dev.idev->open       = lis3lv02d_joystick_open;
-       lis3_dev.idev->close      = lis3lv02d_joystick_close;
+       input_dev->name       = "ST LIS3LV02DL Accelerometer";
+       input_dev->phys       = DRIVER_NAME "/input0";
+       input_dev->id.bustype = BUS_HOST;
+       input_dev->id.vendor  = 0;
+       input_dev->dev.parent = &lis3_dev.pdev->dev;
 
-       set_bit(EV_ABS, lis3_dev.idev->evbit);
-       input_set_abs_params(lis3_dev.idev, ABS_X, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3);
-       input_set_abs_params(lis3_dev.idev, ABS_Y, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3);
-       input_set_abs_params(lis3_dev.idev, ABS_Z, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3);
+       set_bit(EV_ABS, input_dev->evbit);
+       input_set_abs_params(input_dev, ABS_X, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3);
+       input_set_abs_params(input_dev, ABS_Y, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3);
+       input_set_abs_params(input_dev, ABS_Z, -lis3_dev.mdps_max_val, lis3_dev.mdps_max_val, 3, 3);
 
-       err = input_register_device(lis3_dev.idev);
+       err = input_register_polled_device(lis3_dev.idev);
        if (err) {
-               input_free_device(lis3_dev.idev);
+               input_free_polled_device(lis3_dev.idev);
                lis3_dev.idev = NULL;
        }
 
@@ -378,8 +329,9 @@ void lis3lv02d_joystick_disable(void)
        if (!lis3_dev.idev)
                return;
 
-       misc_deregister(&lis3lv02d_misc_device);
-       input_unregister_device(lis3_dev.idev);
+       if (lis3_dev.irq)
+               misc_deregister(&lis3lv02d_misc_device);
+       input_unregister_polled_device(lis3_dev.idev);
        lis3_dev.idev = NULL;
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable);
@@ -390,9 +342,7 @@ static ssize_t lis3lv02d_position_show(struct device *dev,
 {
        int x, y, z;
 
-       lis3lv02d_increase_use(&lis3_dev);
        lis3lv02d_get_xyz(&lis3_dev, &x, &y, &z);
-       lis3lv02d_decrease_use(&lis3_dev);
        return sprintf(buf, "(%d,%d,%d)\n", x, y, z);
 }
 
@@ -406,9 +356,7 @@ static ssize_t lis3lv02d_calibrate_store(struct device *dev,
                                struct device_attribute *attr,
                                const char *buf, size_t count)
 {
-       lis3lv02d_increase_use(&lis3_dev);
        lis3lv02d_calibrate_joystick();
-       lis3lv02d_decrease_use(&lis3_dev);
        return count;
 }
 
@@ -420,9 +368,7 @@ static ssize_t lis3lv02d_rate_show(struct device *dev,
        u8 ctrl;
        int val;
 
-       lis3lv02d_increase_use(&lis3_dev);
        lis3_dev.read(&lis3_dev, CTRL_REG1, &ctrl);
-       lis3lv02d_decrease_use(&lis3_dev);
        val = (ctrl & (CTRL1_DF0 | CTRL1_DF1)) >> 4;
        return sprintf(buf, "%d\n", lis3lv02dl_df_val[val]);
 }
@@ -446,17 +392,17 @@ static struct attribute_group lis3lv02d_attribute_group = {
 
 static int lis3lv02d_add_fs(struct lis3lv02d *lis3)
 {
-       lis3_dev.pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
-       if (IS_ERR(lis3_dev.pdev))
-               return PTR_ERR(lis3_dev.pdev);
+       lis3->pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0);
+       if (IS_ERR(lis3->pdev))
+               return PTR_ERR(lis3->pdev);
 
-       return sysfs_create_group(&lis3_dev.pdev->dev.kobj, &lis3lv02d_attribute_group);
+       return sysfs_create_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group);
 }
 
-int lis3lv02d_remove_fs(void)
+int lis3lv02d_remove_fs(struct lis3lv02d *lis3)
 {
-       sysfs_remove_group(&lis3_dev.pdev->dev.kobj, &lis3lv02d_attribute_group);
-       platform_device_unregister(lis3_dev.pdev);
+       sysfs_remove_group(&lis3->pdev->dev.kobj, &lis3lv02d_attribute_group);
+       platform_device_unregister(lis3->pdev);
        return 0;
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs);
@@ -482,18 +428,35 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
                break;
        default:
                printk(KERN_ERR DRIVER_NAME
-                       ": unknown sensor type 0x%X\n", lis3_dev.whoami);
+                       ": unknown sensor type 0x%X\n", dev->whoami);
                return -EINVAL;
        }
 
-       mutex_init(&dev->lock);
        lis3lv02d_add_fs(dev);
-       lis3lv02d_increase_use(dev);
+       lis3lv02d_poweron(dev);
 
        if (lis3lv02d_joystick_enable())
                printk(KERN_ERR DRIVER_NAME ": joystick initialization failed\n");
 
-       printk("lis3_init_device: irq %d\n", dev->irq);
+       /* passing in platform specific data is purely optional and only
+        * used by the SPI transport layer at the moment */
+       if (dev->pdata) {
+               struct lis3lv02d_platform_data *p = dev->pdata;
+
+               if (p->click_flags && (dev->whoami == LIS_SINGLE_ID)) {
+                       dev->write(dev, CLICK_CFG, p->click_flags);
+                       dev->write(dev, CLICK_TIMELIMIT, p->click_time_limit);
+                       dev->write(dev, CLICK_LATENCY, p->click_latency);
+                       dev->write(dev, CLICK_WINDOW, p->click_window);
+                       dev->write(dev, CLICK_THSZ, p->click_thresh_z & 0xf);
+                       dev->write(dev, CLICK_THSY_X,
+                                       (p->click_thresh_x & 0xf) |
+                                       (p->click_thresh_y << 4));
+               }
+
+               if (p->irq_cfg)
+                       dev->write(dev, CTRL_REG3, p->irq_cfg);
+       }
 
        /* bail if we did not get an IRQ from the bus layer */
        if (!dev->irq) {
@@ -502,11 +465,9 @@ int lis3lv02d_init_device(struct lis3lv02d *dev)
                goto out;
        }
 
-       printk("lis3: registering device\n");
        if (misc_register(&lis3lv02d_misc_device))
                printk(KERN_ERR DRIVER_NAME ": misc_register failed\n");
 out:
-       lis3lv02d_decrease_use(dev);
        return 0;
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_init_device);
index 745ec96806d485a0f93f33932e2a588e6a8ab546..e320e2f511f160ee7a81dac45fec755575f9ee22 100644 (file)
@@ -18,6 +18,8 @@
  *  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/platform_device.h>
+#include <linux/input-polldev.h>
 
 /*
  * The actual chip is STMicroelectronics LIS3LV02DL or LIS3LV02DQ that seems to
  * They can also be connected via I²C.
  */
 
+#include <linux/lis3lv02d.h>
+
 /* 2-byte registers */
 #define LIS_DOUBLE_ID  0x3A /* LIS3LV02D[LQ] */
 /* 1-byte registers */
 #define LIS_SINGLE_ID  0x3B /* LIS[32]02DL and others */
 
-enum lis3lv02d_reg {
+enum lis3_reg {
        WHO_AM_I        = 0x0F,
        OFFSET_X        = 0x16,
        OFFSET_Y        = 0x17,
@@ -60,6 +64,19 @@ enum lis3lv02d_reg {
        FF_WU_THS_L     = 0x34,
        FF_WU_THS_H     = 0x35,
        FF_WU_DURATION  = 0x36,
+};
+
+enum lis302d_reg {
+       CLICK_CFG       = 0x38,
+       CLICK_SRC       = 0x39,
+       CLICK_THSY_X    = 0x3B,
+       CLICK_THSZ      = 0x3C,
+       CLICK_TIMELIMIT = 0x3D,
+       CLICK_LATENCY   = 0x3E,
+       CLICK_WINDOW    = 0x3F,
+};
+
+enum lis3lv02d_reg {
        DD_CFG          = 0x38,
        DD_SRC          = 0x39,
        DD_ACK          = 0x3A,
@@ -169,22 +186,20 @@ struct lis3lv02d {
        s16 (*read_data) (struct lis3lv02d *lis3, int reg);
        int                     mdps_max_val;
 
-       struct input_dev        *idev;     /* input device */
-       struct task_struct      *kthread;  /* kthread for input */
-       struct mutex            lock;
+       struct input_polled_dev *idev;     /* input device */
        struct platform_device  *pdev;     /* platform device */
        atomic_t                count;     /* interrupt count after last read */
        int                     xcalib;    /* calibrated null value for x */
        int                     ycalib;    /* calibrated null value for y */
        int                     zcalib;    /* calibrated null value for z */
-       unsigned char           is_on;     /* whether the device is on or off */
-       unsigned char           usage;     /* usage counter */
        struct axis_conversion  ac;        /* hw -> logical axis */
 
        u32                     irq;       /* IRQ number */
        struct fasync_struct    *async_queue; /* queue for the misc device */
        wait_queue_head_t       misc_wait; /* Wait queue for the misc device */
        unsigned long           misc_opened; /* bit0: whether the device is open */
+
+       struct lis3lv02d_platform_data *pdata;  /* for passing board config */
 };
 
 int lis3lv02d_init_device(struct lis3lv02d *lis3);
@@ -192,6 +207,6 @@ int lis3lv02d_joystick_enable(void);
 void lis3lv02d_joystick_disable(void);
 void lis3lv02d_poweroff(struct lis3lv02d *lis3);
 void lis3lv02d_poweron(struct lis3lv02d *lis3);
-int lis3lv02d_remove_fs(void);
+int lis3lv02d_remove_fs(struct lis3lv02d *lis3);
 
 extern struct lis3lv02d lis3_dev;
index 07ae74b0e191103564e881801ec4bc27225d8470..3827ff04485f9a726c3d5c8f8e6ab1742c309b4e 100644 (file)
@@ -72,6 +72,7 @@ static int __devinit lis302dl_spi_probe(struct spi_device *spi)
        lis3_dev.write = lis3_spi_write;
        lis3_dev.irq = spi->irq;
        lis3_dev.ac = lis3lv02d_axis_normal;
+       lis3_dev.pdata = spi->dev.platform_data;
        spi_set_drvdata(spi, &lis3_dev);
 
        ret = lis3lv02d_init_device(&lis3_dev);
index f27af6a9da4148939859ba5a2749a23d17fb73ba..86142a858238b8ddc0ccf65282ef56e34bd0b8ff 100644 (file)
@@ -12,7 +12,7 @@
  * also work with the MAX6651. It does not distinguish max6650 and max6651
  * chips.
  *
- * Tha datasheet was last seen at:
+ * The datasheet was last seen at:
  *
  *        http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf
  *
@@ -98,6 +98,16 @@ I2C_CLIENT_INSMOD_1(max6650);
 #define MAX6650_CFG_MODE_OPEN_LOOP     0x30
 #define MAX6650_COUNT_MASK             0x03
 
+/*
+ * Alarm status register bits
+ */
+
+#define MAX6650_ALRM_MAX       0x01
+#define MAX6650_ALRM_MIN       0x02
+#define MAX6650_ALRM_TACH      0x04
+#define MAX6650_ALRM_GPIO1     0x08
+#define MAX6650_ALRM_GPIO2     0x10
+
 /* Minimum and maximum values of the FAN-RPM */
 #define FAN_RPM_MIN 240
 #define FAN_RPM_MAX 30000
@@ -151,6 +161,7 @@ struct max6650_data
        u8 tach[4];
        u8 count;
        u8 dac;
+       u8 alarm;
 };
 
 static ssize_t get_fan(struct device *dev, struct device_attribute *devattr,
@@ -418,6 +429,33 @@ static ssize_t set_div(struct device *dev, struct device_attribute *devattr,
        return count;
 }
 
+/*
+ * Get alarm stati:
+ * Possible values:
+ * 0 = no alarm
+ * 1 = alarm
+ */
+
+static ssize_t get_alarm(struct device *dev, struct device_attribute *devattr,
+                        char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+       struct max6650_data *data = max6650_update_device(dev);
+       struct i2c_client *client = to_i2c_client(dev);
+       int alarm = 0;
+
+       if (data->alarm & attr->index) {
+               mutex_lock(&data->update_lock);
+               alarm = 1;
+               data->alarm &= ~attr->index;
+               data->alarm |= i2c_smbus_read_byte_data(client,
+                                                       MAX6650_REG_ALARM);
+               mutex_unlock(&data->update_lock);
+       }
+
+       return sprintf(buf, "%d\n", alarm);
+}
+
 static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, 0);
 static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan, NULL, 1);
 static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, get_fan, NULL, 2);
@@ -426,7 +464,41 @@ static DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO, get_target, set_target);
 static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, get_div, set_div);
 static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, get_enable, set_enable);
 static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm);
+static SENSOR_DEVICE_ATTR(fan1_max_alarm, S_IRUGO, get_alarm, NULL,
+                         MAX6650_ALRM_MAX);
+static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, get_alarm, NULL,
+                         MAX6650_ALRM_MIN);
+static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, get_alarm, NULL,
+                         MAX6650_ALRM_TACH);
+static SENSOR_DEVICE_ATTR(gpio1_alarm, S_IRUGO, get_alarm, NULL,
+                         MAX6650_ALRM_GPIO1);
+static SENSOR_DEVICE_ATTR(gpio2_alarm, S_IRUGO, get_alarm, NULL,
+                         MAX6650_ALRM_GPIO2);
+
+static mode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a,
+                                   int n)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct i2c_client *client = to_i2c_client(dev);
+       u8 alarm_en = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN);
+       struct device_attribute *devattr;
 
+       /*
+        * Hide the alarms that have not been enabled by the firmware
+        */
+
+       devattr = container_of(a, struct device_attribute, attr);
+       if (devattr == &sensor_dev_attr_fan1_max_alarm.dev_attr
+        || devattr == &sensor_dev_attr_fan1_min_alarm.dev_attr
+        || devattr == &sensor_dev_attr_fan1_fault.dev_attr
+        || devattr == &sensor_dev_attr_gpio1_alarm.dev_attr
+        || devattr == &sensor_dev_attr_gpio2_alarm.dev_attr) {
+               if (!(alarm_en & to_sensor_dev_attr(devattr)->index))
+                       return 0;
+       }
+
+       return a->mode;
+}
 
 static struct attribute *max6650_attrs[] = {
        &sensor_dev_attr_fan1_input.dev_attr.attr,
@@ -437,11 +509,17 @@ static struct attribute *max6650_attrs[] = {
        &dev_attr_fan1_div.attr,
        &dev_attr_pwm1_enable.attr,
        &dev_attr_pwm1.attr,
+       &sensor_dev_attr_fan1_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_fan1_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_fan1_fault.dev_attr.attr,
+       &sensor_dev_attr_gpio1_alarm.dev_attr.attr,
+       &sensor_dev_attr_gpio2_alarm.dev_attr.attr,
        NULL
 };
 
 static struct attribute_group max6650_attr_grp = {
        .attrs = max6650_attrs,
+       .is_visible = max6650_attrs_visible,
 };
 
 /*
@@ -659,6 +737,12 @@ static struct max6650_data *max6650_update_device(struct device *dev)
                                                        MAX6650_REG_COUNT);
                data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC);
 
+               /* Alarms are cleared on read in case the condition that
+                * caused the alarm is removed. Keep the value latched here
+                * for providing the register through different alarm files. */
+               data->alarm |= i2c_smbus_read_byte_data(client,
+                                                       MAX6650_REG_ALARM);
+
                data->last_updated = jiffies;
                data->valid = 1;
        }
index 6cbdc2fea7349cce363df97ed0000b0096ba38e4..56cd6004da36e1ec08f94e05b890f61239323c08 100644 (file)
@@ -627,35 +627,35 @@ static struct platform_driver sht_drivers[] = {
                        .owner = THIS_MODULE,
                },
                .probe = sht15_probe,
-               .remove = sht15_remove,
+               .remove = __devexit_p(sht15_remove),
        }, {
                .driver = {
                        .name = "sht11",
                        .owner = THIS_MODULE,
                },
                .probe = sht15_probe,
-               .remove = sht15_remove,
+               .remove = __devexit_p(sht15_remove),
        }, {
                .driver = {
                        .name = "sht15",
                        .owner = THIS_MODULE,
                },
                .probe = sht15_probe,
-               .remove = sht15_remove,
+               .remove = __devexit_p(sht15_remove),
        }, {
                .driver = {
                        .name = "sht71",
                        .owner = THIS_MODULE,
                },
                .probe = sht15_probe,
-               .remove = sht15_remove,
+               .remove = __devexit_p(sht15_remove),
        }, {
                .driver = {
                        .name = "sht75",
                        .owner = THIS_MODULE,
                },
                .probe = sht15_probe,
-               .remove = sht15_remove,
+               .remove = __devexit_p(sht15_remove),
        },
 };
 
diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c
new file mode 100644 (file)
index 0000000..7b34f2c
--- /dev/null
@@ -0,0 +1,690 @@
+/* tmp401.c
+ *
+ * Copyright (C) 2007,2008 Hans de Goede <hdegoede@redhat.com>
+ * Preliminary tmp411 support by:
+ * Gabriel Konat, Sander Leget, Wouter Willems
+ * Copyright (C) 2009 Andre Prendel <andre.prendel@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Driver for the Texas Instruments TMP401 SMBUS temperature sensor IC.
+ *
+ * Note this IC is in some aspect similar to the LM90, but it has quite a
+ * few differences too, for example the local temp has a higher resolution
+ * and thus has 16 bits registers for its value and limit instead of 8 bits.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+
+/* Addresses to scan */
+static const unsigned short normal_i2c[] = { 0x4c, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_2(tmp401, tmp411);
+
+/*
+ * The TMP401 registers, note some registers have different addresses for
+ * reading and writing
+ */
+#define TMP401_STATUS                          0x02
+#define TMP401_CONFIG_READ                     0x03
+#define TMP401_CONFIG_WRITE                    0x09
+#define TMP401_CONVERSION_RATE_READ            0x04
+#define TMP401_CONVERSION_RATE_WRITE           0x0A
+#define TMP401_TEMP_CRIT_HYST                  0x21
+#define TMP401_CONSECUTIVE_ALERT               0x22
+#define TMP401_MANUFACTURER_ID_REG             0xFE
+#define TMP401_DEVICE_ID_REG                   0xFF
+#define TMP411_N_FACTOR_REG                    0x18
+
+static const u8 TMP401_TEMP_MSB[2]                     = { 0x00, 0x01 };
+static const u8 TMP401_TEMP_LSB[2]                     = { 0x15, 0x10 };
+static const u8 TMP401_TEMP_LOW_LIMIT_MSB_READ[2]      = { 0x06, 0x08 };
+static const u8 TMP401_TEMP_LOW_LIMIT_MSB_WRITE[2]     = { 0x0C, 0x0E };
+static const u8 TMP401_TEMP_LOW_LIMIT_LSB[2]           = { 0x17, 0x14 };
+static const u8 TMP401_TEMP_HIGH_LIMIT_MSB_READ[2]     = { 0x05, 0x07 };
+static const u8 TMP401_TEMP_HIGH_LIMIT_MSB_WRITE[2]    = { 0x0B, 0x0D };
+static const u8 TMP401_TEMP_HIGH_LIMIT_LSB[2]          = { 0x16, 0x13 };
+/* These are called the THERM limit / hysteresis / mask in the datasheet */
+static const u8 TMP401_TEMP_CRIT_LIMIT[2]              = { 0x20, 0x19 };
+
+static const u8 TMP411_TEMP_LOWEST_MSB[2]              = { 0x30, 0x34 };
+static const u8 TMP411_TEMP_LOWEST_LSB[2]              = { 0x31, 0x35 };
+static const u8 TMP411_TEMP_HIGHEST_MSB[2]             = { 0x32, 0x36 };
+static const u8 TMP411_TEMP_HIGHEST_LSB[2]             = { 0x33, 0x37 };
+
+/* Flags */
+#define TMP401_CONFIG_RANGE            0x04
+#define TMP401_CONFIG_SHUTDOWN         0x40
+#define TMP401_STATUS_LOCAL_CRIT               0x01
+#define TMP401_STATUS_REMOTE_CRIT              0x02
+#define TMP401_STATUS_REMOTE_OPEN              0x04
+#define TMP401_STATUS_REMOTE_LOW               0x08
+#define TMP401_STATUS_REMOTE_HIGH              0x10
+#define TMP401_STATUS_LOCAL_LOW                0x20
+#define TMP401_STATUS_LOCAL_HIGH               0x40
+
+/* Manufacturer / Device ID's */
+#define TMP401_MANUFACTURER_ID                 0x55
+#define TMP401_DEVICE_ID                       0x11
+#define TMP411_DEVICE_ID                       0x12
+
+/*
+ * Functions declarations
+ */
+
+static int tmp401_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id);
+static int tmp401_detect(struct i2c_client *client, int kind,
+                        struct i2c_board_info *info);
+static int tmp401_remove(struct i2c_client *client);
+static struct tmp401_data *tmp401_update_device(struct device *dev);
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static const struct i2c_device_id tmp401_id[] = {
+       { "tmp401", tmp401 },
+       { "tmp411", tmp411 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tmp401_id);
+
+static struct i2c_driver tmp401_driver = {
+       .class          = I2C_CLASS_HWMON,
+       .driver = {
+               .name   = "tmp401",
+       },
+       .probe          = tmp401_probe,
+       .remove         = tmp401_remove,
+       .id_table       = tmp401_id,
+       .detect         = tmp401_detect,
+       .address_data   = &addr_data,
+};
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct tmp401_data {
+       struct device *hwmon_dev;
+       struct mutex update_lock;
+       char valid; /* zero until following fields are valid */
+       unsigned long last_updated; /* in jiffies */
+       int kind;
+
+       /* register values */
+       u8 status;
+       u8 config;
+       u16 temp[2];
+       u16 temp_low[2];
+       u16 temp_high[2];
+       u8 temp_crit[2];
+       u8 temp_crit_hyst;
+       u16 temp_lowest[2];
+       u16 temp_highest[2];
+};
+
+/*
+ * Sysfs attr show / store functions
+ */
+
+static int tmp401_register_to_temp(u16 reg, u8 config)
+{
+       int temp = reg;
+
+       if (config & TMP401_CONFIG_RANGE)
+               temp -= 64 * 256;
+
+       return (temp * 625 + 80) / 160;
+}
+
+static u16 tmp401_temp_to_register(long temp, u8 config)
+{
+       if (config & TMP401_CONFIG_RANGE) {
+               temp = SENSORS_LIMIT(temp, -64000, 191000);
+               temp += 64000;
+       } else
+               temp = SENSORS_LIMIT(temp, 0, 127000);
+
+       return (temp * 160 + 312) / 625;
+}
+
+static int tmp401_crit_register_to_temp(u8 reg, u8 config)
+{
+       int temp = reg;
+
+       if (config & TMP401_CONFIG_RANGE)
+               temp -= 64;
+
+       return temp * 1000;
+}
+
+static u8 tmp401_crit_temp_to_register(long temp, u8 config)
+{
+       if (config & TMP401_CONFIG_RANGE) {
+               temp = SENSORS_LIMIT(temp, -64000, 191000);
+               temp += 64000;
+       } else
+               temp = SENSORS_LIMIT(temp, 0, 127000);
+
+       return (temp + 500) / 1000;
+}
+
+static ssize_t show_temp_value(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct tmp401_data *data = tmp401_update_device(dev);
+
+       return sprintf(buf, "%d\n",
+               tmp401_register_to_temp(data->temp[index], data->config));
+}
+
+static ssize_t show_temp_min(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct tmp401_data *data = tmp401_update_device(dev);
+
+       return sprintf(buf, "%d\n",
+               tmp401_register_to_temp(data->temp_low[index], data->config));
+}
+
+static ssize_t show_temp_max(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct tmp401_data *data = tmp401_update_device(dev);
+
+       return sprintf(buf, "%d\n",
+               tmp401_register_to_temp(data->temp_high[index], data->config));
+}
+
+static ssize_t show_temp_crit(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct tmp401_data *data = tmp401_update_device(dev);
+
+       return sprintf(buf, "%d\n",
+                       tmp401_crit_register_to_temp(data->temp_crit[index],
+                                                       data->config));
+}
+
+static ssize_t show_temp_crit_hyst(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int temp, index = to_sensor_dev_attr(devattr)->index;
+       struct tmp401_data *data = tmp401_update_device(dev);
+
+       mutex_lock(&data->update_lock);
+       temp = tmp401_crit_register_to_temp(data->temp_crit[index],
+                                               data->config);
+       temp -= data->temp_crit_hyst * 1000;
+       mutex_unlock(&data->update_lock);
+
+       return sprintf(buf, "%d\n", temp);
+}
+
+static ssize_t show_temp_lowest(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct tmp401_data *data = tmp401_update_device(dev);
+
+       return sprintf(buf, "%d\n",
+               tmp401_register_to_temp(data->temp_lowest[index],
+                                       data->config));
+}
+
+static ssize_t show_temp_highest(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct tmp401_data *data = tmp401_update_device(dev);
+
+       return sprintf(buf, "%d\n",
+               tmp401_register_to_temp(data->temp_highest[index],
+                                       data->config));
+}
+
+static ssize_t show_status(struct device *dev,
+       struct device_attribute *devattr, char *buf)
+{
+       int mask = to_sensor_dev_attr(devattr)->index;
+       struct tmp401_data *data = tmp401_update_device(dev);
+
+       if (data->status & mask)
+               return sprintf(buf, "1\n");
+       else
+               return sprintf(buf, "0\n");
+}
+
+static ssize_t store_temp_min(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct tmp401_data *data = tmp401_update_device(dev);
+       long val;
+       u16 reg;
+
+       if (strict_strtol(buf, 10, &val))
+               return -EINVAL;
+
+       reg = tmp401_temp_to_register(val, data->config);
+
+       mutex_lock(&data->update_lock);
+
+       i2c_smbus_write_byte_data(to_i2c_client(dev),
+               TMP401_TEMP_LOW_LIMIT_MSB_WRITE[index], reg >> 8);
+       i2c_smbus_write_byte_data(to_i2c_client(dev),
+               TMP401_TEMP_LOW_LIMIT_LSB[index], reg & 0xFF);
+
+       data->temp_low[index] = reg;
+
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t store_temp_max(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct tmp401_data *data = tmp401_update_device(dev);
+       long val;
+       u16 reg;
+
+       if (strict_strtol(buf, 10, &val))
+               return -EINVAL;
+
+       reg = tmp401_temp_to_register(val, data->config);
+
+       mutex_lock(&data->update_lock);
+
+       i2c_smbus_write_byte_data(to_i2c_client(dev),
+               TMP401_TEMP_HIGH_LIMIT_MSB_WRITE[index], reg >> 8);
+       i2c_smbus_write_byte_data(to_i2c_client(dev),
+               TMP401_TEMP_HIGH_LIMIT_LSB[index], reg & 0xFF);
+
+       data->temp_high[index] = reg;
+
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t store_temp_crit(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count)
+{
+       int index = to_sensor_dev_attr(devattr)->index;
+       struct tmp401_data *data = tmp401_update_device(dev);
+       long val;
+       u8 reg;
+
+       if (strict_strtol(buf, 10, &val))
+               return -EINVAL;
+
+       reg = tmp401_crit_temp_to_register(val, data->config);
+
+       mutex_lock(&data->update_lock);
+
+       i2c_smbus_write_byte_data(to_i2c_client(dev),
+               TMP401_TEMP_CRIT_LIMIT[index], reg);
+
+       data->temp_crit[index] = reg;
+
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute
+       *devattr, const char *buf, size_t count)
+{
+       int temp, index = to_sensor_dev_attr(devattr)->index;
+       struct tmp401_data *data = tmp401_update_device(dev);
+       long val;
+       u8 reg;
+
+       if (strict_strtol(buf, 10, &val))
+               return -EINVAL;
+
+       if (data->config & TMP401_CONFIG_RANGE)
+               val = SENSORS_LIMIT(val, -64000, 191000);
+       else
+               val = SENSORS_LIMIT(val, 0, 127000);
+
+       mutex_lock(&data->update_lock);
+       temp = tmp401_crit_register_to_temp(data->temp_crit[index],
+                                               data->config);
+       val = SENSORS_LIMIT(val, temp - 255000, temp);
+       reg = ((temp - val) + 500) / 1000;
+
+       i2c_smbus_write_byte_data(to_i2c_client(dev),
+               TMP401_TEMP_CRIT_HYST, reg);
+
+       data->temp_crit_hyst = reg;
+
+       mutex_unlock(&data->update_lock);
+
+       return count;
+}
+
+/*
+ * Resets the historical measurements of minimum and maximum temperatures.
+ * This is done by writing any value to any of the minimum/maximum registers
+ * (0x30-0x37).
+ */
+static ssize_t reset_temp_history(struct device *dev,
+       struct device_attribute *devattr, const char *buf, size_t count)
+{
+       long val;
+
+       if (strict_strtol(buf, 10, &val))
+               return -EINVAL;
+
+       if (val != 1) {
+               dev_err(dev, "temp_reset_history value %ld not"
+                       " supported. Use 1 to reset the history!\n", val);
+               return -EINVAL;
+       }
+       i2c_smbus_write_byte_data(to_i2c_client(dev),
+               TMP411_TEMP_LOWEST_MSB[0], val);
+
+       return count;
+}
+
+static struct sensor_device_attribute tmp401_attr[] = {
+       SENSOR_ATTR(temp1_input, 0444, show_temp_value, NULL, 0),
+       SENSOR_ATTR(temp1_min, 0644, show_temp_min, store_temp_min, 0),
+       SENSOR_ATTR(temp1_max, 0644, show_temp_max, store_temp_max, 0),
+       SENSOR_ATTR(temp1_crit, 0644, show_temp_crit, store_temp_crit, 0),
+       SENSOR_ATTR(temp1_crit_hyst, 0644, show_temp_crit_hyst,
+                   store_temp_crit_hyst, 0),
+       SENSOR_ATTR(temp1_min_alarm, 0444, show_status, NULL,
+                   TMP401_STATUS_LOCAL_LOW),
+       SENSOR_ATTR(temp1_max_alarm, 0444, show_status, NULL,
+                   TMP401_STATUS_LOCAL_HIGH),
+       SENSOR_ATTR(temp1_crit_alarm, 0444, show_status, NULL,
+                   TMP401_STATUS_LOCAL_CRIT),
+       SENSOR_ATTR(temp2_input, 0444, show_temp_value, NULL, 1),
+       SENSOR_ATTR(temp2_min, 0644, show_temp_min, store_temp_min, 1),
+       SENSOR_ATTR(temp2_max, 0644, show_temp_max, store_temp_max, 1),
+       SENSOR_ATTR(temp2_crit, 0644, show_temp_crit, store_temp_crit, 1),
+       SENSOR_ATTR(temp2_crit_hyst, 0444, show_temp_crit_hyst, NULL, 1),
+       SENSOR_ATTR(temp2_fault, 0444, show_status, NULL,
+                   TMP401_STATUS_REMOTE_OPEN),
+       SENSOR_ATTR(temp2_min_alarm, 0444, show_status, NULL,
+                   TMP401_STATUS_REMOTE_LOW),
+       SENSOR_ATTR(temp2_max_alarm, 0444, show_status, NULL,
+                   TMP401_STATUS_REMOTE_HIGH),
+       SENSOR_ATTR(temp2_crit_alarm, 0444, show_status, NULL,
+                   TMP401_STATUS_REMOTE_CRIT),
+};
+
+/*
+ * Additional features of the TMP411 chip.
+ * The TMP411 stores the minimum and maximum
+ * temperature measured since power-on, chip-reset, or
+ * minimum and maximum register reset for both the local
+ * and remote channels.
+ */
+static struct sensor_device_attribute tmp411_attr[] = {
+       SENSOR_ATTR(temp1_highest, 0444, show_temp_highest, NULL, 0),
+       SENSOR_ATTR(temp1_lowest, 0444, show_temp_lowest, NULL, 0),
+       SENSOR_ATTR(temp2_highest, 0444, show_temp_highest, NULL, 1),
+       SENSOR_ATTR(temp2_lowest, 0444, show_temp_lowest, NULL, 1),
+       SENSOR_ATTR(temp_reset_history, 0200, NULL, reset_temp_history, 0),
+};
+
+/*
+ * Begin non sysfs callback code (aka Real code)
+ */
+
+static void tmp401_init_client(struct i2c_client *client)
+{
+       int config, config_orig;
+
+       /* Set the conversion rate to 2 Hz */
+       i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, 5);
+
+       /* Start conversions (disable shutdown if necessary) */
+       config = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ);
+       if (config < 0) {
+               dev_warn(&client->dev, "Initialization failed!\n");
+               return;
+       }
+
+       config_orig = config;
+       config &= ~TMP401_CONFIG_SHUTDOWN;
+
+       if (config != config_orig)
+               i2c_smbus_write_byte_data(client, TMP401_CONFIG_WRITE, config);
+}
+
+static int tmp401_detect(struct i2c_client *client, int kind,
+                        struct i2c_board_info *info)
+{
+       struct i2c_adapter *adapter = client->adapter;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       /* Detect and identify the chip */
+       if (kind <= 0) {
+               u8 reg;
+
+               reg = i2c_smbus_read_byte_data(client,
+                                              TMP401_MANUFACTURER_ID_REG);
+               if (reg != TMP401_MANUFACTURER_ID)
+                       return -ENODEV;
+
+               reg = i2c_smbus_read_byte_data(client, TMP401_DEVICE_ID_REG);
+
+               switch (reg) {
+               case TMP401_DEVICE_ID:
+                       kind = tmp401;
+                       break;
+               case TMP411_DEVICE_ID:
+                       kind = tmp411;
+                       break;
+               default:
+                       return -ENODEV;
+               }
+
+               reg = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ);
+               if (reg & 0x1b)
+                       return -ENODEV;
+
+               reg = i2c_smbus_read_byte_data(client,
+                                              TMP401_CONVERSION_RATE_READ);
+               /* Datasheet says: 0x1-0x6 */
+               if (reg > 15)
+                       return -ENODEV;
+       }
+       strlcpy(info->type, tmp401_id[kind - 1].name, I2C_NAME_SIZE);
+
+       return 0;
+}
+
+static int tmp401_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       int i, err = 0;
+       struct tmp401_data *data;
+       const char *names[] = { "TMP401", "TMP411" };
+
+       data = kzalloc(sizeof(struct tmp401_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->update_lock);
+       data->kind = id->driver_data;
+
+       /* Initialize the TMP401 chip */
+       tmp401_init_client(client);
+
+       /* Register sysfs hooks */
+       for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++) {
+               err = device_create_file(&client->dev,
+                                        &tmp401_attr[i].dev_attr);
+               if (err)
+                       goto exit_remove;
+       }
+
+       /* Register aditional tmp411 sysfs hooks */
+       if (data->kind == tmp411) {
+               for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++) {
+                       err = device_create_file(&client->dev,
+                                                &tmp411_attr[i].dev_attr);
+                       if (err)
+                               goto exit_remove;
+               }
+       }
+
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               err = PTR_ERR(data->hwmon_dev);
+               data->hwmon_dev = NULL;
+               goto exit_remove;
+       }
+
+       dev_info(&client->dev, "Detected TI %s chip\n",
+                names[data->kind - 1]);
+
+       return 0;
+
+exit_remove:
+       tmp401_remove(client); /* will also free data for us */
+       return err;
+}
+
+static int tmp401_remove(struct i2c_client *client)
+{
+       struct tmp401_data *data = i2c_get_clientdata(client);
+       int i;
+
+       if (data->hwmon_dev)
+               hwmon_device_unregister(data->hwmon_dev);
+
+       for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++)
+               device_remove_file(&client->dev, &tmp401_attr[i].dev_attr);
+
+       if (data->kind == tmp411) {
+               for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++)
+                       device_remove_file(&client->dev,
+                                          &tmp411_attr[i].dev_attr);
+       }
+
+       kfree(data);
+       return 0;
+}
+
+static struct tmp401_data *tmp401_update_device_reg16(
+       struct i2c_client *client, struct tmp401_data *data)
+{
+       int i;
+
+       for (i = 0; i < 2; i++) {
+               /*
+                * High byte must be read first immediately followed
+                * by the low byte
+                */
+               data->temp[i] = i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_MSB[i]) << 8;
+               data->temp[i] |= i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_LSB[i]);
+               data->temp_low[i] = i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_LOW_LIMIT_MSB_READ[i]) << 8;
+               data->temp_low[i] |= i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_LOW_LIMIT_LSB[i]);
+               data->temp_high[i] = i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_HIGH_LIMIT_MSB_READ[i]) << 8;
+               data->temp_high[i] |= i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_HIGH_LIMIT_LSB[i]);
+               data->temp_crit[i] = i2c_smbus_read_byte_data(client,
+                       TMP401_TEMP_CRIT_LIMIT[i]);
+
+               if (data->kind == tmp411) {
+                       data->temp_lowest[i] = i2c_smbus_read_byte_data(client,
+                               TMP411_TEMP_LOWEST_MSB[i]) << 8;
+                       data->temp_lowest[i] |= i2c_smbus_read_byte_data(
+                               client, TMP411_TEMP_LOWEST_LSB[i]);
+
+                       data->temp_highest[i] = i2c_smbus_read_byte_data(
+                               client, TMP411_TEMP_HIGHEST_MSB[i]) << 8;
+                       data->temp_highest[i] |= i2c_smbus_read_byte_data(
+                               client, TMP411_TEMP_HIGHEST_LSB[i]);
+               }
+       }
+       return data;
+}
+
+static struct tmp401_data *tmp401_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct tmp401_data *data = i2c_get_clientdata(client);
+
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+               data->status = i2c_smbus_read_byte_data(client, TMP401_STATUS);
+               data->config = i2c_smbus_read_byte_data(client,
+                                               TMP401_CONFIG_READ);
+               tmp401_update_device_reg16(client, data);
+
+               data->temp_crit_hyst = i2c_smbus_read_byte_data(client,
+                                               TMP401_TEMP_CRIT_HYST);
+
+               data->last_updated = jiffies;
+               data->valid = 1;
+       }
+
+       mutex_unlock(&data->update_lock);
+
+       return data;
+}
+
+static int __init tmp401_init(void)
+{
+       return i2c_add_driver(&tmp401_driver);
+}
+
+static void __exit tmp401_exit(void)
+{
+       i2c_del_driver(&tmp401_driver);
+}
+
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("Texas Instruments TMP401 temperature sensor driver");
+MODULE_LICENSE("GPL");
+
+module_init(tmp401_init);
+module_exit(tmp401_exit);
index e64b42058b219772d0c28ecf0a8780f8ef7ea1ab..0e9746913d2b718bafdd43dc38be46c8a931ab38 100644 (file)
@@ -36,6 +36,7 @@
     w83627ehf   10      5       4       3      0x8850 0x88    0x5ca3
                                                0x8860 0xa1
     w83627dhg    9      5       4       3      0xa020 0xc1    0x5ca3
+    w83627dhg-p  9      5       4       3      0xb070 0xc1    0x5ca3
     w83667hg     9      5       3       3      0xa510 0xc1    0x5ca3
 */
 
 #include <asm/io.h>
 #include "lm75.h"
 
-enum kinds { w83627ehf, w83627dhg, w83667hg };
+enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg };
 
 /* used to set data->name = w83627ehf_device_names[data->sio_kind] */
 static const char * w83627ehf_device_names[] = {
        "w83627ehf",
        "w83627dhg",
+       "w83627dhg",
        "w83667hg",
 };
 
@@ -86,6 +88,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID");
 #define SIO_W83627EHF_ID       0x8850
 #define SIO_W83627EHG_ID       0x8860
 #define SIO_W83627DHG_ID       0xa020
+#define SIO_W83627DHG_P_ID     0xb070
 #define SIO_W83667HG_ID        0xa510
 #define SIO_ID_MASK            0xFFF0
 
@@ -1517,6 +1520,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
        static const char __initdata sio_name_W83627EHF[] = "W83627EHF";
        static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
        static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
+       static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P";
        static const char __initdata sio_name_W83667HG[] = "W83667HG";
 
        u16 val;
@@ -1542,6 +1546,10 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
                sio_data->kind = w83627dhg;
                sio_name = sio_name_W83627DHG;
                break;
+       case SIO_W83627DHG_P_ID:
+               sio_data->kind = w83627dhg_p;
+               sio_name = sio_name_W83627DHG_P;
+               break;
        case SIO_W83667HG_ID:
                sio_data->kind = w83667hg;
                sio_name = sio_name_W83667HG;
index c8460fa9cfac751b8c236d9ad171f823376951d7..3c259ee7ddda01d61b9462dae9d9d9bfc7625178 100644 (file)
@@ -211,7 +211,7 @@ config I2C_VIA
          will be called i2c-via.
 
 config I2C_VIAPRO
-       tristate "VIA VT82C596/82C686/82xx and CX700/VX800/VX820"
+       tristate "VIA VT82C596/82C686/82xx and CX700/VX8xx"
        depends on PCI
        help
          If you say yes to this option, support will be included for the VIA
@@ -225,8 +225,8 @@ config I2C_VIAPRO
            VT8237R/A/S
            VT8251
            CX700
-           VX800
-           VX820
+           VX800/VX820
+           VX855/VX875
 
          This driver can also be built as a module.  If so, the module
          will be called i2c-viapro.
@@ -513,6 +513,19 @@ config I2C_SIMTEC
          This driver can also be built as a module. If so, the module
          will be called i2c-simtec.
 
+config I2C_STU300
+       tristate "ST Microelectronics DDC I2C interface"
+       depends on MACH_U300
+       default y if MACH_U300
+       help
+         If you say yes to this option, support will be included for the
+         I2C interface from ST Microelectronics simply called "DDC I2C"
+         supporting both I2C and DDC, used in e.g. the U300 series
+         mobile platforms.
+
+         This driver can also be built as a module. If so, the module
+         will be called i2c-stu300.
+
 config I2C_VERSATILE
        tristate "ARM Versatile/Realview I2C bus support"
        depends on ARCH_VERSATILE || ARCH_REALVIEW
index 776acb6403a783bed7bcab070ae93d7384221c50..edeabf00310600830caa27dd96e88e038762f078 100644 (file)
@@ -48,6 +48,7 @@ obj-$(CONFIG_I2C_S6000)               += i2c-s6000.o
 obj-$(CONFIG_I2C_SH7760)       += i2c-sh7760.o
 obj-$(CONFIG_I2C_SH_MOBILE)    += i2c-sh_mobile.o
 obj-$(CONFIG_I2C_SIMTEC)       += i2c-simtec.o
+obj-$(CONFIG_I2C_STU300)       += i2c-stu300.o
 obj-$(CONFIG_I2C_VERSATILE)    += i2c-versatile.o
 
 # External I2C/SMBus adapter drivers
index 67d9dc5b351b57e96d41f97f1d53da5f9c7fc9a1..06e1ecb4919f6258c157358183604accb109482c 100644 (file)
@@ -200,10 +200,10 @@ static int __devinit at91_i2c_probe(struct platform_device *pdev)
        if (!res)
                return -ENXIO;
 
-       if (!request_mem_region(res->start, res->end - res->start + 1, "at91_i2c"))
+       if (!request_mem_region(res->start, resource_size(res), "at91_i2c"))
                return -EBUSY;
 
-       twi_base = ioremap(res->start, res->end - res->start + 1);
+       twi_base = ioremap(res->start, resource_size(res));
        if (!twi_base) {
                rc = -ENOMEM;
                goto fail0;
@@ -252,7 +252,7 @@ fail2:
 fail1:
        iounmap(twi_base);
 fail0:
-       release_mem_region(res->start, res->end - res->start + 1);
+       release_mem_region(res->start, resource_size(res));
 
        return rc;
 }
@@ -268,7 +268,7 @@ static int __devexit at91_i2c_remove(struct platform_device *pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        iounmap(twi_base);
-       release_mem_region(res->start, res->end - res->start + 1);
+       release_mem_region(res->start, resource_size(res));
 
        clk_disable(twi_clk);           /* disable peripheral clock */
        clk_put(twi_clk);
index f78ce523e3db619f1891757679f0253918faf697..532828bc50e6d946f59c5b246ae3aa0a53bc5728 100644 (file)
@@ -389,7 +389,7 @@ i2c_au1550_probe(struct platform_device *pdev)
                goto out;
        }
 
-       priv->ioarea = request_mem_region(r->start, r->end - r->start + 1,
+       priv->ioarea = request_mem_region(r->start, resource_size(r),
                                          pdev->name);
        if (!priv->ioarea) {
                ret = -EBUSY;
index 26d8987e69bf171f2e0431789b4192da2a461a51..b309ac2c3d5cad084785f99ea3ea650713f59acf 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
+#include <linux/io.h>
 #include <linux/mm.h>
 #include <linux/timer.h>
 #include <linux/spinlock.h>
@@ -651,7 +652,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
                goto out_error_get_res;
        }
 
-       iface->regs_base = ioremap(res->start, res->end - res->start + 1);
+       iface->regs_base = ioremap(res->start, resource_size(res));
        if (iface->regs_base == NULL) {
                dev_err(&pdev->dev, "Cannot map IO\n");
                rc = -ENXIO;
index e5a8dae4a2890435f065e2b97017b83179647bcc..87ecace415da39ac49449c25acdd3e377c3f5a8b 100644 (file)
@@ -373,7 +373,7 @@ static int __devinit highlander_i2c_probe(struct platform_device *pdev)
        if (unlikely(!dev))
                return -ENOMEM;
 
-       dev->base = ioremap_nocache(res->start, res->end - res->start + 1);
+       dev->base = ioremap_nocache(res->start, resource_size(res));
        if (unlikely(!dev->base)) {
                ret = -ENXIO;
                goto err;
index 5a4945d1dba499a255953988243db982abe9cc86..c3869d94ad42f71cf05811b1bec45f4f0056cc44 100644 (file)
@@ -469,7 +469,7 @@ mv64xxx_i2c_map_regs(struct platform_device *pd,
        if (!r)
                return -ENODEV;
 
-       size = r->end - r->start + 1;
+       size = resource_size(r);
 
        if (!request_mem_region(r->start, size, drv_data->adapter.name))
                return -EBUSY;
index 3542c6ba98f1ab9ba8bdd5279a8400a35f11592e..0dabe643ec5116faa9140505c6cc464b03bbf8e0 100644 (file)
@@ -234,14 +234,14 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
        if (!i2c)
                return -ENOMEM;
 
-       if (!request_mem_region(res->start, res->end - res->start + 1,
+       if (!request_mem_region(res->start, resource_size(res),
                                pdev->name)) {
                dev_err(&pdev->dev, "Memory region busy\n");
                ret = -EBUSY;
                goto request_mem_failed;
        }
 
-       i2c->base = ioremap(res->start, res->end - res->start + 1);
+       i2c->base = ioremap(res->start, resource_size(res));
        if (!i2c->base) {
                dev_err(&pdev->dev, "Unable to map registers\n");
                ret = -EIO;
@@ -283,7 +283,7 @@ add_adapter_failed:
 request_irq_failed:
        iounmap(i2c->base);
 map_failed:
-       release_mem_region(res->start, res->end - res->start + 1);
+       release_mem_region(res->start, resource_size(res));
 request_mem_failed:
        kfree(i2c);
 
@@ -311,7 +311,7 @@ static int __devexit ocores_i2c_remove(struct platform_device* pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res)
-               release_mem_region(res->start, res->end - res->start + 1);
+               release_mem_region(res->start, resource_size(res));
 
        kfree(i2c);
 
index c73475dd0fba00c2dd5953b3b37ebf5837ad7f37..b606db85525dac6c42223b29a28aa864dc931d78 100644 (file)
@@ -828,7 +828,7 @@ omap_i2c_probe(struct platform_device *pdev)
        dev->idle = 1;
        dev->dev = &pdev->dev;
        dev->irq = irq->start;
-       dev->base = ioremap(mem->start, mem->end - mem->start + 1);
+       dev->base = ioremap(mem->start, resource_size(mem));
        if (!dev->base) {
                r = -ENOMEM;
                goto err_free_mem;
index 7b23891b7d59606d41acef1918cffede3cba724b..c4df9d411cd5cdb4226b302021bead43add5256e 100644 (file)
@@ -27,8 +27,6 @@
 #include <asm/irq.h>
 #include <asm/io.h>
 
-#define res_len(r)             ((r)->end - (r)->start + 1)
-
 struct i2c_pca_pf_data {
        void __iomem                    *reg_base;
        int                             irq;    /* if 0, use polling */
@@ -148,7 +146,7 @@ static int __devinit i2c_pca_pf_probe(struct platform_device *pdev)
                goto e_print;
        }
 
-       if (!request_mem_region(res->start, res_len(res), res->name)) {
+       if (!request_mem_region(res->start, resource_size(res), res->name)) {
                ret = -ENOMEM;
                goto e_print;
        }
@@ -161,13 +159,13 @@ static int __devinit i2c_pca_pf_probe(struct platform_device *pdev)
 
        init_waitqueue_head(&i2c->wait);
 
-       i2c->reg_base = ioremap(res->start, res_len(res));
+       i2c->reg_base = ioremap(res->start, resource_size(res));
        if (!i2c->reg_base) {
                ret = -ENOMEM;
                goto e_remap;
        }
        i2c->io_base = res->start;
-       i2c->io_size = res_len(res);
+       i2c->io_size = resource_size(res);
        i2c->irq = irq;
 
        i2c->adap.nr = pdev->id >= 0 ? pdev->id : 0;
@@ -250,7 +248,7 @@ e_reqirq:
 e_remap:
        kfree(i2c);
 e_alloc:
-       release_mem_region(res->start, res_len(res));
+       release_mem_region(res->start, resource_size(res));
 e_print:
        printk(KERN_ERR "Registering PCA9564/PCA9665 FAILED! (%d)\n", ret);
        return ret;
index 0bdb2d7f0570bd465e59b4b87ef23dd33db04b1d..7b57d5f267e1c28847a1bdb0db530a798ef9ab9a 100644 (file)
@@ -283,7 +283,7 @@ static int __devinit pmcmsptwi_probe(struct platform_device *pldev)
        }
 
        /* reserve the memory region */
-       if (!request_mem_region(res->start, res->end - res->start + 1,
+       if (!request_mem_region(res->start, resource_size(res),
                                pldev->name)) {
                dev_err(&pldev->dev,
                        "Unable to get memory/io address region 0x%08x\n",
@@ -294,7 +294,7 @@ static int __devinit pmcmsptwi_probe(struct platform_device *pldev)
 
        /* remap the memory */
        pmcmsptwi_data.iobase = ioremap_nocache(res->start,
-                                               res->end - res->start + 1);
+                                               resource_size(res));
        if (!pmcmsptwi_data.iobase) {
                dev_err(&pldev->dev,
                        "Unable to ioremap address 0x%08x\n", res->start);
@@ -360,7 +360,7 @@ ret_unmap:
        iounmap(pmcmsptwi_data.iobase);
 
 ret_unreserve:
-       release_mem_region(res->start, res->end - res->start + 1);
+       release_mem_region(res->start, resource_size(res));
 
 ret_err:
        return rc;
@@ -385,7 +385,7 @@ static int __devexit pmcmsptwi_remove(struct platform_device *pldev)
        iounmap(pmcmsptwi_data.iobase);
 
        res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
-       release_mem_region(res->start, res->end - res->start + 1);
+       release_mem_region(res->start, resource_size(res));
 
        return 0;
 }
index 035a6c7e59df846b44ad49ba91400d250580a5e2..762e1e530882f814bb05f9fcc5f39f9e44ef5539 100644 (file)
@@ -993,7 +993,6 @@ static const struct i2c_algorithm i2c_pxa_pio_algorithm = {
        .functionality  = i2c_pxa_functionality,
 };
 
-#define res_len(r)             ((r)->end - (r)->start + 1)
 static int i2c_pxa_probe(struct platform_device *dev)
 {
        struct pxa_i2c *i2c;
@@ -1008,7 +1007,7 @@ static int i2c_pxa_probe(struct platform_device *dev)
        if (res == NULL || irq < 0)
                return -ENODEV;
 
-       if (!request_mem_region(res->start, res_len(res), res->name))
+       if (!request_mem_region(res->start, resource_size(res), res->name))
                return -ENOMEM;
 
        i2c = kzalloc(sizeof(struct pxa_i2c), GFP_KERNEL);
@@ -1038,7 +1037,7 @@ static int i2c_pxa_probe(struct platform_device *dev)
                goto eclk;
        }
 
-       i2c->reg_base = ioremap(res->start, res_len(res));
+       i2c->reg_base = ioremap(res->start, resource_size(res));
        if (!i2c->reg_base) {
                ret = -EIO;
                goto eremap;
@@ -1046,7 +1045,7 @@ static int i2c_pxa_probe(struct platform_device *dev)
        i2c->reg_shift = REG_SHIFT(id->driver_data);
 
        i2c->iobase = res->start;
-       i2c->iosize = res_len(res);
+       i2c->iosize = resource_size(res);
 
        i2c->irq = irq;
 
@@ -1110,7 +1109,7 @@ eremap:
 eclk:
        kfree(i2c);
 emalloc:
-       release_mem_region(res->start, res_len(res));
+       release_mem_region(res->start, resource_size(res));
        return ret;
 }
 
index 079a312d36fd098422a842e53e00b59ac758f395..8f42a4536cdf872d6f10ed8cc4b738d26e642df1 100644 (file)
@@ -828,7 +828,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
                goto err_clk;
        }
 
-       i2c->ioarea = request_mem_region(res->start, (res->end-res->start)+1,
+       i2c->ioarea = request_mem_region(res->start, resource_size(res),
                                         pdev->name);
 
        if (i2c->ioarea == NULL) {
@@ -837,7 +837,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
                goto err_clk;
        }
 
-       i2c->regs = ioremap(res->start, (res->end-res->start)+1);
+       i2c->regs = ioremap(res->start, resource_size(res));
 
        if (i2c->regs == NULL) {
                dev_err(&pdev->dev, "cannot map IO\n");
diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c
new file mode 100644 (file)
index 0000000..182e711
--- /dev/null
@@ -0,0 +1,1029 @@
+/*
+ * Copyright (C) 2007-2009 ST-Ericsson AB
+ * License terms: GNU General Public License (GPL) version 2
+ * ST DDC I2C master mode driver, used in e.g. U300 series platforms.
+ * Author: Linus Walleij <linus.walleij@stericsson.com>
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+/* the name of this kernel module */
+#define NAME "stu300"
+
+/* CR (Control Register) 8bit (R/W) */
+#define I2C_CR                                 (0x00000000)
+#define I2C_CR_RESET_VALUE                     (0x00)
+#define I2C_CR_RESET_UMASK                     (0x00)
+#define I2C_CR_DDC1_ENABLE                     (0x80)
+#define I2C_CR_TRANS_ENABLE                    (0x40)
+#define I2C_CR_PERIPHERAL_ENABLE               (0x20)
+#define I2C_CR_DDC2B_ENABLE                    (0x10)
+#define I2C_CR_START_ENABLE                    (0x08)
+#define I2C_CR_ACK_ENABLE                      (0x04)
+#define I2C_CR_STOP_ENABLE                     (0x02)
+#define I2C_CR_INTERRUPT_ENABLE                        (0x01)
+/* SR1 (Status Register 1) 8bit (R/-) */
+#define I2C_SR1                                        (0x00000004)
+#define I2C_SR1_RESET_VALUE                    (0x00)
+#define I2C_SR1_RESET_UMASK                    (0x00)
+#define I2C_SR1_EVF_IND                                (0x80)
+#define I2C_SR1_ADD10_IND                      (0x40)
+#define I2C_SR1_TRA_IND                                (0x20)
+#define I2C_SR1_BUSY_IND                       (0x10)
+#define I2C_SR1_BTF_IND                                (0x08)
+#define I2C_SR1_ADSL_IND                       (0x04)
+#define I2C_SR1_MSL_IND                                (0x02)
+#define I2C_SR1_SB_IND                         (0x01)
+/* SR2 (Status Register 2) 8bit (R/-) */
+#define I2C_SR2                                        (0x00000008)
+#define I2C_SR2_RESET_VALUE                    (0x00)
+#define I2C_SR2_RESET_UMASK                    (0x40)
+#define I2C_SR2_MASK                           (0xBF)
+#define I2C_SR2_SCLFAL_IND                     (0x80)
+#define I2C_SR2_ENDAD_IND                      (0x20)
+#define I2C_SR2_AF_IND                         (0x10)
+#define I2C_SR2_STOPF_IND                      (0x08)
+#define I2C_SR2_ARLO_IND                       (0x04)
+#define I2C_SR2_BERR_IND                       (0x02)
+#define I2C_SR2_DDC2BF_IND                     (0x01)
+/* CCR (Clock Control Register) 8bit (R/W) */
+#define I2C_CCR                                        (0x0000000C)
+#define I2C_CCR_RESET_VALUE                    (0x00)
+#define I2C_CCR_RESET_UMASK                    (0x00)
+#define I2C_CCR_MASK                           (0xFF)
+#define I2C_CCR_FMSM                           (0x80)
+#define I2C_CCR_CC_MASK                                (0x7F)
+/* OAR1 (Own Address Register 1) 8bit (R/W) */
+#define I2C_OAR1                               (0x00000010)
+#define I2C_OAR1_RESET_VALUE                   (0x00)
+#define I2C_OAR1_RESET_UMASK                   (0x00)
+#define I2C_OAR1_ADD_MASK                      (0xFF)
+/* OAR2 (Own Address Register 2) 8bit (R/W) */
+#define I2C_OAR2                               (0x00000014)
+#define I2C_OAR2_RESET_VALUE                   (0x40)
+#define I2C_OAR2_RESET_UMASK                   (0x19)
+#define I2C_OAR2_MASK                          (0xE6)
+#define I2C_OAR2_FR_25_10MHZ                   (0x00)
+#define I2C_OAR2_FR_10_1667MHZ                 (0x20)
+#define I2C_OAR2_FR_1667_2667MHZ               (0x40)
+#define I2C_OAR2_FR_2667_40MHZ                 (0x60)
+#define I2C_OAR2_FR_40_5333MHZ                 (0x80)
+#define I2C_OAR2_FR_5333_66MHZ                 (0xA0)
+#define I2C_OAR2_FR_66_80MHZ                   (0xC0)
+#define I2C_OAR2_FR_80_100MHZ                  (0xE0)
+#define I2C_OAR2_FR_MASK                       (0xE0)
+#define I2C_OAR2_ADD_MASK                      (0x06)
+/* DR (Data Register) 8bit (R/W) */
+#define I2C_DR                                 (0x00000018)
+#define I2C_DR_RESET_VALUE                     (0x00)
+#define I2C_DR_RESET_UMASK                     (0xFF)
+#define I2C_DR_D_MASK                          (0xFF)
+/* ECCR (Extended Clock Control Register) 8bit (R/W) */
+#define I2C_ECCR                               (0x0000001C)
+#define I2C_ECCR_RESET_VALUE                   (0x00)
+#define I2C_ECCR_RESET_UMASK                   (0xE0)
+#define I2C_ECCR_MASK                          (0x1F)
+#define I2C_ECCR_CC_MASK                       (0x1F)
+
+/*
+ * These events are more or less responses to commands
+ * sent into the hardware, presumably reflecting the state
+ * of an internal state machine.
+ */
+enum stu300_event {
+       STU300_EVENT_NONE = 0,
+       STU300_EVENT_1,
+       STU300_EVENT_2,
+       STU300_EVENT_3,
+       STU300_EVENT_4,
+       STU300_EVENT_5,
+       STU300_EVENT_6,
+       STU300_EVENT_7,
+       STU300_EVENT_8,
+       STU300_EVENT_9
+};
+
+enum stu300_error {
+       STU300_ERROR_NONE = 0,
+       STU300_ERROR_ACKNOWLEDGE_FAILURE,
+       STU300_ERROR_BUS_ERROR,
+       STU300_ERROR_ARBITRATION_LOST
+};
+
+/* timeout waiting for the controller to respond */
+#define STU300_TIMEOUT (msecs_to_jiffies(1000))
+
+/*
+ * The number of address send athemps tried before giving up.
+ * If the first one failes it seems like 5 to 8 attempts are required.
+ */
+#define NUM_ADDR_RESEND_ATTEMPTS 10
+
+/* I2C clock speed, in Hz 0-400kHz*/
+static unsigned int scl_frequency = 100000;
+module_param(scl_frequency, uint,  0644);
+
+/**
+ * struct stu300_dev - the stu300 driver state holder
+ * @pdev: parent platform device
+ * @adapter: corresponding I2C adapter
+ * @phybase: location of I/O area in memory
+ * @physize: size of I/O area in memory
+ * @clk: hardware block clock
+ * @irq: assigned interrupt line
+ * @cmd_issue_lock: this locks the following cmd_ variables
+ * @cmd_complete: acknowledge completion for an I2C command
+ * @cmd_event: expected event coming in as a response to a command
+ * @cmd_err: error code as response to a command
+ * @speed: current bus speed in Hz
+ * @msg_index: index of current message
+ * @msg_len: length of current message
+ */
+struct stu300_dev {
+       struct platform_device  *pdev;
+       struct i2c_adapter      adapter;
+       resource_size_t         phybase;
+       resource_size_t         physize;
+       void __iomem            *virtbase;
+       struct clk              *clk;
+       int                     irq;
+       spinlock_t              cmd_issue_lock;
+       struct completion       cmd_complete;
+       enum stu300_event       cmd_event;
+       enum stu300_error       cmd_err;
+       unsigned int            speed;
+       int                     msg_index;
+       int                     msg_len;
+};
+
+/* Local forward function declarations */
+static int stu300_init_hw(struct stu300_dev *dev);
+
+/*
+ * The block needs writes in both MSW and LSW in order
+ * for all data lines to reach their destination.
+ */
+static inline void stu300_wr8(u32 value, void __iomem *address)
+{
+       writel((value << 16) | value, address);
+}
+
+/*
+ * This merely masks off the duplicates which appear
+ * in bytes 1-3. You _MUST_ use 32-bit bus access on this
+ * device, else it will not work.
+ */
+static inline u32 stu300_r8(void __iomem *address)
+{
+       return readl(address) & 0x000000FFU;
+}
+
+/*
+ * Tells whether a certain event or events occurred in
+ * response to a command. The events represent states in
+ * the internal state machine of the hardware. The events
+ * are not very well described in the hardware
+ * documentation and can only be treated as abstract state
+ * machine states.
+ *
+ * @ret 0 = event has not occurred, any other value means
+ * the event occurred.
+ */
+static int stu300_event_occurred(struct stu300_dev *dev,
+                                  enum stu300_event mr_event) {
+       u32 status1;
+       u32 status2;
+
+       /* What event happened? */
+       status1 = stu300_r8(dev->virtbase + I2C_SR1);
+       if (!(status1 & I2C_SR1_EVF_IND))
+               /* No event at all */
+               return 0;
+       status2 = stu300_r8(dev->virtbase + I2C_SR2);
+
+       switch (mr_event) {
+       case STU300_EVENT_1:
+               if (status1 & I2C_SR1_ADSL_IND)
+                       return 1;
+               break;
+       case STU300_EVENT_2:
+       case STU300_EVENT_3:
+       case STU300_EVENT_7:
+       case STU300_EVENT_8:
+               if (status1 & I2C_SR1_BTF_IND) {
+                       if (status2 & I2C_SR2_AF_IND)
+                               dev->cmd_err = STU300_ERROR_ACKNOWLEDGE_FAILURE;
+                       else if (status2 & I2C_SR2_BERR_IND)
+                               dev->cmd_err = STU300_ERROR_BUS_ERROR;
+                       return 1;
+               }
+               break;
+       case STU300_EVENT_4:
+               if (status2 & I2C_SR2_STOPF_IND)
+                       return 1;
+               break;
+       case STU300_EVENT_5:
+               if (status1 & I2C_SR1_SB_IND)
+                       /* Clear start bit */
+                       return 1;
+               break;
+       case STU300_EVENT_6:
+               if (status2 & I2C_SR2_ENDAD_IND) {
+                       /* First check for any errors */
+                       if (status2 & I2C_SR2_AF_IND)
+                               dev->cmd_err = STU300_ERROR_ACKNOWLEDGE_FAILURE;
+                       return 1;
+               }
+               break;
+       case STU300_EVENT_9:
+               if (status1 & I2C_SR1_ADD10_IND)
+                       return 1;
+               break;
+       default:
+               break;
+       }
+       if (status2 & I2C_SR2_ARLO_IND)
+               dev->cmd_err = STU300_ERROR_ARBITRATION_LOST;
+       return 0;
+}
+
+static irqreturn_t stu300_irh(int irq, void *data)
+{
+       struct stu300_dev *dev = data;
+       int res;
+
+       /* See if this was what we were waiting for */
+       spin_lock(&dev->cmd_issue_lock);
+       if (dev->cmd_event != STU300_EVENT_NONE) {
+               res = stu300_event_occurred(dev, dev->cmd_event);
+               if (res || dev->cmd_err != STU300_ERROR_NONE) {
+                       u32 val;
+
+                       complete(&dev->cmd_complete);
+                       /* Block any multiple interrupts */
+                       val = stu300_r8(dev->virtbase + I2C_CR);
+                       val &= ~I2C_CR_INTERRUPT_ENABLE;
+                       stu300_wr8(val, dev->virtbase + I2C_CR);
+               }
+       }
+       spin_unlock(&dev->cmd_issue_lock);
+       return IRQ_HANDLED;
+}
+
+/*
+ * Sends a command and then waits for the bits masked by *flagmask*
+ * to go high or low by IRQ awaiting.
+ */
+static int stu300_start_and_await_event(struct stu300_dev *dev,
+                                         u8 cr_value,
+                                         enum stu300_event mr_event)
+{
+       int ret;
+
+       if (unlikely(irqs_disabled())) {
+               /* TODO: implement polling for this case if need be. */
+               WARN(1, "irqs are disabled, cannot poll for event\n");
+               return -EIO;
+       }
+
+       /* Lock command issue, fill in an event we wait for */
+       spin_lock_irq(&dev->cmd_issue_lock);
+       init_completion(&dev->cmd_complete);
+       dev->cmd_err = STU300_ERROR_NONE;
+       dev->cmd_event = mr_event;
+       spin_unlock_irq(&dev->cmd_issue_lock);
+
+       /* Turn on interrupt, send command and wait. */
+       cr_value |= I2C_CR_INTERRUPT_ENABLE;
+       stu300_wr8(cr_value, dev->virtbase + I2C_CR);
+       ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
+                                                       STU300_TIMEOUT);
+
+       if (ret < 0) {
+               dev_err(&dev->pdev->dev,
+                      "wait_for_completion_interruptible_timeout() "
+                      "returned %d waiting for event %04x\n", ret, mr_event);
+               return ret;
+       }
+
+       if (ret == 0) {
+               dev_err(&dev->pdev->dev, "controller timed out "
+                      "waiting for event %d, reinit hardware\n", mr_event);
+               (void) stu300_init_hw(dev);
+               return -ETIMEDOUT;
+       }
+
+       if (dev->cmd_err != STU300_ERROR_NONE) {
+               dev_err(&dev->pdev->dev, "controller (start) "
+                      "error %d waiting for event %d, reinit hardware\n",
+                      dev->cmd_err, mr_event);
+               (void) stu300_init_hw(dev);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+/*
+ * This waits for a flag to be set, if it is not set on entry, an interrupt is
+ * configured to wait for the flag using a completion.
+ */
+static int stu300_await_event(struct stu300_dev *dev,
+                               enum stu300_event mr_event)
+{
+       int ret;
+       u32 val;
+
+       if (unlikely(irqs_disabled())) {
+               /* TODO: implement polling for this case if need be. */
+               dev_err(&dev->pdev->dev, "irqs are disabled on this "
+                       "system!\n");
+               return -EIO;
+       }
+
+       /* Is it already here? */
+       spin_lock_irq(&dev->cmd_issue_lock);
+       dev->cmd_err = STU300_ERROR_NONE;
+       if (stu300_event_occurred(dev, mr_event)) {
+               spin_unlock_irq(&dev->cmd_issue_lock);
+               goto exit_await_check_err;
+       }
+       init_completion(&dev->cmd_complete);
+       dev->cmd_err = STU300_ERROR_NONE;
+       dev->cmd_event = mr_event;
+
+       /* Turn on the I2C interrupt for current operation */
+       val = stu300_r8(dev->virtbase + I2C_CR);
+       val |= I2C_CR_INTERRUPT_ENABLE;
+       stu300_wr8(val, dev->virtbase + I2C_CR);
+
+       /* Twice paranoia (possible HW glitch) */
+       stu300_wr8(val, dev->virtbase + I2C_CR);
+
+       /* Check again: is it already here? */
+       if (unlikely(stu300_event_occurred(dev, mr_event))) {
+               /* Disable IRQ again. */
+               val &= ~I2C_CR_INTERRUPT_ENABLE;
+               stu300_wr8(val, dev->virtbase + I2C_CR);
+               spin_unlock_irq(&dev->cmd_issue_lock);
+               goto exit_await_check_err;
+       }
+
+       /* Unlock the command block and wait for the event to occur */
+       spin_unlock_irq(&dev->cmd_issue_lock);
+       ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
+                                                       STU300_TIMEOUT);
+
+       if (ret < 0) {
+               dev_err(&dev->pdev->dev,
+                      "wait_for_completion_interruptible_timeout()"
+                      "returned %d waiting for event %04x\n", ret, mr_event);
+               return ret;
+       }
+
+       if (ret == 0) {
+               if (mr_event != STU300_EVENT_6) {
+                       dev_err(&dev->pdev->dev, "controller "
+                               "timed out waiting for event %d, reinit "
+                               "hardware\n", mr_event);
+                       (void) stu300_init_hw(dev);
+               }
+               return -ETIMEDOUT;
+       }
+
+ exit_await_check_err:
+       if (dev->cmd_err != STU300_ERROR_NONE) {
+               if (mr_event != STU300_EVENT_6) {
+                       dev_err(&dev->pdev->dev, "controller "
+                               "error (await_event) %d waiting for event %d, "
+                              "reinit hardware\n", dev->cmd_err, mr_event);
+                       (void) stu300_init_hw(dev);
+               }
+               return -EIO;
+       }
+
+       return 0;
+}
+
+/*
+ * Waits for the busy bit to go low by repeated polling.
+ */
+#define BUSY_RELEASE_ATTEMPTS 10
+static int stu300_wait_while_busy(struct stu300_dev *dev)
+{
+       unsigned long timeout;
+       int i;
+
+       for (i = 0; i < BUSY_RELEASE_ATTEMPTS; i++) {
+               timeout = jiffies + STU300_TIMEOUT;
+
+               while (!time_after(jiffies, timeout)) {
+                       /* Is not busy? */
+                       if ((stu300_r8(dev->virtbase + I2C_SR1) &
+                            I2C_SR1_BUSY_IND) == 0)
+                               return 0;
+                       msleep(1);
+               }
+
+               dev_err(&dev->pdev->dev, "transaction timed out "
+                       "waiting for device to be free (not busy). "
+                      "Attempt: %d\n", i+1);
+
+               dev_err(&dev->pdev->dev, "base address = "
+                       "0x%08x, reinit hardware\n", (u32) dev->virtbase);
+
+               (void) stu300_init_hw(dev);
+       }
+
+       dev_err(&dev->pdev->dev, "giving up after %d attempts "
+               "to reset the bus.\n",  BUSY_RELEASE_ATTEMPTS);
+
+       return -ETIMEDOUT;
+}
+
+struct stu300_clkset {
+       unsigned long rate;
+       u32 setting;
+};
+
+static const struct stu300_clkset stu300_clktable[] = {
+       { 0, 0xFFU },
+       { 2500000, I2C_OAR2_FR_25_10MHZ },
+       { 10000000, I2C_OAR2_FR_10_1667MHZ },
+       { 16670000, I2C_OAR2_FR_1667_2667MHZ },
+       { 26670000, I2C_OAR2_FR_2667_40MHZ },
+       { 40000000, I2C_OAR2_FR_40_5333MHZ },
+       { 53330000, I2C_OAR2_FR_5333_66MHZ },
+       { 66000000, I2C_OAR2_FR_66_80MHZ },
+       { 80000000, I2C_OAR2_FR_80_100MHZ },
+       { 100000000, 0xFFU },
+};
+
+static int stu300_set_clk(struct stu300_dev *dev, unsigned long clkrate)
+{
+
+       u32 val;
+       int i = 0;
+
+       /* Locate the apropriate clock setting */
+       while (i < ARRAY_SIZE(stu300_clktable) &&
+              stu300_clktable[i].rate < clkrate)
+               i++;
+
+       if (stu300_clktable[i].setting == 0xFFU) {
+               dev_err(&dev->pdev->dev, "too %s clock rate requested "
+                       "(%lu Hz).\n", i ? "high" : "low", clkrate);
+               return -EINVAL;
+       }
+
+       stu300_wr8(stu300_clktable[i].setting,
+                  dev->virtbase + I2C_OAR2);
+
+       dev_dbg(&dev->pdev->dev, "Clock rate %lu Hz, I2C bus speed %d Hz "
+               "virtbase %p\n", clkrate, dev->speed, dev->virtbase);
+
+       if (dev->speed > 100000)
+               /* Fast Mode I2C */
+               val = ((clkrate/dev->speed)-9)/3;
+       else
+               /* Standard Mode I2C */
+               val = ((clkrate/dev->speed)-7)/2;
+
+       /* According to spec the divider must be > 2 */
+       if (val < 0x002) {
+               dev_err(&dev->pdev->dev, "too low clock rate (%lu Hz).\n",
+                       clkrate);
+               return -EINVAL;
+       }
+
+       /* We have 12 bits clock divider only! */
+       if (val & 0xFFFFF000U) {
+               dev_err(&dev->pdev->dev, "too high clock rate (%lu Hz).\n",
+                       clkrate);
+               return -EINVAL;
+       }
+
+       if (dev->speed > 100000) {
+               /* CC6..CC0 */
+               stu300_wr8((val & I2C_CCR_CC_MASK) | I2C_CCR_FMSM,
+                          dev->virtbase + I2C_CCR);
+               dev_dbg(&dev->pdev->dev, "set clock divider to 0x%08x, "
+                       "Fast Mode I2C\n", val);
+       } else {
+               /* CC6..CC0 */
+               stu300_wr8((val & I2C_CCR_CC_MASK),
+                          dev->virtbase + I2C_CCR);
+               dev_dbg(&dev->pdev->dev, "set clock divider to "
+                       "0x%08x, Standard Mode I2C\n", val);
+       }
+
+       /* CC11..CC7 */
+       stu300_wr8(((val >> 7) & 0x1F),
+                  dev->virtbase + I2C_ECCR);
+
+       return 0;
+}
+
+
+static int stu300_init_hw(struct stu300_dev *dev)
+{
+       u32 dummy;
+       unsigned long clkrate;
+       int ret;
+
+       /* Disable controller */
+       stu300_wr8(0x00, dev->virtbase + I2C_CR);
+       /*
+        * Set own address to some default value (0x00).
+        * We do not support slave mode anyway.
+        */
+       stu300_wr8(0x00, dev->virtbase + I2C_OAR1);
+       /*
+        * The I2C controller only operates properly in 26 MHz but we
+        * program this driver as if we didn't know. This will also set the two
+        * high bits of the own address to zero as well.
+        * There is no known hardware issue with running in 13 MHz
+        * However, speeds over 200 kHz are not used.
+        */
+       clkrate = clk_get_rate(dev->clk);
+       ret = stu300_set_clk(dev, clkrate);
+       if (ret)
+               return ret;
+       /*
+        * Enable block, do it TWICE (hardware glitch)
+        * Setting bit 7 can enable DDC mode. (Not used currently.)
+        */
+       stu300_wr8(I2C_CR_PERIPHERAL_ENABLE,
+                                 dev->virtbase + I2C_CR);
+       stu300_wr8(I2C_CR_PERIPHERAL_ENABLE,
+                                 dev->virtbase + I2C_CR);
+       /* Make a dummy read of the status register SR1 & SR2 */
+       dummy = stu300_r8(dev->virtbase + I2C_SR2);
+       dummy = stu300_r8(dev->virtbase + I2C_SR1);
+
+       return 0;
+}
+
+
+
+/* Send slave address. */
+static int stu300_send_address(struct stu300_dev *dev,
+                                struct i2c_msg *msg, int resend)
+{
+       u32 val;
+       int ret;
+
+       if (msg->flags & I2C_M_TEN)
+               /* This is probably how 10 bit addresses look */
+               val = (0xf0 | (((u32) msg->addr & 0x300) >> 7)) &
+                       I2C_DR_D_MASK;
+       else
+               val = ((msg->addr << 1) & I2C_DR_D_MASK);
+
+       if (msg->flags & I2C_M_RD) {
+               /* This is the direction bit */
+               val |= 0x01;
+               if (resend)
+                       dev_dbg(&dev->pdev->dev, "read resend\n");
+       } else if (resend)
+               dev_dbg(&dev->pdev->dev, "write resend\n");
+       stu300_wr8(val, dev->virtbase + I2C_DR);
+
+       /* For 10bit addressing, await 10bit request (EVENT 9) */
+       if (msg->flags & I2C_M_TEN) {
+               ret = stu300_await_event(dev, STU300_EVENT_9);
+               /*
+                * The slave device wants a 10bit address, send the rest
+                * of the bits (the LSBits)
+                */
+               val = msg->addr & I2C_DR_D_MASK;
+               /* This clears "event 9" */
+               stu300_wr8(val, dev->virtbase + I2C_DR);
+               if (ret != 0)
+                       return ret;
+       }
+       /* FIXME: Why no else here? two events for 10bit?
+        * Await event 6 (normal) or event 9 (10bit)
+        */
+
+       if (resend)
+               dev_dbg(&dev->pdev->dev, "await event 6\n");
+       ret = stu300_await_event(dev, STU300_EVENT_6);
+
+       /*
+        * Clear any pending EVENT 6 no matter what happend during
+        * await_event.
+        */
+       val = stu300_r8(dev->virtbase + I2C_CR);
+       val |= I2C_CR_PERIPHERAL_ENABLE;
+       stu300_wr8(val, dev->virtbase + I2C_CR);
+
+       return ret;
+}
+
+static int stu300_xfer_msg(struct i2c_adapter *adap,
+                            struct i2c_msg *msg, int stop)
+{
+       u32 cr;
+       u32 val;
+       u32 i;
+       int ret;
+       int attempts = 0;
+       struct stu300_dev *dev = i2c_get_adapdata(adap);
+
+
+       clk_enable(dev->clk);
+
+       /* Remove this if (0) to trace each and every message. */
+       if (0) {
+               dev_dbg(&dev->pdev->dev, "I2C message to: 0x%04x, len: %d, "
+                       "flags: 0x%04x, stop: %d\n",
+                       msg->addr, msg->len, msg->flags, stop);
+       }
+
+       /* Zero-length messages are not supported by this hardware */
+       if (msg->len == 0) {
+               ret = -EINVAL;
+               goto exit_disable;
+       }
+
+       /*
+        * For some reason, sending the address sometimes fails when running
+        * on  the 13 MHz clock. No interrupt arrives. This is a work around,
+        * which tries to restart and send the address up to 10 times before
+        * really giving up. Usually 5 to 8 attempts are enough.
+        */
+       do {
+               if (attempts)
+                       dev_dbg(&dev->pdev->dev, "wait while busy\n");
+               /* Check that the bus is free, or wait until some timeout */
+               ret = stu300_wait_while_busy(dev);
+               if (ret != 0)
+                       goto exit_disable;
+
+               if (attempts)
+                       dev_dbg(&dev->pdev->dev, "re-int hw\n");
+               /*
+                * According to ST, there is no problem if the clock is
+                * changed between 13 and 26 MHz during a transfer.
+                */
+               ret = stu300_init_hw(dev);
+               if (ret)
+                       goto exit_disable;
+
+               /* Send a start condition */
+               cr = I2C_CR_PERIPHERAL_ENABLE;
+               /* Setting the START bit puts the block in master mode */
+               if (!(msg->flags & I2C_M_NOSTART))
+                       cr |= I2C_CR_START_ENABLE;
+               if ((msg->flags & I2C_M_RD) && (msg->len > 1))
+                       /* On read more than 1 byte, we need ack. */
+                       cr |= I2C_CR_ACK_ENABLE;
+               /* Check that it gets through */
+               if (!(msg->flags & I2C_M_NOSTART)) {
+                       if (attempts)
+                               dev_dbg(&dev->pdev->dev, "send start event\n");
+                       ret = stu300_start_and_await_event(dev, cr,
+                                                            STU300_EVENT_5);
+               }
+
+               if (attempts)
+                       dev_dbg(&dev->pdev->dev, "send address\n");
+
+               if (ret == 0)
+                       /* Send address */
+                       ret = stu300_send_address(dev, msg, attempts != 0);
+
+               if (ret != 0) {
+                       attempts++;
+                       dev_dbg(&dev->pdev->dev, "failed sending address, "
+                               "retrying. Attempt: %d msg_index: %d/%d\n",
+                              attempts, dev->msg_index, dev->msg_len);
+               }
+
+       } while (ret != 0 && attempts < NUM_ADDR_RESEND_ATTEMPTS);
+
+       if (attempts < NUM_ADDR_RESEND_ATTEMPTS && attempts > 0) {
+               dev_dbg(&dev->pdev->dev, "managed to get address "
+                      "through after %d attempts\n", attempts);
+       } else if (attempts == NUM_ADDR_RESEND_ATTEMPTS) {
+               dev_dbg(&dev->pdev->dev, "I give up, tried %d times "
+                      "to resend address.\n",
+                      NUM_ADDR_RESEND_ATTEMPTS);
+               goto exit_disable;
+       }
+
+       if (msg->flags & I2C_M_RD) {
+               /* READ: we read the actual bytes one at a time */
+               for (i = 0; i < msg->len; i++) {
+                       if (i == msg->len-1) {
+                               /*
+                                * Disable ACK and set STOP condition before
+                                * reading last byte
+                                */
+                               val = I2C_CR_PERIPHERAL_ENABLE;
+
+                               if (stop)
+                                       val |= I2C_CR_STOP_ENABLE;
+
+                               stu300_wr8(val,
+                                          dev->virtbase + I2C_CR);
+                       }
+                       /* Wait for this byte... */
+                       ret = stu300_await_event(dev, STU300_EVENT_7);
+                       if (ret != 0)
+                               goto exit_disable;
+                       /* This clears event 7 */
+                       msg->buf[i] = (u8) stu300_r8(dev->virtbase + I2C_DR);
+               }
+       } else {
+               /* WRITE: we send the actual bytes one at a time */
+               for (i = 0; i < msg->len; i++) {
+                       /* Write the byte */
+                       stu300_wr8(msg->buf[i],
+                                  dev->virtbase + I2C_DR);
+                       /* Check status */
+                       ret = stu300_await_event(dev, STU300_EVENT_8);
+                       /* Next write to DR will clear event 8 */
+                       if (ret != 0) {
+                               dev_err(&dev->pdev->dev, "error awaiting "
+                                      "event 8 (%d)\n", ret);
+                               goto exit_disable;
+                       }
+               }
+               /* Check NAK */
+               if (!(msg->flags & I2C_M_IGNORE_NAK)) {
+                       if (stu300_r8(dev->virtbase + I2C_SR2) &
+                           I2C_SR2_AF_IND) {
+                               dev_err(&dev->pdev->dev, "I2C payload "
+                                      "send returned NAK!\n");
+                               ret = -EIO;
+                               goto exit_disable;
+                       }
+               }
+               if (stop) {
+                       /* Send stop condition */
+                       val = I2C_CR_PERIPHERAL_ENABLE;
+                       val |= I2C_CR_STOP_ENABLE;
+                       stu300_wr8(val, dev->virtbase + I2C_CR);
+               }
+       }
+
+       /* Check that the bus is free, or wait until some timeout occurs */
+       ret = stu300_wait_while_busy(dev);
+       if (ret != 0) {
+               dev_err(&dev->pdev->dev, "timout waiting for transfer "
+                      "to commence.\n");
+               goto exit_disable;
+       }
+
+       /* Dummy read status registers */
+       val = stu300_r8(dev->virtbase + I2C_SR2);
+       val = stu300_r8(dev->virtbase + I2C_SR1);
+       ret = 0;
+
+ exit_disable:
+       /* Disable controller */
+       stu300_wr8(0x00, dev->virtbase + I2C_CR);
+       clk_disable(dev->clk);
+       return ret;
+}
+
+static int stu300_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+                        int num)
+{
+       int ret = -1;
+       int i;
+       struct stu300_dev *dev = i2c_get_adapdata(adap);
+       dev->msg_len = num;
+       for (i = 0; i < num; i++) {
+               /*
+                * Another driver appears to send stop for each message,
+                * here we only do that for the last message. Possibly some
+                * peripherals require this behaviour, then their drivers
+                * have to send single messages in order to get "stop" for
+                * each message.
+                */
+               dev->msg_index = i;
+
+               ret = stu300_xfer_msg(adap, &msgs[i], (i == (num - 1)));
+               if (ret != 0) {
+                       num = ret;
+                       break;
+               }
+       }
+
+       return num;
+}
+
+static u32 stu300_func(struct i2c_adapter *adap)
+{
+       /* This is the simplest thing you can think of... */
+       return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR;
+}
+
+static const struct i2c_algorithm stu300_algo = {
+       .master_xfer    = stu300_xfer,
+       .functionality  = stu300_func,
+};
+
+static int __init
+stu300_probe(struct platform_device *pdev)
+{
+       struct stu300_dev *dev;
+       struct i2c_adapter *adap;
+       struct resource *res;
+       int bus_nr;
+       int ret = 0;
+
+       dev = kzalloc(sizeof(struct stu300_dev), GFP_KERNEL);
+       if (!dev) {
+               dev_err(&pdev->dev, "could not allocate device struct\n");
+               ret = -ENOMEM;
+               goto err_no_devmem;
+       }
+
+       bus_nr = pdev->id;
+       dev->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(dev->clk)) {
+               ret = PTR_ERR(dev->clk);
+               dev_err(&pdev->dev, "could not retrieve i2c bus clock\n");
+               goto err_no_clk;
+       }
+
+       dev->pdev = pdev;
+       platform_set_drvdata(pdev, dev);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               ret = -ENOENT;
+               goto err_no_resource;
+       }
+
+       dev->phybase = res->start;
+       dev->physize = resource_size(res);
+
+       if (request_mem_region(dev->phybase, dev->physize,
+                              NAME " I/O Area") == NULL) {
+               ret = -EBUSY;
+               goto err_no_ioregion;
+       }
+
+       dev->virtbase = ioremap(dev->phybase, dev->physize);
+       dev_dbg(&pdev->dev, "initialize bus device I2C%d on virtual "
+               "base %p\n", bus_nr, dev->virtbase);
+       if (!dev->virtbase) {
+               ret = -ENOMEM;
+               goto err_no_ioremap;
+       }
+
+       dev->irq = platform_get_irq(pdev, 0);
+       if (request_irq(dev->irq, stu300_irh, IRQF_DISABLED,
+                       NAME, dev)) {
+               ret = -EIO;
+               goto err_no_irq;
+       }
+
+       dev->speed = scl_frequency;
+
+       clk_enable(dev->clk);
+       ret = stu300_init_hw(dev);
+       clk_disable(dev->clk);
+
+       if (ret != 0) {
+               dev_err(&dev->pdev->dev, "error initializing hardware.\n");
+               goto err_init_hw;
+       }
+
+       /* IRQ event handling initialization */
+       spin_lock_init(&dev->cmd_issue_lock);
+       dev->cmd_event = STU300_EVENT_NONE;
+       dev->cmd_err = STU300_ERROR_NONE;
+
+       adap = &dev->adapter;
+       adap->owner = THIS_MODULE;
+       /* DDC class but actually often used for more generic I2C */
+       adap->class = I2C_CLASS_DDC;
+       strncpy(adap->name, "ST Microelectronics DDC I2C adapter",
+               sizeof(adap->name));
+       adap->nr = bus_nr;
+       adap->algo = &stu300_algo;
+       adap->dev.parent = &pdev->dev;
+       i2c_set_adapdata(adap, dev);
+
+       /* i2c device drivers may be active on return from add_adapter() */
+       ret = i2c_add_numbered_adapter(adap);
+       if (ret) {
+               dev_err(&dev->pdev->dev, "failure adding ST Micro DDC "
+                      "I2C adapter\n");
+               goto err_add_adapter;
+       }
+       return 0;
+
+ err_add_adapter:
+ err_init_hw:
+       free_irq(dev->irq, dev);
+ err_no_irq:
+       iounmap(dev->virtbase);
+ err_no_ioremap:
+       release_mem_region(dev->phybase, dev->physize);
+ err_no_ioregion:
+       platform_set_drvdata(pdev, NULL);
+ err_no_resource:
+       clk_put(dev->clk);
+ err_no_clk:
+       kfree(dev);
+ err_no_devmem:
+       dev_err(&pdev->dev, "failed to add " NAME " adapter: %d\n",
+               pdev->id);
+       return ret;
+}
+
+#ifdef CONFIG_PM
+static int stu300_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct stu300_dev *dev = platform_get_drvdata(pdev);
+
+       /* Turn off everything */
+       stu300_wr8(0x00, dev->virtbase + I2C_CR);
+       return 0;
+}
+
+static int stu300_resume(struct platform_device *pdev)
+{
+       int ret = 0;
+       struct stu300_dev *dev = platform_get_drvdata(pdev);
+
+       clk_enable(dev->clk);
+       ret = stu300_init_hw(dev);
+       clk_disable(dev->clk);
+
+       if (ret != 0)
+               dev_err(&pdev->dev, "error re-initializing hardware.\n");
+       return ret;
+}
+#else
+#define stu300_suspend NULL
+#define stu300_resume NULL
+#endif
+
+static int __exit
+stu300_remove(struct platform_device *pdev)
+{
+       struct stu300_dev *dev = platform_get_drvdata(pdev);
+
+       i2c_del_adapter(&dev->adapter);
+       /* Turn off everything */
+       stu300_wr8(0x00, dev->virtbase + I2C_CR);
+       free_irq(dev->irq, dev);
+       iounmap(dev->virtbase);
+       release_mem_region(dev->phybase, dev->physize);
+       clk_put(dev->clk);
+       platform_set_drvdata(pdev, NULL);
+       kfree(dev);
+       return 0;
+}
+
+static struct platform_driver stu300_i2c_driver = {
+       .driver = {
+               .name   = NAME,
+               .owner  = THIS_MODULE,
+       },
+       .remove         = __exit_p(stu300_remove),
+       .suspend        = stu300_suspend,
+       .resume         = stu300_resume,
+
+};
+
+static int __init stu300_init(void)
+{
+       return platform_driver_probe(&stu300_i2c_driver, stu300_probe);
+}
+
+static void __exit stu300_exit(void)
+{
+       platform_driver_unregister(&stu300_i2c_driver);
+}
+
+/*
+ * The systems using this bus often have very basic devices such
+ * as regulators on the I2C bus, so this needs to be loaded early.
+ * Therefore it is registered in the subsys_initcall().
+ */
+subsys_initcall(stu300_init);
+module_exit(stu300_exit);
+
+MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
+MODULE_DESCRIPTION("ST Micro DDC I2C adapter (" NAME ")");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" NAME);
index fede619ba227b2c5ef9e45f5be24af056f93661a..70de821634631a3e5108221ec6d1753aab0d654f 100644 (file)
@@ -76,7 +76,7 @@ static int i2c_versatile_probe(struct platform_device *dev)
                goto err_out;
        }
 
-       if (!request_mem_region(r->start, r->end - r->start + 1, "versatile-i2c")) {
+       if (!request_mem_region(r->start, resource_size(r), "versatile-i2c")) {
                ret = -EBUSY;
                goto err_out;
        }
@@ -87,7 +87,7 @@ static int i2c_versatile_probe(struct platform_device *dev)
                goto err_release;
        }
 
-       i2c->base = ioremap(r->start, r->end - r->start + 1);
+       i2c->base = ioremap(r->start, resource_size(r));
        if (!i2c->base) {
                ret = -ENOMEM;
                goto err_free;
@@ -118,7 +118,7 @@ static int i2c_versatile_probe(struct platform_device *dev)
  err_free:
        kfree(i2c);
  err_release:
-       release_mem_region(r->start, r->end - r->start + 1);
+       release_mem_region(r->start, resource_size(r));
  err_out:
        return ret;
 }
index 02e6f724b05f262196ad8c57dea9d27155eaa0db..54d810a4d00f86aa3ff687294e235b47a0a4a7cf 100644 (file)
@@ -37,6 +37,7 @@
    VT8251             0x3287             yes
    CX700              0x8324             yes
    VX800/VX820        0x8353             yes
+   VX855/VX875        0x8409             yes
 
    Note: we assume there can only be one device, with one SMBus interface.
 */
@@ -404,6 +405,7 @@ found:
        switch (pdev->device) {
        case PCI_DEVICE_ID_VIA_CX700:
        case PCI_DEVICE_ID_VIA_VX800:
+       case PCI_DEVICE_ID_VIA_VX855:
        case PCI_DEVICE_ID_VIA_8251:
        case PCI_DEVICE_ID_VIA_8237:
        case PCI_DEVICE_ID_VIA_8237A:
@@ -469,6 +471,8 @@ static struct pci_device_id vt596_ids[] = {
          .driver_data = SMBBA3 },
        { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX800),
          .driver_data = SMBBA3 },
+       { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855),
+         .driver_data = SMBBA3 },
        { 0, }
 };
 
index 1a474acc0dddf10bf30648c9fbc519de2af0c28c..7663d57833a06e76d099a11366eb21eecaebc953 100644 (file)
@@ -163,7 +163,6 @@ static struct i2c_algo_bit_data voo_i2c_bit_data = {
 
 static struct i2c_adapter voodoo3_i2c_adapter = {
        .owner          = THIS_MODULE,
-       .class          = I2C_CLASS_TV_ANALOG, 
        .name           = "I2C Voodoo3/Banshee adapter",
        .algo_data      = &voo_i2c_bit_data,
 };
index 8f8c81eb0aee750006a7949ed530d10a4257503c..02d746c9c47451ebb0f14f4a28e20735c1185c4f 100644 (file)
@@ -64,21 +64,6 @@ config SENSORS_PCA9539
          This driver is deprecated and will be dropped soon. Use
          drivers/gpio/pca953x.c instead.
 
-config SENSORS_MAX6875
-       tristate "Maxim MAX6875 Power supply supervisor"
-       depends on EXPERIMENTAL
-       help
-         If you say yes here you get support for the Maxim MAX6875
-         EEPROM-programmable, quad power-supply sequencer/supervisor.
-
-         This provides an interface to program the EEPROM and reset the chip.
-
-         This driver also supports the Maxim MAX6874 hex power-supply
-         sequencer/supervisor if found at a compatible address.
-
-         This driver can also be built as a module.  If so, the module
-         will be called max6875.
-
 config SENSORS_TSL2550
        tristate "Taos TSL2550 ambient light sensor"
        depends on EXPERIMENTAL
index 55a37603718332dcceab0ef5c90f38a6cb054a8e..f4680d16ee341fee40cb6d1c3f615ee8a259eb54 100644 (file)
@@ -11,7 +11,6 @@
 #
 
 obj-$(CONFIG_DS1682)           += ds1682.o
-obj-$(CONFIG_SENSORS_MAX6875)  += max6875.o
 obj-$(CONFIG_SENSORS_PCA9539)  += pca9539.o
 obj-$(CONFIG_SENSORS_PCF8574)  += pcf8574.o
 obj-$(CONFIG_PCF8575)          += pcf8575.o
index 85e2e919d1cd86e36e0c07815edf2b098e87ae49..5ed622ee65c3bfaa45e3adc0481cfb6bc1a0c55c 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/idr.h>
-#include <linux/platform_device.h>
 #include <linux/mutex.h>
 #include <linux/completion.h>
 #include <linux/hardirq.h>
@@ -451,16 +450,6 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
 
        mutex_lock(&core_lock);
 
-       /* Add the adapter to the driver core.
-        * If the parent pointer is not set up,
-        * we add this adapter to the host bus.
-        */
-       if (adap->dev.parent == NULL) {
-               adap->dev.parent = &platform_bus;
-               pr_debug("I2C adapter driver [%s] forgot to specify "
-                        "physical device\n", adap->name);
-       }
-
        /* Set default timeout to 1 second if not already set */
        if (adap->timeout == 0)
                adap->timeout = HZ;
@@ -1022,7 +1011,8 @@ module_exit(i2c_exit);
  */
 int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 {
-       int ret;
+       unsigned long orig_jiffies;
+       int ret, try;
 
        /* REVISIT the fault reporting model here is weak:
         *
@@ -1060,7 +1050,15 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                        mutex_lock_nested(&adap->bus_lock, adap->level);
                }
 
-               ret = adap->algo->master_xfer(adap,msgs,num);
+               /* Retry automatically on arbitration loss */
+               orig_jiffies = jiffies;
+               for (ret = 0, try = 0; try <= adap->retries; try++) {
+                       ret = adap->algo->master_xfer(adap, msgs, num);
+                       if (ret != -EAGAIN)
+                               break;
+                       if (time_after(jiffies, orig_jiffies + adap->timeout))
+                               break;
+               }
                mutex_unlock(&adap->bus_lock);
 
                return ret;
@@ -1509,7 +1507,7 @@ struct i2c_adapter* i2c_get_adapter(int id)
        struct i2c_adapter *adapter;
 
        mutex_lock(&core_lock);
-       adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id);
+       adapter = idr_find(&i2c_adapter_idr, id);
        if (adapter && !try_module_get(adapter->owner))
                adapter = NULL;
 
@@ -1995,14 +1993,27 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
                   char read_write, u8 command, int protocol,
                   union i2c_smbus_data *data)
 {
+       unsigned long orig_jiffies;
+       int try;
        s32 res;
 
        flags &= I2C_M_TEN | I2C_CLIENT_PEC;
 
        if (adapter->algo->smbus_xfer) {
                mutex_lock(&adapter->bus_lock);
-               res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write,
-                                               command, protocol, data);
+
+               /* Retry automatically on arbitration loss */
+               orig_jiffies = jiffies;
+               for (res = 0, try = 0; try <= adapter->retries; try++) {
+                       res = adapter->algo->smbus_xfer(adapter, addr, flags,
+                                                       read_write, command,
+                                                       protocol, data);
+                       if (res != -EAGAIN)
+                               break;
+                       if (time_after(jiffies,
+                                      orig_jiffies + adapter->timeout))
+                               break;
+               }
                mutex_unlock(&adapter->bus_lock);
        } else
                res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
index ba1488bd84307bb90850977573d2e80c9778af69..c14ca144cffe035d7722b6bb9fb8720652ad11bc 100644 (file)
@@ -3,7 +3,8 @@
 
 int generic_ide_suspend(struct device *dev, pm_message_t mesg)
 {
-       ide_drive_t *drive = dev->driver_data, *pair = ide_get_pair_dev(drive);
+       ide_drive_t *drive = dev_get_drvdata(dev);
+       ide_drive_t *pair = ide_get_pair_dev(drive);
        ide_hwif_t *hwif = drive->hwif;
        struct request *rq;
        struct request_pm_state rqpm;
@@ -34,7 +35,8 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg)
 
 int generic_ide_resume(struct device *dev)
 {
-       ide_drive_t *drive = dev->driver_data, *pair = ide_get_pair_dev(drive);
+       ide_drive_t *drive = dev_get_drvdata(dev);
+       ide_drive_t *pair = ide_get_pair_dev(drive);
        ide_hwif_t *hwif = drive->hwif;
        struct request *rq;
        struct request_pm_state rqpm;
index f371b0de314f75374a6728d206dabb3a24ef676e..79e0af3fd158a229d2e1f2945e9d270297f4cc4f 100644 (file)
@@ -535,7 +535,7 @@ static int ide_register_port(ide_hwif_t *hwif)
 
        /* register with global device tree */
        dev_set_name(&hwif->gendev, hwif->name);
-       hwif->gendev.driver_data = hwif;
+       dev_set_drvdata(&hwif->gendev, hwif);
        if (hwif->gendev.parent == NULL)
                hwif->gendev.parent = hwif->dev;
        hwif->gendev.release = hwif_release_dev;
@@ -987,9 +987,9 @@ static void hwif_register_devices(ide_hwif_t *hwif)
                int ret;
 
                dev_set_name(dev, "%u.%u", hwif->index, i);
+               dev_set_drvdata(dev, drive);
                dev->parent = &hwif->gendev;
                dev->bus = &ide_bus_type;
-               dev->driver_data = drive;
                dev->release = drive_release_dev;
 
                ret = device_register(dev);
index ee9b55ecc62b10741d1c7693d00ca8209f66ca78..b579fbe88370c6c254c47ad4e681946b3a902a9d 100644 (file)
@@ -112,7 +112,7 @@ out:
 
 static int __devexit plat_ide_remove(struct platform_device *pdev)
 {
-       struct ide_host *host = pdev->dev.driver_data;
+       struct ide_host *host = dev_get_drvdata(&pdev->dev);
 
        ide_host_remove(host);
 
index a6dfeb0b3372898cb7c4a59dd2604c71981edd92..e76cac64c53307852a442adac5264fe387c625e3 100644 (file)
@@ -35,6 +35,7 @@
 
 #include <linux/errno.h>
 #include <linux/kernel.h>
+#include <linux/kmemcheck.h>
 #include <linux/string.h>
 #include <asm/bug.h>
 #include <asm/byteorder.h>
@@ -387,6 +388,7 @@ csr1212_new_descriptor_leaf(u8 dtype, u32 specifier_id,
        if (!kv)
                return NULL;
 
+       kmemcheck_annotate_variable(kv->value.leaf.data[0]);
        CSR1212_DESCRIPTOR_LEAF_SET_TYPE(kv, dtype);
        CSR1212_DESCRIPTOR_LEAF_SET_SPECIFIER_ID(kv, specifier_id);
 
index 4ca103577c0a3d809964cd519ec4d793f7c2213e..f5c586c2bba658cdfbef07d7e268431c0f64bfdb 100644 (file)
@@ -361,7 +361,7 @@ static int eth1394_new_node(struct eth1394_host_info *hi,
        node_info->pdg.sz = 0;
        node_info->fifo = CSR1212_INVALID_ADDR_SPACE;
 
-       ud->device.driver_data = node_info;
+       dev_set_drvdata(&ud->device, node_info);
        new_node->ud = ud;
 
        priv = netdev_priv(hi->dev);
@@ -406,7 +406,7 @@ static int eth1394_remove(struct device *dev)
        list_del(&old_node->list);
        kfree(old_node);
 
-       node_info = (struct eth1394_node_info*)ud->device.driver_data;
+       node_info = dev_get_drvdata(&ud->device);
 
        spin_lock_irqsave(&node_info->pdg.lock, flags);
        /* The partial datagram list should be empty, but we'll just
@@ -416,7 +416,7 @@ static int eth1394_remove(struct device *dev)
        spin_unlock_irqrestore(&node_info->pdg.lock, flags);
 
        kfree(node_info);
-       ud->device.driver_data = NULL;
+       dev_set_drvdata(&ud->device, NULL);
        return 0;
 }
 
@@ -688,7 +688,7 @@ static void ether1394_host_reset(struct hpsb_host *host)
        ether1394_reset_priv(dev, 0);
 
        list_for_each_entry(node, &priv->ip_node_list, list) {
-               node_info = node->ud->device.driver_data;
+               node_info = dev_get_drvdata(&node->ud->device);
 
                spin_lock_irqsave(&node_info->pdg.lock, flags);
 
@@ -872,8 +872,7 @@ static __be16 ether1394_parse_encap(struct sk_buff *skb, struct net_device *dev,
                if (!node)
                        return cpu_to_be16(0);
 
-               node_info =
-                   (struct eth1394_node_info *)node->ud->device.driver_data;
+               node_info = dev_get_drvdata(&node->ud->device);
 
                /* Update our speed/payload/fifo_offset table */
                node_info->maxpayload = maxpayload;
@@ -1080,7 +1079,7 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid,
                priv->ud_list[NODEID_TO_NODE(srcid)] = ud;
        }
 
-       node_info = (struct eth1394_node_info *)ud->device.driver_data;
+       node_info = dev_get_drvdata(&ud->device);
 
        /* First, did we receive a fragmented or unfragmented datagram? */
        hdr->words.word1 = ntohs(hdr->words.word1);
@@ -1617,8 +1616,7 @@ static int ether1394_tx(struct sk_buff *skb, struct net_device *dev)
                if (!node)
                        goto fail;
 
-               node_info =
-                   (struct eth1394_node_info *)node->ud->device.driver_data;
+               node_info = dev_get_drvdata(&node->ud->device);
                if (node_info->fifo == CSR1212_INVALID_ADDR_SPACE)
                        goto fail;
 
index a6d55bebe61ac1b3013f387d009116f4385cbfe0..5122b5a8aa2db1aea54221a70377a70d6e6ed021 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/bitmap.h>
 #include <linux/kernel.h>
+#include <linux/kmemcheck.h>
 #include <linux/list.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
@@ -39,7 +40,10 @@ struct nodemgr_csr_info {
        struct hpsb_host *host;
        nodeid_t nodeid;
        unsigned int generation;
+
+       kmemcheck_bitfield_begin(flags);
        unsigned int speed_unverified:1;
+       kmemcheck_bitfield_end(flags);
 };
 
 
@@ -1293,6 +1297,7 @@ static void nodemgr_node_scan_one(struct hpsb_host *host,
        u8 *speed;
 
        ci = kmalloc(sizeof(*ci), GFP_KERNEL);
+       kmemcheck_annotate_bitfield(ci, flags);
        if (!ci)
                return;
 
index a51ab233342de0f3e9fbf4be79d499ca3ab044cd..83b734aec923f795a5e4d79dcc162e68f5efaf5d 100644 (file)
@@ -718,7 +718,7 @@ static int sbp2_remove(struct device *dev)
        struct scsi_device *sdev;
 
        ud = container_of(dev, struct unit_directory, device);
-       lu = ud->device.driver_data;
+       lu = dev_get_drvdata(&ud->device);
        if (!lu)
                return 0;
 
@@ -746,7 +746,7 @@ static int sbp2_remove(struct device *dev)
 
 static int sbp2_update(struct unit_directory *ud)
 {
-       struct sbp2_lu *lu = ud->device.driver_data;
+       struct sbp2_lu *lu = dev_get_drvdata(&ud->device);
 
        if (sbp2_reconnect_device(lu) != 0) {
                /*
@@ -815,7 +815,7 @@ static struct sbp2_lu *sbp2_alloc_device(struct unit_directory *ud)
        atomic_set(&lu->state, SBP2LU_STATE_RUNNING);
        INIT_WORK(&lu->protocol_work, NULL);
 
-       ud->device.driver_data = lu;
+       dev_set_drvdata(&ud->device, lu);
 
        hi = hpsb_get_hostinfo(&sbp2_highlevel, ud->ne->host);
        if (!hi) {
@@ -1051,7 +1051,7 @@ static void sbp2_remove_device(struct sbp2_lu *lu)
                hpsb_unregister_addrspace(&sbp2_highlevel, hi->host,
                                          lu->status_fifo_addr);
 
-       lu->ud->device.driver_data = NULL;
+       dev_set_drvdata(&lu->ud->device, NULL);
 
        module_put(hi->host->driver->owner);
 no_hi:
index 5c04cfb54cb9244dd93dd4f916a8be2538d7aa20..158a214da2f7fd36b3c215203edc368a1fdb1cb1 100644 (file)
@@ -760,9 +760,9 @@ int ib_device_register_sysfs(struct ib_device *device)
        int i;
 
        class_dev->class      = &ib_class;
-       class_dev->driver_data = device;
        class_dev->parent     = device->dma_device;
        dev_set_name(class_dev, device->name);
+       dev_set_drvdata(class_dev, device);
 
        INIT_LIST_HEAD(&device->port_list);
 
index 85905ab9391fec6703765117fcc29d0500d038d2..ce4e6eff4792519193ebe9aa29d6e8aff5aaf5c5 100644 (file)
@@ -636,7 +636,7 @@ static ssize_t  ehca_show_##name(struct device *dev,                       \
        struct hipz_query_hca *rblock;                                     \
        int data;                                                          \
                                                                           \
-       shca = dev->driver_data;                                           \
+       shca = dev_get_drvdata(dev);                                       \
                                                                           \
        rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);                      \
        if (!rblock) {                                                     \
@@ -680,7 +680,7 @@ static ssize_t ehca_show_adapter_handle(struct device *dev,
                                        struct device_attribute *attr,
                                        char *buf)
 {
-       struct ehca_shca *shca = dev->driver_data;
+       struct ehca_shca *shca = dev_get_drvdata(dev);
 
        return sprintf(buf, "%llx\n", shca->ipz_hca_handle.handle);
 
@@ -749,7 +749,7 @@ static int __devinit ehca_probe(struct of_device *dev,
 
        shca->ofdev = dev;
        shca->ipz_hca_handle.handle = *handle;
-       dev->dev.driver_data = shca;
+       dev_set_drvdata(&dev->dev, shca);
 
        ret = ehca_sense_attributes(shca);
        if (ret < 0) {
@@ -878,7 +878,7 @@ probe1:
 
 static int __devexit ehca_remove(struct of_device *dev)
 {
-       struct ehca_shca *shca = dev->dev.driver_data;
+       struct ehca_shca *shca = dev_get_drvdata(&dev->dev);
        unsigned long flags;
        int ret;
 
index 5d445f48789b899528c1f30d1f1115f324d553a5..7c237e6ac7112f318c4a9fe941704948d612970e 100644 (file)
@@ -1265,8 +1265,14 @@ static struct device_type input_dev_type = {
        .uevent         = input_dev_uevent,
 };
 
+static char *input_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "input/%s", dev_name(dev));
+}
+
 struct class input_class = {
        .name           = "input",
+       .nodename       = input_nodename,
 };
 EXPORT_SYMBOL_GPL(input_class);
 
index 356b3a25efa24c4568a909c59dedaa7ebcbc040c..1c0b529c06aaa596b8fe4a663cd275ed4f39ead6 100644 (file)
@@ -35,7 +35,7 @@
 #include <linux/input.h>
 #include <linux/gameport.h>
 #include <linux/jiffies.h>
-#include <asm/timex.h>
+#include <linux/timex.h>
 
 #define DRIVER_DESC    "Analog joystick and gamepad driver"
 
index d6a30cee7bc79b63f5ed124d48dc36ac55bd9e05..6d67af5387adcfdff514133ca9f1ce9d0bf39f8b 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/input.h>
 #include <linux/platform_device.h>
+#include <linux/timex.h>
 #include <asm/io.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
index 69af8385ab141bc78329e103653d55103eb53558..2957d48e0045fa05d68bb38aafe6ec8c9d3462d8 100644 (file)
@@ -569,7 +569,7 @@ static int wm97xx_probe(struct device *dev)
        mutex_init(&wm->codec_mutex);
 
        wm->dev = dev;
-       dev->driver_data = wm;
+       dev_set_drvdata(dev, wm);
        wm->ac97 = to_ac97_t(dev);
 
        /* check that we have a supported codec */
index 928d2ed8865f6b296b2fe9550d599b016d06f606..b115726dc088b169003a725ba29de8a4171e58a9 100644 (file)
@@ -114,7 +114,7 @@ static int __devinit xenkbd_probe(struct xenbus_device *dev,
                xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
                return -ENOMEM;
        }
-       dev->dev.driver_data = info;
+       dev_set_drvdata(&dev->dev, info);
        info->xbdev = dev;
        info->irq = -1;
        snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename);
@@ -186,7 +186,7 @@ static int __devinit xenkbd_probe(struct xenbus_device *dev,
 
 static int xenkbd_resume(struct xenbus_device *dev)
 {
-       struct xenkbd_info *info = dev->dev.driver_data;
+       struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
 
        xenkbd_disconnect_backend(info);
        memset(info->page, 0, PAGE_SIZE);
@@ -195,7 +195,7 @@ static int xenkbd_resume(struct xenbus_device *dev)
 
 static int xenkbd_remove(struct xenbus_device *dev)
 {
-       struct xenkbd_info *info = dev->dev.driver_data;
+       struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
 
        xenkbd_disconnect_backend(info);
        if (info->kbd)
@@ -266,7 +266,7 @@ static void xenkbd_disconnect_backend(struct xenkbd_info *info)
 static void xenkbd_backend_changed(struct xenbus_device *dev,
                                   enum xenbus_state backend_state)
 {
-       struct xenkbd_info *info = dev->dev.driver_data;
+       struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
        int ret, val;
 
        switch (backend_state) {
index 0ddf9044948aeeb0a8d8affefb1c1afec36c252d..fde377c60cca753eafe9c358f7e562c6d538ad7b 100644 (file)
@@ -72,7 +72,7 @@ MODULE_PARM_DESC(verbose,"Verbose log operations "
                 "(default 0)");
 
 struct thermostat {
-       struct i2c_client       clt;
+       struct i2c_client       *clt;
        u8                      temps[3];
        u8                      cached_temp[3];
        u8                      initial_limits[3];
@@ -87,9 +87,6 @@ static struct of_device * of_dev;
 static struct thermostat* thermostat;
 static struct task_struct *thread_therm = NULL;
 
-static int attach_one_thermostat(struct i2c_adapter *adapter, int addr,
-                                int busno);
-
 static void write_both_fan_speed(struct thermostat *th, int speed);
 static void write_fan_speed(struct thermostat *th, int speed, int fan);
 
@@ -101,7 +98,7 @@ write_reg(struct thermostat* th, int reg, u8 data)
        
        tmp[0] = reg;
        tmp[1] = data;
-       rc = i2c_master_send(&th->clt, (const char *)tmp, 2);
+       rc = i2c_master_send(th->clt, (const char *)tmp, 2);
        if (rc < 0)
                return rc;
        if (rc != 2)
@@ -116,12 +113,12 @@ read_reg(struct thermostat* th, int reg)
        int rc;
 
        reg_addr = (u8)reg;
-       rc = i2c_master_send(&th->clt, &reg_addr, 1);
+       rc = i2c_master_send(th->clt, &reg_addr, 1);
        if (rc < 0)
                return rc;
        if (rc != 1)
                return -ENODEV;
-       rc = i2c_master_recv(&th->clt, (char *)&data, 1);
+       rc = i2c_master_recv(th->clt, (char *)&data, 1);
        if (rc < 0)
                return rc;
        return data;
@@ -131,26 +128,36 @@ static int
 attach_thermostat(struct i2c_adapter *adapter)
 {
        unsigned long bus_no;
+       struct i2c_board_info info;
+       struct i2c_client *client;
 
        if (strncmp(adapter->name, "uni-n", 5))
                return -ENODEV;
        bus_no = simple_strtoul(adapter->name + 6, NULL, 10);
        if (bus_no != therm_bus)
                return -ENODEV;
-       return attach_one_thermostat(adapter, therm_address, bus_no);
+
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       strlcpy(info.type, "therm_adt746x", I2C_NAME_SIZE);
+       info.addr = therm_address;
+       client = i2c_new_device(adapter, &info);
+       if (!client)
+               return -ENODEV;
+
+       /*
+        * Let i2c-core delete that device on driver removal.
+        * This is safe because i2c-core holds the core_lock mutex for us.
+        */
+       list_add_tail(&client->detected, &client->driver->clients);
+       return 0;
 }
 
 static int
-detach_thermostat(struct i2c_adapter *adapter)
+remove_thermostat(struct i2c_client *client)
 {
-       struct thermostat* th;
+       struct thermostat *th = i2c_get_clientdata(client);
        int i;
        
-       if (thermostat == NULL)
-               return 0;
-
-       th = thermostat;
-
        if (thread_therm != NULL) {
                kthread_stop(thread_therm);
        }
@@ -166,8 +173,6 @@ detach_thermostat(struct i2c_adapter *adapter)
 
        write_both_fan_speed(th, -1);
 
-       i2c_detach_client(&th->clt);
-
        thermostat = NULL;
 
        kfree(th);
@@ -175,14 +180,6 @@ detach_thermostat(struct i2c_adapter *adapter)
        return 0;
 }
 
-static struct i2c_driver thermostat_driver = {  
-       .driver = {
-               .name   = "therm_adt746x",
-       },
-       .attach_adapter = attach_thermostat,
-       .detach_adapter = detach_thermostat,
-};
-
 static int read_fan_speed(struct thermostat *th, u8 addr)
 {
        u8 tmp[2];
@@ -371,8 +368,8 @@ static void set_limit(struct thermostat *th, int i)
                th->limits[i] = default_limits_local[i] + limit_adjust;
 }
 
-static int attach_one_thermostat(struct i2c_adapter *adapter, int addr,
-                                int busno)
+static int probe_thermostat(struct i2c_client *client,
+                           const struct i2c_device_id *id)
 {
        struct thermostat* th;
        int rc;
@@ -385,16 +382,12 @@ static int attach_one_thermostat(struct i2c_adapter *adapter, int addr,
        if (!th)
                return -ENOMEM;
 
-       th->clt.addr = addr;
-       th->clt.adapter = adapter;
-       th->clt.driver = &thermostat_driver;
-       strcpy(th->clt.name, "thermostat");
+       i2c_set_clientdata(client, th);
+       th->clt = client;
 
        rc = read_reg(th, 0);
        if (rc < 0) {
-               printk(KERN_ERR "adt746x: Thermostat failed to read config "
-                               "from bus %d !\n",
-                               busno);
+               dev_err(&client->dev, "Thermostat failed to read config!\n");
                kfree(th);
                return -ENODEV;
        }
@@ -423,14 +416,6 @@ static int attach_one_thermostat(struct i2c_adapter *adapter, int addr,
 
        thermostat = th;
 
-       if (i2c_attach_client(&th->clt)) {
-               printk(KERN_INFO "adt746x: Thermostat failed to attach "
-                                "client !\n");
-               thermostat = NULL;
-               kfree(th);
-               return -ENODEV;
-       }
-
        /* be sure to really write fan speed the first time */
        th->last_speed[0] = -2;
        th->last_speed[1] = -2;
@@ -456,6 +441,21 @@ static int attach_one_thermostat(struct i2c_adapter *adapter, int addr,
        return 0;
 }
 
+static const struct i2c_device_id therm_adt746x_id[] = {
+       { "therm_adt746x", 0 },
+       { }
+};
+
+static struct i2c_driver thermostat_driver = {
+       .driver = {
+               .name   = "therm_adt746x",
+       },
+       .attach_adapter = attach_thermostat,
+       .probe = probe_thermostat,
+       .remove = remove_thermostat,
+       .id_table = therm_adt746x_id,
+};
+
 /* 
  * Now, unfortunately, sysfs doesn't give us a nice void * we could
  * pass around to the attribute functions, so we don't really have
index 817607e2af6a9c89193cc390ab16d2455dc7a0f7..a028598af2d32ae030596bff2e83145420271d65 100644 (file)
@@ -286,22 +286,6 @@ struct fcu_fan_table       fcu_fans[] = {
        },
 };
 
-/*
- * i2c_driver structure to attach to the host i2c controller
- */
-
-static int therm_pm72_attach(struct i2c_adapter *adapter);
-static int therm_pm72_detach(struct i2c_adapter *adapter);
-
-static struct i2c_driver therm_pm72_driver =
-{
-       .driver = {
-               .name   = "therm_pm72",
-       },
-       .attach_adapter = therm_pm72_attach,
-       .detach_adapter = therm_pm72_detach,
-};
-
 /*
  * Utility function to create an i2c_client structure and
  * attach it to one of u3 adapters
@@ -310,6 +294,7 @@ static struct i2c_client *attach_i2c_chip(int id, const char *name)
 {
        struct i2c_client *clt;
        struct i2c_adapter *adap;
+       struct i2c_board_info info;
 
        if (id & 0x200)
                adap = k2;
@@ -320,31 +305,21 @@ static struct i2c_client *attach_i2c_chip(int id, const char *name)
        if (adap == NULL)
                return NULL;
 
-       clt = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
-       if (clt == NULL)
-               return NULL;
-
-       clt->addr = (id >> 1) & 0x7f;
-       clt->adapter = adap;
-       clt->driver = &therm_pm72_driver;
-       strncpy(clt->name, name, I2C_NAME_SIZE-1);
-
-       if (i2c_attach_client(clt)) {
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       info.addr = (id >> 1) & 0x7f;
+       strlcpy(info.type, "therm_pm72", I2C_NAME_SIZE);
+       clt = i2c_new_device(adap, &info);
+       if (!clt) {
                printk(KERN_ERR "therm_pm72: Failed to attach to i2c ID 0x%x\n", id);
-               kfree(clt);
                return NULL;
        }
-       return clt;
-}
 
-/*
- * Utility function to get rid of the i2c_client structure
- * (will also detach from the adapter hopepfully)
- */
-static void detach_i2c_chip(struct i2c_client *clt)
-{
-       i2c_detach_client(clt);
-       kfree(clt);
+       /*
+        * Let i2c-core delete that device on driver removal.
+        * This is safe because i2c-core holds the core_lock mutex for us.
+        */
+       list_add_tail(&clt->detected, &clt->driver->clients);
+       return clt;
 }
 
 /*
@@ -1203,8 +1178,6 @@ static int init_cpu_state(struct cpu_pid_state *state, int index)
 
        return 0;
  fail:
-       if (state->monitor)
-               detach_i2c_chip(state->monitor);
        state->monitor = NULL;
        
        return -ENODEV;
@@ -1232,7 +1205,6 @@ static void dispose_cpu_state(struct cpu_pid_state *state)
                device_remove_file(&of_dev->dev, &dev_attr_cpu1_intake_fan_rpm);
        }
 
-       detach_i2c_chip(state->monitor);
        state->monitor = NULL;
 }
 
@@ -1407,7 +1379,6 @@ static void dispose_backside_state(struct backside_pid_state *state)
        device_remove_file(&of_dev->dev, &dev_attr_backside_temperature);
        device_remove_file(&of_dev->dev, &dev_attr_backside_fan_pwm);
 
-       detach_i2c_chip(state->monitor);
        state->monitor = NULL;
 }
  
@@ -1532,7 +1503,6 @@ static void dispose_drives_state(struct drives_pid_state *state)
        device_remove_file(&of_dev->dev, &dev_attr_drives_temperature);
        device_remove_file(&of_dev->dev, &dev_attr_drives_fan_rpm);
 
-       detach_i2c_chip(state->monitor);
        state->monitor = NULL;
 }
 
@@ -1654,7 +1624,6 @@ static void dispose_dimms_state(struct dimm_pid_state *state)
 
        device_remove_file(&of_dev->dev, &dev_attr_dimms_temperature);
 
-       detach_i2c_chip(state->monitor);
        state->monitor = NULL;
 }
 
@@ -1779,7 +1748,6 @@ static void dispose_slots_state(struct slots_pid_state *state)
        device_remove_file(&of_dev->dev, &dev_attr_slots_temperature);
        device_remove_file(&of_dev->dev, &dev_attr_slots_fan_pwm);
 
-       detach_i2c_chip(state->monitor);
        state->monitor = NULL;
 }
 
@@ -2008,8 +1976,6 @@ static int attach_fcu(void)
  */
 static void detach_fcu(void)
 {
-       if (fcu)
-               detach_i2c_chip(fcu);
        fcu = NULL;
 }
 
@@ -2060,12 +2026,21 @@ static int therm_pm72_attach(struct i2c_adapter *adapter)
        return 0;
 }
 
+static int therm_pm72_probe(struct i2c_client *client,
+                           const struct i2c_device_id *id)
+{
+       /* Always succeed, the real work was done in therm_pm72_attach() */
+       return 0;
+}
+
 /*
- * Called on every adapter when the driver or the i2c controller
+ * Called when any of the devices which participates into thermal management
  * is going away.
  */
-static int therm_pm72_detach(struct i2c_adapter *adapter)
+static int therm_pm72_remove(struct i2c_client *client)
 {
+       struct i2c_adapter *adapter = client->adapter;
+
        mutex_lock(&driver_lock);
 
        if (state != state_detached)
@@ -2096,6 +2071,30 @@ static int therm_pm72_detach(struct i2c_adapter *adapter)
        return 0;
 }
 
+/*
+ * i2c_driver structure to attach to the host i2c controller
+ */
+
+static const struct i2c_device_id therm_pm72_id[] = {
+       /*
+        * Fake device name, thermal management is done by several
+        * chips but we don't need to differentiate between them at
+        * this point.
+        */
+       { "therm_pm72", 0 },
+       { }
+};
+
+static struct i2c_driver therm_pm72_driver = {
+       .driver = {
+               .name   = "therm_pm72",
+       },
+       .attach_adapter = therm_pm72_attach,
+       .probe          = therm_pm72_probe,
+       .remove         = therm_pm72_remove,
+       .id_table       = therm_pm72_id,
+};
+
 static int fan_check_loc_match(const char *loc, int fan)
 {
        char    tmp[64];
index 3da0a02efd7668f6088dd28eb05f88b7c1d0b768..40023313a760ac9005b74e04c17b3f7def7daa6e 100644 (file)
 
 #define LOG_TEMP               0                       /* continously log temperature */
 
-static int                     do_probe( struct i2c_adapter *adapter, int addr, int kind);
-
-/* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */
-static const unsigned short    normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
-                                                0x4c, 0x4d, 0x4e, 0x4f,
-                                                0x2c, 0x2d, 0x2e, 0x2f,
-                                                I2C_CLIENT_END };
-
-I2C_CLIENT_INSMOD;
-
 static struct {
        volatile int            running;
        struct task_struct      *poll_task;
@@ -315,53 +305,54 @@ static int control_loop(void *dummy)
 static int
 do_attach( struct i2c_adapter *adapter )
 {
-       int ret = 0;
+       /* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */
+       static const unsigned short scan_ds1775[] = {
+               0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+               I2C_CLIENT_END
+       };
+       static const unsigned short scan_adm1030[] = {
+               0x2c, 0x2d, 0x2e, 0x2f,
+               I2C_CLIENT_END
+       };
 
        if( strncmp(adapter->name, "uni-n", 5) )
                return 0;
 
        if( !x.running ) {
-               ret = i2c_probe( adapter, &addr_data, &do_probe );
+               struct i2c_board_info info;
+
+               memset(&info, 0, sizeof(struct i2c_board_info));
+               strlcpy(info.type, "therm_ds1775", I2C_NAME_SIZE);
+               i2c_new_probed_device(adapter, &info, scan_ds1775);
+
+               strlcpy(info.type, "therm_adm1030", I2C_NAME_SIZE);
+               i2c_new_probed_device(adapter, &info, scan_adm1030);
+
                if( x.thermostat && x.fan ) {
                        x.running = 1;
                        x.poll_task = kthread_run(control_loop, NULL, "g4fand");
                }
        }
-       return ret;
+       return 0;
 }
 
 static int
-do_detach( struct i2c_client *client )
+do_remove(struct i2c_client *client)
 {
-       int err;
-
-       if( (err=i2c_detach_client(client)) )
-               printk(KERN_ERR "failed to detach thermostat client\n");
-       else {
-               if( x.running ) {
-                       x.running = 0;
-                       kthread_stop(x.poll_task);
-                       x.poll_task = NULL;
-               }
-               if( client == x.thermostat )
-                       x.thermostat = NULL;
-               else if( client == x.fan )
-                       x.fan = NULL;
-               else {
-                       printk(KERN_ERR "g4fan: bad client\n");
-               }
-               kfree( client );
+       if (x.running) {
+               x.running = 0;
+               kthread_stop(x.poll_task);
+               x.poll_task = NULL;
        }
-       return err;
-}
+       if (client == x.thermostat)
+               x.thermostat = NULL;
+       else if (client == x.fan)
+               x.fan = NULL;
+       else
+               printk(KERN_ERR "g4fan: bad client\n");
 
-static struct i2c_driver g4fan_driver = {  
-       .driver = {
-               .name   = "therm_windtunnel",
-       },
-       .attach_adapter = do_attach,
-       .detach_client  = do_detach,
-};
+       return 0;
+}
 
 static int
 attach_fan( struct i2c_client *cl )
@@ -374,13 +365,8 @@ attach_fan( struct i2c_client *cl )
                goto out;
        printk("ADM1030 fan controller [@%02x]\n", cl->addr );
 
-       strlcpy( cl->name, "ADM1030 fan controller", sizeof(cl->name) );
-
-       if( !i2c_attach_client(cl) )
-               x.fan = cl;
+       x.fan = cl;
  out:
-       if( cl != x.fan )
-               kfree( cl );
        return 0;
 }
 
@@ -412,39 +398,47 @@ attach_thermostat( struct i2c_client *cl )
        x.temp = temp;
        x.overheat_temp = os_temp;
        x.overheat_hyst = hyst_temp;
-       
-       strlcpy( cl->name, "DS1775 thermostat", sizeof(cl->name) );
-
-       if( !i2c_attach_client(cl) )
-               x.thermostat = cl;
+       x.thermostat = cl;
 out:
-       if( cl != x.thermostat )
-               kfree( cl );
        return 0;
 }
 
+enum chip { ds1775, adm1030 };
+
+static const struct i2c_device_id therm_windtunnel_id[] = {
+       { "therm_ds1775", ds1775 },
+       { "therm_adm1030", adm1030 },
+       { }
+};
+
 static int
-do_probe( struct i2c_adapter *adapter, int addr, int kind )
+do_probe(struct i2c_client *cl, const struct i2c_device_id *id)
 {
-       struct i2c_client *cl;
+       struct i2c_adapter *adapter = cl->adapter;
 
        if( !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA
                                     | I2C_FUNC_SMBUS_WRITE_BYTE) )
                return 0;
 
-       if( !(cl=kzalloc(sizeof(*cl), GFP_KERNEL)) )
-               return -ENOMEM;
-
-       cl->addr = addr;
-       cl->adapter = adapter;
-       cl->driver = &g4fan_driver;
-       cl->flags = 0;
-
-       if( addr < 0x48 )
+       switch (id->driver_data) {
+       case adm1030:
                return attach_fan( cl );
-       return attach_thermostat( cl );
+       case ds1775:
+               return attach_thermostat(cl);
+       }
+       return 0;
 }
 
+static struct i2c_driver g4fan_driver = {
+       .driver = {
+               .name   = "therm_windtunnel",
+       },
+       .attach_adapter = do_attach,
+       .probe          = do_probe,
+       .remove         = do_remove,
+       .id_table       = therm_windtunnel_id,
+};
+
 
 /************************************************************************/
 /*     initialization / cleanup                                        */
index b92b959fe16e3a9d57ad4a610bd137f138a3d25d..529886c7a8263ae4d4d01df89b7b513695d983c3 100644 (file)
 struct wf_lm75_sensor {
        int                     ds1775 : 1;
        int                     inited : 1;
-       struct  i2c_client      i2c;
+       struct  i2c_client      *i2c;
        struct  wf_sensor       sens;
 };
 #define wf_to_lm75(c) container_of(c, struct wf_lm75_sensor, sens)
-#define i2c_to_lm75(c) container_of(c, struct wf_lm75_sensor, i2c)
-
-static int wf_lm75_attach(struct i2c_adapter *adapter);
-static int wf_lm75_detach(struct i2c_client *client);
-
-static struct i2c_driver wf_lm75_driver = {
-       .driver = {
-               .name   = "wf_lm75",
-       },
-       .attach_adapter = wf_lm75_attach,
-       .detach_client  = wf_lm75_detach,
-};
 
 static int wf_lm75_get(struct wf_sensor *sr, s32 *value)
 {
        struct wf_lm75_sensor *lm = wf_to_lm75(sr);
        s32 data;
 
-       if (lm->i2c.adapter == NULL)
+       if (lm->i2c == NULL)
                return -ENODEV;
 
        /* Init chip if necessary */
        if (!lm->inited) {
-               u8 cfg_new, cfg = (u8)i2c_smbus_read_byte_data(&lm->i2c, 1);
+               u8 cfg_new, cfg = (u8)i2c_smbus_read_byte_data(lm->i2c, 1);
 
                DBG("wf_lm75: Initializing %s, cfg was: %02x\n",
                    sr->name, cfg);
@@ -73,7 +61,7 @@ static int wf_lm75_get(struct wf_sensor *sr, s32 *value)
                 * the firmware for now
                 */
                cfg_new = cfg & ~0x01;
-               i2c_smbus_write_byte_data(&lm->i2c, 1, cfg_new);
+               i2c_smbus_write_byte_data(lm->i2c, 1, cfg_new);
                lm->inited = 1;
 
                /* If we just powered it up, let's wait 200 ms */
@@ -81,7 +69,7 @@ static int wf_lm75_get(struct wf_sensor *sr, s32 *value)
        }
 
        /* Read temperature register */
-       data = (s32)le16_to_cpu(i2c_smbus_read_word_data(&lm->i2c, 0));
+       data = (s32)le16_to_cpu(i2c_smbus_read_word_data(lm->i2c, 0));
        data <<= 8;
        *value = data;
 
@@ -92,12 +80,6 @@ static void wf_lm75_release(struct wf_sensor *sr)
 {
        struct wf_lm75_sensor *lm = wf_to_lm75(sr);
 
-       /* check if client is registered and detach from i2c */
-       if (lm->i2c.adapter) {
-               i2c_detach_client(&lm->i2c);
-               lm->i2c.adapter = NULL;
-       }
-
        kfree(lm);
 }
 
@@ -107,59 +89,77 @@ static struct wf_sensor_ops wf_lm75_ops = {
        .owner          = THIS_MODULE,
 };
 
-static struct wf_lm75_sensor *wf_lm75_create(struct i2c_adapter *adapter,
-                                            u8 addr, int ds1775,
-                                            const char *loc)
+static int wf_lm75_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
 {
        struct wf_lm75_sensor *lm;
        int rc;
 
-       DBG("wf_lm75: creating  %s device at address 0x%02x\n",
-           ds1775 ? "ds1775" : "lm75", addr);
-
        lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL);
        if (lm == NULL)
-               return NULL;
+               return -ENODEV;
+
+       lm->inited = 0;
+       lm->ds1775 = id->driver_data;
+       lm->i2c = client;
+       lm->sens.name = client->dev.platform_data;
+       lm->sens.ops = &wf_lm75_ops;
+       i2c_set_clientdata(client, lm);
+
+       rc = wf_register_sensor(&lm->sens);
+       if (rc) {
+               i2c_set_clientdata(client, NULL);
+               kfree(lm);
+       }
+
+       return rc;
+}
+
+static struct i2c_client *wf_lm75_create(struct i2c_adapter *adapter,
+                                            u8 addr, int ds1775,
+                                            const char *loc)
+{
+       struct i2c_board_info info;
+       struct i2c_client *client;
+       char *name;
+
+       DBG("wf_lm75: creating  %s device at address 0x%02x\n",
+           ds1775 ? "ds1775" : "lm75", addr);
 
        /* Usual rant about sensor names not beeing very consistent in
         * the device-tree, oh well ...
         * Add more entries below as you deal with more setups
         */
        if (!strcmp(loc, "Hard drive") || !strcmp(loc, "DRIVE BAY"))
-               lm->sens.name = "hd-temp";
+               name = "hd-temp";
        else if (!strcmp(loc, "Incoming Air Temp"))
-               lm->sens.name = "incoming-air-temp";
+               name = "incoming-air-temp";
        else if (!strcmp(loc, "ODD Temp"))
-               lm->sens.name = "optical-drive-temp";
+               name = "optical-drive-temp";
        else if (!strcmp(loc, "HD Temp"))
-               lm->sens.name = "hard-drive-temp";
+               name = "hard-drive-temp";
        else
                goto fail;
 
-       lm->inited = 0;
-       lm->sens.ops = &wf_lm75_ops;
-       lm->ds1775 = ds1775;
-       lm->i2c.addr = (addr >> 1) & 0x7f;
-       lm->i2c.adapter = adapter;
-       lm->i2c.driver = &wf_lm75_driver;
-       strncpy(lm->i2c.name, lm->sens.name, I2C_NAME_SIZE-1);
-
-       rc = i2c_attach_client(&lm->i2c);
-       if (rc) {
-               printk(KERN_ERR "windfarm: failed to attach %s %s to i2c,"
-                      " err %d\n", ds1775 ? "ds1775" : "lm75",
-                      lm->i2c.name, rc);
-               goto fail;
-       }
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       info.addr = (addr >> 1) & 0x7f;
+       info.platform_data = name;
+       strlcpy(info.type, ds1775 ? "wf_ds1775" : "wf_lm75", I2C_NAME_SIZE);
 
-       if (wf_register_sensor(&lm->sens)) {
-               i2c_detach_client(&lm->i2c);
+       client = i2c_new_device(adapter, &info);
+       if (client == NULL) {
+               printk(KERN_ERR "windfarm: failed to attach %s %s to i2c\n",
+                      ds1775 ? "ds1775" : "lm75", name);
                goto fail;
        }
 
-       return lm;
+       /*
+        * Let i2c-core delete that device on driver removal.
+        * This is safe because i2c-core holds the core_lock mutex for us.
+        */
+       list_add_tail(&client->detected, &client->driver->clients);
+       return client;
  fail:
-       kfree(lm);
        return NULL;
 }
 
@@ -202,21 +202,38 @@ static int wf_lm75_attach(struct i2c_adapter *adapter)
        return 0;
 }
 
-static int wf_lm75_detach(struct i2c_client *client)
+static int wf_lm75_remove(struct i2c_client *client)
 {
-       struct wf_lm75_sensor *lm = i2c_to_lm75(client);
+       struct wf_lm75_sensor *lm = i2c_get_clientdata(client);
 
        DBG("wf_lm75: i2c detatch called for %s\n", lm->sens.name);
 
        /* Mark client detached */
-       lm->i2c.adapter = NULL;
+       lm->i2c = NULL;
 
        /* release sensor */
        wf_unregister_sensor(&lm->sens);
 
+       i2c_set_clientdata(client, NULL);
        return 0;
 }
 
+static const struct i2c_device_id wf_lm75_id[] = {
+       { "wf_lm75", 0 },
+       { "wf_ds1775", 1 },
+       { }
+};
+
+static struct i2c_driver wf_lm75_driver = {
+       .driver = {
+               .name   = "wf_lm75",
+       },
+       .attach_adapter = wf_lm75_attach,
+       .probe          = wf_lm75_probe,
+       .remove         = wf_lm75_remove,
+       .id_table       = wf_lm75_id,
+};
+
 static int __init wf_lm75_sensor_init(void)
 {
        /* Don't register on old machines that use therm_pm72 for now */
index e207a90d6b2762fa887bdfdc30344958f00a8373..e2a55ecda2b28aa2c80114dd7d6c7ec0cd519827 100644 (file)
 #define MAX6690_EXTERNAL_TEMP  1
 
 struct wf_6690_sensor {
-       struct i2c_client       i2c;
+       struct i2c_client       *i2c;
        struct wf_sensor        sens;
 };
 
 #define wf_to_6690(x)  container_of((x), struct wf_6690_sensor, sens)
-#define i2c_to_6690(x) container_of((x), struct wf_6690_sensor, i2c)
-
-static int wf_max6690_attach(struct i2c_adapter *adapter);
-static int wf_max6690_detach(struct i2c_client *client);
-
-static struct i2c_driver wf_max6690_driver = {
-       .driver = {
-               .name           = "wf_max6690",
-       },
-       .attach_adapter = wf_max6690_attach,
-       .detach_client  = wf_max6690_detach,
-};
 
 static int wf_max6690_get(struct wf_sensor *sr, s32 *value)
 {
        struct wf_6690_sensor *max = wf_to_6690(sr);
        s32 data;
 
-       if (max->i2c.adapter == NULL)
+       if (max->i2c == NULL)
                return -ENODEV;
 
        /* chip gets initialized by firmware */
-       data = i2c_smbus_read_byte_data(&max->i2c, MAX6690_EXTERNAL_TEMP);
+       data = i2c_smbus_read_byte_data(max->i2c, MAX6690_EXTERNAL_TEMP);
        if (data < 0)
                return data;
        *value = data << 16;
@@ -64,10 +52,6 @@ static void wf_max6690_release(struct wf_sensor *sr)
 {
        struct wf_6690_sensor *max = wf_to_6690(sr);
 
-       if (max->i2c.adapter) {
-               i2c_detach_client(&max->i2c);
-               max->i2c.adapter = NULL;
-       }
        kfree(max);
 }
 
@@ -77,19 +61,40 @@ static struct wf_sensor_ops wf_max6690_ops = {
        .owner          = THIS_MODULE,
 };
 
-static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr,
-                             const char *loc)
+static int wf_max6690_probe(struct i2c_client *client,
+                           const struct i2c_device_id *id)
 {
        struct wf_6690_sensor *max;
-       char *name;
+       int rc;
 
        max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL);
        if (max == NULL) {
-               printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor %s: "
-                      "no memory\n", loc);
-               return;
+               printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor: "
+                      "no memory\n");
+               return -ENOMEM;
+       }
+
+       max->i2c = client;
+       max->sens.name = client->dev.platform_data;
+       max->sens.ops = &wf_max6690_ops;
+       i2c_set_clientdata(client, max);
+
+       rc = wf_register_sensor(&max->sens);
+       if (rc) {
+               i2c_set_clientdata(client, NULL);
+               kfree(max);
        }
 
+       return rc;
+}
+
+static struct i2c_client *wf_max6690_create(struct i2c_adapter *adapter,
+                                           u8 addr, const char *loc)
+{
+       struct i2c_board_info info;
+       struct i2c_client *client;
+       char *name;
+
        if (!strcmp(loc, "BACKSIDE"))
                name = "backside-temp";
        else if (!strcmp(loc, "NB Ambient"))
@@ -99,27 +104,26 @@ static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr,
        else
                goto fail;
 
-       max->sens.ops = &wf_max6690_ops;
-       max->sens.name = name;
-       max->i2c.addr = addr >> 1;
-       max->i2c.adapter = adapter;
-       max->i2c.driver = &wf_max6690_driver;
-       strncpy(max->i2c.name, name, I2C_NAME_SIZE-1);
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       info.addr = addr >> 1;
+       info.platform_data = name;
+       strlcpy(info.type, "wf_max6690", I2C_NAME_SIZE);
 
-       if (i2c_attach_client(&max->i2c)) {
+       client = i2c_new_device(adapter, &info);
+       if (client == NULL) {
                printk(KERN_ERR "windfarm: failed to attach MAX6690 sensor\n");
                goto fail;
        }
 
-       if (wf_register_sensor(&max->sens)) {
-               i2c_detach_client(&max->i2c);
-               goto fail;
-       }
-
-       return;
+       /*
+        * Let i2c-core delete that device on driver removal.
+        * This is safe because i2c-core holds the core_lock mutex for us.
+        */
+       list_add_tail(&client->detected, &client->driver->clients);
+       return client;
 
  fail:
-       kfree(max);
+       return NULL;
 }
 
 static int wf_max6690_attach(struct i2c_adapter *adapter)
@@ -154,16 +158,31 @@ static int wf_max6690_attach(struct i2c_adapter *adapter)
        return 0;
 }
 
-static int wf_max6690_detach(struct i2c_client *client)
+static int wf_max6690_remove(struct i2c_client *client)
 {
-       struct wf_6690_sensor *max = i2c_to_6690(client);
+       struct wf_6690_sensor *max = i2c_get_clientdata(client);
 
-       max->i2c.adapter = NULL;
+       max->i2c = NULL;
        wf_unregister_sensor(&max->sens);
 
        return 0;
 }
 
+static const struct i2c_device_id wf_max6690_id[] = {
+       { "wf_max6690", 0 },
+       { }
+};
+
+static struct i2c_driver wf_max6690_driver = {
+       .driver = {
+               .name           = "wf_max6690",
+       },
+       .attach_adapter = wf_max6690_attach,
+       .probe          = wf_max6690_probe,
+       .remove         = wf_max6690_remove,
+       .id_table       = wf_max6690_id,
+};
+
 static int __init wf_max6690_sensor_init(void)
 {
        /* Don't register on old machines that use therm_pm72 for now */
index 7847e981ac33eaeaead929137aa68e0ef13937f2..5da729e58f99294ec43cd23ec7bee680da7e70b7 100644 (file)
@@ -39,7 +39,7 @@ struct wf_sat {
        struct mutex            mutex;
        unsigned long           last_read; /* jiffies when cache last updated */
        u8                      cache[16];
-       struct i2c_client       i2c;
+       struct i2c_client       *i2c;
        struct device_node      *node;
 };
 
@@ -54,18 +54,6 @@ struct wf_sat_sensor {
 };
 
 #define wf_to_sat(c)   container_of(c, struct wf_sat_sensor, sens)
-#define i2c_to_sat(c)  container_of(c, struct wf_sat, i2c)
-
-static int wf_sat_attach(struct i2c_adapter *adapter);
-static int wf_sat_detach(struct i2c_client *client);
-
-static struct i2c_driver wf_sat_driver = {
-       .driver = {
-               .name           = "wf_smu_sat",
-       },
-       .attach_adapter = wf_sat_attach,
-       .detach_client  = wf_sat_detach,
-};
 
 struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id,
                                                  unsigned int *size)
@@ -81,13 +69,13 @@ struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id,
        if (sat_id > 1 || (sat = sats[sat_id]) == NULL)
                return NULL;
 
-       err = i2c_smbus_write_word_data(&sat->i2c, 8, id << 8);
+       err = i2c_smbus_write_word_data(sat->i2c, 8, id << 8);
        if (err) {
                printk(KERN_ERR "smu_sat_get_sdb_part wr error %d\n", err);
                return NULL;
        }
 
-       err = i2c_smbus_read_word_data(&sat->i2c, 9);
+       err = i2c_smbus_read_word_data(sat->i2c, 9);
        if (err < 0) {
                printk(KERN_ERR "smu_sat_get_sdb_part rd len error\n");
                return NULL;
@@ -105,7 +93,7 @@ struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id,
                return NULL;
 
        for (i = 0; i < len; i += 4) {
-               err = i2c_smbus_read_i2c_block_data(&sat->i2c, 0xa, 4, data);
+               err = i2c_smbus_read_i2c_block_data(sat->i2c, 0xa, 4, data);
                if (err < 0) {
                        printk(KERN_ERR "smu_sat_get_sdb_part rd err %d\n",
                               err);
@@ -138,7 +126,7 @@ static int wf_sat_read_cache(struct wf_sat *sat)
 {
        int err;
 
-       err = i2c_smbus_read_i2c_block_data(&sat->i2c, 0x3f, 16, sat->cache);
+       err = i2c_smbus_read_i2c_block_data(sat->i2c, 0x3f, 16, sat->cache);
        if (err < 0)
                return err;
        sat->last_read = jiffies;
@@ -161,7 +149,7 @@ static int wf_sat_get(struct wf_sensor *sr, s32 *value)
        int i, err;
        s32 val;
 
-       if (sat->i2c.adapter == NULL)
+       if (sat->i2c == NULL)
                return -ENODEV;
 
        mutex_lock(&sat->mutex);
@@ -193,10 +181,6 @@ static void wf_sat_release(struct wf_sensor *sr)
        struct wf_sat *sat = sens->sat;
 
        if (atomic_dec_and_test(&sat->refcnt)) {
-               if (sat->i2c.adapter) {
-                       i2c_detach_client(&sat->i2c);
-                       sat->i2c.adapter = NULL;
-               }
                if (sat->nr >= 0)
                        sats[sat->nr] = NULL;
                kfree(sat);
@@ -212,38 +196,58 @@ static struct wf_sensor_ops wf_sat_ops = {
 
 static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev)
 {
+       struct i2c_board_info info;
+       struct i2c_client *client;
+       const u32 *reg;
+       u8 addr;
+
+       reg = of_get_property(dev, "reg", NULL);
+       if (reg == NULL)
+               return;
+       addr = *reg;
+       DBG(KERN_DEBUG "wf_sat: creating sat at address %x\n", addr);
+
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       info.addr = (addr >> 1) & 0x7f;
+       info.platform_data = dev;
+       strlcpy(info.type, "wf_sat", I2C_NAME_SIZE);
+
+       client = i2c_new_device(adapter, &info);
+       if (client == NULL) {
+               printk(KERN_ERR "windfarm: failed to attach smu-sat to i2c\n");
+               return;
+       }
+
+       /*
+        * Let i2c-core delete that device on driver removal.
+        * This is safe because i2c-core holds the core_lock mutex for us.
+        */
+       list_add_tail(&client->detected, &client->driver->clients);
+}
+
+static int wf_sat_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct device_node *dev = client->dev.platform_data;
        struct wf_sat *sat;
        struct wf_sat_sensor *sens;
        const u32 *reg;
        const char *loc, *type;
-       u8 addr, chip, core;
+       u8 chip, core;
        struct device_node *child;
        int shift, cpu, index;
        char *name;
        int vsens[2], isens[2];
 
-       reg = of_get_property(dev, "reg", NULL);
-       if (reg == NULL)
-               return;
-       addr = *reg;
-       DBG(KERN_DEBUG "wf_sat: creating sat at address %x\n", addr);
-
        sat = kzalloc(sizeof(struct wf_sat), GFP_KERNEL);
        if (sat == NULL)
-               return;
+               return -ENOMEM;
        sat->nr = -1;
        sat->node = of_node_get(dev);
        atomic_set(&sat->refcnt, 0);
        mutex_init(&sat->mutex);
-       sat->i2c.addr = (addr >> 1) & 0x7f;
-       sat->i2c.adapter = adapter;
-       sat->i2c.driver = &wf_sat_driver;
-       strncpy(sat->i2c.name, "smu-sat", I2C_NAME_SIZE-1);
-
-       if (i2c_attach_client(&sat->i2c)) {
-               printk(KERN_ERR "windfarm: failed to attach smu-sat to i2c\n");
-               goto fail;
-       }
+       sat->i2c = client;
+       i2c_set_clientdata(client, sat);
 
        vsens[0] = vsens[1] = -1;
        isens[0] = isens[1] = -1;
@@ -344,10 +348,7 @@ static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev)
        if (sat->nr >= 0)
                sats[sat->nr] = sat;
 
-       return;
-
- fail:
-       kfree(sat);
+       return 0;
 }
 
 static int wf_sat_attach(struct i2c_adapter *adapter)
@@ -366,16 +367,32 @@ static int wf_sat_attach(struct i2c_adapter *adapter)
        return 0;
 }
 
-static int wf_sat_detach(struct i2c_client *client)
+static int wf_sat_remove(struct i2c_client *client)
 {
-       struct wf_sat *sat = i2c_to_sat(client);
+       struct wf_sat *sat = i2c_get_clientdata(client);
 
        /* XXX TODO */
 
-       sat->i2c.adapter = NULL;
+       sat->i2c = NULL;
+       i2c_set_clientdata(client, NULL);
        return 0;
 }
 
+static const struct i2c_device_id wf_sat_id[] = {
+       { "wf_sat", 0 },
+       { }
+};
+
+static struct i2c_driver wf_sat_driver = {
+       .driver = {
+               .name           = "wf_smu_sat",
+       },
+       .attach_adapter = wf_sat_attach,
+       .probe          = wf_sat_probe,
+       .remove         = wf_sat_remove,
+       .id_table       = wf_sat_id,
+};
+
 static int __init sat_sensors_init(void)
 {
        return i2c_add_driver(&wf_sat_driver);
index 823ceba6efa8dcccc95b14cf72986195c52b3ae8..1128d3fba797f38a89f39849eea012bc9daa22d1 100644 (file)
@@ -1513,6 +1513,7 @@ static const struct file_operations _ctl_fops = {
 static struct miscdevice _dm_misc = {
        .minor          = MISC_DYNAMIC_MINOR,
        .name           = DM_NAME,
+       .devnode        = "mapper/control",
        .fops           = &_ctl_fops
 };
 
index 3fd8b1e65483da53070f0fe633e82843ac1a5ba0..48db308fae67103b221eeb1c10e4411560b88135 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/slab.h>
 #include <linux/idr.h>
 #include <linux/hdreg.h>
-#include <linux/blktrace_api.h>
 
 #include <trace/events/block.h>
 
index 223c36ede5ae66e3552682c63bc9fc9df4394d57..ba69beeb0e21a850aab9d1a49b11c409b332f44e 100644 (file)
@@ -2,8 +2,14 @@
 # Multimedia device configuration
 #
 
-menu "Multimedia devices"
+menuconfig MEDIA_SUPPORT
+       tristate "Multimedia support"
        depends on HAS_IOMEM
+       help
+         If you want to use Video for Linux, DVB for Linux, or DAB adapters,
+         enable this option and other options below.
+
+if MEDIA_SUPPORT
 
 comment "Multimedia core support"
 
@@ -136,4 +142,4 @@ config USB_DABUSB
          module will be called dabusb.
 endif # DAB
 
-endmenu
+endif # MEDIA_SUPPORT
index 78412c9c424a13e492a59ad467368716755be6b2..149d54cdf7b97a4ff92107e3afffbb1c773a1ddc 100644 (file)
@@ -416,6 +416,24 @@ static int simple_std_setup(struct dvb_frontend *fe,
        return 0;
 }
 
+static int simple_set_aux_byte(struct dvb_frontend *fe, u8 config, u8 aux)
+{
+       struct tuner_simple_priv *priv = fe->tuner_priv;
+       int rc;
+       u8 buffer[2];
+
+       buffer[0] = (config & ~0x38) | 0x18;
+       buffer[1] = aux;
+
+       tuner_dbg("setting aux byte: 0x%02x 0x%02x\n", buffer[0], buffer[1]);
+
+       rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2);
+       if (2 != rc)
+               tuner_warn("i2c i/o error: rc == %d (should be 2)\n", rc);
+
+       return rc == 2 ? 0 : rc;
+}
+
 static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer,
                            u16 div, u8 config, u8 cb)
 {
@@ -424,17 +442,10 @@ static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer,
 
        switch (priv->type) {
        case TUNER_LG_TDVS_H06XF:
-               /* Set the Auxiliary Byte. */
-               buffer[0] = buffer[2];
-               buffer[0] &= ~0x20;
-               buffer[0] |= 0x18;
-               buffer[1] = 0x20;
-               tuner_dbg("tv 0x%02x 0x%02x\n", buffer[0], buffer[1]);
-
-               rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2);
-               if (2 != rc)
-                       tuner_warn("i2c i/o error: rc == %d "
-                                  "(should be 2)\n", rc);
+               simple_set_aux_byte(fe, config, 0x20);
+               break;
+       case TUNER_PHILIPS_FQ1216LME_MK3:
+               simple_set_aux_byte(fe, config, 0x60); /* External AGC */
                break;
        case TUNER_MICROTUNE_4042FI5:
        {
@@ -506,6 +517,11 @@ static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer)
        case TUNER_THOMSON_DTT761X:
                buffer[3] = 0x39;
                break;
+       case TUNER_PHILIPS_FQ1216LME_MK3:
+               tuner_err("This tuner doesn't have FM\n");
+               /* Set the low band for sanity, since it covers 88-108 MHz */
+               buffer[3] = 0x01;
+               break;
        case TUNER_MICROTUNE_4049FM5:
        default:
                buffer[3] = 0xa4;
@@ -678,12 +694,12 @@ static int simple_set_radio_freq(struct dvb_frontend *fe,
                return 0;
        }
 
-       /* Bandswitch byte */
-       simple_radio_bandswitch(fe, &buffer[0]);
-
        buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) |
                    TUNER_RATIO_SELECT_50; /* 50 kHz step */
 
+       /* Bandswitch byte */
+       simple_radio_bandswitch(fe, &buffer[0]);
+
        /* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps
           freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) =
           freq * (1/800) */
index 7c0bc064c008966b05316c842657dec7ae0972c7..6a7f1a417c278eff34d835029b4894fde8cedd48 100644 (file)
@@ -578,6 +578,31 @@ static struct tuner_params tuner_fm1216me_mk3_params[] = {
        },
 };
 
+/* ------------ TUNER_PHILIPS_FM1216MK5 - Philips PAL ------------ */
+
+static struct tuner_range tuner_fm1216mk5_pal_ranges[] = {
+       { 16 * 158.00 /*MHz*/, 0xce, 0x01, },
+       { 16 * 441.00 /*MHz*/, 0xce, 0x02, },
+       { 16 * 864.00        , 0xce, 0x04, },
+};
+
+static struct tuner_params tuner_fm1216mk5_params[] = {
+       {
+               .type   = TUNER_PARAM_TYPE_PAL,
+               .ranges = tuner_fm1216mk5_pal_ranges,
+               .count  = ARRAY_SIZE(tuner_fm1216mk5_pal_ranges),
+               .cb_first_if_lower_freq = 1,
+               .has_tda9887 = 1,
+               .port1_active = 1,
+               .port2_active = 1,
+               .port2_invert_for_secam_lc = 1,
+               .port1_fm_high_sensitivity = 1,
+               .default_top_mid = -2,
+               .default_top_secam_mid = -2,
+               .default_top_secam_high = -2,
+       },
+};
+
 /* ------------ TUNER_LG_NTSC_NEW_TAPC - LGINNOTEK NTSC ------------ */
 
 static struct tuner_params tuner_lg_ntsc_new_tapc_params[] = {
@@ -1254,6 +1279,28 @@ static struct tuner_params tuner_tcl_mf02gip_5n_params[] = {
        },
 };
 
+/* 80-89 */
+/* --------- TUNER_PHILIPS_FQ1216LME_MK3 -- active loopthrough, no FM ------- */
+
+static struct tuner_params tuner_fq1216lme_mk3_params[] = {
+       {
+               .type   = TUNER_PARAM_TYPE_PAL,
+               .ranges = tuner_fm1216me_mk3_pal_ranges,
+               .count  = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges),
+               .cb_first_if_lower_freq = 1, /* not specified, but safe to do */
+               .has_tda9887 = 1, /* TDA9886 */
+               .port1_active = 1,
+               .port2_active = 1,
+               .port2_invert_for_secam_lc = 1,
+               .default_top_low = 4,
+               .default_top_mid = 4,
+               .default_top_high = 4,
+               .default_top_secam_low = 4,
+               .default_top_secam_mid = 4,
+               .default_top_secam_high = 4,
+       },
+};
+
 /* --------------------------------------------------------------------- */
 
 struct tunertype tuners[] = {
@@ -1694,6 +1741,18 @@ struct tunertype tuners[] = {
                .initdata = tua603x_agc112,
                .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 },
        },
+               [TUNER_PHILIPS_FM1216MK5] = { /* Philips PAL */
+               .name   = "Philips PAL/SECAM multi (FM1216 MK5)",
+               .params = tuner_fm1216mk5_params,
+               .count  = ARRAY_SIZE(tuner_fm1216mk5_params),
+       },
+
+       /* 80-89 */
+       [TUNER_PHILIPS_FQ1216LME_MK3] = { /* PAL/SECAM, Loop-thru, no FM */
+               .name = "Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough",
+               .params = tuner_fq1216lme_mk3_params,
+               .count  = ARRAY_SIZE(tuner_fq1216lme_mk3_params),
+       },
 };
 EXPORT_SYMBOL(tuners);
 
index 1adce9ff52ce0fea7daee80fa46f94e15f85d1b4..b6da9c3873fef280ba89d00234053d3a62b11ec6 100644 (file)
@@ -30,7 +30,7 @@ MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
 static int no_poweroff;
 module_param(no_poweroff, int, 0644);
-MODULE_PARM_DESC(debug, "0 (default) powers device off when not used.\n"
+MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n"
        "1 keep device energized and with tuner ready all the times.\n"
        "  Faster, but consumes more power and keeps the device hotter\n");
 
@@ -48,7 +48,7 @@ MODULE_PARM_DESC(audio_std,
        "NICAM/A\n"
        "NICAM/B\n");
 
-static char firmware_name[FIRMWARE_NAME_MAX];
+static char firmware_name[30];
 module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0);
 MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the "
                                "default firmware name\n");
@@ -272,7 +272,7 @@ static int load_all_firmwares(struct dvb_frontend *fe)
                fname = firmware_name;
 
        tuner_dbg("Reading firmware %s\n", fname);
-       rc = request_firmware(&fw, fname, &priv->i2c_props.adap->dev);
+       rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent);
        if (rc < 0) {
                if (rc == -ENOENT)
                        tuner_err("Error: firmware %s not found.\n",
@@ -917,22 +917,29 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
         * that xc2028 will be in a safe state.
         * Maybe this might also be needed for DTV.
         */
-       if (new_mode == T_ANALOG_TV) {
+       if (new_mode == T_ANALOG_TV)
                rc = send_seq(priv, {0x00, 0x00});
-       } else if (priv->cur_fw.type & ATSC) {
-               offset = 1750000;
-       } else {
-               offset = 2750000;
+
+       /*
+        * Digital modes require an offset to adjust to the
+        * proper frequency.
+        * Analog modes require offset = 0
+        */
+       if (new_mode == T_DIGITAL_TV) {
+               /* Sets the offset according with firmware */
+               if (priv->cur_fw.type & DTV6)
+                       offset = 1750000;
+               else if (priv->cur_fw.type & DTV7)
+                       offset = 2250000;
+               else    /* DTV8 or DTV78 */
+                       offset = 2750000;
+
                /*
-                * We must adjust the offset by 500kHz in two cases in order
-                * to correctly center the IF output:
-                * 1) When the ZARLINK456 or DIBCOM52 tables were explicitly
-                *    selected and a 7MHz channel is tuned;
-                * 2) When tuning a VHF channel with DTV78 firmware.
+                * We must adjust the offset by 500kHz  when
+                * tuning a 7MHz VHF channel with DTV78 firmware
+                * (used in Australia, Italy and Germany)
                 */
-               if (((priv->cur_fw.type & DTV7) &&
-                    (priv->cur_fw.scode_table & (ZARLINK456 | DIBCOM52))) ||
-                   ((priv->cur_fw.type & DTV78) && freq < 470000000))
+               if ((priv->cur_fw.type & DTV78) && freq < 470000000)
                        offset -= 500000;
        }
 
@@ -991,7 +998,7 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe,
                if (priv->ctrl.input1)
                        type |= INPUT1;
                return generic_set_freq(fe, (625l * p->frequency) / 10,
-                               T_ANALOG_TV, type, 0, 0);
+                               T_RADIO, type, 0, 0);
        }
 
        /* if std is not defined, choose one */
@@ -1022,21 +1029,20 @@ static int xc2028_set_params(struct dvb_frontend *fe,
        switch(fe->ops.info.type) {
        case FE_OFDM:
                bw = p->u.ofdm.bandwidth;
-               break;
-       case FE_QAM:
-               tuner_info("WARN: There are some reports that "
-                          "QAM 6 MHz doesn't work.\n"
-                          "If this works for you, please report by "
-                          "e-mail to: v4l-dvb-maintainer@linuxtv.org\n");
-               bw = BANDWIDTH_6_MHZ;
-               type |= QAM;
+               /*
+                * The only countries with 6MHz seem to be Taiwan/Uruguay.
+                * Both seem to require QAM firmware for OFDM decoding
+                * Tested in Taiwan by Terry Wu <terrywu2009@gmail.com>
+                */
+               if (bw == BANDWIDTH_6_MHZ)
+                       type |= QAM;
                break;
        case FE_ATSC:
                bw = BANDWIDTH_6_MHZ;
                /* The only ATSC firmware (at least on v2.7) is D2633 */
                type |= ATSC | D2633;
                break;
-       /* DVB-S is not supported */
+       /* DVB-S and pure QAM (FE_QAM) are not supported */
        default:
                return -EINVAL;
        }
index b54598550dc43da789cc7b6fdbc6acf3792aa5c8..f4ffcdc9b848919c5953372375eedacabb0210b6 100644 (file)
@@ -3,6 +3,7 @@
  *
  *  Copyright (c) 2007 Xceive Corporation
  *  Copyright (c) 2007 Steven Toth <stoth@linuxtv.org>
+ *  Copyright (c) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -36,14 +37,20 @@ static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
 
+static int no_poweroff;
+module_param(no_poweroff, int, 0644);
+MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n"
+       "\t\t1 keep device energized and with tuner ready all the times.\n"
+       "\t\tFaster, but consumes more power and keeps the device hotter");
+
 static DEFINE_MUTEX(xc5000_list_mutex);
 static LIST_HEAD(hybrid_tuner_instance_list);
 
 #define dprintk(level, fmt, arg...) if (debug >= level) \
        printk(KERN_INFO "%s: " fmt, "xc5000", ## arg)
 
-#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.1.fw"
-#define XC5000_DEFAULT_FIRMWARE_SIZE 12332
+#define XC5000_DEFAULT_FIRMWARE "dvb-fe-xc5000-1.6.114.fw"
+#define XC5000_DEFAULT_FIRMWARE_SIZE 12401
 
 struct xc5000_priv {
        struct tuner_i2c_props i2c_props;
@@ -83,11 +90,11 @@ struct xc5000_priv {
 #define XREG_D_CODE       0x04
 #define XREG_IF_OUT       0x05
 #define XREG_SEEK_MODE    0x07
-#define XREG_POWER_DOWN   0x0A
+#define XREG_POWER_DOWN   0x0A /* Obsolete */
 #define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */
 #define XREG_SMOOTHEDCVBS 0x0E
 #define XREG_XTALFREQ     0x0F
-#define XREG_FINERFFREQ   0x10
+#define XREG_FINERFREQ    0x10
 #define XREG_DDIMODE      0x11
 
 #define XREG_ADC_ENV      0x00
@@ -100,6 +107,7 @@ struct xc5000_priv {
 #define XREG_VERSION      0x07
 #define XREG_PRODUCT_ID   0x08
 #define XREG_BUSY         0x09
+#define XREG_BUILD        0x0D
 
 /*
    Basic firmware description. This will remain with
@@ -191,27 +199,36 @@ static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
        {"FM Radio-INPUT1",   0x0208, 0x9002}
 };
 
-static int  xc5000_is_firmware_loaded(struct dvb_frontend *fe);
-static int  xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len);
-static int  xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len);
-static void xc5000_TunerReset(struct dvb_frontend *fe);
+static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe);
+static int xc5000_is_firmware_loaded(struct dvb_frontend *fe);
+static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val);
+static int xc5000_TunerReset(struct dvb_frontend *fe);
 
 static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
 {
-       return xc5000_writeregs(priv, buf, len)
-               ? XC_RESULT_I2C_WRITE_FAILURE : XC_RESULT_SUCCESS;
+       struct i2c_msg msg = { .addr = priv->i2c_props.addr,
+                              .flags = 0, .buf = buf, .len = len };
+
+       if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
+               printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", len);
+               return XC_RESULT_I2C_WRITE_FAILURE;
+       }
+       return XC_RESULT_SUCCESS;
 }
 
+/* This routine is never used because the only time we read data from the
+   i2c bus is when we read registers, and we want that to be an atomic i2c
+   transaction in case we are on a multi-master bus */
 static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
 {
-       return xc5000_readregs(priv, buf, len)
-               ? XC_RESULT_I2C_READ_FAILURE : XC_RESULT_SUCCESS;
-}
+       struct i2c_msg msg = { .addr = priv->i2c_props.addr,
+               .flags = I2C_M_RD, .buf = buf, .len = len };
 
-static int xc_reset(struct dvb_frontend *fe)
-{
-       xc5000_TunerReset(fe);
-       return XC_RESULT_SUCCESS;
+       if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
+               printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", len);
+               return -EREMOTEIO;
+       }
+       return 0;
 }
 
 static void xc_wait(int wait_ms)
@@ -219,7 +236,7 @@ static void xc_wait(int wait_ms)
        msleep(wait_ms);
 }
 
-static void xc5000_TunerReset(struct dvb_frontend *fe)
+static int xc5000_TunerReset(struct dvb_frontend *fe)
 {
        struct xc5000_priv *priv = fe->tuner_priv;
        int ret;
@@ -232,16 +249,21 @@ static void xc5000_TunerReset(struct dvb_frontend *fe)
                                           priv->i2c_props.adap->algo_data,
                                           DVB_FRONTEND_COMPONENT_TUNER,
                                           XC5000_TUNER_RESET, 0);
-               if (ret)
+               if (ret) {
                        printk(KERN_ERR "xc5000: reset failed\n");
-       } else
+                       return XC_RESULT_RESET_FAILURE;
+               }
+       } else {
                printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n");
+               return XC_RESULT_RESET_FAILURE;
+       }
+       return XC_RESULT_SUCCESS;
 }
 
 static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
 {
        u8 buf[4];
-       int WatchDogTimer = 5;
+       int WatchDogTimer = 100;
        int result;
 
        buf[0] = (regAddr >> 8) & 0xFF;
@@ -263,7 +285,7 @@ static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
                                                /* busy flag cleared */
                                        break;
                                        } else {
-                                               xc_wait(100); /* wait 5 ms */
+                                               xc_wait(5); /* wait 5 ms */
                                                WatchDogTimer--;
                                        }
                                }
@@ -276,25 +298,6 @@ static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
        return result;
 }
 
-static int xc_read_reg(struct xc5000_priv *priv, u16 regAddr, u16 *i2cData)
-{
-       u8 buf[2];
-       int result;
-
-       buf[0] = (regAddr >> 8) & 0xFF;
-       buf[1] = regAddr & 0xFF;
-       result = xc_send_i2c_data(priv, buf, 2);
-       if (result != XC_RESULT_SUCCESS)
-               return result;
-
-       result = xc_read_i2c_data(priv, buf, 2);
-       if (result != XC_RESULT_SUCCESS)
-               return result;
-
-       *i2cData = buf[0] * 256 + buf[1];
-       return result;
-}
-
 static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
 {
        struct xc5000_priv *priv = fe->tuner_priv;
@@ -309,7 +312,7 @@ static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
                len = i2c_sequence[index] * 256 + i2c_sequence[index+1];
                if (len == 0x0000) {
                        /* RESET command */
-                       result = xc_reset(fe);
+                       result = xc5000_TunerReset(fe);
                        index += 2;
                        if (result != XC_RESULT_SUCCESS)
                                return result;
@@ -371,15 +374,6 @@ static int xc_SetTVStandard(struct xc5000_priv *priv,
        return ret;
 }
 
-static int xc_shutdown(struct xc5000_priv *priv)
-{
-       return XC_RESULT_SUCCESS;
-       /* Fixme: cannot bring tuner back alive once shutdown
-        *        without reloading the driver modules.
-        *    return xc_write_reg(priv, XREG_POWER_DOWN, 0);
-        */
-}
-
 static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode)
 {
        dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode,
@@ -408,7 +402,10 @@ static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz)
 
        freq_code = (u16)(freq_hz / 15625);
 
-       return xc_write_reg(priv, XREG_RF_FREQ, freq_code);
+       /* Starting in firmware version 1.1.44, Xceive recommends using the
+          FINERFREQ for all normal tuning (the doc indicates reg 0x03 should
+          only be used for fast scanning for channel lock) */
+       return xc_write_reg(priv, XREG_FINERFREQ, freq_code);
 }
 
 
@@ -424,7 +421,7 @@ static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz)
 
 static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope)
 {
-       return xc_read_reg(priv, XREG_ADC_ENV, adc_envelope);
+       return xc5000_readreg(priv, XREG_ADC_ENV, adc_envelope);
 }
 
 static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
@@ -433,8 +430,8 @@ static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
        u16 regData;
        u32 tmp;
 
-       result = xc_read_reg(priv, XREG_FREQ_ERROR, &regData);
-       if (result)
+       result = xc5000_readreg(priv, XREG_FREQ_ERROR, &regData);
+       if (result != XC_RESULT_SUCCESS)
                return result;
 
        tmp = (u32)regData;
@@ -444,7 +441,7 @@ static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
 
 static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status)
 {
-       return xc_read_reg(priv, XREG_LOCK, lock_status);
+       return xc5000_readreg(priv, XREG_LOCK, lock_status);
 }
 
 static int xc_get_version(struct xc5000_priv *priv,
@@ -454,8 +451,8 @@ static int xc_get_version(struct xc5000_priv *priv,
        u16 data;
        int result;
 
-       result = xc_read_reg(priv, XREG_VERSION, &data);
-       if (result)
+       result = xc5000_readreg(priv, XREG_VERSION, &data);
+       if (result != XC_RESULT_SUCCESS)
                return result;
 
        (*hw_majorversion) = (data >> 12) & 0x0F;
@@ -466,13 +463,18 @@ static int xc_get_version(struct xc5000_priv *priv,
        return 0;
 }
 
+static int xc_get_buildversion(struct xc5000_priv *priv, u16 *buildrev)
+{
+       return xc5000_readreg(priv, XREG_BUILD, buildrev);
+}
+
 static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz)
 {
        u16 regData;
        int result;
 
-       result = xc_read_reg(priv, XREG_HSYNC_FREQ, &regData);
-       if (result)
+       result = xc5000_readreg(priv, XREG_HSYNC_FREQ, &regData);
+       if (result != XC_RESULT_SUCCESS)
                return result;
 
        (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100;
@@ -481,12 +483,12 @@ static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz)
 
 static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines)
 {
-       return xc_read_reg(priv, XREG_FRAME_LINES, frame_lines);
+       return xc5000_readreg(priv, XREG_FRAME_LINES, frame_lines);
 }
 
 static int xc_get_quality(struct xc5000_priv *priv, u16 *quality)
 {
-       return xc_read_reg(priv, XREG_QUALITY, quality);
+       return xc5000_readreg(priv, XREG_QUALITY, quality);
 }
 
 static u16 WaitForLock(struct xc5000_priv *priv)
@@ -504,7 +506,9 @@ static u16 WaitForLock(struct xc5000_priv *priv)
        return lockState;
 }
 
-static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz)
+#define XC_TUNE_ANALOG  0
+#define XC_TUNE_DIGITAL 1
+static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode)
 {
        int found = 0;
 
@@ -513,8 +517,10 @@ static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz)
        if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS)
                return 0;
 
-       if (WaitForLock(priv) == 1)
-               found = 1;
+       if (mode == XC_TUNE_ANALOG) {
+               if (WaitForLock(priv) == 1)
+                       found = 1;
+       }
 
        return found;
 }
@@ -536,32 +542,7 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
        }
 
        *val = (bval[0] << 8) | bval[1];
-       return 0;
-}
-
-static int xc5000_writeregs(struct xc5000_priv *priv, u8 *buf, u8 len)
-{
-       struct i2c_msg msg = { .addr = priv->i2c_props.addr,
-               .flags = 0, .buf = buf, .len = len };
-
-       if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
-               printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n",
-                       (int)len);
-               return -EREMOTEIO;
-       }
-       return 0;
-}
-
-static int xc5000_readregs(struct xc5000_priv *priv, u8 *buf, u8 len)
-{
-       struct i2c_msg msg = { .addr = priv->i2c_props.addr,
-               .flags = I2C_M_RD, .buf = buf, .len = len };
-
-       if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
-               printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", (int)len);
-               return -EREMOTEIO;
-       }
-       return 0;
+       return XC_RESULT_SUCCESS;
 }
 
 static int xc5000_fwupload(struct dvb_frontend *fe)
@@ -575,13 +556,13 @@ static int xc5000_fwupload(struct dvb_frontend *fe)
                XC5000_DEFAULT_FIRMWARE);
 
        ret = request_firmware(&fw, XC5000_DEFAULT_FIRMWARE,
-               &priv->i2c_props.adap->dev);
+               priv->i2c_props.adap->dev.parent);
        if (ret) {
                printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
                ret = XC_RESULT_RESET_FAILURE;
                goto out;
        } else {
-               printk(KERN_INFO "xc5000: firmware read %Zu bytes.\n",
+               printk(KERN_DEBUG "xc5000: firmware read %Zu bytes.\n",
                       fw->size);
                ret = XC_RESULT_SUCCESS;
        }
@@ -590,8 +571,9 @@ static int xc5000_fwupload(struct dvb_frontend *fe)
                printk(KERN_ERR "xc5000: firmware incorrect size\n");
                ret = XC_RESULT_RESET_FAILURE;
        } else {
-               printk(KERN_INFO "xc5000: firmware upload\n");
+               printk(KERN_INFO "xc5000: firmware uploading...\n");
                ret = xc_load_i2c_sequence(fe,  fw->data);
+               printk(KERN_INFO "xc5000: firmware upload complete...\n");
        }
 
 out:
@@ -609,6 +591,7 @@ static void xc_debug_dump(struct xc5000_priv *priv)
        u16 quality;
        u8 hw_majorversion = 0, hw_minorversion = 0;
        u8 fw_majorversion = 0, fw_minorversion = 0;
+       u16 fw_buildversion = 0;
 
        /* Wait for stats to stabilize.
         * Frame Lines needs two frame times after initial lock
@@ -628,9 +611,10 @@ static void xc_debug_dump(struct xc5000_priv *priv)
 
        xc_get_version(priv,  &hw_majorversion, &hw_minorversion,
                &fw_majorversion, &fw_minorversion);
-       dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n",
+       xc_get_buildversion(priv,  &fw_buildversion);
+       dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x.%04x\n",
                hw_majorversion, hw_minorversion,
-               fw_majorversion, fw_minorversion);
+               fw_majorversion, fw_minorversion, fw_buildversion);
 
        xc_get_hsync_freq(priv,  &hsync_freq_hz);
        dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz);
@@ -648,27 +632,57 @@ static int xc5000_set_params(struct dvb_frontend *fe,
        struct xc5000_priv *priv = fe->tuner_priv;
        int ret;
 
+       if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS)
+               xc_load_fw_and_init_tuner(fe);
+
        dprintk(1, "%s() frequency=%d (Hz)\n", __func__, params->frequency);
 
-       switch (params->u.vsb.modulation) {
-       case VSB_8:
-       case VSB_16:
-               dprintk(1, "%s() VSB modulation\n", __func__);
+       if (fe->ops.info.type == FE_ATSC) {
+               dprintk(1, "%s() ATSC\n", __func__);
+               switch (params->u.vsb.modulation) {
+               case VSB_8:
+               case VSB_16:
+                       dprintk(1, "%s() VSB modulation\n", __func__);
+                       priv->rf_mode = XC_RF_MODE_AIR;
+                       priv->freq_hz = params->frequency - 1750000;
+                       priv->bandwidth = BANDWIDTH_6_MHZ;
+                       priv->video_standard = DTV6;
+                       break;
+               case QAM_64:
+               case QAM_256:
+               case QAM_AUTO:
+                       dprintk(1, "%s() QAM modulation\n", __func__);
+                       priv->rf_mode = XC_RF_MODE_CABLE;
+                       priv->freq_hz = params->frequency - 1750000;
+                       priv->bandwidth = BANDWIDTH_6_MHZ;
+                       priv->video_standard = DTV6;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       } else if (fe->ops.info.type == FE_OFDM) {
+               dprintk(1, "%s() OFDM\n", __func__);
+               switch (params->u.ofdm.bandwidth) {
+               case BANDWIDTH_6_MHZ:
+                       priv->bandwidth = BANDWIDTH_6_MHZ;
+                       priv->video_standard = DTV6;
+                       priv->freq_hz = params->frequency - 1750000;
+                       break;
+               case BANDWIDTH_7_MHZ:
+                       printk(KERN_ERR "xc5000 bandwidth 7MHz not supported\n");
+                       return -EINVAL;
+               case BANDWIDTH_8_MHZ:
+                       priv->bandwidth = BANDWIDTH_8_MHZ;
+                       priv->video_standard = DTV8;
+                       priv->freq_hz = params->frequency - 2750000;
+                       break;
+               default:
+                       printk(KERN_ERR "xc5000 bandwidth not set!\n");
+                       return -EINVAL;
+               }
                priv->rf_mode = XC_RF_MODE_AIR;
-               priv->freq_hz = params->frequency - 1750000;
-               priv->bandwidth = BANDWIDTH_6_MHZ;
-               priv->video_standard = DTV6;
-               break;
-       case QAM_64:
-       case QAM_256:
-       case QAM_AUTO:
-               dprintk(1, "%s() QAM modulation\n", __func__);
-               priv->rf_mode = XC_RF_MODE_CABLE;
-               priv->freq_hz = params->frequency - 1750000;
-               priv->bandwidth = BANDWIDTH_6_MHZ;
-               priv->video_standard = DTV6;
-               break;
-       default:
+       } else {
+               printk(KERN_ERR "xc5000 modulation type not supported!\n");
                return -EINVAL;
        }
 
@@ -698,7 +712,7 @@ static int xc5000_set_params(struct dvb_frontend *fe,
                return -EIO;
        }
 
-       xc_tune_channel(priv, priv->freq_hz);
+       xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL);
 
        if (debug)
                xc_debug_dump(priv);
@@ -725,8 +739,6 @@ static int xc5000_is_firmware_loaded(struct dvb_frontend *fe)
        return ret;
 }
 
-static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe);
-
 static int xc5000_set_analog_params(struct dvb_frontend *fe,
        struct analog_parameters *params)
 {
@@ -807,7 +819,7 @@ tune_channel:
                return -EREMOTEIO;
        }
 
-       xc_tune_channel(priv, priv->freq_hz);
+       xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG);
 
        if (debug)
                xc_debug_dump(priv);
@@ -875,18 +887,18 @@ static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe)
 
 static int xc5000_sleep(struct dvb_frontend *fe)
 {
-       struct xc5000_priv *priv = fe->tuner_priv;
        int ret;
 
        dprintk(1, "%s()\n", __func__);
 
-       /* On Pinnacle PCTV HD 800i, the tuner cannot be reinitialized
-        * once shutdown without reloading the driver. Maybe I am not
-        * doing something right.
-        *
-        */
+       /* Avoid firmware reload on slow devices */
+       if (no_poweroff)
+               return 0;
 
-       ret = xc_shutdown(priv);
+       /* According to Xceive technical support, the "powerdown" register
+          was removed in newer versions of the firmware.  The "supported"
+          way to sleep the tuner is to pull the reset pin low for 10ms */
+       ret = xc5000_TunerReset(fe);
        if (ret != XC_RESULT_SUCCESS) {
                printk(KERN_ERR
                        "xc5000: %s() unable to shutdown tuner\n",
@@ -991,7 +1003,7 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
        /* Check if firmware has been loaded. It is possible that another
           instance of the driver has loaded the firmware.
         */
-       if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
+       if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != XC_RESULT_SUCCESS)
                goto fail;
 
        switch (id) {
index 3e1c472092ab238af0e26e1ef89917b220477aa7..9e2148a199676e0c45fb1472ba69b79f61a0e5b8 100644 (file)
@@ -1,9 +1,7 @@
 /*
- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
- *
- * flexcop-common.h - common header file for device-specific source files also.
- *
- * see flexcop.c for copyright information.
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-common.h - common header file for device-specific source files
+ * see flexcop.c for copyright information
  */
 #ifndef __FLEXCOP_COMMON_H__
 #define __FLEXCOP_COMMON_H__
index f7afab5944cfc2395c8b30592dc9740da22325cc..efb4a6c2b57a5d39cf9c70a5cef455a9dbb528e4 100644 (file)
@@ -1,34 +1,27 @@
 /*
- * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
- *
- * flexcop-fe-tuner.c - methods for attaching a frontend and controlling DiSEqC.
- *
- * see flexcop.c for copyright information.
+ * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ * flexcop-fe-tuner.c - methods for frontend attachment and DiSEqC controlling
+ * see flexcop.c for copyright information
  */
 #include <media/tuner.h>
-
 #include "flexcop.h"
-
-#include "stv0299.h"
-#include "mt352.h"
-#include "nxt200x.h"
-#include "bcm3510.h"
-#include "stv0297.h"
 #include "mt312.h"
-#include "lgdt330x.h"
-#include "dvb-pll.h"
-#include "tuner-simple.h"
-
+#include "stv0299.h"
 #include "s5h1420.h"
 #include "itd1000.h"
-
-#include "cx24123.h"
 #include "cx24113.h"
-
+#include "cx24123.h"
 #include "isl6421.h"
+#include "mt352.h"
+#include "bcm3510.h"
+#include "nxt200x.h"
+#include "dvb-pll.h"
+#include "lgdt330x.h"
+#include "tuner-simple.h"
+#include "stv0297.h"
 
 /* lnb control */
-
+#if defined(CONFIG_DVB_MT312_MODULE) || defined(CONFIG_DVB_STV0299_MODULE)
 static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 {
        struct flexcop_device *fc = fe->dvb->priv;
@@ -37,65 +30,62 @@ static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage
 
        v = fc->read_ibi_reg(fc, misc_204);
        switch (voltage) {
-               case SEC_VOLTAGE_OFF:
-                       v.misc_204.ACPI1_sig = 1;
-                       break;
-               case SEC_VOLTAGE_13:
-                       v.misc_204.ACPI1_sig = 0;
-                       v.misc_204.LNB_L_H_sig = 0;
-                       break;
-               case SEC_VOLTAGE_18:
-                       v.misc_204.ACPI1_sig = 0;
-                       v.misc_204.LNB_L_H_sig = 1;
-                       break;
-               default:
-                       err("unknown SEC_VOLTAGE value");
-                       return -EINVAL;
+       case SEC_VOLTAGE_OFF:
+               v.misc_204.ACPI1_sig = 1;
+               break;
+       case SEC_VOLTAGE_13:
+               v.misc_204.ACPI1_sig = 0;
+               v.misc_204.LNB_L_H_sig = 0;
+               break;
+       case SEC_VOLTAGE_18:
+               v.misc_204.ACPI1_sig = 0;
+               v.misc_204.LNB_L_H_sig = 1;
+               break;
+       default:
+               err("unknown SEC_VOLTAGE value");
+               return -EINVAL;
        }
        return fc->write_ibi_reg(fc, misc_204, v);
 }
+#endif
 
+#if defined(CONFIG_DVB_S5H1420_MODULE) || defined(CONFIG_DVB_STV0299_MODULE) \
+       || defined(CONFIG_DVB_MT312_MODULE)
 static int flexcop_sleep(struct dvb_frontend* fe)
 {
        struct flexcop_device *fc = fe->dvb->priv;
-/*     flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204); */
-
        if (fc->fe_sleep)
                return fc->fe_sleep(fe);
-
-/*     v.misc_204.ACPI3_sig = 1;
-       fc->write_ibi_reg(fc,misc_204,v);*/
-
        return 0;
 }
+#endif
 
+/* SkyStar2 DVB-S rev 2.3 */
+#if defined(CONFIG_DVB_MT312_MODULE)
 static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
 {
-       /* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */
+/* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */
        struct flexcop_device *fc = fe->dvb->priv;
        flexcop_ibi_value v;
        u16 ax;
        v.raw = 0;
-
        deb_tuner("tone = %u\n",tone);
 
        switch (tone) {
-               case SEC_TONE_ON:
-                       ax = 0x01ff;
-                       break;
-               case SEC_TONE_OFF:
-                       ax = 0;
-                       break;
-               default:
-                       err("unknown SEC_TONE value");
-                       return -EINVAL;
+       case SEC_TONE_ON:
+               ax = 0x01ff;
+               break;
+       case SEC_TONE_OFF:
+               ax = 0;
+               break;
+       default:
+               err("unknown SEC_TONE value");
+               return -EINVAL;
        }
 
        v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */
-
        v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax;
        v.lnb_switch_freq_200.LNB_CTLLowCount_sig  = ax == 0 ? 0x1ff : ax;
-
        return fc->write_ibi_reg(fc,lnb_switch_freq_200,v);
 }
 
@@ -110,17 +100,16 @@ static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data)
 static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data)
 {
        int i, par = 1, d;
-
        for (i = 7; i >= 0; i--) {
                d = (data >> i) & 1;
                par ^= d;
                flexcop_diseqc_send_bit(fe, d);
        }
-
        flexcop_diseqc_send_bit(fe, par);
 }
 
-static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, unsigned long burst)
+static int flexcop_send_diseqc_msg(struct dvb_frontend *fe,
+       int len, u8 *msg, unsigned long burst)
 {
        int i;
 
@@ -129,7 +118,6 @@ static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, un
 
        for (i = 0; i < len; i++)
                flexcop_diseqc_send_byte(fe,msg[i]);
-
        mdelay(16);
 
        if (burst != -1) {
@@ -146,50 +134,110 @@ static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, un
        return 0;
 }
 
-static int flexcop_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
+static int flexcop_diseqc_send_master_cmd(struct dvb_frontend *fe,
+       struct dvb_diseqc_master_cmd *cmd)
 {
        return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0);
 }
 
-static int flexcop_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+static int flexcop_diseqc_send_burst(struct dvb_frontend *fe,
+       fe_sec_mini_cmd_t minicmd)
 {
        return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd);
 }
 
-/* dvb-s stv0299 */
-static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
+static struct mt312_config skystar23_samsung_tbdu18132_config = {
+       .demod_address = 0x0e,
+};
+
+static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *params)
+{
+       u8 buf[4];
+       u32 div;
+       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf,
+       .len = sizeof(buf) };
+       struct flexcop_device *fc = fe->dvb->priv;
+       div = (params->frequency + (125/2)) / 125;
+
+       buf[0] = (div >> 8) & 0x7f;
+       buf[1] = (div >> 0) & 0xff;
+       buf[2] = 0x84 | ((div >> 10) & 0x60);
+       buf[3] = 0x80;
+
+       if (params->frequency < 1550000)
+               buf[3] |= 0x02;
+
+       if (fe->ops.i2c_gate_ctrl)
+               fe->ops.i2c_gate_ctrl(fe, 1);
+       if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1)
+               return -EIO;
+       return 0;
+}
+
+static int skystar2_rev23_attach(struct flexcop_device *fc,
+       struct i2c_adapter *i2c)
+{
+       fc->fe = dvb_attach(mt312_attach, &skystar23_samsung_tbdu18132_config, i2c);
+       if (fc->fe != NULL) {
+               struct dvb_frontend_ops *ops = &fc->fe->ops;
+               ops->tuner_ops.set_params   =
+                       skystar23_samsung_tbdu18132_tuner_set_params;
+               ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
+               ops->diseqc_send_burst      = flexcop_diseqc_send_burst;
+               ops->set_tone               = flexcop_set_tone;
+               ops->set_voltage            = flexcop_set_voltage;
+               fc->fe_sleep                = ops->sleep;
+               ops->sleep                  = flexcop_sleep;
+               return 1;
+       }
+       return 0;
+}
+#endif
+
+/* SkyStar2 DVB-S rev 2.6 */
+#if defined(CONFIG_DVB_STV0299_MODULE)
+static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe,
+       u32 srate, u32 ratio)
 {
        u8 aclk = 0;
        u8 bclk = 0;
 
-       if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
-       else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
-       else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
-       else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
-       else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
-       else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
-
-       stv0299_writereg (fe, 0x13, aclk);
-       stv0299_writereg (fe, 0x14, bclk);
-       stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
-       stv0299_writereg (fe, 0x20, (ratio >>  8) & 0xff);
-       stv0299_writereg (fe, 0x21, (ratio      ) & 0xf0);
+       if (srate < 1500000) {
+               aclk = 0xb7; bclk = 0x47;
+       } else if (srate < 3000000) {
+               aclk = 0xb7; bclk = 0x4b;
+       } else if (srate < 7000000) {
+               aclk = 0xb7; bclk = 0x4f;
+       } else if (srate < 14000000) {
+               aclk = 0xb7; bclk = 0x53;
+       } else if (srate < 30000000) {
+               aclk = 0xb6; bclk = 0x53;
+       } else if (srate < 45000000) {
+               aclk = 0xb4; bclk = 0x51;
+       }
 
+       stv0299_writereg(fe, 0x13, aclk);
+       stv0299_writereg(fe, 0x14, bclk);
+       stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
+       stv0299_writereg(fe, 0x20, (ratio >>  8) & 0xff);
+       stv0299_writereg(fe, 0x21,  ratio        & 0xf0);
        return 0;
 }
 
-static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
+static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *params)
 {
        u8 buf[4];
        u32 div;
-       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+       struct i2c_msg msg = {
+       .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
        struct flexcop_device *fc = fe->dvb->priv;
-
        div = params->frequency / 125;
 
        buf[0] = (div >> 8) & 0x7f;
        buf[1] = div & 0xff;
-       buf[2] = 0x84;  /* 0xC4 */
+       buf[2] = 0x84; /* 0xC4 */
        buf[3] = 0x08;
 
        if (params->frequency < 1500000)
@@ -203,48 +251,48 @@ static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend* fe, struct dv
 }
 
 static u8 samsung_tbmu24112_inittab[] = {
-            0x01, 0x15,
-            0x02, 0x30,
-            0x03, 0x00,
-            0x04, 0x7D,
-            0x05, 0x35,
-            0x06, 0x02,
-            0x07, 0x00,
-            0x08, 0xC3,
-            0x0C, 0x00,
-            0x0D, 0x81,
-            0x0E, 0x23,
-            0x0F, 0x12,
-            0x10, 0x7E,
-            0x11, 0x84,
-            0x12, 0xB9,
-            0x13, 0x88,
-            0x14, 0x89,
-            0x15, 0xC9,
-            0x16, 0x00,
-            0x17, 0x5C,
-            0x18, 0x00,
-            0x19, 0x00,
-            0x1A, 0x00,
-            0x1C, 0x00,
-            0x1D, 0x00,
-            0x1E, 0x00,
-            0x1F, 0x3A,
-            0x20, 0x2E,
-            0x21, 0x80,
-            0x22, 0xFF,
-            0x23, 0xC1,
-            0x28, 0x00,
-            0x29, 0x1E,
-            0x2A, 0x14,
-            0x2B, 0x0F,
-            0x2C, 0x09,
-            0x2D, 0x05,
-            0x31, 0x1F,
-            0x32, 0x19,
-            0x33, 0xFE,
-            0x34, 0x93,
-            0xff, 0xff,
+       0x01, 0x15,
+       0x02, 0x30,
+       0x03, 0x00,
+       0x04, 0x7D,
+       0x05, 0x35,
+       0x06, 0x02,
+       0x07, 0x00,
+       0x08, 0xC3,
+       0x0C, 0x00,
+       0x0D, 0x81,
+       0x0E, 0x23,
+       0x0F, 0x12,
+       0x10, 0x7E,
+       0x11, 0x84,
+       0x12, 0xB9,
+       0x13, 0x88,
+       0x14, 0x89,
+       0x15, 0xC9,
+       0x16, 0x00,
+       0x17, 0x5C,
+       0x18, 0x00,
+       0x19, 0x00,
+       0x1A, 0x00,
+       0x1C, 0x00,
+       0x1D, 0x00,
+       0x1E, 0x00,
+       0x1F, 0x3A,
+       0x20, 0x2E,
+       0x21, 0x80,
+       0x22, 0xFF,
+       0x23, 0xC1,
+       0x28, 0x00,
+       0x29, 0x1E,
+       0x2A, 0x14,
+       0x2B, 0x0F,
+       0x2C, 0x09,
+       0x2D, 0x05,
+       0x31, 0x1F,
+       0x32, 0x19,
+       0x33, 0xFE,
+       0x34, 0x93,
+       0xff, 0xff,
 };
 
 static struct stv0299_config samsung_tbmu24112_config = {
@@ -259,27 +307,155 @@ static struct stv0299_config samsung_tbmu24112_config = {
        .set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
 };
 
-/* dvb-t mt352 */
-static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
+static int skystar2_rev26_attach(struct flexcop_device *fc,
+       struct i2c_adapter *i2c)
+{
+       fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
+       if (fc->fe != NULL) {
+               struct dvb_frontend_ops *ops  = &fc->fe->ops;
+               ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
+               ops->set_voltage = flexcop_set_voltage;
+               fc->fe_sleep = ops->sleep;
+               ops->sleep = flexcop_sleep;
+               return 1;
+       }
+       return 0;
+}
+#endif
+
+/* SkyStar2 DVB-S rev 2.7 */
+#if defined(CONFIG_DVB_S5H1420_MODULE)
+static struct s5h1420_config skystar2_rev2_7_s5h1420_config = {
+       .demod_address = 0x53,
+       .invert = 1,
+       .repeated_start_workaround = 1,
+       .serial_mpeg = 1,
+};
+
+static struct itd1000_config skystar2_rev2_7_itd1000_config = {
+       .i2c_address = 0x61,
+};
+
+static int skystar2_rev27_attach(struct flexcop_device *fc,
+       struct i2c_adapter *i2c)
+{
+       flexcop_ibi_value r108;
+       struct i2c_adapter *i2c_tuner;
+
+       /* enable no_base_addr - no repeated start when reading */
+       fc->fc_i2c_adap[0].no_base_addr = 1;
+       fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config,
+                           i2c);
+       if (!fc->fe)
+               goto fail;
+
+       i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe);
+       if (!i2c_tuner)
+               goto fail;
+
+       fc->fe_sleep = fc->fe->ops.sleep;
+       fc->fe->ops.sleep = flexcop_sleep;
+
+       /* enable no_base_addr - no repeated start when reading */
+       fc->fc_i2c_adap[2].no_base_addr = 1;
+       if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
+                       0x08, 1, 1)) {
+               err("ISL6421 could NOT be attached");
+               goto fail_isl;
+       }
+       info("ISL6421 successfully attached");
+
+       /* the ITD1000 requires a lower i2c clock - is it a problem ? */
+       r108.raw = 0x00000506;
+       fc->write_ibi_reg(fc, tw_sm_c_108, r108);
+       if (!dvb_attach(itd1000_attach, fc->fe, i2c_tuner,
+                       &skystar2_rev2_7_itd1000_config)) {
+               err("ITD1000 could NOT be attached");
+               /* Should i2c clock be restored? */
+               goto fail_isl;
+       }
+       info("ITD1000 successfully attached");
+
+       return 1;
+
+fail_isl:
+       fc->fc_i2c_adap[2].no_base_addr = 0;
+fail:
+       /* for the next devices we need it again */
+       fc->fc_i2c_adap[0].no_base_addr = 0;
+       return 0;
+}
+#endif
+
+/* SkyStar2 rev 2.8 */
+#if defined(CONFIG_DVB_CX24123_MODULE)
+static struct cx24123_config skystar2_rev2_8_cx24123_config = {
+       .demod_address = 0x55,
+       .dont_use_pll = 1,
+       .agc_callback = cx24113_agc_callback,
+};
+
+static const struct cx24113_config skystar2_rev2_8_cx24113_config = {
+       .i2c_addr = 0x54,
+       .xtal_khz = 10111,
+};
+
+static int skystar2_rev28_attach(struct flexcop_device *fc,
+       struct i2c_adapter *i2c)
+{
+       struct i2c_adapter *i2c_tuner;
+
+       fc->fe = dvb_attach(cx24123_attach, &skystar2_rev2_8_cx24123_config,
+                           i2c);
+       if (!fc->fe)
+               return 0;
+
+       i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);;
+       if (!i2c_tuner)
+               return 0;
+
+       if (!dvb_attach(cx24113_attach, fc->fe, &skystar2_rev2_8_cx24113_config,
+                       i2c_tuner)) {
+               err("CX24113 could NOT be attached");
+               return 0;
+       }
+       info("CX24113 successfully attached");
+
+       fc->fc_i2c_adap[2].no_base_addr = 1;
+       if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
+                       0x08, 0, 0)) {
+               err("ISL6421 could NOT be attached");
+               fc->fc_i2c_adap[2].no_base_addr = 0;
+               return 0;
+       }
+       info("ISL6421 successfully attached");
+       /* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an
+        * IR-receiver (PIC16F818) - but the card has no input for that ??? */
+       return 1;
+}
+#endif
+
+/* AirStar DVB-T */
+#if defined(CONFIG_DVB_MT352_MODULE)
+static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe)
 {
-       static u8 mt352_clock_config [] = { 0x89, 0x18, 0x2d };
-       static u8 mt352_reset [] = { 0x50, 0x80 };
-       static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
-       static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 };
+       static u8 mt352_clock_config[] = { 0x89, 0x18, 0x2d };
+       static u8 mt352_reset[] = { 0x50, 0x80 };
+       static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 };
+       static u8 mt352_agc_cfg[] = { 0x67, 0x28, 0xa1 };
        static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
 
        mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
        udelay(2000);
        mt352_write(fe, mt352_reset, sizeof(mt352_reset));
        mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
-
        mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
        mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
-
        return 0;
 }
 
-static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
+static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
 {
        u32 div;
        unsigned char bs = 0;
@@ -287,19 +463,20 @@ static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend* fe, struct dvb_fro
        if (buf_len < 5)
                return -EINVAL;
 
-       #define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
+#define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
        div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
-
-       if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09;
-       if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a;
-       if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08;
+       if (params->frequency >= 48000000 && params->frequency <= 154000000) \
+               bs = 0x09;
+       if (params->frequency >= 161000000 && params->frequency <= 439000000) \
+               bs = 0x0a;
+       if (params->frequency >= 447000000 && params->frequency <= 863000000) \
+               bs = 0x08;
 
        pllbuf[0] = 0x61;
        pllbuf[1] = div >> 8;
        pllbuf[2] = div & 0xff;
        pllbuf[3] = 0xcc;
        pllbuf[4] = bs;
-
        return 5;
 }
 
@@ -308,70 +485,95 @@ static struct mt352_config samsung_tdtc9251dh0_config = {
        .demod_init    = samsung_tdtc9251dh0_demod_init,
 };
 
-static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+static int airstar_dvbt_attach(struct flexcop_device *fc,
+       struct i2c_adapter *i2c)
+{
+       fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
+       if (fc->fe != NULL) {
+               fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
+               return 1;
+       }
+       return 0;
+}
+#endif
+
+/* AirStar ATSC 1st generation */
+#if defined(CONFIG_DVB_BCM3510_MODULE)
+static int flexcop_fe_request_firmware(struct dvb_frontend *fe,
+       const struct firmware **fw, char* name)
 {
        struct flexcop_device *fc = fe->dvb->priv;
        return request_firmware(fw, name, fc->dev);
 }
 
-static struct lgdt330x_config air2pc_atsc_hd5000_config = {
-       .demod_address       = 0x59,
-       .demod_chip          = LGDT3303,
-       .serial_mpeg         = 0x04,
-       .clock_polarity_flip = 1,
-};
-
-static struct nxt200x_config samsung_tbmv_config = {
-       .demod_address    = 0x0a,
-};
-
 static struct bcm3510_config air2pc_atsc_first_gen_config = {
        .demod_address    = 0x0f,
        .request_firmware = flexcop_fe_request_firmware,
 };
 
-static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
+static int airstar_atsc1_attach(struct flexcop_device *fc,
+       struct i2c_adapter *i2c)
 {
-       u8 buf[4];
-       u32 div;
-       struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
-       struct flexcop_device *fc = fe->dvb->priv;
-
-       div = (params->frequency + (125/2)) / 125;
+       fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
+       return fc->fe != NULL;
+}
+#endif
 
-       buf[0] = (div >> 8) & 0x7f;
-       buf[1] = (div >> 0) & 0xff;
-       buf[2] = 0x84 | ((div >> 10) & 0x60);
-       buf[3] = 0x80;
+/* AirStar ATSC 2nd generation */
+#if defined(CONFIG_DVB_NXT200X_MODULE)
+static struct nxt200x_config samsung_tbmv_config = {
+       .demod_address = 0x0a,
+};
 
-       if (params->frequency < 1550000)
-               buf[3] |= 0x02;
+static int airstar_atsc2_attach(struct flexcop_device *fc,
+       struct i2c_adapter *i2c)
+{
+       fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c);
+       if (!fc->fe)
+               return 0;
 
-       if (fe->ops.i2c_gate_ctrl)
-               fe->ops.i2c_gate_ctrl(fe, 1);
-       if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1)
-               return -EIO;
-       return 0;
+       return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
+                           DVB_PLL_SAMSUNG_TBMV);
 }
+#endif
 
-static struct mt312_config skystar23_samsung_tbdu18132_config = {
-
-       .demod_address = 0x0e,
+/* AirStar ATSC 3rd generation */
+#if defined(CONFIG_DVB_LGDT330X_MODULE)
+static struct lgdt330x_config air2pc_atsc_hd5000_config = {
+       .demod_address       = 0x59,
+       .demod_chip          = LGDT3303,
+       .serial_mpeg         = 0x04,
+       .clock_polarity_flip = 1,
 };
 
+static int airstar_atsc3_attach(struct flexcop_device *fc,
+       struct i2c_adapter *i2c)
+{
+       fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c);
+       if (!fc->fe)
+               return 0;
+
+       return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
+                           TUNER_LG_TDVS_H06XF);
+}
+#endif
+
+/* CableStar2 DVB-C */
+#if defined(CONFIG_DVB_STV0297_MODULE)
 static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
-                                              struct dvb_frontend_parameters *fep)
+               struct dvb_frontend_parameters *fep)
 {
        struct flexcop_device *fc = fe->dvb->priv;
        u8 buf[4];
        u16 div;
        int ret;
 
-/*  62.5 kHz * 10 */
+/* 62.5 kHz * 10 */
 #define REF_FREQ    625
 #define FREQ_OFFSET 36125
 
-       div = ((fep->frequency/1000 + FREQ_OFFSET ) * 10)  / REF_FREQ; // 4 MHz = 4000 KHz
+       div = ((fep->frequency/1000 + FREQ_OFFSET) * 10) / REF_FREQ;
+/* 4 MHz = 4000 KHz */
 
        buf[0] = (u8)( div >> 8) & 0x7f;
        buf[1] = (u8)        div & 0xff;
@@ -384,11 +586,11 @@ static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
  * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95 */
        buf[2] = 0x95;
 
-// Range(MHz)  C1 *  RE RTS BS4 BS3 BS2 BS1  Byte 5
-//  47 - 153   0  *  0   0   0   0   0   1   0x01
-// 153 - 430   0  *  0   0   0   0   1   0   0x02
-// 430 - 822   0  *  0   0   1   0   0   0   0x08
-// 822 - 862   1  *  0   0   1   0   0   0   0x88
+/* Range(MHz)  C1 *  RE RTS BS4 BS3 BS2 BS1  Byte 5
+ *  47 - 153   0  *  0   0   0   0   0   1   0x01
+ * 153 - 430   0  *  0   0   0   0   1   0   0x02
+ * 430 - 822   0  *  0   0   1   0   0   0   0x08
+ * 822 - 862   1  *  0   0   1   0   0   0   0x88 */
 
             if (fep->frequency <= 153000000) buf[3] = 0x01;
        else if (fep->frequency <= 430000000) buf[3] = 0x02;
@@ -397,11 +599,11 @@ static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
 
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 0);
-       deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n",fep->frequency, buf[0],buf[1],buf[2],buf[3]);
+       deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n", fep->frequency,
+       buf[0], buf[1], buf[2], buf[3]);
        ret = fc->i2c_request(&fc->fc_i2c_adap[2],
-               FC_WRITE, 0x61, buf[0], &buf[1], 3);
+                       FC_WRITE, 0x61, buf[0], &buf[1], 3);
        deb_tuner("tuner write returned: %d\n",ret);
-
        return ret;
 }
 
@@ -481,182 +683,73 @@ static u8 alps_tdee4_stv0297_inittab[] = {
 static struct stv0297_config alps_tdee4_stv0297_config = {
        .demod_address = 0x1c,
        .inittab = alps_tdee4_stv0297_inittab,
-//     .invert = 1,
-//     .pll_set = alps_tdee4_stv0297_pll_set,
-};
-
-
-/* SkyStar2 rev2.7 (a/u) */
-static struct s5h1420_config skystar2_rev2_7_s5h1420_config = {
-       .demod_address = 0x53,
-       .invert = 1,
-       .repeated_start_workaround = 1,
-       .serial_mpeg = 1,
-};
-
-static struct itd1000_config skystar2_rev2_7_itd1000_config = {
-       .i2c_address = 0x61,
 };
 
-/* SkyStar2 rev2.8 */
-static struct cx24123_config skystar2_rev2_8_cx24123_config = {
-       .demod_address = 0x55,
-       .dont_use_pll = 1,
-       .agc_callback = cx24113_agc_callback,
-};
-
-static const struct cx24113_config skystar2_rev2_8_cx24113_config = {
-       .i2c_addr = 0x54,
-       .xtal_khz = 10111,
-};
-
-/* try to figure out the frontend, each card/box can have on of the following list */
-int flexcop_frontend_init(struct flexcop_device *fc)
+static int cablestar2_attach(struct flexcop_device *fc,
+       struct i2c_adapter *i2c)
 {
-       struct dvb_frontend_ops *ops;
-       struct i2c_adapter *i2c = &fc->fc_i2c_adap[0].i2c_adap;
-       struct i2c_adapter *i2c_tuner;
-
-       /* enable no_base_addr - no repeated start when reading */
-       fc->fc_i2c_adap[0].no_base_addr = 1;
-       fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config, i2c);
-       if (fc->fe != NULL) {
-               flexcop_ibi_value r108;
-               i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe);
-               ops = &fc->fe->ops;
-
-               fc->fe_sleep = ops->sleep;
-               ops->sleep   = flexcop_sleep;
-
-               fc->dev_type = FC_SKY_REV27;
-
-               /* enable no_base_addr - no repeated start when reading */
-               fc->fc_i2c_adap[2].no_base_addr = 1;
-               if (dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, 0x08, 1, 1) == NULL)
-                       err("ISL6421 could NOT be attached");
-               else
-                       info("ISL6421 successfully attached");
-
-               /* the ITD1000 requires a lower i2c clock - it slows down the stuff for everyone - but is it a problem ? */
-               r108.raw = 0x00000506;
-               fc->write_ibi_reg(fc, tw_sm_c_108, r108);
-               if (i2c_tuner) {
-                       if (dvb_attach(itd1000_attach, fc->fe, i2c_tuner, &skystar2_rev2_7_itd1000_config) == NULL)
-                               err("ITD1000 could NOT be attached");
-                       else
-                               info("ITD1000 successfully attached");
-               }
-               goto fe_found;
-       }
-       fc->fc_i2c_adap[0].no_base_addr = 0; /* for the next devices we need it again */
-
-       /* try the sky v2.8 (cx24123, isl6421) */
-       fc->fe = dvb_attach(cx24123_attach,
-               &skystar2_rev2_8_cx24123_config, i2c);
-       if (fc->fe != NULL) {
-               i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);
-               if (i2c_tuner != NULL) {
-                       if (dvb_attach(cx24113_attach, fc->fe,
-                                       &skystar2_rev2_8_cx24113_config,
-                                       i2c_tuner) == NULL)
-                               err("CX24113 could NOT be attached");
-                       else
-                               info("CX24113 successfully attached");
-               }
-
-               fc->dev_type = FC_SKY_REV28;
-
-               fc->fc_i2c_adap[2].no_base_addr = 1;
-               if (dvb_attach(isl6421_attach, fc->fe,
-                      &fc->fc_i2c_adap[2].i2c_adap, 0x08, 0, 0) == NULL)
-                       err("ISL6421 could NOT be attached");
-               else
-                       info("ISL6421 successfully attached");
-
-               /* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an
-                * IR-receiver (PIC16F818) - but the card has no input for
-                * that ??? */
-
-               goto fe_found;
-    }
-
-       /* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
-       fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
-       if (fc->fe != NULL) {
-               ops = &fc->fe->ops;
-
-               ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
-
-               ops->set_voltage = flexcop_set_voltage;
-
-               fc->fe_sleep = ops->sleep;
-               ops->sleep = flexcop_sleep;
-
-               fc->dev_type = FC_SKY_REV26;
-               goto fe_found;
-       }
-
-       /* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
-       fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
-       if (fc->fe != NULL) {
-               fc->dev_type = FC_AIR_DVBT;
-               fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
-               goto fe_found;
-       }
-
-       /* try the air atsc 2nd generation (nxt2002) */
-       fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c);
-       if (fc->fe != NULL) {
-               fc->dev_type = FC_AIR_ATSC2;
-               dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, DVB_PLL_SAMSUNG_TBMV);
-               goto fe_found;
-       }
-
-       fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c);
-       if (fc->fe != NULL) {
-               fc->dev_type = FC_AIR_ATSC3;
-               dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
-                               TUNER_LG_TDVS_H06XF);
-               goto fe_found;
-       }
-
-       /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
-       fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
-       if (fc->fe != NULL) {
-               fc->dev_type = FC_AIR_ATSC1;
-               goto fe_found;
-       }
-
-       /* try the cable dvb (stv0297) */
        fc->fc_i2c_adap[0].no_base_addr = 1;
        fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
-       if (fc->fe != NULL) {
-               fc->dev_type = FC_CABLE;
-               fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
-               goto fe_found;
+       if (!fc->fe) {
+               /* Reset for next frontend to try */
+               fc->fc_i2c_adap[0].no_base_addr = 0;
+               return 0;
        }
-       fc->fc_i2c_adap[0].no_base_addr = 0;
-
-       /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
-       fc->fe = dvb_attach(mt312_attach,
-               &skystar23_samsung_tbdu18132_config, i2c);
-       if (fc->fe != NULL) {
-               ops = &fc->fe->ops;
-
-               ops->tuner_ops.set_params = skystar23_samsung_tbdu18132_tuner_set_params;
-
-               ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
-               ops->diseqc_send_burst      = flexcop_diseqc_send_burst;
-               ops->set_tone               = flexcop_set_tone;
-               ops->set_voltage            = flexcop_set_voltage;
-
-               fc->fe_sleep                = ops->sleep;
-               ops->sleep                  = flexcop_sleep;
+       fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
+       return 1;
+}
+#endif
+
+static struct {
+       flexcop_device_type_t type;
+       int (*attach)(struct flexcop_device *, struct i2c_adapter *);
+} flexcop_frontends[] = {
+#if defined(CONFIG_DVB_S5H1420_MODULE)
+       { FC_SKY_REV27, skystar2_rev27_attach },
+#endif
+#if defined(CONFIG_DVB_CX24123_MODULE)
+       { FC_SKY_REV28, skystar2_rev28_attach },
+#endif
+#if defined(CONFIG_DVB_STV0299_MODULE)
+       { FC_SKY_REV26, skystar2_rev26_attach },
+#endif
+#if defined(CONFIG_DVB_MT352_MODULE)
+       { FC_AIR_DVBT, airstar_dvbt_attach },
+#endif
+#if defined(CONFIG_DVB_NXT200X_MODULE)
+       { FC_AIR_ATSC2, airstar_atsc2_attach },
+#endif
+#if defined(CONFIG_DVB_LGDT330X_MODULE)
+       { FC_AIR_ATSC3, airstar_atsc3_attach },
+#endif
+#if defined(CONFIG_DVB_BCM3510_MODULE)
+       { FC_AIR_ATSC1, airstar_atsc1_attach },
+#endif
+#if defined(CONFIG_DVB_STV0297_MODULE)
+       { FC_CABLE, cablestar2_attach },
+#endif
+#if defined(CONFIG_DVB_MT312_MODULE)
+       { FC_SKY_REV23, skystar2_rev23_attach },
+#endif
+};
 
-               fc->dev_type                = FC_SKY_REV23;
-               goto fe_found;
+/* try to figure out the frontend */
+int flexcop_frontend_init(struct flexcop_device *fc)
+{
+       int i;
+       for (i = 0; i < ARRAY_SIZE(flexcop_frontends); i++) {
+               /* type needs to be set before, because of some workarounds
+                * done based on the probed card type */
+               fc->dev_type = flexcop_frontends[i].type;
+               if (flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap))
+                       goto fe_found;
+               /* Clean up partially attached frontend */
+               if (fc->fe) {
+                       dvb_frontend_detach(fc->fe);
+                       fc->fe = NULL;
+               }
        }
-
+       fc->dev_type = FC_UNK;
        err("no frontend driver found for this B2C2/FlexCop adapter");
        return -ENODEV;
 
@@ -664,9 +757,7 @@ fe_found:
        info("found '%s' .", fc->fe->ops.info.name);
        if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
                err("frontend registration failed!");
-               ops = &fc->fe->ops;
-               if (ops->release != NULL)
-                       ops->release(fc->fe);
+               dvb_frontend_detach(fc->fe);
                fc->fe = NULL;
                return -EINVAL;
        }
@@ -680,6 +771,5 @@ void flexcop_frontend_exit(struct flexcop_device *fc)
                dvb_unregister_frontend(fc->fe);
                dvb_frontend_detach(fc->fe);
        }
-
        fc->init_state &= ~FC_STATE_FE_INIT;
 }
index e2bed5076485635b7338fbde2b3f3e1f9aeb0f7b..fd1df2352764d4efa7296aeaeaf81d385512d4f4 100644 (file)
@@ -200,7 +200,7 @@ static int flexcop_master_xfer(struct i2c_adapter *i2c_adap,
                                        msgs[i].buf[0], &msgs[i].buf[1],
                                        msgs[i].len - 1);
                if (ret < 0) {
-                       err("i2c master_xfer failed");
+                       deb_i2c("i2c master_xfer failed");
                        break;
                }
        }
index e56627d2f0f42ddeaafdd38a5730fce0b192e527..f06f3a9070f564ca13e7c6bd28254b7891d4f6bf 100644 (file)
@@ -46,16 +46,16 @@ static const char *flexcop_revision_names[] = {
 };
 
 static const char *flexcop_device_names[] = {
-       "Unknown device",
-       "Air2PC/AirStar 2 DVB-T",
-       "Air2PC/AirStar 2 ATSC 1st generation",
-       "Air2PC/AirStar 2 ATSC 2nd generation",
-       "Sky2PC/SkyStar 2 DVB-S",
-       "Sky2PC/SkyStar 2 DVB-S (old version)",
-       "Cable2PC/CableStar 2 DVB-C",
-       "Air2PC/AirStar 2 ATSC 3rd generation (HD5000)",
-       "Sky2PC/SkyStar 2 DVB-S rev 2.7a/u",
-       "Sky2PC/SkyStar 2 DVB-S rev 2.8",
+       [FC_UNK]        = "Unknown device",
+       [FC_CABLE]      = "Cable2PC/CableStar 2 DVB-C",
+       [FC_AIR_DVBT]   = "Air2PC/AirStar 2 DVB-T",
+       [FC_AIR_ATSC1]  = "Air2PC/AirStar 2 ATSC 1st generation",
+       [FC_AIR_ATSC2]  = "Air2PC/AirStar 2 ATSC 2nd generation",
+       [FC_AIR_ATSC3]  = "Air2PC/AirStar 2 ATSC 3rd generation (HD5000)",
+       [FC_SKY_REV23]  = "Sky2PC/SkyStar 2 DVB-S rev 2.3 (old version)",
+       [FC_SKY_REV26]  = "Sky2PC/SkyStar 2 DVB-S rev 2.6",
+       [FC_SKY_REV27]  = "Sky2PC/SkyStar 2 DVB-S rev 2.7a/u",
+       [FC_SKY_REV28]  = "Sky2PC/SkyStar 2 DVB-S rev 2.8",
 };
 
 static const char *flexcop_bus_names[] = {
index 56d8fab688bb91f4ca1c404ed86aeacbefbaa411..a24c125331f0adbed30e1f9a289661483741f57b 100644 (file)
@@ -508,12 +508,6 @@ static int __devinit bt878_probe(struct pci_dev *dev,
        pci_set_master(dev);
        pci_set_drvdata(dev, bt);
 
-/*        if(init_bt878(btv) < 0) {
-               bt878_remove(dev);
-               return -EIO;
-       }
-*/
-
        if ((result = bt878_mem_alloc(bt))) {
                printk(KERN_ERR "bt878: failed to allocate memory!\n");
                goto fail2;
@@ -579,7 +573,7 @@ static struct pci_driver bt878_pci_driver = {
       .name    = "bt878",
       .id_table = bt878_pci_tbl,
       .probe   = bt878_probe,
-      .remove  = bt878_remove,
+      .remove  = __devexit_p(bt878_remove),
 };
 
 static int bt878_pci_driver_registered;
index 971a8b18f6dd7214a9b797697e09baf386ff7ed8..4dbd7d4185af2dba90dd610c62e49f1738cdda1d 100644 (file)
@@ -51,6 +51,9 @@
 #ifndef PCI_VENDOR_ID_TRIGEM
 #define PCI_VENDOR_ID_TRIGEM   0x109f
 #endif
+#ifndef PCI_VENDOR_ID_AXESS
+#define PCI_VENDOR_ID_AXESS    0x195d
+#endif
 #ifndef PCI_DEVICE_ID_DM1105
 #define PCI_DEVICE_ID_DM1105   0x036f
 #endif
@@ -60,6 +63,9 @@
 #ifndef PCI_DEVICE_ID_DW2004
 #define PCI_DEVICE_ID_DW2004   0x2004
 #endif
+#ifndef PCI_DEVICE_ID_DM05
+#define PCI_DEVICE_ID_DM05     0x1105
+#endif
 /* ----------------------------------------------- */
 /* sdmc dm1105 registers */
 
 #define DM1105_LNB_13V                         0x00010100
 #define DM1105_LNB_18V                         0x00000100
 
+/* GPIO's for LNB power control for Axess DM05 */
+#define DM05_LNB_MASK                          0x00000000
+#define DM05_LNB_13V                           0x00020000
+#define DM05_LNB_18V                           0x00030000
+
 static int ir_debug;
 module_param(ir_debug, int, 0644);
 MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
@@ -188,6 +199,8 @@ struct dm1105dvb {
 
        /* irq */
        struct work_struct work;
+       struct workqueue_struct *wq;
+       char wqn[16];
 
        /* dma */
        dma_addr_t dma_addr;
@@ -313,15 +326,25 @@ static inline struct dm1105dvb *frontend_to_dm1105dvb(struct dvb_frontend *fe)
 static int dm1105dvb_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
 {
        struct dm1105dvb *dm1105dvb = frontend_to_dm1105dvb(fe);
+       u32 lnb_mask, lnb_13v, lnb_18v;
 
-               if (voltage == SEC_VOLTAGE_18) {
-                       outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR));
-                       outl(DM1105_LNB_18V, dm_io_mem(DM1105_GPIOVAL));
-               } else  {
-               /*LNB ON-13V by default!*/
-                       outl(DM1105_LNB_MASK, dm_io_mem(DM1105_GPIOCTR));
-                       outl(DM1105_LNB_13V, dm_io_mem(DM1105_GPIOVAL));
-               }
+       switch (dm1105dvb->pdev->subsystem_device) {
+       case PCI_DEVICE_ID_DM05:
+               lnb_mask = DM05_LNB_MASK;
+               lnb_13v = DM05_LNB_13V;
+               lnb_18v = DM05_LNB_18V;
+               break;
+       default:
+               lnb_mask = DM1105_LNB_MASK;
+               lnb_13v = DM1105_LNB_13V;
+               lnb_18v = DM1105_LNB_18V;
+       }
+
+       outl(lnb_mask, dm_io_mem(DM1105_GPIOCTR));
+       if (voltage == SEC_VOLTAGE_18)
+               outl(lnb_18v , dm_io_mem(DM1105_GPIOVAL));
+       else
+               outl(lnb_13v, dm_io_mem(DM1105_GPIOVAL));
 
        return 0;
 }
@@ -440,7 +463,7 @@ static irqreturn_t dm1105dvb_irq(int irq, void *dev_id)
        case (INTSTS_TSIRQ | INTSTS_IR):
                dm1105dvb->nextwrp = inl(dm_io_mem(DM1105_WRP)) -
                                        inl(dm_io_mem(DM1105_STADR));
-               schedule_work(&dm1105dvb->work);
+               queue_work(dm1105dvb->wq, &dm1105dvb->work);
                break;
        case INTSTS_IR:
                dm1105dvb->ir.ir_command = inl(dm_io_mem(DM1105_IRCODE));
@@ -567,46 +590,44 @@ static int __devinit frontend_init(struct dm1105dvb *dm1105dvb)
        int ret;
 
        switch (dm1105dvb->pdev->subsystem_device) {
-       case PCI_DEVICE_ID_DW2002:
+       case PCI_DEVICE_ID_DW2004:
                dm1105dvb->fe = dvb_attach(
-                       stv0299_attach, &sharp_z0194a_config,
+                       cx24116_attach, &serit_sp2633_config,
                        &dm1105dvb->i2c_adap);
+               if (dm1105dvb->fe)
+                       dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage;
 
+               break;
+       default:
+               dm1105dvb->fe = dvb_attach(
+                       stv0299_attach, &sharp_z0194a_config,
+                       &dm1105dvb->i2c_adap);
                if (dm1105dvb->fe) {
                        dm1105dvb->fe->ops.set_voltage =
                                                        dm1105dvb_set_voltage;
                        dvb_attach(dvb_pll_attach, dm1105dvb->fe, 0x60,
                                        &dm1105dvb->i2c_adap, DVB_PLL_OPERA1);
+                       break;
                }
 
-               if (!dm1105dvb->fe) {
-                       dm1105dvb->fe = dvb_attach(
-                               stv0288_attach, &earda_config,
-                               &dm1105dvb->i2c_adap);
-                       if (dm1105dvb->fe) {
-                               dm1105dvb->fe->ops.set_voltage =
-                                                       dm1105dvb_set_voltage;
-                               dvb_attach(stb6000_attach, dm1105dvb->fe, 0x61,
-                                               &dm1105dvb->i2c_adap);
-                       }
+               dm1105dvb->fe = dvb_attach(
+                       stv0288_attach, &earda_config,
+                       &dm1105dvb->i2c_adap);
+               if (dm1105dvb->fe) {
+                       dm1105dvb->fe->ops.set_voltage =
+                                               dm1105dvb_set_voltage;
+                       dvb_attach(stb6000_attach, dm1105dvb->fe, 0x61,
+                                       &dm1105dvb->i2c_adap);
+                       break;
                }
 
-               if (!dm1105dvb->fe) {
-                       dm1105dvb->fe = dvb_attach(
-                               si21xx_attach, &serit_config,
-                               &dm1105dvb->i2c_adap);
-                       if (dm1105dvb->fe)
-                               dm1105dvb->fe->ops.set_voltage =
-                                                       dm1105dvb_set_voltage;
-               }
-               break;
-       case PCI_DEVICE_ID_DW2004:
                dm1105dvb->fe = dvb_attach(
-                       cx24116_attach, &serit_sp2633_config,
+                       si21xx_attach, &serit_config,
                        &dm1105dvb->i2c_adap);
                if (dm1105dvb->fe)
-                       dm1105dvb->fe->ops.set_voltage = dm1105dvb_set_voltage;
-               break;
+                       dm1105dvb->fe->ops.set_voltage =
+                                               dm1105dvb_set_voltage;
+
        }
 
        if (!dm1105dvb->fe) {
@@ -630,10 +651,17 @@ static void __devinit dm1105dvb_read_mac(struct dm1105dvb *dm1105dvb, u8 *mac)
        static u8 command[1] = { 0x28 };
 
        struct i2c_msg msg[] = {
-               { .addr = IIC_24C01_addr >> 1, .flags = 0,
-                               .buf = command, .len = 1 },
-               { .addr = IIC_24C01_addr >> 1, .flags = I2C_M_RD,
-                               .buf = mac, .len = 6 },
+               {
+                       .addr = IIC_24C01_addr >> 1,
+                       .flags = 0,
+                       .buf = command,
+                       .len = 1
+               }, {
+                       .addr = IIC_24C01_addr >> 1,
+                       .flags = I2C_M_RD,
+                       .buf = mac,
+                       .len = 6
+               },
        };
 
        dm1105_i2c_xfer(&dm1105dvb->i2c_adap, msg , 2);
@@ -752,14 +780,22 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
        dm1105_ir_init(dm1105dvb);
 
        INIT_WORK(&dm1105dvb->work, dm1105_dmx_buffer);
+       sprintf(dm1105dvb->wqn, "%s/%d", dvb_adapter->name, dvb_adapter->num);
+       dm1105dvb->wq = create_singlethread_workqueue(dm1105dvb->wqn);
+       if (!dm1105dvb->wq)
+               goto err_dvb_net;
 
        ret = request_irq(pdev->irq, dm1105dvb_irq, IRQF_SHARED,
                                                DRIVER_NAME, dm1105dvb);
        if (ret < 0)
-               goto err_free_irq;
+               goto err_workqueue;
 
        return 0;
 
+err_workqueue:
+       destroy_workqueue(dm1105dvb->wq);
+err_dvb_net:
+       dvb_net_release(&dm1105dvb->dvbnet);
 err_disconnect_frontend:
        dmx->disconnect_frontend(dmx);
 err_remove_mem_frontend:
@@ -776,8 +812,6 @@ err_i2c_del_adapter:
        i2c_del_adapter(&dm1105dvb->i2c_adap);
 err_dm1105dvb_hw_exit:
        dm1105dvb_hw_exit(dm1105dvb);
-err_free_irq:
-       free_irq(pdev->irq, dm1105dvb);
 err_pci_iounmap:
        pci_iounmap(pdev, dm1105dvb->io_mem);
 err_pci_release_regions:
@@ -833,6 +867,11 @@ static struct pci_device_id dm1105_id_table[] __devinitdata = {
                .device = PCI_DEVICE_ID_DM1105,
                .subvendor = PCI_ANY_ID,
                .subdevice = PCI_DEVICE_ID_DW2004,
+       }, {
+               .vendor = PCI_VENDOR_ID_AXESS,
+               .device = PCI_DEVICE_ID_DM05,
+               .subvendor = PCI_VENDOR_ID_AXESS,
+               .subdevice = PCI_DEVICE_ID_DM05,
        }, {
                /* empty */
        },
index c35fbb8d8f4a1b5c8c07cda277ad23f76cb558ab..6d6121eb5d592ea9157f0a8610069abc8ab4d8c9 100644 (file)
@@ -244,19 +244,13 @@ static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
 {
        struct dvb_device *dvbdev = file->private_data;
        struct dmxdev *dmxdev = dvbdev->priv;
-       int ret;
 
-       if (dmxdev->exit) {
-               mutex_unlock(&dmxdev->mutex);
+       if (dmxdev->exit)
                return -ENODEV;
-       }
 
-       //mutex_lock(&dmxdev->mutex);
-       ret = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
-                                    file->f_flags & O_NONBLOCK,
-                                    buf, count, ppos);
-       //mutex_unlock(&dmxdev->mutex);
-       return ret;
+       return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
+                                     file->f_flags & O_NONBLOCK,
+                                     buf, count, ppos);
 }
 
 static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,
index e2eca0b1fe7cfad6dc1215aa6d2bd1247497b93e..cfe2768d24af58133ecd47ba8461e25aa062d12b 100644 (file)
 */
 // #define DVB_DEMUX_SECTION_LOSS_LOG
 
+static int dvb_demux_tscheck;
+module_param(dvb_demux_tscheck, int, 0644);
+MODULE_PARM_DESC(dvb_demux_tscheck,
+               "enable transport stream continuity and TEI check");
+
+#define dprintk_tscheck(x...) do {                              \
+               if (dvb_demux_tscheck && printk_ratelimit())    \
+                       printk(x);                              \
+       } while (0)
+
 /******************************************************************************
  * static inlined helper functions
  ******************************************************************************/
@@ -376,6 +386,36 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
        u16 pid = ts_pid(buf);
        int dvr_done = 0;
 
+       if (dvb_demux_tscheck) {
+               if (!demux->cnt_storage)
+                       demux->cnt_storage = vmalloc(MAX_PID + 1);
+
+               if (!demux->cnt_storage) {
+                       printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n");
+                       dvb_demux_tscheck = 0;
+                       goto no_dvb_demux_tscheck;
+               }
+
+               /* check pkt counter */
+               if (pid < MAX_PID) {
+                       if (buf[1] & 0x80)
+                               dprintk_tscheck("TEI detected. "
+                                               "PID=0x%x data1=0x%x\n",
+                                               pid, buf[1]);
+
+                       if ((buf[3] & 0xf) != demux->cnt_storage[pid])
+                               dprintk_tscheck("TS packet counter mismatch. "
+                                               "PID=0x%x expected 0x%x "
+                                               "got 0x%x\n",
+                                               pid, demux->cnt_storage[pid],
+                                               buf[3] & 0xf);
+
+                       demux->cnt_storage[pid] = ((buf[3] & 0xf) + 1)&0xf;
+               };
+               /* end check */
+       };
+no_dvb_demux_tscheck:
+
        list_for_each_entry(feed, &demux->feed_list, list_head) {
                if ((feed->pid != pid) && (feed->pid != 0x2000))
                        continue;
@@ -1160,6 +1200,7 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
        int i;
        struct dmx_demux *dmx = &dvbdemux->dmx;
 
+       dvbdemux->cnt_storage = NULL;
        dvbdemux->users = 0;
        dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter));
 
@@ -1226,6 +1267,7 @@ EXPORT_SYMBOL(dvb_dmx_init);
 
 void dvb_dmx_release(struct dvb_demux *dvbdemux)
 {
+       vfree(dvbdemux->cnt_storage);
        vfree(dvbdemux->filter);
        vfree(dvbdemux->feed);
 }
index 2c5f915329ca9c5658e68628208f57c58c856364..2fe05d03240d75ca8f6631772f4c8a3baf9aaf5a 100644 (file)
@@ -42,6 +42,8 @@
 
 #define DVB_DEMUX_MASK_MAX 18
 
+#define MAX_PID 0x1fff
+
 struct dvb_demux_filter {
        struct dmx_section_filter filter;
        u8 maskandmode[DMX_MAX_FILTER_SIZE];
@@ -127,6 +129,8 @@ struct dvb_demux {
 
        struct mutex mutex;
        spinlock_t lock;
+
+       uint8_t *cnt_storage; /* for TS continuity check */
 };
 
 int dvb_dmx_init(struct dvb_demux *dvbdemux);
index ebc78157b9b8ced38cf637b9c336a0009f868836..f50ca7292a7d4e8bd6c69ffd58368db0c749b923 100644 (file)
@@ -543,6 +543,7 @@ restart:
 
                if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) {
                        /* got signal or quitting */
+                       fepriv->exit = 1;
                        break;
                }
 
@@ -656,6 +657,7 @@ restart:
        }
 
        fepriv->thread = NULL;
+       fepriv->exit = 0;
        mb();
 
        dvb_frontend_wakeup(fe);
index a454ee8f1e438939ecfd584d7fa90cdd2ec9c7b1..479dd05762a5d57a3bbcccad3aeb14807f2e0665 100644 (file)
@@ -447,6 +447,15 @@ static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
        return 0;
 }
 
+static char *dvb_nodename(struct device *dev)
+{
+       struct dvb_device *dvbdev = dev_get_drvdata(dev);
+
+       return kasprintf(GFP_KERNEL, "dvb/adapter%d/%s%d",
+               dvbdev->adapter->num, dnames[dvbdev->type], dvbdev->id);
+}
+
+
 static int __init init_dvbdev(void)
 {
        int retval;
@@ -469,6 +478,7 @@ static int __init init_dvbdev(void)
                goto error;
        }
        dvb_class->dev_uevent = dvb_uevent;
+       dvb_class->nodename = dvb_nodename;
        return 0;
 
 error:
index 1bb66e1ed5a7d7a267b023d86ca0490b28bb7beb..496c1a37034ced8d9ab89aaff3cd2ef30c024b08 100644 (file)
@@ -261,6 +261,7 @@ config DVB_USB_DW2102
        select DVB_STB6000 if !DVB_FE_CUSTOMISE
        select DVB_CX24116 if !DVB_FE_CUSTOMISE
        select DVB_SI21XX if !DVB_FE_CUSTOMISE
+       select DVB_TDA10021 if !DVB_FE_CUSTOMISE
        help
          Say Y here to support the DvbWorld DVB-S/S2 USB2.0 receivers
          and the TeVii S650.
index 53bfc8e42fb940f9651d0e66e16efc7fe57fa8d3..4cb31e7c13c2856be433e2feb3feee225d02db64 100644 (file)
@@ -40,7 +40,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 static DEFINE_MUTEX(af9015_usb_mutex);
 
 static struct af9015_config af9015_config;
-static struct dvb_usb_device_properties af9015_properties[2];
+static struct dvb_usb_device_properties af9015_properties[3];
 static int af9015_properties_count = ARRAY_SIZE(af9015_properties);
 
 static struct af9013_config af9015_af9013_config[] = {
@@ -538,7 +538,7 @@ exit:
 /* dump eeprom */
 static int af9015_eeprom_dump(struct dvb_usb_device *d)
 {
-       char buf[52], buf2[4];
+       char buf[4+3*16+1], buf2[4];
        u8 reg, val;
 
        for (reg = 0; ; reg++) {
@@ -1261,7 +1261,11 @@ static struct usb_device_id af9015_usb_table[] = {
        {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_395U_2)},
        {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_395U_3)},
        {USB_DEVICE(USB_VID_AFATECH,   USB_PID_TREKSTOR_DVBT)},
-       {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)},
+/* 20 */{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)},
+       {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805)},
+       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_CONCEPTRONIC_CTVDIGRCU)},
+       {USB_DEVICE(USB_VID_KWORLD_2,  USB_PID_KWORLD_MC810)},
+       {USB_DEVICE(USB_VID_KYE,       USB_PID_GENIUS_TVGO_DVB_T03)},
        {0},
 };
 MODULE_DEVICE_TABLE(usb, af9015_usb_table);
@@ -1321,7 +1325,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 
                .i2c_algo = &af9015_i2c_algo,
 
-               .num_device_descs = 9,
+               .num_device_descs = 9, /* max 9 */
                .devices = {
                        {
                                .name = "Afatech AF9015 DVB-T USB2.0 stick",
@@ -1426,7 +1430,7 @@ static struct dvb_usb_device_properties af9015_properties[] = {
 
                .i2c_algo = &af9015_i2c_algo,
 
-               .num_device_descs = 9,
+               .num_device_descs = 9, /* max 9 */
                .devices = {
                        {
                                .name = "Xtensions XD-380",
@@ -1478,7 +1482,85 @@ static struct dvb_usb_device_properties af9015_properties[] = {
                                .warm_ids = {NULL},
                        },
                }
-       }
+       }, {
+               .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+               .usb_ctrl = DEVICE_SPECIFIC,
+               .download_firmware = af9015_download_firmware,
+               .firmware = "dvb-usb-af9015.fw",
+               .no_reconnect = 1,
+
+               .size_of_priv = sizeof(struct af9015_state), \
+
+               .num_adapters = 2,
+               .adapter = {
+                       {
+                               .caps = DVB_USB_ADAP_HAS_PID_FILTER |
+                               DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+
+                               .pid_filter_count = 32,
+                               .pid_filter       = af9015_pid_filter,
+                               .pid_filter_ctrl  = af9015_pid_filter_ctrl,
+
+                               .frontend_attach =
+                                       af9015_af9013_frontend_attach,
+                               .tuner_attach    = af9015_tuner_attach,
+                               .stream = {
+                                       .type = USB_BULK,
+                                       .count = 6,
+                                       .endpoint = 0x84,
+                               },
+                       },
+                       {
+                               .frontend_attach =
+                                       af9015_af9013_frontend_attach,
+                               .tuner_attach    = af9015_tuner_attach,
+                               .stream = {
+                                       .type = USB_BULK,
+                                       .count = 6,
+                                       .endpoint = 0x85,
+                                       .u = {
+                                               .bulk = {
+                                                       .buffersize =
+                                               TS_USB20_MAX_PACKET_SIZE,
+                                               }
+                                       }
+                               },
+                       }
+               },
+
+               .identify_state = af9015_identify_state,
+
+               .rc_query         = af9015_rc_query,
+               .rc_interval      = 150,
+
+               .i2c_algo = &af9015_i2c_algo,
+
+               .num_device_descs = 4, /* max 9 */
+               .devices = {
+                       {
+                               .name = "AverMedia AVerTV Volar GPS 805 (A805)",
+                               .cold_ids = {&af9015_usb_table[21], NULL},
+                               .warm_ids = {NULL},
+                       },
+                       {
+                               .name = "Conceptronic USB2.0 DVB-T CTVDIGRCU " \
+                                       "V3.0",
+                               .cold_ids = {&af9015_usb_table[22], NULL},
+                               .warm_ids = {NULL},
+                       },
+                       {
+                               .name = "KWorld Digial MC-810",
+                               .cold_ids = {&af9015_usb_table[23], NULL},
+                               .warm_ids = {NULL},
+                       },
+                       {
+                               .name = "Genius TVGo DVB-T03",
+                               .cold_ids = {&af9015_usb_table[24], NULL},
+                               .warm_ids = {NULL},
+                       },
+               }
+       },
 };
 
 static int af9015_usb_probe(struct usb_interface *intf,
index 8ddbadf62194c4733046c3d0e39c702f75c3acb6..818b2ab584bf927bd00d0e1e369a24c94f2b9bca 100644 (file)
@@ -1346,9 +1346,9 @@ static int dib0700_xc5000_tuner_callback(void *priv, int component,
        if (command == XC5000_TUNER_RESET) {
                /* Reset the tuner */
                dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 0);
-               msleep(330); /* from Windows USB trace */
+               msleep(10);
                dib0700_set_gpio(adap->dev, GPIO1, GPIO_OUT, 1);
-               msleep(330); /* from Windows USB trace */
+               msleep(10);
        } else {
                err("xc5000: unknown tuner callback command: %d\n", command);
                return -EINVAL;
@@ -1493,6 +1493,10 @@ struct usb_device_id dib0700_usb_id_table[] = {
        { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC_B210) },
        { USB_DEVICE(USB_VID_YUAN,      USB_PID_YUAN_MC770) },
        { USB_DEVICE(USB_VID_ELGATO,    USB_PID_ELGATO_EYETV_DTT) },
+/* 50 */{ USB_DEVICE(USB_VID_ELGATO,   USB_PID_ELGATO_EYETV_DTT_Dlx) },
+       { USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_H) },
+       { USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_T3) },
+       { USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_T5) },
        { 0 }           /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -1692,7 +1696,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        },
                },
 
-               .num_device_descs = 11,
+               .num_device_descs = 12,
                .devices = {
                        {   "DiBcom STK7070P reference design",
                                { &dib0700_usb_id_table[15], NULL },
@@ -1726,8 +1730,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                { &dib0700_usb_id_table[30], NULL },
                                { NULL },
                        },
-                       {   "Terratec Cinergy T USB XXS",
-                               { &dib0700_usb_id_table[33], NULL },
+                       {   "Terratec Cinergy T USB XXS/ T3",
+                               { &dib0700_usb_id_table[33],
+                                       &dib0700_usb_id_table[52], NULL },
                                { NULL },
                        },
                        {   "Elgato EyeTV DTT",
@@ -1738,6 +1743,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                { &dib0700_usb_id_table[45], NULL },
                                { NULL },
                        },
+                       {   "Elgato EyeTV Dtt Dlx PD378S",
+                               { &dib0700_usb_id_table[50], NULL },
+                               { NULL },
+                       },
                },
 
                .rc_interval      = DEFAULT_RC_INTERVAL,
@@ -1784,8 +1793,9 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                { &dib0700_usb_id_table[36], NULL },
                                { NULL },
                        },
-                       {  "Terratec Cinergy DT USB XS Diversity",
-                               { &dib0700_usb_id_table[43], NULL },
+                       {  "Terratec Cinergy DT USB XS Diversity/ T5",
+                               { &dib0700_usb_id_table[43],
+                                       &dib0700_usb_id_table[53], NULL},
                                { NULL },
                        },
                        {  "Sony PlayTV",
@@ -1812,7 +1822,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        },
                },
 
-               .num_device_descs = 7,
+               .num_device_descs = 8,
                .devices = {
                        {   "Terratec Cinergy HT USB XE",
                                { &dib0700_usb_id_table[27], NULL },
@@ -1842,6 +1852,11 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                                { &dib0700_usb_id_table[48], NULL },
                                { NULL },
                        },
+                       {   "Leadtek WinFast DTV Dongle H",
+                               { &dib0700_usb_id_table[51], NULL },
+                               { NULL },
+                       },
+
                },
                .rc_interval      = DEFAULT_RC_INTERVAL,
                .rc_key_map       = dib0700_rc_keys,
index 8ee6cd4da9e7c1053099792ef5ec0700bbd29ccf..8dbad1ec53c404782d16c33e8929976a3ad8e386 100644 (file)
@@ -133,14 +133,17 @@ static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num
 
        for (i = 0; i < num; i++) {
                /* write/read request */
-               if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+               if (i+1 < num && (msg[i].flags & I2C_M_RD) == 0
+                                         && (msg[i+1].flags & I2C_M_RD)) {
                        if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,
                                                msg[i+1].buf,msg[i+1].len) < 0)
                                break;
                        i++;
-               } else
+               } else if ((msg[i].flags & I2C_M_RD) == 0) {
                        if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0)
                                break;
+               } else
+                       break;
        }
 
        mutex_unlock(&d->i2c_mutex);
index f506c74119f3bfb48d5714d2f3ad6d36e11d3066..9593b72899946c3e3f95f97e6cad7ebe191459b6 100644 (file)
@@ -80,6 +80,7 @@
 #define USB_PID_COMPRO_DVBU2000_UNK_WARM               0x010d
 #define USB_PID_COMPRO_VIDEOMATE_U500                  0x1e78
 #define USB_PID_COMPRO_VIDEOMATE_U500_PC               0x1e80
+#define USB_PID_CONCEPTRONIC_CTVDIGRCU                 0xe397
 #define USB_PID_CONEXANT_D680_DMB                      0x86d6
 #define USB_PID_DIBCOM_HOOK_DEFAULT                    0x0064
 #define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM             0x0065
@@ -97,6 +98,7 @@
 #define USB_PID_DPOSH_M9206_COLD                       0x9206
 #define USB_PID_DPOSH_M9206_WARM                       0xa090
 #define USB_PID_UNIWILL_STK7700P                       0x6003
+#define USB_PID_GENIUS_TVGO_DVB_T03                    0x4012
 #define USB_PID_GRANDTEC_DVBT_USB_COLD                 0x0fa0
 #define USB_PID_GRANDTEC_DVBT_USB_WARM                 0x0fa1
 #define USB_PID_INTEL_CE9500                           0x9500
 #define USB_PID_KWORLD_395U                            0xe396
 #define USB_PID_KWORLD_395U_2                          0xe39b
 #define USB_PID_KWORLD_395U_3                          0xe395
+#define USB_PID_KWORLD_MC810                           0xc810
 #define USB_PID_KWORLD_PC160_2T                                0xc160
 #define USB_PID_KWORLD_VSTREAM_COLD                    0x17de
 #define USB_PID_KWORLD_VSTREAM_WARM                    0x17df
 #define USB_PID_AVERMEDIA_A309                         0xa309
 #define USB_PID_AVERMEDIA_A310                         0xa310
 #define USB_PID_AVERMEDIA_A850                         0x850a
+#define USB_PID_AVERMEDIA_A805                         0xa805
 #define USB_PID_TECHNOTREND_CONNECT_S2400               0x3006
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY       0x005a
 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2     0x0081
 #define USB_PID_TERRATEC_CINERGY_HT_EXPRESS            0x0060
 #define USB_PID_TERRATEC_CINERGY_T_EXPRESS             0x0062
 #define USB_PID_TERRATEC_CINERGY_T_XXS                 0x0078
+#define USB_PID_TERRATEC_T3                            0x10a0
+#define USB_PID_TERRATEC_T5                            0x10a1
 #define USB_PID_PINNACLE_EXPRESSCARD_320CX             0x022e
 #define USB_PID_PINNACLE_PCTV2000E                     0x022c
 #define USB_PID_PINNACLE_PCTV_DVB_T_FLASH              0x0228
 #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_WINFAST_DTV_DONGLE_H                   0x60f6
 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2          0x6f01
 #define USB_PID_WINFAST_DTV_DONGLE_GOLD                        0x6029
 #define USB_PID_GENPIX_8PSK_REV_1_COLD                 0x0200
 #define USB_PID_MSI_DIGI_VOX_MINI_III                   0x8807
 #define USB_PID_SONY_PLAYTV                            0x0003
 #define USB_PID_ELGATO_EYETV_DTT                       0x0021
+#define USB_PID_ELGATO_EYETV_DTT_Dlx                   0x0020
 
 #endif
index 2d5352e54dc018d05959ab9d83f5634e126d2b83..e441d274e6c117010f1da2ee91f083782f0823e4 100644 (file)
@@ -196,7 +196,7 @@ struct dvb_usb_device_properties {
 #define CYPRESS_FX2     3
        int        usb_ctrl;
        int        (*download_firmware) (struct usb_device *, const struct firmware *);
-       const char firmware[FIRMWARE_NAME_MAX];
+       const char *firmware;
        int        no_reconnect;
 
        int size_of_priv;
@@ -223,7 +223,7 @@ struct dvb_usb_device_properties {
        int generic_bulk_ctrl_endpoint;
 
        int num_device_descs;
-       struct dvb_usb_device_description devices[11];
+       struct dvb_usb_device_description devices[12];
 };
 
 /**
index c65f273ff313cda9d874f3183f343949da953169..75de49c0d94370e34e3922b398c5847bf55c7361 100644 (file)
@@ -1,7 +1,7 @@
 /* DVB USB framework compliant Linux driver for the
-*      DVBWorld DVB-S 2101, 2102, DVB-S2 2104 Card
-*
-* Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
+*      DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101,
+*      TeVii S600, S650 Cards
+* Copyright (C) 2008,2009 Igor M. Liplianin (liplianin@me.by)
 *
 *      This program is free software; you can redistribute it and/or modify it
 *      under the terms of the GNU General Public License as published by the
@@ -17,6 +17,7 @@
 #include "stb6000.h"
 #include "eds1547.h"
 #include "cx24116.h"
+#include "tda1002x.h"
 
 #ifndef USB_PID_DW2102
 #define USB_PID_DW2102 0x2102
 #define USB_PID_DW2104 0x2104
 #endif
 
+#ifndef USB_PID_DW3101
+#define USB_PID_DW3101 0x3101
+#endif
+
 #ifndef USB_PID_CINERGY_S
 #define USB_PID_CINERGY_S 0x0064
 #endif
 
+#ifndef USB_PID_TEVII_S650
+#define USB_PID_TEVII_S650 0xd650
+#endif
+
 #define DW210X_READ_MSG 0
 #define DW210X_WRITE_MSG 1
 
 #define DW2102_VOLTAGE_CTRL (0x1800)
 #define DW2102_RC_QUERY (0x1a00)
 
-struct dw210x_state {
-       u32 last_key_pressed;
-};
-struct dw210x_rc_keys {
-       u32 keycode;
-       u32 event;
+struct dvb_usb_rc_keys_table {
+       struct dvb_usb_rc_key *rc_keys;
+       int rc_keys_size;
 };
 
 /* debug */
 static int dvb_usb_dw2102_debug;
 module_param_named(debug, dvb_usb_dw2102_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer (or-able))." DVB_USB_DEBUG_STATUS);
+MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer 4=rc(or-able))."
+                                               DVB_USB_DEBUG_STATUS);
+
+/* keymaps */
+static int ir_keymap;
+module_param_named(keymap, ir_keymap, int, 0644);
+MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs  ...");
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
@@ -79,7 +91,7 @@ static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
 static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                int num)
 {
-struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
        int i = 0, ret = 0;
        u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0};
        u16 value;
@@ -205,6 +217,7 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
        mutex_unlock(&d->i2c_mutex);
        return num;
 }
+
 static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
 {
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
@@ -219,7 +232,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
        case 2: {
                /* read */
                /* first write first register number */
-               u8 ibuf [msg[1].len + 2], obuf[3];
+               u8 ibuf[msg[1].len + 2], obuf[3];
                obuf[0] = 0xd0;
                obuf[1] = msg[0].len;
                obuf[2] = msg[0].buf[0];
@@ -293,7 +306,7 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
        case 2: {
                /* read */
                /* first write first register number */
-               u8 ibuf [msg[1].len + 2], obuf[3];
+               u8 ibuf[msg[1].len + 2], obuf[3];
                obuf[0] = 0xaa;
                obuf[1] = msg[0].len;
                obuf[2] = msg[0].buf[0];
@@ -360,6 +373,69 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
        return num;
 }
 
+static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+                                                               int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       int ret = 0, i;
+
+       if (!d)
+               return -ENODEV;
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       switch (num) {
+       case 2: {
+               /* read */
+               /* first write first register number */
+               u8 ibuf[msg[1].len + 2], obuf[3];
+               obuf[0] = msg[0].addr << 1;
+               obuf[1] = msg[0].len;
+               obuf[2] = msg[0].buf[0];
+               ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+                               obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+               /* second read registers */
+               ret = dw210x_op_rw(d->udev, 0xc3, 0x19 , 0,
+                               ibuf, msg[1].len + 2, DW210X_READ_MSG);
+               memcpy(msg[1].buf, ibuf + 2, msg[1].len);
+
+               break;
+       }
+       case 1:
+               switch (msg[0].addr) {
+               case 0x60:
+               case 0x0c: {
+                       /* write to register */
+                       u8 obuf[msg[0].len + 2];
+                       obuf[0] = msg[0].addr << 1;
+                       obuf[1] = msg[0].len;
+                       memcpy(obuf + 2, msg[0].buf, msg[0].len);
+                       ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+                                       obuf, msg[0].len + 2, DW210X_WRITE_MSG);
+                       break;
+               }
+               case(DW2102_RC_QUERY): {
+                       u8 ibuf[2];
+                       ret  = dw210x_op_rw(d->udev, 0xb8, 0, 0,
+                                       ibuf, 2, DW210X_READ_MSG);
+                       memcpy(msg[0].buf, ibuf , 2);
+                       break;
+               }
+               }
+
+               break;
+       }
+
+       for (i = 0; i < num; i++) {
+               deb_xfer("%02x:%02x: %s ", i, msg[i].addr,
+                               msg[i].flags == 0 ? ">>>" : "<<<");
+               debug_dump(msg[i].buf, msg[i].len, deb_xfer);
+       }
+
+       mutex_unlock(&d->i2c_mutex);
+       return num;
+}
+
 static u32 dw210x_i2c_func(struct i2c_adapter *adapter)
 {
        return I2C_FUNC_I2C;
@@ -385,6 +461,11 @@ static struct i2c_algorithm dw2104_i2c_algo = {
        .functionality = dw210x_i2c_func,
 };
 
+static struct i2c_algorithm dw3101_i2c_algo = {
+       .master_xfer = dw3101_i2c_transfer,
+       .functionality = dw210x_i2c_func,
+};
+
 static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
 {
        int i;
@@ -404,6 +485,7 @@ static int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
                        debug_dump(eepromline, 16, deb_xfer);
                }
        }
+
        memcpy(mac, eeprom + 8, 6);
        return 0;
 };
@@ -448,6 +530,11 @@ static struct si21xx_config serit_sp1511lhb_config = {
 
 };
 
+static struct tda10023_config dw3101_tda10023_config = {
+       .demod_address = 0x0c,
+       .invert = 1,
+};
+
 static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
 {
        if ((d->fe = dvb_attach(cx24116_attach, &dw2104_config,
@@ -460,6 +547,7 @@ static int dw2104_frontend_attach(struct dvb_usb_adapter *d)
 }
 
 static struct dvb_usb_device_properties dw2102_properties;
+static struct dvb_usb_device_properties dw2104_properties;
 
 static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
 {
@@ -497,6 +585,17 @@ static int dw2102_frontend_attach(struct dvb_usb_adapter *d)
        return -EIO;
 }
 
+static int dw3101_frontend_attach(struct dvb_usb_adapter *d)
+{
+       d->fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config,
+                               &d->dev->i2c_adap, 0x48);
+       if (d->fe != NULL) {
+               info("Attached tda10023!\n");
+               return 0;
+       }
+       return -EIO;
+}
+
 static int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
 {
        dvb_attach(dvb_pll_attach, adap->fe, 0x60,
@@ -512,6 +611,14 @@ static int dw2102_earda_tuner_attach(struct dvb_usb_adapter *adap)
        return 0;
 }
 
+static int dw3101_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       dvb_attach(dvb_pll_attach, adap->fe, 0x60,
+               &adap->dev->i2c_adap, DVB_PLL_TUA6034);
+
+       return 0;
+}
+
 static struct dvb_usb_rc_key dw210x_rc_keys[] = {
        { 0xf8, 0x0a, KEY_Q },          /*power*/
        { 0xf8, 0x0c, KEY_M },          /*mute*/
@@ -544,44 +651,147 @@ static struct dvb_usb_rc_key dw210x_rc_keys[] = {
        { 0xf8, 0x40, KEY_F },          /*full*/
        { 0xf8, 0x1e, KEY_W },          /*tvmode*/
        { 0xf8, 0x1b, KEY_B },          /*recall*/
+};
 
+static struct dvb_usb_rc_key tevii_rc_keys[] = {
+       { 0xf8, 0x0a, KEY_POWER },
+       { 0xf8, 0x0c, KEY_MUTE },
+       { 0xf8, 0x11, KEY_1 },
+       { 0xf8, 0x12, KEY_2 },
+       { 0xf8, 0x13, KEY_3 },
+       { 0xf8, 0x14, KEY_4 },
+       { 0xf8, 0x15, KEY_5 },
+       { 0xf8, 0x16, KEY_6 },
+       { 0xf8, 0x17, KEY_7 },
+       { 0xf8, 0x18, KEY_8 },
+       { 0xf8, 0x19, KEY_9 },
+       { 0xf8, 0x10, KEY_0 },
+       { 0xf8, 0x1c, KEY_MENU },
+       { 0xf8, 0x0f, KEY_VOLUMEDOWN },
+       { 0xf8, 0x1a, KEY_LAST },
+       { 0xf8, 0x0e, KEY_OPEN },
+       { 0xf8, 0x04, KEY_RECORD },
+       { 0xf8, 0x09, KEY_VOLUMEUP },
+       { 0xf8, 0x08, KEY_CHANNELUP },
+       { 0xf8, 0x07, KEY_PVR },
+       { 0xf8, 0x0b, KEY_TIME },
+       { 0xf8, 0x02, KEY_RIGHT },
+       { 0xf8, 0x03, KEY_LEFT },
+       { 0xf8, 0x00, KEY_UP },
+       { 0xf8, 0x1f, KEY_OK },
+       { 0xf8, 0x01, KEY_DOWN },
+       { 0xf8, 0x05, KEY_TUNER },
+       { 0xf8, 0x06, KEY_CHANNELDOWN },
+       { 0xf8, 0x40, KEY_PLAYPAUSE },
+       { 0xf8, 0x1e, KEY_REWIND },
+       { 0xf8, 0x1b, KEY_FAVORITES },
+       { 0xf8, 0x1d, KEY_BACK },
+       { 0xf8, 0x4d, KEY_FASTFORWARD },
+       { 0xf8, 0x44, KEY_EPG },
+       { 0xf8, 0x4c, KEY_INFO },
+       { 0xf8, 0x41, KEY_AB },
+       { 0xf8, 0x43, KEY_AUDIO },
+       { 0xf8, 0x45, KEY_SUBTITLE },
+       { 0xf8, 0x4a, KEY_LIST },
+       { 0xf8, 0x46, KEY_F1 },
+       { 0xf8, 0x47, KEY_F2 },
+       { 0xf8, 0x5e, KEY_F3 },
+       { 0xf8, 0x5c, KEY_F4 },
+       { 0xf8, 0x52, KEY_F5 },
+       { 0xf8, 0x5a, KEY_F6 },
+       { 0xf8, 0x56, KEY_MODE },
+       { 0xf8, 0x58, KEY_SWITCHVIDEOMODE },
 };
 
+static struct dvb_usb_rc_key tbs_rc_keys[] = {
+       { 0xf8, 0x84, KEY_POWER },
+       { 0xf8, 0x94, KEY_MUTE },
+       { 0xf8, 0x87, KEY_1 },
+       { 0xf8, 0x86, KEY_2 },
+       { 0xf8, 0x85, KEY_3 },
+       { 0xf8, 0x8b, KEY_4 },
+       { 0xf8, 0x8a, KEY_5 },
+       { 0xf8, 0x89, KEY_6 },
+       { 0xf8, 0x8f, KEY_7 },
+       { 0xf8, 0x8e, KEY_8 },
+       { 0xf8, 0x8d, KEY_9 },
+       { 0xf8, 0x92, KEY_0 },
+       { 0xf8, 0x96, KEY_CHANNELUP },
+       { 0xf8, 0x91, KEY_CHANNELDOWN },
+       { 0xf8, 0x93, KEY_VOLUMEUP },
+       { 0xf8, 0x8c, KEY_VOLUMEDOWN },
+       { 0xf8, 0x83, KEY_RECORD },
+       { 0xf8, 0x98, KEY_PAUSE  },
+       { 0xf8, 0x99, KEY_OK },
+       { 0xf8, 0x9a, KEY_SHUFFLE },
+       { 0xf8, 0x81, KEY_UP },
+       { 0xf8, 0x90, KEY_LEFT },
+       { 0xf8, 0x82, KEY_RIGHT },
+       { 0xf8, 0x88, KEY_DOWN },
+       { 0xf8, 0x95, KEY_FAVORITES },
+       { 0xf8, 0x97, KEY_SUBTITLE },
+       { 0xf8, 0x9d, KEY_ZOOM },
+       { 0xf8, 0x9f, KEY_EXIT },
+       { 0xf8, 0x9e, KEY_MENU },
+       { 0xf8, 0x9c, KEY_EPG },
+       { 0xf8, 0x80, KEY_PREVIOUS },
+       { 0xf8, 0x9b, KEY_MODE }
+};
 
+static struct dvb_usb_rc_keys_table keys_tables[] = {
+       { dw210x_rc_keys, ARRAY_SIZE(dw210x_rc_keys) },
+       { tevii_rc_keys, ARRAY_SIZE(tevii_rc_keys) },
+       { tbs_rc_keys, ARRAY_SIZE(tbs_rc_keys) },
+};
 
 static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
-       struct dw210x_state *st = d->priv;
+       struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+       int keymap_size = d->props.rc_key_map_size;
        u8 key[2];
-       struct i2c_msg msg[] = {
-               {.addr = DW2102_RC_QUERY, .flags = I2C_M_RD, .buf = key,
-               .len = 2},
+       struct i2c_msg msg = {
+               .addr = DW2102_RC_QUERY,
+               .flags = I2C_M_RD,
+               .buf = key,
+               .len = 2
        };
        int i;
+       /* override keymap */
+       if ((ir_keymap > 0) && (ir_keymap <= ARRAY_SIZE(keys_tables))) {
+               keymap = keys_tables[ir_keymap - 1].rc_keys ;
+               keymap_size = keys_tables[ir_keymap - 1].rc_keys_size;
+       }
 
        *state = REMOTE_NO_KEY_PRESSED;
-       if (dw2102_i2c_transfer(&d->i2c_adap, msg, 1) == 1) {
-               for (i = 0; i < ARRAY_SIZE(dw210x_rc_keys); i++) {
-                       if (dw210x_rc_keys[i].data == msg[0].buf[0]) {
+       if (dw2102_i2c_transfer(&d->i2c_adap, &msg, 1) == 1) {
+               for (i = 0; i < keymap_size ; i++) {
+                       if (keymap[i].data == msg.buf[0]) {
                                *state = REMOTE_KEY_PRESSED;
-                               *event = dw210x_rc_keys[i].event;
-                               st->last_key_pressed =
-                                       dw210x_rc_keys[i].event;
+                               *event = keymap[i].event;
                                break;
                        }
-               st->last_key_pressed = 0;
+
                }
+
+               if ((*state) == REMOTE_KEY_PRESSED)
+                       deb_rc("%s: found rc key: %x, %x, event: %x\n",
+                                       __func__, key[0], key[1], (*event));
+               else if (key[0] != 0xff)
+                       deb_rc("%s: unknown rc key: %x, %x\n",
+                                       __func__, key[0], key[1]);
+
        }
-       /* info("key: %x %x\n",key[0],key[1]); */
+
        return 0;
 }
 
 static struct usb_device_id dw2102_table[] = {
        {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)},
        {USB_DEVICE(USB_VID_CYPRESS, 0x2101)},
-       {USB_DEVICE(USB_VID_CYPRESS, 0x2104)},
-       {USB_DEVICE(0x9022, 0xd650)},
+       {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)},
+       {USB_DEVICE(0x9022, USB_PID_TEVII_S650)},
        {USB_DEVICE(USB_VID_TERRATEC, USB_PID_CINERGY_S)},
+       {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)},
        { }
 };
 
@@ -642,11 +852,16 @@ static int dw2102_load_firmware(struct usb_device *dev,
                }
                /* init registers */
                switch (dev->descriptor.idProduct) {
+               case USB_PID_TEVII_S650:
+                       dw2104_properties.rc_key_map = tevii_rc_keys;
+                       dw2104_properties.rc_key_map_size =
+                                       ARRAY_SIZE(tevii_rc_keys);
                case USB_PID_DW2104:
-               case 0xd650:
                        reset = 1;
                        dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1,
                                        DW210X_WRITE_MSG);
+                       /* break omitted intentionally */
+               case USB_PID_DW3101:
                        reset = 0;
                        dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
                                        DW210X_WRITE_MSG);
@@ -690,6 +905,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
                                        DW210X_READ_MSG);
                        break;
                }
+
                msleep(100);
                kfree(p);
        }
@@ -700,7 +916,6 @@ static struct dvb_usb_device_properties dw2102_properties = {
        .caps = DVB_USB_IS_AN_I2C_ADAPTER,
        .usb_ctrl = DEVICE_SPECIFIC,
        .firmware = "dvb-usb-dw2102.fw",
-       .size_of_priv = sizeof(struct dw210x_state),
        .no_reconnect = 1,
 
        .i2c_algo = &dw2102_serit_i2c_algo,
@@ -714,7 +929,7 @@ static struct dvb_usb_device_properties dw2102_properties = {
        .num_adapters = 1,
        .download_firmware = dw2102_load_firmware,
        .read_mac_address = dw210x_read_mac_address,
-               .adapter = {
+       .adapter = {
                {
                        .frontend_attach = dw2102_frontend_attach,
                        .streaming_ctrl = NULL,
@@ -752,7 +967,6 @@ static struct dvb_usb_device_properties dw2104_properties = {
        .caps = DVB_USB_IS_AN_I2C_ADAPTER,
        .usb_ctrl = DEVICE_SPECIFIC,
        .firmware = "dvb-usb-dw2104.fw",
-       .size_of_priv = sizeof(struct dw210x_state),
        .no_reconnect = 1,
 
        .i2c_algo = &dw2104_i2c_algo,
@@ -796,12 +1010,57 @@ static struct dvb_usb_device_properties dw2104_properties = {
        }
 };
 
+static struct dvb_usb_device_properties dw3101_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+       .usb_ctrl = DEVICE_SPECIFIC,
+       .firmware = "dvb-usb-dw3101.fw",
+       .no_reconnect = 1,
+
+       .i2c_algo = &dw3101_i2c_algo,
+       .rc_key_map = dw210x_rc_keys,
+       .rc_key_map_size = ARRAY_SIZE(dw210x_rc_keys),
+       .rc_interval = 150,
+       .rc_query = dw2102_rc_query,
+
+       .generic_bulk_ctrl_endpoint = 0x81,
+       /* parameter for the MPEG2-data transfer */
+       .num_adapters = 1,
+       .download_firmware = dw2102_load_firmware,
+       .read_mac_address = dw210x_read_mac_address,
+       .adapter = {
+               {
+                       .frontend_attach = dw3101_frontend_attach,
+                       .streaming_ctrl = NULL,
+                       .tuner_attach = dw3101_tuner_attach,
+                       .stream = {
+                               .type = USB_BULK,
+                               .count = 8,
+                               .endpoint = 0x82,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 4096,
+                                       }
+                               }
+                       },
+               }
+       },
+       .num_device_descs = 1,
+       .devices = {
+               { "DVBWorld DVB-C 3101 USB2.0",
+                       {&dw2102_table[5], NULL},
+                       {NULL},
+               },
+       }
+};
+
 static int dw2102_probe(struct usb_interface *intf,
                const struct usb_device_id *id)
 {
        if (0 == dvb_usb_device_init(intf, &dw2102_properties,
                        THIS_MODULE, NULL, adapter_nr) ||
            0 == dvb_usb_device_init(intf, &dw2104_properties,
+                       THIS_MODULE, NULL, adapter_nr) ||
+           0 == dvb_usb_device_init(intf, &dw3101_properties,
                        THIS_MODULE, NULL, adapter_nr)) {
                return 0;
        }
@@ -833,6 +1092,8 @@ module_init(dw2102_module_init);
 module_exit(dw2102_module_exit);
 
 MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
-MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104 USB2.0 device");
+MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104,"
+                               " DVB-C 3101 USB2.0,"
+                               " TeVii S600, S650 USB2.0 devices");
 MODULE_VERSION("0.1");
 MODULE_LICENSE("GPL");
index e3370734e95a2d625e736a8718de9d671ab759e1..5cd0b0eb6ce148dc0b0be35bcd0f6a2570c9f1fc 100644 (file)
@@ -5,4 +5,5 @@
 #include "dvb-usb.h"
 
 #define deb_xfer(args...) dprintk(dvb_usb_dw2102_debug, 0x02, args)
+#define deb_rc(args...)   dprintk(dvb_usb_dw2102_debug, 0x04, args)
 #endif
index 3dd6843864ed8a05f33baedd437af45bff412c86..afb444db43ad971df82b810ad09485cefc5c8a9b 100644 (file)
@@ -223,7 +223,7 @@ static struct usb_device_id gp8psk_usb_table [] = {
            { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) },
            { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) },
            { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) },
-           { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) },
+/*         { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, */
            { 0 },
 };
 MODULE_DEVICE_TABLE(usb, gp8psk_usb_table);
@@ -254,7 +254,7 @@ static struct dvb_usb_device_properties gp8psk_properties = {
 
        .generic_bulk_ctrl_endpoint = 0x01,
 
-       .num_device_descs = 4,
+       .num_device_descs = 3,
        .devices = {
                { .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver",
                  .cold_ids = { &gp8psk_usb_table[0], NULL },
@@ -268,10 +268,6 @@ static struct dvb_usb_device_properties gp8psk_properties = {
                  .cold_ids = { NULL },
                  .warm_ids = { &gp8psk_usb_table[3], NULL },
                },
-               { .name = "Genpix SkyWalker-CW3K DVB-S receiver",
-                 .cold_ids = { NULL },
-                 .warm_ids = { &gp8psk_usb_table[4], NULL },
-               },
                { NULL },
        }
 };
index 4e207658c5d95a0c58dca4d62e6b664ad7e41f3f..2b6eeeab5b257ff2e2469afb8f0587da98a4ea0f 100644 (file)
@@ -225,7 +225,7 @@ fail_free:
 
 static int node_remove(struct device *dev)
 {
-       struct firedtv *fdtv = dev->driver_data;
+       struct firedtv *fdtv = dev_get_drvdata(dev);
 
        fdtv_dvb_unregister(fdtv);
 
@@ -242,7 +242,7 @@ static int node_remove(struct device *dev)
 
 static int node_update(struct unit_directory *ud)
 {
-       struct firedtv *fdtv = ud->device.driver_data;
+       struct firedtv *fdtv = dev_get_drvdata(&ud->device);
 
        if (fdtv->isochannel >= 0)
                cmp_establish_pp_connection(fdtv, fdtv->subunit,
index 9d308dd32a5ce4337efe97f594b2663aebe5570f..5742fde79d99d71f25bc62d390984a42294d1ab8 100644 (file)
@@ -268,7 +268,7 @@ struct firedtv *fdtv_alloc(struct device *dev,
        if (!fdtv)
                return NULL;
 
-       dev->driver_data        = fdtv;
+       dev_set_drvdata(dev, fdtv);
        fdtv->device            = dev;
        fdtv->isochannel        = -1;
        fdtv->voltage           = 0xff;
index 46a6324d7b730fe0e0b1ab2212ad32ab582aa213..27bca2e283dfc4a0a00ea070da033788997b27df 100644 (file)
@@ -18,7 +18,7 @@
 #include "firedtv.h"
 
 /* fixed table with older keycodes, geared towards MythTV */
-const static u16 oldtable[] = {
+static const u16 oldtable[] = {
 
        /* code from device: 0x4501...0x451f */
 
@@ -62,7 +62,7 @@ const static u16 oldtable[] = {
 };
 
 /* user-modifiable table for a remote as sold in 2008 */
-const static u16 keytable[] = {
+static const u16 keytable[] = {
 
        /* code from device: 0x0300...0x031f */
 
index 23e4cffeba38a789f1e03359c35a66685501dd71..be967ac09a3962e3f704a862998dfd43574d586d 100644 (file)
@@ -35,6 +35,21 @@ config DVB_STB6100
          A Silicon tuner from ST used in conjunction with the STB0899
          demodulator. Say Y when you want to support this tuner.
 
+config DVB_STV090x
+       tristate "STV0900/STV0903(A/B) based"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         DVB-S/S2/DSS Multistandard Professional/Broadcast demodulators.
+         Say Y when you want to support these frontends.
+
+config DVB_STV6110x
+       tristate "STV6110/(A) based tuners"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A Silicon tuner that supports DVB-S and DVB-S2 modes
+
 comment "DVB-S (satellite) frontends"
        depends on DVB_CORE
 
@@ -506,6 +521,13 @@ config DVB_ISL6421
        help
          An SEC control chip.
 
+config DVB_ISL6423
+       tristate "ISL6423 SEC controller"
+       depends on DVB_CORE && I2C
+       default m if DVB_FE_CUSTOMISE
+       help
+         A SEC controller chip from Intersil
+
 config DVB_LGS8GL5
        tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)"
        depends on DVB_CORE && I2C
index bc2b00abd1064612310cc58d9f3ae98ffacb0a37..832473c1e512765feb454597c8fd55d19053b166 100644 (file)
@@ -71,4 +71,6 @@ obj-$(CONFIG_DVB_STB6000) += stb6000.o
 obj-$(CONFIG_DVB_S921) += s921.o
 obj-$(CONFIG_DVB_STV6110) += stv6110.o
 obj-$(CONFIG_DVB_STV0900) += stv0900.o
-
+obj-$(CONFIG_DVB_STV090x) += stv090x.o
+obj-$(CONFIG_DVB_STV6110x) += stv6110x.o
+obj-$(CONFIG_DVB_ISL6423) += isl6423.o
index b2b50fb4cfd338002102b868e87b0cac1032954a..136c5863d81b5859d38fefd33b496932e8f6cca5 100644 (file)
@@ -1455,7 +1455,7 @@ static int af9013_download_firmware(struct af9013_state *state)
                af9013_ops.info.name);
 
        /* request the firmware, this will block and timeout */
-       ret = request_firmware(&fw, fw_file,  &state->i2c->dev);
+       ret = request_firmware(&fw, fw_file, state->i2c->dev.parent);
        if (ret) {
                err("did not find the firmware file. (%s) "
                        "Please see linux/Documentation/dvb/ for more details" \
index 35731258bb0a7b6d2025c7df0192c5e5bba8a2d7..956b80f4979ca95af361162ec6adde484a1c9c89 100644 (file)
@@ -367,11 +367,90 @@ static struct {
        { 0x8231, 0x13 },
 };
 
-/* QAM Modulation table */
+/* QAM64 Modulation table */
 static struct {
        u16 reg;
        u16 data;
-} QAM_mod_tab[] = {
+} QAM64_mod_tab[] = {
+       { 0x00a3, 0x09 },
+       { 0x00a4, 0x00 },
+       { 0x0081, 0xc4 },
+       { 0x00a5, 0x40 },
+       { 0x00aa, 0x77 },
+       { 0x00ad, 0x77 },
+       { 0x00a6, 0x67 },
+       { 0x0262, 0x20 },
+       { 0x021c, 0x30 },
+       { 0x00b8, 0x3e },
+       { 0x00b9, 0xf0 },
+       { 0x00ba, 0x01 },
+       { 0x00bb, 0x18 },
+       { 0x00bc, 0x50 },
+       { 0x00bd, 0x00 },
+       { 0x00be, 0xea },
+       { 0x00bf, 0xef },
+       { 0x00c0, 0xfc },
+       { 0x00c1, 0xbd },
+       { 0x00c2, 0x1f },
+       { 0x00c3, 0xfc },
+       { 0x00c4, 0xdd },
+       { 0x00c5, 0xaf },
+       { 0x00c6, 0x00 },
+       { 0x00c7, 0x38 },
+       { 0x00c8, 0x30 },
+       { 0x00c9, 0x05 },
+       { 0x00ca, 0x4a },
+       { 0x00cb, 0xd0 },
+       { 0x00cc, 0x01 },
+       { 0x00cd, 0xd9 },
+       { 0x00ce, 0x6f },
+       { 0x00cf, 0xf9 },
+       { 0x00d0, 0x70 },
+       { 0x00d1, 0xdf },
+       { 0x00d2, 0xf7 },
+       { 0x00d3, 0xc2 },
+       { 0x00d4, 0xdf },
+       { 0x00d5, 0x02 },
+       { 0x00d6, 0x9a },
+       { 0x00d7, 0xd0 },
+       { 0x0250, 0x0d },
+       { 0x0251, 0xcd },
+       { 0x0252, 0xe0 },
+       { 0x0253, 0x05 },
+       { 0x0254, 0xa7 },
+       { 0x0255, 0xff },
+       { 0x0256, 0xed },
+       { 0x0257, 0x5b },
+       { 0x0258, 0xae },
+       { 0x0259, 0xe6 },
+       { 0x025a, 0x3d },
+       { 0x025b, 0x0f },
+       { 0x025c, 0x0d },
+       { 0x025d, 0xea },
+       { 0x025e, 0xf2 },
+       { 0x025f, 0x51 },
+       { 0x0260, 0xf5 },
+       { 0x0261, 0x06 },
+       { 0x021a, 0x00 },
+       { 0x0546, 0x40 },
+       { 0x0210, 0xc7 },
+       { 0x0211, 0xaa },
+       { 0x0212, 0xab },
+       { 0x0213, 0x02 },
+       { 0x0502, 0x00 },
+       { 0x0121, 0x04 },
+       { 0x0122, 0x04 },
+       { 0x052e, 0x10 },
+       { 0x00a4, 0xca },
+       { 0x00a7, 0x40 },
+       { 0x0526, 0x01 },
+};
+
+/* QAM256 Modulation table */
+static struct {
+       u16 reg;
+       u16 data;
+} QAM256_mod_tab[] = {
        { 0x80a3, 0x09 },
        { 0x80a4, 0x00 },
        { 0x8081, 0xc4 },
@@ -464,12 +543,19 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
                au8522_set_if(fe, state->config->vsb_if);
                break;
        case QAM_64:
+               dprintk("%s() QAM 64\n", __func__);
+               for (i = 0; i < ARRAY_SIZE(QAM64_mod_tab); i++)
+                       au8522_writereg(state,
+                               QAM64_mod_tab[i].reg,
+                               QAM64_mod_tab[i].data);
+               au8522_set_if(fe, state->config->qam_if);
+               break;
        case QAM_256:
-               dprintk("%s() QAM 64/256\n", __func__);
-               for (i = 0; i < ARRAY_SIZE(QAM_mod_tab); i++)
+               dprintk("%s() QAM 256\n", __func__);
+               for (i = 0; i < ARRAY_SIZE(QAM256_mod_tab); i++)
                        au8522_writereg(state,
-                               QAM_mod_tab[i].reg,
-                               QAM_mod_tab[i].data);
+                               QAM256_mod_tab[i].reg,
+                               QAM256_mod_tab[i].data);
                au8522_set_if(fe, state->config->qam_if);
                break;
        default:
index 9b9f57264ceff0bd76c7685477ae22486d2a4b5a..2410d8b59b6b428aa7621ed8b71839bef23282a8 100644 (file)
@@ -492,7 +492,7 @@ static int cx24116_firmware_ondemand(struct dvb_frontend *fe)
                printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n",
                        __func__, CX24116_DEFAULT_FIRMWARE);
                ret = request_firmware(&fw, CX24116_DEFAULT_FIRMWARE,
-                       &state->i2c->dev);
+                       state->i2c->dev.parent);
                printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n",
                        __func__);
                if (ret) {
index 172f1f928f0271f8e64bc7daa12ea999033ee2d6..0100755352216ef3d180a270009a2bcde20b76bc 100644 (file)
@@ -123,10 +123,10 @@ static int drx_load_fw(struct drx397xD_state *s, enum fw_ix ix)
        }
        memset(&fw[ix].data[0], 0, sizeof(fw[0].data));
 
-       if (request_firmware(&fw[ix].file, fw[ix].name, &s->i2c->dev) != 0) {
+       rc = request_firmware(&fw[ix].file, fw[ix].name, s->i2c->dev.parent);
+       if (rc != 0) {
                printk(KERN_ERR "%s: Firmware \"%s\" not available\n",
                       mod_name, fw[ix].name);
-               rc = -ENOENT;
                goto exit_err;
        }
 
diff --git a/drivers/media/dvb/frontends/isl6423.c b/drivers/media/dvb/frontends/isl6423.c
new file mode 100644 (file)
index 0000000..dca5beb
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+       Intersil ISL6423 SEC and LNB Power supply controller
+
+       Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU General Public License as published by
+       the Free Software Foundation; either version 2 of the License, or
+       (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/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "isl6423.h"
+
+static unsigned int verbose;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "Set Verbosity level");
+
+#define FE_ERROR                               0
+#define FE_NOTICE                              1
+#define FE_INFO                                        2
+#define FE_DEBUG                               3
+#define FE_DEBUGREG                            4
+
+#define dprintk(__y, __z, format, arg...) do {                                         \
+       if (__z) {                                                                      \
+               if      ((verbose > FE_ERROR) && (verbose > __y))                       \
+                       printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);          \
+               else if ((verbose > FE_NOTICE) && (verbose > __y))                      \
+                       printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);       \
+               else if ((verbose > FE_INFO) && (verbose > __y))                        \
+                       printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);         \
+               else if ((verbose > FE_DEBUG) && (verbose > __y))                       \
+                       printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);        \
+       } else {                                                                        \
+               if (verbose > __y)                                                      \
+                       printk(format, ##arg);                                          \
+       }                                                                               \
+} while (0)
+
+struct isl6423_dev {
+       const struct isl6423_config     *config;
+       struct i2c_adapter              *i2c;
+
+       u8 reg_3;
+       u8 reg_4;
+
+       unsigned int verbose;
+};
+
+static int isl6423_write(struct isl6423_dev *isl6423, u8 reg)
+{
+       struct i2c_adapter *i2c = isl6423->i2c;
+       u8 addr                 = isl6423->config->addr;
+       int err = 0;
+
+       struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = &reg, .len = 1 };
+
+       dprintk(FE_DEBUG, 1, "write reg %02X", reg);
+       err = i2c_transfer(i2c, &msg, 1);
+       if (err < 0)
+               goto exit;
+       return 0;
+
+exit:
+       dprintk(FE_ERROR, 1, "I/O error <%d>", err);
+       return err;
+}
+
+static int isl6423_set_modulation(struct dvb_frontend *fe)
+{
+       struct isl6423_dev *isl6423             = (struct isl6423_dev *) fe->sec_priv;
+       const struct isl6423_config *config     = isl6423->config;
+       int err = 0;
+       u8 reg_2 = 0;
+
+       reg_2 = 0x01 << 5;
+
+       if (config->mod_extern)
+               reg_2 |= (1 << 3);
+       else
+               reg_2 |= (1 << 4);
+
+       err = isl6423_write(isl6423, reg_2);
+       if (err < 0)
+               goto exit;
+       return 0;
+
+exit:
+       dprintk(FE_ERROR, 1, "I/O error <%d>", err);
+       return err;
+}
+
+static int isl6423_voltage_boost(struct dvb_frontend *fe, long arg)
+{
+       struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv;
+       u8 reg_3 = isl6423->reg_3;
+       u8 reg_4 = isl6423->reg_4;
+       int err = 0;
+
+       if (arg) {
+               /* EN = 1, VSPEN = 1, VBOT = 1 */
+               reg_4 |= (1 << 4);
+               reg_4 |= 0x1;
+               reg_3 |= (1 << 3);
+       } else {
+               /* EN = 1, VSPEN = 1, VBOT = 0 */
+               reg_4 |= (1 << 4);
+               reg_4 &= ~0x1;
+               reg_3 |= (1 << 3);
+       }
+       err = isl6423_write(isl6423, reg_3);
+       if (err < 0)
+               goto exit;
+
+       err = isl6423_write(isl6423, reg_4);
+       if (err < 0)
+               goto exit;
+
+       isl6423->reg_3 = reg_3;
+       isl6423->reg_4 = reg_4;
+
+       return 0;
+exit:
+       dprintk(FE_ERROR, 1, "I/O error <%d>", err);
+       return err;
+}
+
+
+static int isl6423_set_voltage(struct dvb_frontend *fe,
+                              enum fe_sec_voltage voltage)
+{
+       struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv;
+       u8 reg_3 = isl6423->reg_3;
+       u8 reg_4 = isl6423->reg_4;
+       int err = 0;
+
+       switch (voltage) {
+       case SEC_VOLTAGE_OFF:
+               /* EN = 0 */
+               reg_4 &= ~(1 << 4);
+               break;
+
+       case SEC_VOLTAGE_13:
+               /* EN = 1, VSPEN = 1, VTOP = 0, VBOT = 0 */
+               reg_4 |= (1 << 4);
+               reg_4 &= ~0x3;
+               reg_3 |= (1 << 3);
+               break;
+
+       case SEC_VOLTAGE_18:
+               /* EN = 1, VSPEN = 1, VTOP = 1, VBOT = 0 */
+               reg_4 |= (1 << 4);
+               reg_4 |=  0x2;
+               reg_4 &= ~0x1;
+               reg_3 |= (1 << 3);
+               break;
+
+       default:
+               break;
+       }
+       err = isl6423_write(isl6423, reg_3);
+       if (err < 0)
+               goto exit;
+
+       err = isl6423_write(isl6423, reg_4);
+       if (err < 0)
+               goto exit;
+
+       isl6423->reg_3 = reg_3;
+       isl6423->reg_4 = reg_4;
+
+       return 0;
+exit:
+       dprintk(FE_ERROR, 1, "I/O error <%d>", err);
+       return err;
+}
+
+static int isl6423_set_current(struct dvb_frontend *fe)
+{
+       struct isl6423_dev *isl6423             = (struct isl6423_dev *) fe->sec_priv;
+       u8 reg_3 = isl6423->reg_3;
+       const struct isl6423_config *config     = isl6423->config;
+       int err = 0;
+
+       switch (config->current_max) {
+       case SEC_CURRENT_275m:
+               /* 275mA */
+               /* ISELH = 0, ISELL = 0 */
+               reg_3 &= ~0x3;
+               break;
+
+       case SEC_CURRENT_515m:
+               /* 515mA */
+               /* ISELH = 0, ISELL = 1 */
+               reg_3 &= ~0x2;
+               reg_3 |=  0x1;
+               break;
+
+       case SEC_CURRENT_635m:
+               /* 635mA */
+               /* ISELH = 1, ISELL = 0 */
+               reg_3 &= ~0x1;
+               reg_3 |=  0x2;
+               break;
+
+       case SEC_CURRENT_800m:
+               /* 800mA */
+               /* ISELH = 1, ISELL = 1 */
+               reg_3 |= 0x3;
+               break;
+       }
+
+       err = isl6423_write(isl6423, reg_3);
+       if (err < 0)
+               goto exit;
+
+       switch (config->curlim) {
+       case SEC_CURRENT_LIM_ON:
+               /* DCL = 0 */
+               reg_3 &= ~0x10;
+               break;
+
+       case SEC_CURRENT_LIM_OFF:
+               /* DCL = 1 */
+               reg_3 |= 0x10;
+               break;
+       }
+
+       err = isl6423_write(isl6423, reg_3);
+       if (err < 0)
+               goto exit;
+
+       isl6423->reg_3 = reg_3;
+
+       return 0;
+exit:
+       dprintk(FE_ERROR, 1, "I/O error <%d>", err);
+       return err;
+}
+
+static void isl6423_release(struct dvb_frontend *fe)
+{
+       isl6423_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+       kfree(fe->sec_priv);
+       fe->sec_priv = NULL;
+}
+
+struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe,
+                                   struct i2c_adapter *i2c,
+                                   const struct isl6423_config *config)
+{
+       struct isl6423_dev *isl6423;
+
+       isl6423 = kzalloc(sizeof(struct isl6423_dev), GFP_KERNEL);
+       if (!isl6423)
+               return NULL;
+
+       isl6423->config = config;
+       isl6423->i2c    = i2c;
+       fe->sec_priv    = isl6423;
+
+       /* SR3H = 0, SR3M = 1, SR3L = 0 */
+       isl6423->reg_3 = 0x02 << 5;
+       /* SR4H = 0, SR4M = 1, SR4L = 1 */
+       isl6423->reg_4 = 0x03 << 5;
+
+       if (isl6423_set_current(fe))
+               goto exit;
+
+       if (isl6423_set_modulation(fe))
+               goto exit;
+
+       fe->ops.release_sec             = isl6423_release;
+       fe->ops.set_voltage             = isl6423_set_voltage;
+       fe->ops.enable_high_lnb_voltage = isl6423_voltage_boost;
+       isl6423->verbose                = verbose;
+
+       return fe;
+
+exit:
+       kfree(isl6423);
+       fe->sec_priv = NULL;
+       return NULL;
+}
+EXPORT_SYMBOL(isl6423_attach);
+
+MODULE_DESCRIPTION("ISL6423 SEC");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/isl6423.h b/drivers/media/dvb/frontends/isl6423.h
new file mode 100644 (file)
index 0000000..e1a37fb
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+       Intersil ISL6423 SEC and LNB Power supply controller
+
+       Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU General Public License as published by
+       the Free Software Foundation; either version 2 of the License, or
+       (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 __ISL_6423_H
+#define __ISL_6423_H
+
+#include <linux/dvb/frontend.h>
+
+enum isl6423_current {
+       SEC_CURRENT_275m = 0,
+       SEC_CURRENT_515m,
+       SEC_CURRENT_635m,
+       SEC_CURRENT_800m,
+};
+
+enum isl6423_curlim {
+       SEC_CURRENT_LIM_ON = 1,
+       SEC_CURRENT_LIM_OFF
+};
+
+struct isl6423_config {
+       enum isl6423_current current_max;
+       enum isl6423_curlim curlim;
+       u8 addr;
+       u8 mod_extern;
+};
+
+#if defined(CONFIG_DVB_ISL6423) || (defined(CONFIG_DVB_ISL6423_MODULE) && defined(MODULE))
+
+
+extern struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe,
+                                          struct i2c_adapter *i2c,
+                                          const struct isl6423_config *config);
+
+#else
+static inline struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe,
+                                                 struct i2c_adapter *i2c,
+                                                 const struct isl6423_config *config)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+
+#endif /* CONFIG_DVB_ISL6423 */
+
+#endif /* __ISL_6423_H */
index d92d0557a80b719cdcf3e99bc876df6d56bad2eb..fde8c59700fbee05d63b6b6433adedd7ec9499a9 100644 (file)
@@ -19,6 +19,7 @@
  *
  */
 
+#include <asm/div64.h>
 #include <linux/dvb/frontend.h>
 #include "dvb_math.h"
 #include "lgdt3305.h"
@@ -496,27 +497,15 @@ static int lgdt3305_set_if(struct lgdt3305_state *state,
 
        nco = if_freq_khz / 10;
 
-#define LGDT3305_64BIT_DIVISION_ENABLED 0
-       /* FIXME: 64bit division disabled to avoid linking error:
-        * WARNING: "__udivdi3" [lgdt3305.ko] undefined!
-        */
        switch (param->u.vsb.modulation) {
        case VSB_8:
-#if LGDT3305_64BIT_DIVISION_ENABLED
                nco <<= 24;
-               nco /= 625;
-#else
-               nco *= ((1 << 24) / 625);
-#endif
+               do_div(nco, 625);
                break;
        case QAM_64:
        case QAM_256:
-#if LGDT3305_64BIT_DIVISION_ENABLED
                nco <<= 28;
-               nco /= 625;
-#else
-               nco *= ((1 << 28) / 625);
-#endif
+               do_div(nco, 625);
                break;
        default:
                return -EINVAL;
index f9785dfe735b770d25cc4efddf8d82fdb59d5371..fde27645bbed67918aca946c1f551dee7a961cea 100644 (file)
        } while (0)
 
 static int debug;
-static int fake_signal_str;
+static int fake_signal_str = 1;
 
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 
 module_param(fake_signal_str, int, 0644);
 MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913."
-"Signal strength calculation is slow.(default:off).");
+"Signal strength calculation is slow.(default:on).");
 
 /* LGS8GXX internal helper functions */
 
@@ -610,7 +610,7 @@ static int lgs8gxx_read_signal_agc(struct lgs8gxx_state *priv, u16 *signal)
        else
                cat = 0;
 
-       *signal = cat;
+       *signal = cat * 65535 / 5;
 
        return 0;
 }
@@ -630,8 +630,8 @@ static int lgs8913_read_signal_strength(struct lgs8gxx_state *priv, u16 *signal)
 
        if (fake_signal_str) {
                if ((t & 0xC0) == 0xC0) {
-                       dprintk("Fake signal strength as 50\n");
-                       *signal = 0x32;
+                       dprintk("Fake signal strength\n");
+                       *signal = 0x7FFF;
                } else
                        *signal = 0;
                return 0;
index 1dcc56f32bff71e92a1c1b94e9ef2463bbe4b725..71f607fe8fc7ca87326ad21e3fbf8fd7eeba9983 100644 (file)
@@ -133,7 +133,7 @@ static struct dvb_frontend *lnbx2x_attach(struct dvb_frontend *fe,
        /* override frontend ops */
        fe->ops.set_voltage = lnbp21_set_voltage;
        fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
-       printk(KERN_INFO "LNBx2x attached on addr=%x", lnbp21->i2c_addr);
+       printk(KERN_INFO "LNBx2x attached on addr=%x\n", lnbp21->i2c_addr);
 
        return fe;
 }
index 5ac9b15920f8df47f8c8d11b10d93a14c972401d..a621f727935f217eb91f78e84a025bfc7a36767b 100644 (file)
@@ -77,7 +77,7 @@ static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg,
        ret = i2c_transfer(state->i2c, msg, 2);
 
        if (ret != 2) {
-               printk(KERN_ERR "%s: ret == %d\n", __func__, ret);
+               printk(KERN_DEBUG "%s: ret == %d\n", __func__, ret);
                return -EREMOTEIO;
        }
 
index a8429ebfa8a2e6da67208e926d5644f74e583a02..eac20650499fb510217a1ccf4bba9598083f60c7 100644 (file)
@@ -879,7 +879,8 @@ static int nxt2002_init(struct dvb_frontend* fe)
 
        /* request the firmware, this will block until someone uploads it */
        printk("nxt2002: Waiting for firmware upload (%s)...\n", NXT2002_DEFAULT_FIRMWARE);
-       ret = request_firmware(&fw, NXT2002_DEFAULT_FIRMWARE, &state->i2c->dev);
+       ret = request_firmware(&fw, NXT2002_DEFAULT_FIRMWARE,
+                              state->i2c->dev.parent);
        printk("nxt2002: Waiting for firmware upload(2)...\n");
        if (ret) {
                printk("nxt2002: No firmware uploaded (timeout or file not found?)\n");
@@ -943,7 +944,8 @@ static int nxt2004_init(struct dvb_frontend* fe)
 
        /* request the firmware, this will block until someone uploads it */
        printk("nxt2004: Waiting for firmware upload (%s)...\n", NXT2004_DEFAULT_FIRMWARE);
-       ret = request_firmware(&fw, NXT2004_DEFAULT_FIRMWARE, &state->i2c->dev);
+       ret = request_firmware(&fw, NXT2004_DEFAULT_FIRMWARE,
+                              state->i2c->dev.parent);
        printk("nxt2004: Waiting for firmware upload(2)...\n");
        if (ret) {
                printk("nxt2004: No firmware uploaded (timeout or file not found?)\n");
index 5ed32544de3964798a38f6683109acd92b693971..8133ea3cddd783023ff581c47c904b412ac47c0f 100644 (file)
@@ -340,7 +340,7 @@ static int or51132_set_parameters(struct dvb_frontend* fe,
                }
                printk("or51132: Waiting for firmware upload(%s)...\n",
                       fwname);
-               ret = request_firmware(&fw, fwname, &state->i2c->dev);
+               ret = request_firmware(&fw, fwname, state->i2c->dev.parent);
                if (ret) {
                        printk(KERN_WARNING "or51132: No firmware up"
                               "loaded(timeout or file not found?)\n");
index 762d5af62d7a38bab2e944428a55f69fdaa7cf01..67dc8ec634e2da56790dc7ab17a5f8c57bc7dc58 100644 (file)
@@ -60,8 +60,6 @@
                } \
        } while (0)
 
-#define dmd_choose(a, b)       (demod = STV0900_DEMOD_2 ? b : a))
-
 static int stvdebug;
 
 #define dprintk(args...) \
diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c
new file mode 100644 (file)
index 0000000..96ef745
--- /dev/null
@@ -0,0 +1,4299 @@
+/*
+       STV0900/0903 Multistandard Broadcast Frontend driver
+       Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+       Copyright (C) ST Microelectronics
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU General Public License as published by
+       the Free Software Foundation; either version 2 of the License, or
+       (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/mutex.h>
+
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
+#include "stv6110x.h" /* for demodulator internal modes */
+
+#include "stv090x_reg.h"
+#include "stv090x.h"
+#include "stv090x_priv.h"
+
+static unsigned int verbose;
+module_param(verbose, int, 0644);
+
+struct mutex demod_lock;
+
+/* DVBS1 and DSS C/N Lookup table */
+static const struct stv090x_tab stv090x_s1cn_tab[] = {
+       {   0, 8917 }, /*  0.0dB */
+       {   5, 8801 }, /*  0.5dB */
+       {  10, 8667 }, /*  1.0dB */
+       {  15, 8522 }, /*  1.5dB */
+       {  20, 8355 }, /*  2.0dB */
+       {  25, 8175 }, /*  2.5dB */
+       {  30, 7979 }, /*  3.0dB */
+       {  35, 7763 }, /*  3.5dB */
+       {  40, 7530 }, /*  4.0dB */
+       {  45, 7282 }, /*  4.5dB */
+       {  50, 7026 }, /*  5.0dB */
+       {  55, 6781 }, /*  5.5dB */
+       {  60, 6514 }, /*  6.0dB */
+       {  65, 6241 }, /*  6.5dB */
+       {  70, 5965 }, /*  7.0dB */
+       {  75, 5690 }, /*  7.5dB */
+       {  80, 5424 }, /*  8.0dB */
+       {  85, 5161 }, /*  8.5dB */
+       {  90, 4902 }, /*  9.0dB */
+       {  95, 4654 }, /*  9.5dB */
+       { 100, 4417 }, /* 10.0dB */
+       { 105, 4186 }, /* 10.5dB */
+       { 110, 3968 }, /* 11.0dB */
+       { 115, 3757 }, /* 11.5dB */
+       { 120, 3558 }, /* 12.0dB */
+       { 125, 3366 }, /* 12.5dB */
+       { 130, 3185 }, /* 13.0dB */
+       { 135, 3012 }, /* 13.5dB */
+       { 140, 2850 }, /* 14.0dB */
+       { 145, 2698 }, /* 14.5dB */
+       { 150, 2550 }, /* 15.0dB */
+       { 160, 2283 }, /* 16.0dB */
+       { 170, 2042 }, /* 17.0dB */
+       { 180, 1827 }, /* 18.0dB */
+       { 190, 1636 }, /* 19.0dB */
+       { 200, 1466 }, /* 20.0dB */
+       { 210, 1315 }, /* 21.0dB */
+       { 220, 1181 }, /* 22.0dB */
+       { 230, 1064 }, /* 23.0dB */
+       { 240,  960 }, /* 24.0dB */
+       { 250,  869 }, /* 25.0dB */
+       { 260,  792 }, /* 26.0dB */
+       { 270,  724 }, /* 27.0dB */
+       { 280,  665 }, /* 28.0dB */
+       { 290,  616 }, /* 29.0dB */
+       { 300,  573 }, /* 30.0dB */
+       { 310,  537 }, /* 31.0dB */
+       { 320,  507 }, /* 32.0dB */
+       { 330,  483 }, /* 33.0dB */
+       { 400,  398 }, /* 40.0dB */
+       { 450,  381 }, /* 45.0dB */
+       { 500,  377 }  /* 50.0dB */
+};
+
+/* DVBS2 C/N Lookup table */
+static const struct stv090x_tab stv090x_s2cn_tab[] = {
+       { -30, 13348 }, /* -3.0dB */
+       { -20, 12640 }, /* -2d.0B */
+       { -10, 11883 }, /* -1.0dB */
+       {   0, 11101 }, /* -0.0dB */
+       {   5, 10718 }, /*  0.5dB */
+       {  10, 10339 }, /*  1.0dB */
+       {  15,  9947 }, /*  1.5dB */
+       {  20,  9552 }, /*  2.0dB */
+       {  25,  9183 }, /*  2.5dB */
+       {  30,  8799 }, /*  3.0dB */
+       {  35,  8422 }, /*  3.5dB */
+       {  40,  8062 }, /*  4.0dB */
+       {  45,  7707 }, /*  4.5dB */
+       {  50,  7353 }, /*  5.0dB */
+       {  55,  7025 }, /*  5.5dB */
+       {  60,  6684 }, /*  6.0dB */
+       {  65,  6331 }, /*  6.5dB */
+       {  70,  6036 }, /*  7.0dB */
+       {  75,  5727 }, /*  7.5dB */
+       {  80,  5437 }, /*  8.0dB */
+       {  85,  5164 }, /*  8.5dB */
+       {  90,  4902 }, /*  9.0dB */
+       {  95,  4653 }, /*  9.5dB */
+       { 100,  4408 }, /* 10.0dB */
+       { 105,  4187 }, /* 10.5dB */
+       { 110,  3961 }, /* 11.0dB */
+       { 115,  3751 }, /* 11.5dB */
+       { 120,  3558 }, /* 12.0dB */
+       { 125,  3368 }, /* 12.5dB */
+       { 130,  3191 }, /* 13.0dB */
+       { 135,  3017 }, /* 13.5dB */
+       { 140,  2862 }, /* 14.0dB */
+       { 145,  2710 }, /* 14.5dB */
+       { 150,  2565 }, /* 15.0dB */
+       { 160,  2300 }, /* 16.0dB */
+       { 170,  2058 }, /* 17.0dB */
+       { 180,  1849 }, /* 18.0dB */
+       { 190,  1663 }, /* 19.0dB */
+       { 200,  1495 }, /* 20.0dB */
+       { 210,  1349 }, /* 21.0dB */
+       { 220,  1222 }, /* 22.0dB */
+       { 230,  1110 }, /* 23.0dB */
+       { 240,  1011 }, /* 24.0dB */
+       { 250,   925 }, /* 25.0dB */
+       { 260,   853 }, /* 26.0dB */
+       { 270,   789 }, /* 27.0dB */
+       { 280,   734 }, /* 28.0dB */
+       { 290,   690 }, /* 29.0dB */
+       { 300,   650 }, /* 30.0dB */
+       { 310,   619 }, /* 31.0dB */
+       { 320,   593 }, /* 32.0dB */
+       { 330,   571 }, /* 33.0dB */
+       { 400,   498 }, /* 40.0dB */
+       { 450,   484 }, /* 45.0dB */
+       { 500,   481 }  /* 50.0dB */
+};
+
+/* RF level C/N lookup table */
+static const struct stv090x_tab stv090x_rf_tab[] = {
+       {  -5, 0xcaa1 }, /*  -5dBm */
+       { -10, 0xc229 }, /* -10dBm */
+       { -15, 0xbb08 }, /* -15dBm */
+       { -20, 0xb4bc }, /* -20dBm */
+       { -25, 0xad5a }, /* -25dBm */
+       { -30, 0xa298 }, /* -30dBm */
+       { -35, 0x98a8 }, /* -35dBm */
+       { -40, 0x8389 }, /* -40dBm */
+       { -45, 0x59be }, /* -45dBm */
+       { -50, 0x3a14 }, /* -50dBm */
+       { -55, 0x2d11 }, /* -55dBm */
+       { -60, 0x210d }, /* -60dBm */
+       { -65, 0xa14f }, /* -65dBm */
+       { -70, 0x07aa }  /* -70dBm */
+};
+
+
+static struct stv090x_reg stv0900_initval[] = {
+
+       { STV090x_OUTCFG,               0x00 },
+       { STV090x_MODECFG,              0xff },
+       { STV090x_AGCRF1CFG,            0x11 },
+       { STV090x_AGCRF2CFG,            0x13 },
+       { STV090x_TSGENERAL1X,          0x14 },
+       { STV090x_TSTTNR2,              0x21 },
+       { STV090x_TSTTNR4,              0x21 },
+       { STV090x_P2_DISTXCTL,          0x22 },
+       { STV090x_P2_F22TX,             0xc0 },
+       { STV090x_P2_F22RX,             0xc0 },
+       { STV090x_P2_DISRXCTL,          0x00 },
+       { STV090x_P2_DMDCFGMD,          0xF9 },
+       { STV090x_P2_DEMOD,             0x08 },
+       { STV090x_P2_DMDCFG3,           0xc4 },
+       { STV090x_P2_CARFREQ,           0xed },
+       { STV090x_P2_LDT,               0xd0 },
+       { STV090x_P2_LDT2,              0xb8 },
+       { STV090x_P2_TMGCFG,            0xd2 },
+       { STV090x_P2_TMGTHRISE,         0x20 },
+       { STV090x_P1_TMGCFG,            0xd2 },
+
+       { STV090x_P2_TMGTHFALL,         0x00 },
+       { STV090x_P2_FECSPY,            0x88 },
+       { STV090x_P2_FSPYDATA,          0x3a },
+       { STV090x_P2_FBERCPT4,          0x00 },
+       { STV090x_P2_FSPYBER,           0x10 },
+       { STV090x_P2_ERRCTRL1,          0x35 },
+       { STV090x_P2_ERRCTRL2,          0xc1 },
+       { STV090x_P2_CFRICFG,           0xf8 },
+       { STV090x_P2_NOSCFG,            0x1c },
+       { STV090x_P2_DMDTOM,            0x20 },
+       { STV090x_P2_CORRELMANT,        0x70 },
+       { STV090x_P2_CORRELABS,         0x88 },
+       { STV090x_P2_AGC2O,             0x5b },
+       { STV090x_P2_AGC2REF,           0x38 },
+       { STV090x_P2_CARCFG,            0xe4 },
+       { STV090x_P2_ACLC,              0x1A },
+       { STV090x_P2_BCLC,              0x09 },
+       { STV090x_P2_CARHDR,            0x08 },
+       { STV090x_P2_KREFTMG,           0xc1 },
+       { STV090x_P2_SFRUPRATIO,        0xf0 },
+       { STV090x_P2_SFRLOWRATIO,       0x70 },
+       { STV090x_P2_SFRSTEP,           0x58 },
+       { STV090x_P2_TMGCFG2,           0x01 },
+       { STV090x_P2_CAR2CFG,           0x26 },
+       { STV090x_P2_BCLC2S2Q,          0x86 },
+       { STV090x_P2_BCLC2S28,          0x86 },
+       { STV090x_P2_SMAPCOEF7,         0x77 },
+       { STV090x_P2_SMAPCOEF6,         0x85 },
+       { STV090x_P2_SMAPCOEF5,         0x77 },
+       { STV090x_P2_TSCFGL,            0x20 },
+       { STV090x_P2_DMDCFG2,           0x3b },
+       { STV090x_P2_MODCODLST0,        0xff },
+       { STV090x_P2_MODCODLST1,        0xff },
+       { STV090x_P2_MODCODLST2,        0xff },
+       { STV090x_P2_MODCODLST3,        0xff },
+       { STV090x_P2_MODCODLST4,        0xff },
+       { STV090x_P2_MODCODLST5,        0xff },
+       { STV090x_P2_MODCODLST6,        0xff },
+       { STV090x_P2_MODCODLST7,        0xcc },
+       { STV090x_P2_MODCODLST8,        0xcc },
+       { STV090x_P2_MODCODLST9,        0xcc },
+       { STV090x_P2_MODCODLSTA,        0xcc },
+       { STV090x_P2_MODCODLSTB,        0xcc },
+       { STV090x_P2_MODCODLSTC,        0xcc },
+       { STV090x_P2_MODCODLSTD,        0xcc },
+       { STV090x_P2_MODCODLSTE,        0xcc },
+       { STV090x_P2_MODCODLSTF,        0xcf },
+       { STV090x_P1_DISTXCTL,          0x22 },
+       { STV090x_P1_F22TX,             0xc0 },
+       { STV090x_P1_F22RX,             0xc0 },
+       { STV090x_P1_DISRXCTL,          0x00 },
+       { STV090x_P1_DMDCFGMD,          0xf9 },
+       { STV090x_P1_DEMOD,             0x08 },
+       { STV090x_P1_DMDCFG3,           0xc4 },
+       { STV090x_P1_DMDTOM,            0x20 },
+       { STV090x_P1_CARFREQ,           0xed },
+       { STV090x_P1_LDT,               0xd0 },
+       { STV090x_P1_LDT2,              0xb8 },
+       { STV090x_P1_TMGCFG,            0xd2 },
+       { STV090x_P1_TMGTHRISE,         0x20 },
+       { STV090x_P1_TMGTHFALL,         0x00 },
+       { STV090x_P1_SFRUPRATIO,        0xf0 },
+       { STV090x_P1_SFRLOWRATIO,       0x70 },
+       { STV090x_P1_TSCFGL,            0x20 },
+       { STV090x_P1_FECSPY,            0x88 },
+       { STV090x_P1_FSPYDATA,          0x3a },
+       { STV090x_P1_FBERCPT4,          0x00 },
+       { STV090x_P1_FSPYBER,           0x10 },
+       { STV090x_P1_ERRCTRL1,          0x35 },
+       { STV090x_P1_ERRCTRL2,          0xc1 },
+       { STV090x_P1_CFRICFG,           0xf8 },
+       { STV090x_P1_NOSCFG,            0x1c },
+       { STV090x_P1_CORRELMANT,        0x70 },
+       { STV090x_P1_CORRELABS,         0x88 },
+       { STV090x_P1_AGC2O,             0x5b },
+       { STV090x_P1_AGC2REF,           0x38 },
+       { STV090x_P1_CARCFG,            0xe4 },
+       { STV090x_P1_ACLC,              0x1A },
+       { STV090x_P1_BCLC,              0x09 },
+       { STV090x_P1_CARHDR,            0x08 },
+       { STV090x_P1_KREFTMG,           0xc1 },
+       { STV090x_P1_SFRSTEP,           0x58 },
+       { STV090x_P1_TMGCFG2,           0x01 },
+       { STV090x_P1_CAR2CFG,           0x26 },
+       { STV090x_P1_BCLC2S2Q,          0x86 },
+       { STV090x_P1_BCLC2S28,          0x86 },
+       { STV090x_P1_SMAPCOEF7,         0x77 },
+       { STV090x_P1_SMAPCOEF6,         0x85 },
+       { STV090x_P1_SMAPCOEF5,         0x77 },
+       { STV090x_P1_DMDCFG2,           0x3b },
+       { STV090x_P1_MODCODLST0,        0xff },
+       { STV090x_P1_MODCODLST1,        0xff },
+       { STV090x_P1_MODCODLST2,        0xff },
+       { STV090x_P1_MODCODLST3,        0xff },
+       { STV090x_P1_MODCODLST4,        0xff },
+       { STV090x_P1_MODCODLST5,        0xff },
+       { STV090x_P1_MODCODLST6,        0xff },
+       { STV090x_P1_MODCODLST7,        0xcc },
+       { STV090x_P1_MODCODLST8,        0xcc },
+       { STV090x_P1_MODCODLST9,        0xcc },
+       { STV090x_P1_MODCODLSTA,        0xcc },
+       { STV090x_P1_MODCODLSTB,        0xcc },
+       { STV090x_P1_MODCODLSTC,        0xcc },
+       { STV090x_P1_MODCODLSTD,        0xcc },
+       { STV090x_P1_MODCODLSTE,        0xcc },
+       { STV090x_P1_MODCODLSTF,        0xcf },
+       { STV090x_GENCFG,               0x1d },
+       { STV090x_NBITER_NF4,           0x37 },
+       { STV090x_NBITER_NF5,           0x29 },
+       { STV090x_NBITER_NF6,           0x37 },
+       { STV090x_NBITER_NF7,           0x33 },
+       { STV090x_NBITER_NF8,           0x31 },
+       { STV090x_NBITER_NF9,           0x2f },
+       { STV090x_NBITER_NF10,          0x39 },
+       { STV090x_NBITER_NF11,          0x3a },
+       { STV090x_NBITER_NF12,          0x29 },
+       { STV090x_NBITER_NF13,          0x37 },
+       { STV090x_NBITER_NF14,          0x33 },
+       { STV090x_NBITER_NF15,          0x2f },
+       { STV090x_NBITER_NF16,          0x39 },
+       { STV090x_NBITER_NF17,          0x3a },
+       { STV090x_NBITERNOERR,          0x04 },
+       { STV090x_GAINLLR_NF4,          0x0C },
+       { STV090x_GAINLLR_NF5,          0x0F },
+       { STV090x_GAINLLR_NF6,          0x11 },
+       { STV090x_GAINLLR_NF7,          0x14 },
+       { STV090x_GAINLLR_NF8,          0x17 },
+       { STV090x_GAINLLR_NF9,          0x19 },
+       { STV090x_GAINLLR_NF10,         0x20 },
+       { STV090x_GAINLLR_NF11,         0x21 },
+       { STV090x_GAINLLR_NF12,         0x0D },
+       { STV090x_GAINLLR_NF13,         0x0F },
+       { STV090x_GAINLLR_NF14,         0x13 },
+       { STV090x_GAINLLR_NF15,         0x1A },
+       { STV090x_GAINLLR_NF16,         0x1F },
+       { STV090x_GAINLLR_NF17,         0x21 },
+       { STV090x_RCCFGH,               0x20 },
+       { STV090x_P1_FECM,              0x01 }, /* disable DSS modes */
+       { STV090x_P2_FECM,              0x01 }, /* disable DSS modes */
+       { STV090x_P1_PRVIT,             0x2F }, /* disable PR 6/7 */
+       { STV090x_P2_PRVIT,             0x2F }, /* disable PR 6/7 */
+};
+
+static struct stv090x_reg stv0903_initval[] = {
+       { STV090x_OUTCFG,               0x00 },
+       { STV090x_AGCRF1CFG,            0x11 },
+       { STV090x_STOPCLK1,             0x48 },
+       { STV090x_STOPCLK2,             0x14 },
+       { STV090x_TSTTNR1,              0x27 },
+       { STV090x_TSTTNR2,              0x21 },
+       { STV090x_P1_DISTXCTL,          0x22 },
+       { STV090x_P1_F22TX,             0xc0 },
+       { STV090x_P1_F22RX,             0xc0 },
+       { STV090x_P1_DISRXCTL,          0x00 },
+       { STV090x_P1_DMDCFGMD,          0xF9 },
+       { STV090x_P1_DEMOD,             0x08 },
+       { STV090x_P1_DMDCFG3,           0xc4 },
+       { STV090x_P1_CARFREQ,           0xed },
+       { STV090x_P1_TNRCFG2,           0x82 },
+       { STV090x_P1_LDT,               0xd0 },
+       { STV090x_P1_LDT2,              0xb8 },
+       { STV090x_P1_TMGCFG,            0xd2 },
+       { STV090x_P1_TMGTHRISE,         0x20 },
+       { STV090x_P1_TMGTHFALL,         0x00 },
+       { STV090x_P1_SFRUPRATIO,        0xf0 },
+       { STV090x_P1_SFRLOWRATIO,       0x70 },
+       { STV090x_P1_TSCFGL,            0x20 },
+       { STV090x_P1_FECSPY,            0x88 },
+       { STV090x_P1_FSPYDATA,          0x3a },
+       { STV090x_P1_FBERCPT4,          0x00 },
+       { STV090x_P1_FSPYBER,           0x10 },
+       { STV090x_P1_ERRCTRL1,          0x35 },
+       { STV090x_P1_ERRCTRL2,          0xc1 },
+       { STV090x_P1_CFRICFG,           0xf8 },
+       { STV090x_P1_NOSCFG,            0x1c },
+       { STV090x_P1_DMDTOM,            0x20 },
+       { STV090x_P1_CORRELMANT,        0x70 },
+       { STV090x_P1_CORRELABS,         0x88 },
+       { STV090x_P1_AGC2O,             0x5b },
+       { STV090x_P1_AGC2REF,           0x38 },
+       { STV090x_P1_CARCFG,            0xe4 },
+       { STV090x_P1_ACLC,              0x1A },
+       { STV090x_P1_BCLC,              0x09 },
+       { STV090x_P1_CARHDR,            0x08 },
+       { STV090x_P1_KREFTMG,           0xc1 },
+       { STV090x_P1_SFRSTEP,           0x58 },
+       { STV090x_P1_TMGCFG2,           0x01 },
+       { STV090x_P1_CAR2CFG,           0x26 },
+       { STV090x_P1_BCLC2S2Q,          0x86 },
+       { STV090x_P1_BCLC2S28,          0x86 },
+       { STV090x_P1_SMAPCOEF7,         0x77 },
+       { STV090x_P1_SMAPCOEF6,         0x85 },
+       { STV090x_P1_SMAPCOEF5,         0x77 },
+       { STV090x_P1_DMDCFG2,           0x3b },
+       { STV090x_P1_MODCODLST0,        0xff },
+       { STV090x_P1_MODCODLST1,        0xff },
+       { STV090x_P1_MODCODLST2,        0xff },
+       { STV090x_P1_MODCODLST3,        0xff },
+       { STV090x_P1_MODCODLST4,        0xff },
+       { STV090x_P1_MODCODLST5,        0xff },
+       { STV090x_P1_MODCODLST6,        0xff },
+       { STV090x_P1_MODCODLST7,        0xcc },
+       { STV090x_P1_MODCODLST8,        0xcc },
+       { STV090x_P1_MODCODLST9,        0xcc },
+       { STV090x_P1_MODCODLSTA,        0xcc },
+       { STV090x_P1_MODCODLSTB,        0xcc },
+       { STV090x_P1_MODCODLSTC,        0xcc },
+       { STV090x_P1_MODCODLSTD,        0xcc },
+       { STV090x_P1_MODCODLSTE,        0xcc },
+       { STV090x_P1_MODCODLSTF,        0xcf },
+       { STV090x_GENCFG,               0x1c },
+       { STV090x_NBITER_NF4,           0x37 },
+       { STV090x_NBITER_NF5,           0x29 },
+       { STV090x_NBITER_NF6,           0x37 },
+       { STV090x_NBITER_NF7,           0x33 },
+       { STV090x_NBITER_NF8,           0x31 },
+       { STV090x_NBITER_NF9,           0x2f },
+       { STV090x_NBITER_NF10,          0x39 },
+       { STV090x_NBITER_NF11,          0x3a },
+       { STV090x_NBITER_NF12,          0x29 },
+       { STV090x_NBITER_NF13,          0x37 },
+       { STV090x_NBITER_NF14,          0x33 },
+       { STV090x_NBITER_NF15,          0x2f },
+       { STV090x_NBITER_NF16,          0x39 },
+       { STV090x_NBITER_NF17,          0x3a },
+       { STV090x_NBITERNOERR,          0x04 },
+       { STV090x_GAINLLR_NF4,          0x0C },
+       { STV090x_GAINLLR_NF5,          0x0F },
+       { STV090x_GAINLLR_NF6,          0x11 },
+       { STV090x_GAINLLR_NF7,          0x14 },
+       { STV090x_GAINLLR_NF8,          0x17 },
+       { STV090x_GAINLLR_NF9,          0x19 },
+       { STV090x_GAINLLR_NF10,         0x20 },
+       { STV090x_GAINLLR_NF11,         0x21 },
+       { STV090x_GAINLLR_NF12,         0x0D },
+       { STV090x_GAINLLR_NF13,         0x0F },
+       { STV090x_GAINLLR_NF14,         0x13 },
+       { STV090x_GAINLLR_NF15,         0x1A },
+       { STV090x_GAINLLR_NF16,         0x1F },
+       { STV090x_GAINLLR_NF17,         0x21 },
+       { STV090x_RCCFGH,               0x20 },
+       { STV090x_P1_FECM,              0x01 }, /*disable the DSS mode */
+       { STV090x_P1_PRVIT,             0x2f }  /*disable puncture rate 6/7*/
+};
+
+static struct stv090x_reg stv0900_cut20_val[] = {
+
+       { STV090x_P2_DMDCFG3,           0xe8 },
+       { STV090x_P2_DMDCFG4,           0x10 },
+       { STV090x_P2_CARFREQ,           0x38 },
+       { STV090x_P2_CARHDR,            0x20 },
+       { STV090x_P2_KREFTMG,           0x5a },
+       { STV090x_P2_SMAPCOEF7,         0x06 },
+       { STV090x_P2_SMAPCOEF6,         0x00 },
+       { STV090x_P2_SMAPCOEF5,         0x04 },
+       { STV090x_P2_NOSCFG,            0x0c },
+       { STV090x_P1_DMDCFG3,           0xe8 },
+       { STV090x_P1_DMDCFG4,           0x10 },
+       { STV090x_P1_CARFREQ,           0x38 },
+       { STV090x_P1_CARHDR,            0x20 },
+       { STV090x_P1_KREFTMG,           0x5a },
+       { STV090x_P1_SMAPCOEF7,         0x06 },
+       { STV090x_P1_SMAPCOEF6,         0x00 },
+       { STV090x_P1_SMAPCOEF5,         0x04 },
+       { STV090x_P1_NOSCFG,            0x0c },
+       { STV090x_GAINLLR_NF4,          0x21 },
+       { STV090x_GAINLLR_NF5,          0x21 },
+       { STV090x_GAINLLR_NF6,          0x20 },
+       { STV090x_GAINLLR_NF7,          0x1F },
+       { STV090x_GAINLLR_NF8,          0x1E },
+       { STV090x_GAINLLR_NF9,          0x1E },
+       { STV090x_GAINLLR_NF10,         0x1D },
+       { STV090x_GAINLLR_NF11,         0x1B },
+       { STV090x_GAINLLR_NF12,         0x20 },
+       { STV090x_GAINLLR_NF13,         0x20 },
+       { STV090x_GAINLLR_NF14,         0x20 },
+       { STV090x_GAINLLR_NF15,         0x20 },
+       { STV090x_GAINLLR_NF16,         0x20 },
+       { STV090x_GAINLLR_NF17,         0x21 },
+};
+
+static struct stv090x_reg stv0903_cut20_val[] = {
+       { STV090x_P1_DMDCFG3,           0xe8 },
+       { STV090x_P1_DMDCFG4,           0x10 },
+       { STV090x_P1_CARFREQ,           0x38 },
+       { STV090x_P1_CARHDR,            0x20 },
+       { STV090x_P1_KREFTMG,           0x5a },
+       { STV090x_P1_SMAPCOEF7,         0x06 },
+       { STV090x_P1_SMAPCOEF6,         0x00 },
+       { STV090x_P1_SMAPCOEF5,         0x04 },
+       { STV090x_P1_NOSCFG,            0x0c },
+       { STV090x_GAINLLR_NF4,          0x21 },
+       { STV090x_GAINLLR_NF5,          0x21 },
+       { STV090x_GAINLLR_NF6,          0x20 },
+       { STV090x_GAINLLR_NF7,          0x1F },
+       { STV090x_GAINLLR_NF8,          0x1E },
+       { STV090x_GAINLLR_NF9,          0x1E },
+       { STV090x_GAINLLR_NF10,         0x1D },
+       { STV090x_GAINLLR_NF11,         0x1B },
+       { STV090x_GAINLLR_NF12,         0x20 },
+       { STV090x_GAINLLR_NF13,         0x20 },
+       { STV090x_GAINLLR_NF14,         0x20 },
+       { STV090x_GAINLLR_NF15,         0x20 },
+       { STV090x_GAINLLR_NF16,         0x20 },
+       { STV090x_GAINLLR_NF17,         0x21 }
+};
+
+/* Cut 2.0 Long Frame Tracking CR loop */
+static struct stv090x_long_frame_crloop stv090x_s2_crl_cut20[] = {
+       /* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
+       { STV090x_QPSK_12,  0x1f, 0x3f, 0x1e, 0x3f, 0x3d, 0x1f, 0x3d, 0x3e, 0x3d, 0x1e },
+       { STV090x_QPSK_35,  0x2f, 0x3f, 0x2e, 0x2f, 0x3d, 0x0f, 0x0e, 0x2e, 0x3d, 0x0e },
+       { STV090x_QPSK_23,  0x2f, 0x3f, 0x2e, 0x2f, 0x0e, 0x0f, 0x0e, 0x1e, 0x3d, 0x3d },
+       { STV090x_QPSK_34,  0x3f, 0x3f, 0x3e, 0x1f, 0x0e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d },
+       { STV090x_QPSK_45,  0x3f, 0x3f, 0x3e, 0x1f, 0x0e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d },
+       { STV090x_QPSK_56,  0x3f, 0x3f, 0x3e, 0x1f, 0x0e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d },
+       { STV090x_QPSK_89,  0x3f, 0x3f, 0x3e, 0x1f, 0x1e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d },
+       { STV090x_QPSK_910, 0x3f, 0x3f, 0x3e, 0x1f, 0x1e, 0x3e, 0x0e, 0x1e, 0x3d, 0x3d },
+       { STV090x_8PSK_35,  0x3c, 0x3e, 0x1c, 0x2e, 0x0c, 0x1e, 0x2b, 0x2d, 0x1b, 0x1d },
+       { STV090x_8PSK_23,  0x1d, 0x3e, 0x3c, 0x2e, 0x2c, 0x1e, 0x0c, 0x2d, 0x2b, 0x1d },
+       { STV090x_8PSK_34,  0x0e, 0x3e, 0x3d, 0x2e, 0x0d, 0x1e, 0x2c, 0x2d, 0x0c, 0x1d },
+       { STV090x_8PSK_56,  0x2e, 0x3e, 0x1e, 0x2e, 0x2d, 0x1e, 0x3c, 0x2d, 0x2c, 0x1d },
+       { STV090x_8PSK_89,  0x3e, 0x3e, 0x1e, 0x2e, 0x3d, 0x1e, 0x0d, 0x2d, 0x3c, 0x1d },
+       { STV090x_8PSK_910, 0x3e, 0x3e, 0x1e, 0x2e, 0x3d, 0x1e, 0x1d, 0x2d, 0x0d, 0x1d }
+};
+
+/* Cut 3.0 Long Frame Tracking CR loop */
+static struct stv090x_long_frame_crloop stv090x_s2_crl_cut30[] = {
+       /* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
+       { STV090x_QPSK_12,  0x3c, 0x2c, 0x0c, 0x2c, 0x1b, 0x2c, 0x1b, 0x1c, 0x0b, 0x3b },
+       { STV090x_QPSK_35,  0x0d, 0x0d, 0x0c, 0x0d, 0x1b, 0x3c, 0x1b, 0x1c, 0x0b, 0x3b },
+       { STV090x_QPSK_23,  0x1d, 0x0d, 0x0c, 0x1d, 0x2b, 0x3c, 0x1b, 0x1c, 0x0b, 0x3b },
+       { STV090x_QPSK_34,  0x1d, 0x1d, 0x0c, 0x1d, 0x2b, 0x3c, 0x1b, 0x1c, 0x0b, 0x3b },
+       { STV090x_QPSK_45,  0x2d, 0x1d, 0x1c, 0x1d, 0x2b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b },
+       { STV090x_QPSK_56,  0x2d, 0x1d, 0x1c, 0x1d, 0x2b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b },
+       { STV090x_QPSK_89,  0x3d, 0x2d, 0x1c, 0x1d, 0x3b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b },
+       { STV090x_QPSK_910, 0x3d, 0x2d, 0x1c, 0x1d, 0x3b, 0x3c, 0x2b, 0x0c, 0x1b, 0x3b },
+       { STV090x_8PSK_35,  0x39, 0x29, 0x39, 0x19, 0x19, 0x19, 0x19, 0x19, 0x09, 0x19 },
+       { STV090x_8PSK_23,  0x2a, 0x39, 0x1a, 0x0a, 0x39, 0x0a, 0x29, 0x39, 0x29, 0x0a },
+       { STV090x_8PSK_34,  0x2b, 0x3a, 0x1b, 0x1b, 0x3a, 0x1b, 0x1a, 0x0b, 0x1a, 0x3a },
+       { STV090x_8PSK_56,  0x0c, 0x1b, 0x3b, 0x3b, 0x1b, 0x3b, 0x3a, 0x3b, 0x3a, 0x1b },
+       { STV090x_8PSK_89,  0x0d, 0x3c, 0x2c, 0x2c, 0x2b, 0x0c, 0x0b, 0x3b, 0x0b, 0x1b },
+       { STV090x_8PSK_910, 0x0d, 0x0d, 0x2c, 0x3c, 0x3b, 0x1c, 0x0b, 0x3b, 0x0b, 0x1b }
+};
+
+/* Cut 2.0 Long Frame Tracking CR Loop */
+static struct stv090x_long_frame_crloop stv090x_s2_apsk_crl_cut20[] = {
+       /* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
+       { STV090x_16APSK_23,  0x0c, 0x0c, 0x0c, 0x0c, 0x1d, 0x0c, 0x3c, 0x0c, 0x2c, 0x0c },
+       { STV090x_16APSK_34,  0x0c, 0x0c, 0x0c, 0x0c, 0x0e, 0x0c, 0x2d, 0x0c, 0x1d, 0x0c },
+       { STV090x_16APSK_45,  0x0c, 0x0c, 0x0c, 0x0c, 0x1e, 0x0c, 0x3d, 0x0c, 0x2d, 0x0c },
+       { STV090x_16APSK_56,  0x0c, 0x0c, 0x0c, 0x0c, 0x1e, 0x0c, 0x3d, 0x0c, 0x2d, 0x0c },
+       { STV090x_16APSK_89,  0x0c, 0x0c, 0x0c, 0x0c, 0x2e, 0x0c, 0x0e, 0x0c, 0x3d, 0x0c },
+       { STV090x_16APSK_910, 0x0c, 0x0c, 0x0c, 0x0c, 0x2e, 0x0c, 0x0e, 0x0c, 0x3d, 0x0c },
+       { STV090x_32APSK_34,  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c },
+       { STV090x_32APSK_45,  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c },
+       { STV090x_32APSK_56,  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c },
+       { STV090x_32APSK_89,  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c },
+       { STV090x_32APSK_910, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c }
+};
+
+/* Cut 3.0 Long Frame Tracking CR Loop */
+static struct stv090x_long_frame_crloop        stv090x_s2_apsk_crl_cut30[] = {
+       /* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
+       { STV090x_16APSK_23,  0x0a, 0x0a, 0x0a, 0x0a, 0x1a, 0x0a, 0x3a, 0x0a, 0x2a, 0x0a },
+       { STV090x_16APSK_34,  0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0a, 0x3b, 0x0a, 0x1b, 0x0a },
+       { STV090x_16APSK_45,  0x0a, 0x0a, 0x0a, 0x0a, 0x1b, 0x0a, 0x3b, 0x0a, 0x2b, 0x0a },
+       { STV090x_16APSK_56,  0x0a, 0x0a, 0x0a, 0x0a, 0x1b, 0x0a, 0x3b, 0x0a, 0x2b, 0x0a },
+       { STV090x_16APSK_89,  0x0a, 0x0a, 0x0a, 0x0a, 0x2b, 0x0a, 0x0c, 0x0a, 0x3b, 0x0a },
+       { STV090x_16APSK_910, 0x0a, 0x0a, 0x0a, 0x0a, 0x2b, 0x0a, 0x0c, 0x0a, 0x3b, 0x0a },
+       { STV090x_32APSK_34,  0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a },
+       { STV090x_32APSK_45,  0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a },
+       { STV090x_32APSK_56,  0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a },
+       { STV090x_32APSK_89,  0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a },
+       { STV090x_32APSK_910, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a }
+};
+
+static struct stv090x_long_frame_crloop stv090x_s2_lowqpsk_crl_cut20[] = {
+       /* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
+       { STV090x_QPSK_14,  0x0f, 0x3f, 0x0e, 0x3f, 0x2d, 0x2f, 0x2d, 0x1f, 0x3d, 0x3e },
+       { STV090x_QPSK_13,  0x0f, 0x3f, 0x0e, 0x3f, 0x2d, 0x2f, 0x3d, 0x0f, 0x3d, 0x2e },
+       { STV090x_QPSK_25,  0x1f, 0x3f, 0x1e, 0x3f, 0x3d, 0x1f, 0x3d, 0x3e, 0x3d, 0x2e }
+};
+
+static struct stv090x_long_frame_crloop        stv090x_s2_lowqpsk_crl_cut30[] = {
+       /* MODCOD  2MPon 2MPoff 5MPon 5MPoff 10MPon 10MPoff 20MPon 20MPoff 30MPon 30MPoff */
+       { STV090x_QPSK_14,  0x0c, 0x3c, 0x0b, 0x3c, 0x2a, 0x2c, 0x2a, 0x1c, 0x3a, 0x3b },
+       { STV090x_QPSK_13,  0x0c, 0x3c, 0x0b, 0x3c, 0x2a, 0x2c, 0x3a, 0x0c, 0x3a, 0x2b },
+       { STV090x_QPSK_25,  0x1c, 0x3c, 0x1b, 0x3c, 0x3a, 0x1c, 0x3a, 0x3b, 0x3a, 0x2b }
+};
+
+/* Cut 2.0 Short Frame Tracking CR Loop */
+static struct stv090x_short_frame_crloop stv090x_s2_short_crl_cut20[] = {
+       /* MODCOD         2M    5M    10M   20M   30M */
+       { STV090x_QPSK,   0x2f, 0x2e, 0x0e, 0x0e, 0x3d },
+       { STV090x_8PSK,   0x3e, 0x0e, 0x2d, 0x0d, 0x3c },
+       { STV090x_16APSK, 0x1e, 0x1e, 0x1e, 0x3d, 0x2d },
+       { STV090x_32APSK, 0x1e, 0x1e, 0x1e, 0x3d, 0x2d }
+};
+
+/* Cut 3.0 Short Frame Tracking CR Loop */
+static struct stv090x_short_frame_crloop stv090x_s2_short_crl_cut30[] = {
+       /* MODCOD         2M    5M    10M   20M   30M */
+       { STV090x_QPSK,   0x2C, 0x2B, 0x0B, 0x0B, 0x3A },
+       { STV090x_8PSK,   0x3B, 0x0B, 0x2A, 0x0A, 0x39 },
+       { STV090x_16APSK, 0x1B, 0x1B, 0x1B, 0x3A, 0x2A },
+       { STV090x_32APSK, 0x1B, 0x1B, 0x1B, 0x3A, 0x2A }
+};
+
+static inline s32 comp2(s32 __x, s32 __width)
+{
+       if (__width == 32)
+               return __x;
+       else
+               return (__x >= (1 << (__width - 1))) ? (__x - (1 << __width)) : __x;
+}
+
+static int stv090x_read_reg(struct stv090x_state *state, unsigned int reg)
+{
+       const struct stv090x_config *config = state->config;
+       int ret;
+
+       u8 b0[] = { reg >> 8, reg & 0xff };
+       u8 buf;
+
+       struct i2c_msg msg[] = {
+               { .addr = config->address, .flags       = 0,            .buf = b0,   .len = 2 },
+               { .addr = config->address, .flags       = I2C_M_RD,     .buf = &buf, .len = 1 }
+       };
+
+       ret = i2c_transfer(state->i2c, msg, 2);
+       if (ret != 2) {
+               if (ret != -ERESTARTSYS)
+                       dprintk(FE_ERROR, 1,
+                               "Read error, Reg=[0x%02x], Status=%d",
+                               reg, ret);
+
+               return ret < 0 ? ret : -EREMOTEIO;
+       }
+       if (unlikely(*state->verbose >= FE_DEBUGREG))
+               dprintk(FE_ERROR, 1, "Reg=[0x%02x], data=%02x",
+                       reg, buf);
+
+       return (unsigned int) buf;
+}
+
+static int stv090x_write_regs(struct stv090x_state *state, unsigned int reg, u8 *data, u32 count)
+{
+       const struct stv090x_config *config = state->config;
+       int ret;
+       u8 buf[2 + count];
+       struct i2c_msg i2c_msg = { .addr = config->address, .flags = 0, .buf = buf, .len = 2 + count };
+
+       buf[0] = reg >> 8;
+       buf[1] = reg & 0xff;
+       memcpy(&buf[2], data, count);
+
+       if (unlikely(*state->verbose >= FE_DEBUGREG)) {
+               int i;
+
+               printk(KERN_DEBUG "%s [0x%04x]:", __func__, reg);
+               for (i = 0; i < count; i++)
+                       printk(" %02x", data[i]);
+               printk("\n");
+       }
+
+       ret = i2c_transfer(state->i2c, &i2c_msg, 1);
+       if (ret != 1) {
+               if (ret != -ERESTARTSYS)
+                       dprintk(FE_ERROR, 1, "Reg=[0x%04x], Data=[0x%02x ...], Count=%u, Status=%d",
+                               reg, data[0], count, ret);
+               return ret < 0 ? ret : -EREMOTEIO;
+       }
+
+       return 0;
+}
+
+static int stv090x_write_reg(struct stv090x_state *state, unsigned int reg, u8 data)
+{
+       return stv090x_write_regs(state, reg, &data, 1);
+}
+
+static int stv090x_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       u32 reg;
+
+       reg = STV090x_READ_DEMOD(state, I2CRPT);
+       if (enable) {
+               dprintk(FE_DEBUG, 1, "Enable Gate");
+               STV090x_SETFIELD_Px(reg, I2CT_ON_FIELD, 1);
+               if (STV090x_WRITE_DEMOD(state, I2CRPT, reg) < 0)
+                       goto err;
+
+       } else {
+               dprintk(FE_DEBUG, 1, "Disable Gate");
+               STV090x_SETFIELD_Px(reg, I2CT_ON_FIELD, 0);
+               if ((STV090x_WRITE_DEMOD(state, I2CRPT, reg)) < 0)
+                       goto err;
+       }
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static void stv090x_get_lock_tmg(struct stv090x_state *state)
+{
+       switch (state->algo) {
+       case STV090x_BLIND_SEARCH:
+               dprintk(FE_DEBUG, 1, "Blind Search");
+               if (state->srate <= 1500000) {  /*10Msps< SR <=15Msps*/
+                       state->DemodTimeout = 1500;
+                       state->FecTimeout = 400;
+               } else if (state->srate <= 5000000) {  /*10Msps< SR <=15Msps*/
+                       state->DemodTimeout = 1000;
+                       state->FecTimeout = 300;
+               } else {  /*SR >20Msps*/
+                       state->DemodTimeout = 700;
+                       state->FecTimeout = 100;
+               }
+               break;
+
+       case STV090x_COLD_SEARCH:
+       case STV090x_WARM_SEARCH:
+       default:
+               dprintk(FE_DEBUG, 1, "Normal Search");
+               if (state->srate <= 1000000) {  /*SR <=1Msps*/
+                       state->DemodTimeout = 4500;
+                       state->FecTimeout = 1700;
+               } else if (state->srate <= 2000000) { /*1Msps < SR <= 2Msps */
+                       state->DemodTimeout = 2500;
+                       state->FecTimeout = 1100;
+               } else if (state->srate <= 5000000) { /*2Msps < SR <= 5Msps */
+                       state->DemodTimeout = 1000;
+                       state->FecTimeout = 550;
+               } else if (state->srate <= 10000000) { /*5Msps < SR <= 10Msps */
+                       state->DemodTimeout = 700;
+                       state->FecTimeout = 250;
+               } else if (state->srate <= 20000000) { /*10Msps < SR <= 20Msps */
+                       state->DemodTimeout = 400;
+                       state->FecTimeout = 130;
+               } else {   /*SR >20Msps*/
+                       state->DemodTimeout = 300;
+                       state->FecTimeout = 100;
+               }
+               break;
+       }
+
+       if (state->algo == STV090x_WARM_SEARCH)
+               state->DemodTimeout /= 2;
+}
+
+static int stv090x_set_srate(struct stv090x_state *state, u32 srate)
+{
+       u32 sym;
+
+       if (srate > 60000000) {
+               sym  = (srate << 4); /* SR * 2^16 / master_clk */
+               sym /= (state->mclk >> 12);
+       } else if (srate > 6000000) {
+               sym  = (srate << 6);
+               sym /= (state->mclk >> 10);
+       } else {
+               sym  = (srate << 9);
+               sym /= (state->mclk >> 7);
+       }
+
+       if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0x7f) < 0) /* MSB */
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, SFRINIT0, (sym & 0xff)) < 0) /* LSB */
+               goto err;
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_set_max_srate(struct stv090x_state *state, u32 clk, u32 srate)
+{
+       u32 sym;
+
+       srate = 105 * (srate / 100);
+       if (srate > 60000000) {
+               sym  = (srate << 4); /* SR * 2^16 / master_clk */
+               sym /= (state->mclk >> 12);
+       } else if (srate > 6000000) {
+               sym  = (srate << 6);
+               sym /= (state->mclk >> 10);
+       } else {
+               sym  = (srate << 9);
+               sym /= (state->mclk >> 7);
+       }
+
+       if (sym < 0x7fff) {
+               if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0) /* MSB */
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0) /* LSB */
+                       goto err;
+       } else {
+               if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x7f) < 0) /* MSB */
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, SFRUP0, 0xff) < 0) /* LSB */
+                       goto err;
+       }
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_set_min_srate(struct stv090x_state *state, u32 clk, u32 srate)
+{
+       u32 sym;
+
+       srate = 95 * (srate / 100);
+       if (srate > 60000000) {
+               sym  = (srate << 4); /* SR * 2^16 / master_clk */
+               sym /= (state->mclk >> 12);
+       } else if (srate > 6000000) {
+               sym  = (srate << 6);
+               sym /= (state->mclk >> 10);
+       } else {
+               sym  = (srate << 9);
+               sym /= (state->mclk >> 7);
+       }
+
+       if (STV090x_WRITE_DEMOD(state, SFRLOW1, ((sym >> 8) & 0xff)) < 0) /* MSB */
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, SFRLOW0, (sym & 0xff)) < 0) /* LSB */
+               goto err;
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static u32 stv090x_car_width(u32 srate, enum stv090x_rolloff rolloff)
+{
+       u32 ro;
+
+       switch (rolloff) {
+       case STV090x_RO_20:
+               ro = 20;
+               break;
+       case STV090x_RO_25:
+               ro = 25;
+               break;
+       case STV090x_RO_35:
+       default:
+               ro = 35;
+               break;
+       }
+
+       return srate + (srate * ro) / 100;
+}
+
+static int stv090x_set_vit_thacq(struct stv090x_state *state)
+{
+       if (STV090x_WRITE_DEMOD(state, VTH12, 0x96) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, VTH23, 0x64) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, VTH34, 0x36) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, VTH56, 0x23) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, VTH67, 0x1e) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, VTH78, 0x19) < 0)
+               goto err;
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_set_vit_thtracq(struct stv090x_state *state)
+{
+       if (STV090x_WRITE_DEMOD(state, VTH12, 0xd0) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, VTH23, 0x7d) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, VTH34, 0x53) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, VTH56, 0x2f) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, VTH67, 0x24) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, VTH78, 0x1f) < 0)
+               goto err;
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_set_viterbi(struct stv090x_state *state)
+{
+       switch (state->search_mode) {
+       case STV090x_SEARCH_AUTO:
+               if (STV090x_WRITE_DEMOD(state, FECM, 0x10) < 0) /* DVB-S and DVB-S2 */
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, PRVIT, 0x3f) < 0) /* all puncture rate */
+                       goto err;
+               break;
+       case STV090x_SEARCH_DVBS1:
+               if (STV090x_WRITE_DEMOD(state, FECM, 0x00) < 0) /* disable DSS */
+                       goto err;
+               switch (state->fec) {
+               case STV090x_PR12:
+                       if (STV090x_WRITE_DEMOD(state, PRVIT, 0x01) < 0)
+                               goto err;
+                       break;
+
+               case STV090x_PR23:
+                       if (STV090x_WRITE_DEMOD(state, PRVIT, 0x02) < 0)
+                               goto err;
+                       break;
+
+               case STV090x_PR34:
+                       if (STV090x_WRITE_DEMOD(state, PRVIT, 0x04) < 0)
+                               goto err;
+                       break;
+
+               case STV090x_PR56:
+                       if (STV090x_WRITE_DEMOD(state, PRVIT, 0x08) < 0)
+                               goto err;
+                       break;
+
+               case STV090x_PR78:
+                       if (STV090x_WRITE_DEMOD(state, PRVIT, 0x20) < 0)
+                               goto err;
+                       break;
+
+               default:
+                       if (STV090x_WRITE_DEMOD(state, PRVIT, 0x2f) < 0) /* all */
+                               goto err;
+                       break;
+               }
+               break;
+       case STV090x_SEARCH_DSS:
+               if (STV090x_WRITE_DEMOD(state, FECM, 0x80) < 0)
+                       goto err;
+               switch (state->fec) {
+               case STV090x_PR12:
+                       if (STV090x_WRITE_DEMOD(state, PRVIT, 0x01) < 0)
+                               goto err;
+                       break;
+
+               case STV090x_PR23:
+                       if (STV090x_WRITE_DEMOD(state, PRVIT, 0x02) < 0)
+                               goto err;
+                       break;
+
+               case STV090x_PR67:
+                       if (STV090x_WRITE_DEMOD(state, PRVIT, 0x10) < 0)
+                               goto err;
+                       break;
+
+               default:
+                       if (STV090x_WRITE_DEMOD(state, PRVIT, 0x13) < 0) /* 1/2, 2/3, 6/7 */
+                               goto err;
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_stop_modcod(struct stv090x_state *state)
+{
+       if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0xff) < 0)
+               goto err;
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_activate_modcod(struct stv090x_state *state)
+{
+       if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xfc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0xcc) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0xcf) < 0)
+               goto err;
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_activate_modcod_single(struct stv090x_state *state)
+{
+
+       if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xf0) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0x0f) < 0)
+               goto err;
+
+       return 0;
+
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_vitclk_ctl(struct stv090x_state *state, int enable)
+{
+       u32 reg;
+
+       switch (state->demod) {
+       case STV090x_DEMODULATOR_0:
+               mutex_lock(&demod_lock);
+               reg = stv090x_read_reg(state, STV090x_STOPCLK2);
+               STV090x_SETFIELD(reg, STOP_CLKVIT1_FIELD, enable);
+               if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
+                       goto err;
+               mutex_unlock(&demod_lock);
+               break;
+
+       case STV090x_DEMODULATOR_1:
+               mutex_lock(&demod_lock);
+               reg = stv090x_read_reg(state, STV090x_STOPCLK2);
+               STV090x_SETFIELD(reg, STOP_CLKVIT2_FIELD, enable);
+               if (stv090x_write_reg(state, STV090x_STOPCLK2, reg) < 0)
+                       goto err;
+               mutex_unlock(&demod_lock);
+               break;
+
+       default:
+               dprintk(FE_ERROR, 1, "Wrong demodulator!");
+               break;
+       }
+       return 0;
+err:
+       mutex_unlock(&demod_lock);
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_dvbs_track_crl(struct stv090x_state *state)
+{
+       if (state->dev_ver >= 0x30) {
+               /* Set ACLC BCLC optimised value vs SR */
+               if (state->srate >= 15000000) {
+                       if (STV090x_WRITE_DEMOD(state, ACLC, 0x2b) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, BCLC, 0x1a) < 0)
+                               goto err;
+               } else if ((state->srate >= 7000000) && (15000000 > state->srate)) {
+                       if (STV090x_WRITE_DEMOD(state, ACLC, 0x0c) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, BCLC, 0x1b) < 0)
+                               goto err;
+               } else if (state->srate < 7000000) {
+                       if (STV090x_WRITE_DEMOD(state, ACLC, 0x2c) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, BCLC, 0x1c) < 0)
+                               goto err;
+               }
+
+       } else {
+               /* Cut 2.0 */
+               if (STV090x_WRITE_DEMOD(state, ACLC, 0x1a) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, BCLC, 0x09) < 0)
+                       goto err;
+       }
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_delivery_search(struct stv090x_state *state)
+{
+       u32 reg;
+
+       switch (state->search_mode) {
+       case STV090x_SEARCH_DVBS1:
+       case STV090x_SEARCH_DSS:
+               reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+               STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
+               STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
+               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+                       goto err;
+
+               /* Activate Viterbi decoder in legacy search,
+                * do not use FRESVIT1, might impact VITERBI2
+                */
+               if (stv090x_vitclk_ctl(state, 0) < 0)
+                       goto err;
+
+               if (stv090x_dvbs_track_crl(state) < 0)
+                       goto err;
+
+               if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x22) < 0) /* disable DVB-S2 */
+                       goto err;
+
+               if (stv090x_set_vit_thacq(state) < 0)
+                       goto err;
+               if (stv090x_set_viterbi(state) < 0)
+                       goto err;
+               break;
+
+       case STV090x_SEARCH_DVBS2:
+               reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+               STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0);
+               STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
+               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+                       goto err;
+               STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
+               STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
+               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+                       goto err;
+
+               if (stv090x_vitclk_ctl(state, 1) < 0)
+                       goto err;
+
+               if (STV090x_WRITE_DEMOD(state, ACLC, 0x1a) < 0) /* stop DVB-S CR loop */
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, BCLC, 0x09) < 0)
+                       goto err;
+
+               if (state->dev_ver <= 0x20) {
+                       /* enable S2 carrier loop */
+                       if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x26) < 0)
+                               goto err;
+               } else {
+                       /* > Cut 3: Stop carrier 3 */
+                       if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x66) < 0)
+                               goto err;
+               }
+
+               if (state->demod_mode != STV090x_SINGLE) {
+                       /* Cut 2: enable link during search */
+                       if (stv090x_activate_modcod(state) < 0)
+                               goto err;
+               } else {
+                       /* Single demodulator
+                        * Authorize SHORT and LONG frames,
+                        * QPSK, 8PSK, 16APSK and 32APSK
+                        */
+                       if (stv090x_activate_modcod_single(state) < 0)
+                               goto err;
+               }
+
+               break;
+
+       case STV090x_SEARCH_AUTO:
+       default:
+               /* enable DVB-S2 and DVB-S2 in Auto MODE */
+               reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+               STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
+               STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
+               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+                       goto err;
+
+               if (stv090x_vitclk_ctl(state, 0) < 0)
+                       goto err;
+
+               if (stv090x_dvbs_track_crl(state) < 0)
+                       goto err;
+
+               if (state->dev_ver <= 0x20) {
+                       /* enable S2 carrier loop */
+                       if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x26) < 0)
+                               goto err;
+               } else {
+                       /* > Cut 3: Stop carrier 3 */
+                       if (STV090x_WRITE_DEMOD(state, CAR2CFG, 0x66) < 0)
+                               goto err;
+               }
+
+               if (state->demod_mode != STV090x_SINGLE) {
+                       /* Cut 2: enable link during search */
+                       if (stv090x_activate_modcod(state) < 0)
+                               goto err;
+               } else {
+                       /* Single demodulator
+                        * Authorize SHORT and LONG frames,
+                        * QPSK, 8PSK, 16APSK and 32APSK
+                        */
+                       if (stv090x_activate_modcod_single(state) < 0)
+                               goto err;
+               }
+
+               if (state->srate >= 2000000) {
+                       /* Srate >= 2MSPS, Viterbi threshold to acquire */
+                       if (stv090x_set_vit_thacq(state) < 0)
+                               goto err;
+               } else {
+                       /* Srate < 2MSPS, Reset Viterbi thresholdto track
+                        * and then re-acquire
+                        */
+                       if (stv090x_set_vit_thtracq(state) < 0)
+                               goto err;
+               }
+
+               if (stv090x_set_viterbi(state) < 0)
+                       goto err;
+               break;
+       }
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_start_search(struct stv090x_state *state)
+{
+       u32 reg, freq_abs;
+       s16 freq;
+
+       /* Reset demodulator */
+       reg = STV090x_READ_DEMOD(state, DMDISTATE);
+       STV090x_SETFIELD_Px(reg, I2C_DEMOD_MODE_FIELD, 0x1f);
+       if (STV090x_WRITE_DEMOD(state, DMDISTATE, reg) < 0)
+               goto err;
+
+       if (state->dev_ver <= 0x20) {
+               if (state->srate <= 5000000) {
+                       if (STV090x_WRITE_DEMOD(state, CARCFG, 0x44) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, CFRUP1, 0x0f) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, CFRUP1, 0xff) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, CFRLOW1, 0xf0) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, CFRLOW0, 0x00) < 0)
+                               goto err;
+
+                       /*enlarge the timing bandwith for Low SR*/
+                       if (STV090x_WRITE_DEMOD(state, RTCS2, 0x68) < 0)
+                               goto err;
+               } else {
+                       /* If the symbol rate is >5 Msps
+                       Set The carrier search up and low to auto mode */
+                       if (STV090x_WRITE_DEMOD(state, CARCFG, 0xc4) < 0)
+                               goto err;
+                       /*reduce the timing bandwith for high SR*/
+                       if (STV090x_WRITE_DEMOD(state, RTCS2, 0x44) < 0)
+                               goto err;
+               }
+       } else {
+               /* >= Cut 3 */
+               if (state->srate <= 5000000) {
+                       /* enlarge the timing bandwith for Low SR */
+                       STV090x_WRITE_DEMOD(state, RTCS2, 0x68);
+               } else {
+                       /* reduce timing bandwith for high SR */
+                       STV090x_WRITE_DEMOD(state, RTCS2, 0x44);
+               }
+
+               /* Set CFR min and max to manual mode */
+               STV090x_WRITE_DEMOD(state, CARCFG, 0x46);
+
+               if (state->algo == STV090x_WARM_SEARCH) {
+                       /* WARM Start
+                        * CFR min = -1MHz,
+                        * CFR max = +1MHz
+                        */
+                       freq_abs  = 1000 << 16;
+                       freq_abs /= (state->mclk / 1000);
+                       freq      = (s16) freq_abs;
+               } else {
+                       /* COLD Start
+                        * CFR min =- (SearchRange / 2 + 600KHz)
+                        * CFR max = +(SearchRange / 2 + 600KHz)
+                        * (600KHz for the tuner step size)
+                        */
+                       freq_abs  = (state->search_range / 2000) + 600;
+                       freq_abs  = freq_abs << 16;
+                       freq_abs /= (state->mclk / 1000);
+                       freq      = (s16) freq_abs;
+               }
+
+               if (STV090x_WRITE_DEMOD(state, CFRUP1, MSB(freq)) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, CFRUP1, LSB(freq)) < 0)
+                       goto err;
+
+               freq *= -1;
+
+               if (STV090x_WRITE_DEMOD(state, CFRLOW1, MSB(freq)) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, CFRLOW0, LSB(freq)) < 0)
+                       goto err;
+
+       }
+
+       if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0) < 0)
+               goto err;
+
+       if (state->dev_ver >= 0x20) {
+               if (STV090x_WRITE_DEMOD(state, EQUALCFG, 0x41) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, FFECFG, 0x41) < 0)
+                       goto err;
+
+               if ((state->search_mode == STV090x_DVBS1)       ||
+                       (state->search_mode == STV090x_DSS)     ||
+                       (state->search_mode == STV090x_SEARCH_AUTO)) {
+
+                       if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x82) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, VAVSRVIT, 0x00) < 0)
+                               goto err;
+               }
+       }
+
+       if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0xe0) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0xc0) < 0)
+               goto err;
+
+       reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+       STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 0);
+       STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0);
+       if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+               goto err;
+       reg = STV090x_READ_DEMOD(state, DMDCFG2);
+       STV090x_SETFIELD_Px(reg, S1S2_SEQUENTIAL_FIELD, 0x0);
+       if (STV090x_WRITE_DEMOD(state, DMDCFG2, reg) < 0)
+               goto err;
+
+       if (state->dev_ver >= 0x20) {
+               /*Frequency offset detector setting*/
+               if (state->srate < 2000000) {
+                       if (state->dev_ver <= 0x20) {
+                               /* Cut 2 */
+                               if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x39) < 0)
+                                       goto err;
+                       } else {
+                               /* Cut 2 */
+                               if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x89) < 0)
+                                       goto err;
+                       }
+                       if (STV090x_WRITE_DEMOD(state, CARHDR, 0x40) < 0)
+                               goto err;
+               }
+
+               if (state->srate < 10000000) {
+                       if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x4c) < 0)
+                               goto err;
+               } else {
+                       if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x4b) < 0)
+                               goto err;
+               }
+       } else {
+               if (state->srate < 10000000) {
+                       if (STV090x_WRITE_DEMOD(state, CARFREQ, 0xef) < 0)
+                               goto err;
+               } else {
+                       if (STV090x_WRITE_DEMOD(state, CARFREQ, 0xed) < 0)
+                               goto err;
+               }
+       }
+
+       switch (state->algo) {
+       case STV090x_WARM_SEARCH:
+               /* The symbol rate and the exact
+                * carrier Frequency are known
+                */
+               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0)
+                       goto err;
+               break;
+
+       case STV090x_COLD_SEARCH:
+               /* The symbol rate is known */
+               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0)
+                       goto err;
+               break;
+
+       default:
+               break;
+       }
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_get_agc2_min_level(struct stv090x_state *state)
+{
+       u32 agc2_min = 0, agc2 = 0, freq_init, freq_step, reg;
+       s32 i, j, steps, dir;
+
+       if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
+               goto err;
+       reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+       STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 1);
+       STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 1);
+       if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+               goto err;
+
+       if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x83) < 0) /* SR = 65 Msps Max */
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, SFRUP0, 0xc0) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x82) < 0) /* SR= 400 ksps Min */
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, SFRLOW0, 0xa0) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x00) < 0) /* stop acq @ coarse carrier state */
+               goto err;
+       if (stv090x_set_srate(state, 1000000) < 0)
+               goto err;
+
+       steps  = -1 + state->search_range / 1000000;
+       steps /= 2;
+       steps  = (2 * steps) + 1;
+       if (steps < 0)
+               steps = 1;
+
+       dir = 1;
+       freq_step = (1000000 * 256) / (state->mclk / 256);
+       freq_init = 0;
+
+       for (i = 0; i < steps; i++) {
+               if (dir > 0)
+                       freq_init = freq_init + (freq_step * i);
+               else
+                       freq_init = freq_init - (freq_step * i);
+
+               dir = -1;
+
+               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Demod RESET */
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, CFRINIT1, (freq_init >> 8) & 0xff) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, CFRINIT0, freq_init & 0xff) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x58) < 0) /* Demod RESET */
+                       goto err;
+               msleep(10);
+               for (j = 0; j < 10; j++) {
+                       agc2 += STV090x_READ_DEMOD(state, AGC2I1) << 8;
+                       agc2 |= STV090x_READ_DEMOD(state, AGC2I0);
+               }
+               agc2 /= 10;
+               agc2_min = 0xffff;
+               if (agc2 < 0xffff)
+                       agc2_min = agc2;
+       }
+
+       return agc2_min;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static u32 stv090x_get_srate(struct stv090x_state *state, u32 clk)
+{
+       u8 r3, r2, r1, r0;
+       s32 srate, int_1, int_2, tmp_1, tmp_2;
+
+       r3 = STV090x_READ_DEMOD(state, SFR3);
+       r2 = STV090x_READ_DEMOD(state, SFR2);
+       r1 = STV090x_READ_DEMOD(state, SFR1);
+       r0 = STV090x_READ_DEMOD(state, SFR0);
+
+       srate = ((r3 << 24) | (r2 << 16) | (r1 <<  8) | r0);
+
+       int_1 = clk >> 16;
+       int_2 = srate >> 16;
+
+       tmp_1 = clk % 0x10000;
+       tmp_2 = srate % 0x10000;
+
+       srate = (int_1 * int_2) +
+               ((int_1 * tmp_2) >> 16) +
+               ((int_2 * tmp_1) >> 16);
+
+       return srate;
+}
+
+static u32 stv090x_srate_srch_coarse(struct stv090x_state *state)
+{
+       struct dvb_frontend *fe = &state->frontend;
+
+       int tmg_lock = 0, i;
+       s32 tmg_cpt = 0, dir = 1, steps, cur_step = 0, freq;
+       u32 srate_coarse = 0, agc2 = 0, car_step = 1200, reg;
+
+       reg = STV090x_READ_DEMOD(state, DMDISTATE);
+       STV090x_SETFIELD_Px(reg, I2C_DEMOD_MODE_FIELD, 0x1f); /* Demod RESET */
+       if (STV090x_WRITE_DEMOD(state, DMDISTATE, reg) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, TMGCFG, 0x12) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0xf0) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0xe0) < 0)
+               goto err;
+       reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+       STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 1);
+       STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 1);
+       if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+               goto err;
+
+       if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x83) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, SFRUP0, 0xc0) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x82) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, SFRLOW0, 0xa0) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x60) < 0)
+               goto err;
+
+       if (state->dev_ver >= 0x30) {
+               if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x99) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x95) < 0)
+                       goto err;
+
+       } else if (state->dev_ver >= 0x20) {
+               if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x6a) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, SFRSTEP, 0x95) < 0)
+                       goto err;
+       }
+
+       if (state->srate <= 2000000)
+               car_step = 1000;
+       else if (state->srate <= 5000000)
+               car_step = 2000;
+       else if (state->srate <= 12000000)
+               car_step = 3000;
+       else
+               car_step = 5000;
+
+       steps  = -1 + ((state->search_range / 1000) / car_step);
+       steps /= 2;
+       steps  = (2 * steps) + 1;
+       if (steps < 0)
+               steps = 1;
+       else if (steps > 10) {
+               steps = 11;
+               car_step = (state->search_range / 1000) / 10;
+       }
+       cur_step = 0;
+       dir = 1;
+       freq = state->frequency;
+
+       while ((!tmg_lock) && (cur_step < steps)) {
+               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5f) < 0) /* Demod RESET */
+                       goto err;
+               reg = STV090x_READ_DEMOD(state, DMDISTATE);
+               STV090x_SETFIELD_Px(reg, I2C_DEMOD_MODE_FIELD, 0x00); /* trigger acquisition */
+               if (STV090x_WRITE_DEMOD(state, DMDISTATE, reg) < 0)
+                       goto err;
+               msleep(50);
+               for (i = 0; i < 10; i++) {
+                       reg = STV090x_READ_DEMOD(state, DSTATUS);
+                       if (STV090x_GETFIELD_Px(reg, TMGLOCK_QUALITY_FIELD) >= 2)
+                               tmg_cpt++;
+                       agc2 += STV090x_READ_DEMOD(state, AGC2I1) << 8;
+                       agc2 |= STV090x_READ_DEMOD(state, AGC2I0);
+               }
+               agc2 /= 10;
+               srate_coarse = stv090x_get_srate(state, state->mclk);
+               cur_step++;
+               dir *= -1;
+               if ((tmg_cpt >= 5) && (agc2 < 0x1f00) && (srate_coarse < 55000000) && (srate_coarse > 850000))
+                       tmg_lock = 1;
+               else if (cur_step < steps) {
+                       if (dir > 0)
+                               freq += cur_step * car_step;
+                       else
+                               freq -= cur_step * car_step;
+
+                       /* Setup tuner */
+                       if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+                               goto err;
+
+                       if (state->config->tuner_set_frequency) {
+                               if (state->config->tuner_set_frequency(fe, state->frequency) < 0)
+                                       goto err;
+                       }
+
+                       if (state->config->tuner_set_bandwidth) {
+                               if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
+                                       goto err;
+                       }
+
+                       if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+                               goto err;
+
+                       msleep(50);
+
+                       if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+                               goto err;
+
+                       if (state->config->tuner_get_status) {
+                               if (state->config->tuner_get_status(fe, &reg) < 0)
+                                       goto err;
+                       }
+
+                       if (reg)
+                               dprintk(FE_DEBUG, 1, "Tuner phase locked");
+                       else
+                               dprintk(FE_DEBUG, 1, "Tuner unlocked");
+
+                       if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+                               goto err;
+
+               }
+       }
+       if (!tmg_lock)
+               srate_coarse = 0;
+       else
+               srate_coarse = stv090x_get_srate(state, state->mclk);
+
+       return srate_coarse;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static u32 stv090x_srate_srch_fine(struct stv090x_state *state)
+{
+       u32 srate_coarse, freq_coarse, sym, reg;
+
+       srate_coarse = stv090x_get_srate(state, state->mclk);
+       freq_coarse  = STV090x_READ_DEMOD(state, CFR2) << 8;
+       freq_coarse |= STV090x_READ_DEMOD(state, CFR1);
+       sym = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */
+
+       if (sym < state->srate)
+               srate_coarse = 0;
+       else {
+               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0) /* Demod RESET */
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0x01) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0x20) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0x00) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, TMGCFG, 0xd2) < 0)
+                       goto err;
+               reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+               STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0x00);
+               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+                       goto err;
+
+               if (state->dev_ver >= 0x30) {
+                       if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x79) < 0)
+                               goto err;
+               } else if (state->dev_ver >= 0x20) {
+                       if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0)
+                               goto err;
+               }
+
+               if (srate_coarse > 3000000) {
+                       sym  = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */
+                       sym  = (sym / 1000) * 65536;
+                       sym /= (state->mclk / 1000);
+                       if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0)
+                               goto err;
+                       sym  = 10 * (srate_coarse / 13); /* SFRLOW = SFR - 30% */
+                       sym  = (sym / 1000) * 65536;
+                       sym /= (state->mclk / 1000);
+                       if (STV090x_WRITE_DEMOD(state, SFRLOW1, (sym >> 8) & 0x7f) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, SFRLOW0, sym & 0xff) < 0)
+                               goto err;
+                       sym  = (srate_coarse / 1000) * 65536;
+                       sym /= (state->mclk / 1000);
+                       if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0xff) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, SFRINIT0, sym & 0xff) < 0)
+                               goto err;
+               } else {
+                       sym  = 13 * (srate_coarse / 10); /* SFRUP = SFR + 30% */
+                       sym  = (sym / 100) * 65536;
+                       sym /= (state->mclk / 100);
+                       if (STV090x_WRITE_DEMOD(state, SFRUP1, (sym >> 8) & 0x7f) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, SFRUP0, sym & 0xff) < 0)
+                               goto err;
+                       sym  = 10 * (srate_coarse / 14); /* SFRLOW = SFR - 30% */
+                       sym  = (sym / 100) * 65536;
+                       sym /= (state->mclk / 100);
+                       if (STV090x_WRITE_DEMOD(state, SFRLOW1, (sym >> 8) & 0x7f) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, SFRLOW0, sym & 0xff) < 0)
+                               goto err;
+                       sym  = (srate_coarse / 100) * 65536;
+                       sym /= (state->mclk / 100);
+                       if (STV090x_WRITE_DEMOD(state, SFRINIT1, (sym >> 8) & 0xff) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, SFRINIT0, sym & 0xff) < 0)
+                               goto err;
+               }
+               if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x20) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, CFRINIT1, (freq_coarse >> 8) & 0xff) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, CFRINIT0, freq_coarse & 0xff) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0) /* trigger acquisition */
+                       goto err;
+       }
+
+       return srate_coarse;
+
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_get_dmdlock(struct stv090x_state *state, s32 timeout)
+{
+       s32 timer = 0, lock = 0;
+       u32 reg;
+       u8 stat;
+
+       while ((timer < timeout) && (!lock)) {
+               reg = STV090x_READ_DEMOD(state, DMDSTATE);
+               stat = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD);
+
+               switch (stat) {
+               case 0: /* searching */
+               case 1: /* first PLH detected */
+               default:
+                       dprintk(FE_DEBUG, 1, "Demodulator searching ..");
+                       lock = 0;
+                       break;
+               case 2: /* DVB-S2 mode */
+               case 3: /* DVB-S1/legacy mode */
+                       reg = STV090x_READ_DEMOD(state, DSTATUS);
+                       lock = STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD);
+                       break;
+               }
+
+               if (!lock)
+                       msleep(10);
+               else
+                       dprintk(FE_DEBUG, 1, "Demodulator acquired LOCK");
+
+               timer += 10;
+       }
+       return lock;
+}
+
+static int stv090x_blind_search(struct stv090x_state *state)
+{
+       u32 agc2, reg, srate_coarse;
+       s32 timeout_dmd = 500, cpt_fail, agc2_ovflw, i;
+       u8 k_ref, k_max, k_min;
+       int coarse_fail, lock;
+
+       k_max = 120;
+       k_min = 30;
+
+       agc2 = stv090x_get_agc2_min_level(state);
+
+       if (agc2 > STV090x_SEARCH_AGC2_TH(state->dev_ver)) {
+               lock = 0;
+       } else {
+
+               if (state->dev_ver <= 0x20) {
+                       if (STV090x_WRITE_DEMOD(state, CARCFG, 0xc4) < 0)
+                               goto err;
+               } else {
+                       /* > Cut 3 */
+                       if (STV090x_WRITE_DEMOD(state, CARCFG, 0x06) < 0)
+                               goto err;
+               }
+
+               if (STV090x_WRITE_DEMOD(state, RTCS2, 0x44) < 0)
+                       goto err;
+
+               if (state->dev_ver >= 0x20) {
+                       if (STV090x_WRITE_DEMOD(state, EQUALCFG, 0x41) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, FFECFG, 0x41) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x82) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, VAVSRVIT, 0x00) < 0) /* set viterbi hysteresis */
+                               goto err;
+               }
+
+               k_ref = k_max;
+               do {
+                       if (STV090x_WRITE_DEMOD(state, KREFTMG, k_ref) < 0)
+                               goto err;
+                       if (stv090x_srate_srch_coarse(state) != 0) {
+                               srate_coarse = stv090x_srate_srch_fine(state);
+                               if (srate_coarse != 0) {
+                                       stv090x_get_lock_tmg(state);
+                                       lock = stv090x_get_dmdlock(state, timeout_dmd);
+                               } else {
+                                       lock = 0;
+                               }
+                       } else {
+                               cpt_fail = 0;
+                               agc2_ovflw = 0;
+                               for (i = 0; i < 10; i++) {
+                                       agc2  = STV090x_READ_DEMOD(state, AGC2I1) << 8;
+                                       agc2 |= STV090x_READ_DEMOD(state, AGC2I0);
+                                       if (agc2 >= 0xff00)
+                                               agc2_ovflw++;
+                                       reg = STV090x_READ_DEMOD(state, DSTATUS2);
+                                       if ((STV090x_GETFIELD_Px(reg, CFR_OVERFLOW_FIELD) == 0x01) &&
+                                           (STV090x_GETFIELD_Px(reg, DEMOD_DELOCK_FIELD) == 0x01))
+
+                                               cpt_fail++;
+                               }
+                               if ((cpt_fail > 7) || (agc2_ovflw > 7))
+                                       coarse_fail = 1;
+
+                               lock = 0;
+                       }
+                       k_ref -= 30;
+               } while ((k_ref >= k_min) && (!lock) && (!coarse_fail));
+       }
+
+       return lock;
+
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_chk_tmg(struct stv090x_state *state)
+{
+       u32 reg;
+       s32 tmg_cpt = 0, i;
+       u8 freq, tmg_thh, tmg_thl;
+       int tmg_lock;
+
+       freq = STV090x_READ_DEMOD(state, CARFREQ);
+       tmg_thh = STV090x_READ_DEMOD(state, TMGTHRISE);
+       tmg_thl = STV090x_READ_DEMOD(state, TMGTHFALL);
+       if (STV090x_WRITE_DEMOD(state, TMGTHRISE, 0x20) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, TMGTHFALL, 0x00) < 0)
+               goto err;
+
+       reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+       STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0x00); /* stop carrier offset search */
+       if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, RTC, 0x80) < 0)
+               goto err;
+
+       if (STV090x_WRITE_DEMOD(state, RTCS2, 0x40) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x00) < 0)
+               goto err;
+
+       if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0) /* set car ofset to 0 */
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x65) < 0)
+               goto err;
+
+       if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0) /* trigger acquisition */
+               goto err;
+       msleep(10);
+
+       for (i = 0; i < 10; i++) {
+               reg = STV090x_READ_DEMOD(state, DSTATUS);
+               if (STV090x_GETFIELD_Px(reg, TMGLOCK_QUALITY_FIELD) >= 2)
+                       tmg_cpt++;
+               msleep(1);
+       }
+       if (tmg_cpt >= 3)
+               tmg_lock = 1;
+
+       if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, RTC, 0x88) < 0) /* DVB-S1 timing */
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, RTCS2, 0x68) < 0) /* DVB-S2 timing */
+               goto err;
+
+       if (STV090x_WRITE_DEMOD(state, CARFREQ, freq) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, TMGTHRISE, tmg_thh) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, TMGTHFALL, tmg_thl) < 0)
+               goto err;
+
+       return  tmg_lock;
+
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd)
+{
+       struct dvb_frontend *fe = &state->frontend;
+
+       u32 reg;
+       s32 car_step, steps, cur_step, dir, freq, timeout_lock;
+       int lock = 0;
+
+       if (state->srate >= 10000000)
+               timeout_lock = timeout_dmd / 3;
+       else
+               timeout_lock = timeout_dmd / 2;
+
+       lock = stv090x_get_dmdlock(state, timeout_lock); /* cold start wait */
+       if (!lock) {
+               if (state->srate >= 10000000) {
+                       if (stv090x_chk_tmg(state)) {
+                               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+                                       goto err;
+                               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0)
+                                       goto err;
+                               lock = stv090x_get_dmdlock(state, timeout_dmd);
+                       } else {
+                               lock = 0;
+                       }
+               } else {
+                       if (state->srate <= 4000000)
+                               car_step = 1000;
+                       else if (state->srate <= 7000000)
+                               car_step = 2000;
+                       else if (state->srate <= 10000000)
+                               car_step = 3000;
+                       else
+                               car_step = 5000;
+
+                       steps  = (state->search_range / 1000) / car_step;
+                       steps /= 2;
+                       steps  = 2 * (steps + 1);
+                       if (steps < 0)
+                               steps = 2;
+                       else if (steps > 12)
+                               steps = 12;
+
+                       cur_step = 1;
+                       dir = 1;
+
+                       if (!lock) {
+                               freq = state->frequency;
+                               state->tuner_bw = stv090x_car_width(state->srate, state->rolloff) + state->srate;
+                               while ((cur_step <= steps) && (!lock)) {
+                                       if (dir > 0)
+                                               freq += cur_step * car_step;
+                                       else
+                                               freq -= cur_step * car_step;
+
+                                       /* Setup tuner */
+                                       if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+                                               goto err;
+
+                                       if (state->config->tuner_set_frequency) {
+                                               if (state->config->tuner_set_frequency(fe, state->frequency) < 0)
+                                                       goto err;
+                                       }
+
+                                       if (state->config->tuner_set_bandwidth) {
+                                               if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
+                                                       goto err;
+                                       }
+
+                                       if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+                                               goto err;
+
+                                       msleep(50);
+
+                                       if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+                                               goto err;
+
+                                       if (state->config->tuner_get_status) {
+                                               if (state->config->tuner_get_status(fe, &reg) < 0)
+                                                       goto err;
+                                       }
+
+                                       if (reg)
+                                               dprintk(FE_DEBUG, 1, "Tuner phase locked");
+                                       else
+                                               dprintk(FE_DEBUG, 1, "Tuner unlocked");
+
+                                       if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+                                               goto err;
+
+                                       STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1c);
+                                       if (state->delsys == STV090x_DVBS2) {
+                                               reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+                                               STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0);
+                                               STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
+                                               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+                                                       goto err;
+                                               STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
+                                               STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
+                                               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+                                                       goto err;
+                                       }
+                                       if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0)
+                                               goto err;
+                                       if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0)
+                                               goto err;
+                                       if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+                                               goto err;
+                                       if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0)
+                                               goto err;
+                                       lock = stv090x_get_dmdlock(state, (timeout_dmd / 3));
+
+                                       dir *= -1;
+                                       cur_step++;
+                               }
+                       }
+               }
+       }
+
+       return lock;
+
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_get_loop_params(struct stv090x_state *state, s32 *freq_inc, s32 *timeout_sw, s32 *steps)
+{
+       s32 timeout, inc, steps_max, srate, car_max;
+
+       srate = state->srate;
+       car_max = state->search_range / 1000;
+       car_max += car_max / 10;
+       car_max  = 65536 * (car_max / 2);
+       car_max /= (state->mclk / 1000);
+
+       if (car_max > 0x4000)
+               car_max = 0x4000 ; /* maxcarrier should be<= +-1/4 Mclk */
+
+       inc  = srate;
+       inc /= state->mclk / 1000;
+       inc *= 256;
+       inc *= 256;
+       inc /= 1000;
+
+       switch (state->search_mode) {
+       case STV090x_SEARCH_DVBS1:
+       case STV090x_SEARCH_DSS:
+               inc *= 3; /* freq step = 3% of srate */
+               timeout = 20;
+               break;
+
+       case STV090x_SEARCH_DVBS2:
+               inc *= 4;
+               timeout = 25;
+               break;
+
+       case STV090x_SEARCH_AUTO:
+       default:
+               inc *= 3;
+               timeout = 25;
+               break;
+       }
+       inc /= 100;
+       if ((inc > car_max) || (inc < 0))
+               inc = car_max / 2; /* increment <= 1/8 Mclk */
+
+       timeout *= 27500; /* 27.5 Msps reference */
+       if (srate > 0)
+               timeout /= (srate / 1000);
+
+       if ((timeout > 100) || (timeout < 0))
+               timeout = 100;
+
+       steps_max = (car_max / inc) + 1; /* min steps = 3 */
+       if ((steps_max > 100) || (steps_max < 0)) {
+               steps_max = 100; /* max steps <= 100 */
+               inc = car_max / steps_max;
+       }
+       *freq_inc = inc;
+       *timeout_sw = timeout;
+       *steps = steps_max;
+
+       return 0;
+}
+
+static int stv090x_chk_signal(struct stv090x_state *state)
+{
+       s32 offst_car, agc2, car_max;
+       int no_signal;
+
+       offst_car  = STV090x_READ_DEMOD(state, CFR2) << 8;
+       offst_car |= STV090x_READ_DEMOD(state, CFR1);
+       offst_car = comp2(offst_car, 16);
+
+       agc2  = STV090x_READ_DEMOD(state, AGC2I1) << 8;
+       agc2 |= STV090x_READ_DEMOD(state, AGC2I0);
+       car_max = state->search_range / 1000;
+
+       car_max += (car_max / 10); /* 10% margin */
+       car_max  = (65536 * car_max / 2);
+       car_max /= state->mclk / 1000;
+
+       if (car_max > 0x4000)
+               car_max = 0x4000;
+
+       if ((agc2 > 0x2000) || (offst_car > 2 * car_max) || (offst_car < -2 * car_max)) {
+               no_signal = 1;
+               dprintk(FE_DEBUG, 1, "No Signal");
+       } else {
+               no_signal = 0;
+               dprintk(FE_DEBUG, 1, "Found Signal");
+       }
+
+       return no_signal;
+}
+
+static int stv090x_search_car_loop(struct stv090x_state *state, s32 inc, s32 timeout, int zigzag, s32 steps_max)
+{
+       int no_signal, lock = 0;
+       s32 cpt_step = 0, offst_freq, car_max;
+       u32 reg;
+
+       car_max  = state->search_range / 1000;
+       car_max += (car_max / 10);
+       car_max  = (65536 * car_max / 2);
+       car_max /= (state->mclk / 1000);
+       if (car_max > 0x4000)
+               car_max = 0x4000;
+
+       if (zigzag)
+               offst_freq = 0;
+       else
+               offst_freq = -car_max + inc;
+
+       do {
+               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1c) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, CFRINIT1, ((offst_freq / 256) & 0xff)) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, CFRINIT0, offst_freq & 0xff) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0)
+                       goto err;
+
+               reg = STV090x_READ_DEMOD(state, PDELCTRL1);
+               STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0x1); /* stop DVB-S2 packet delin */
+               if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0)
+                       goto err;
+
+               if (zigzag) {
+                       if (offst_freq >= 0)
+                               offst_freq = -offst_freq - 2 * inc;
+                       else
+                               offst_freq = -offst_freq;
+               } else {
+                       offst_freq += 2 * inc;
+               }
+
+               cpt_step++;
+
+               lock = stv090x_get_dmdlock(state, timeout);
+               no_signal = stv090x_chk_signal(state);
+
+       } while ((!lock) &&
+                (!no_signal) &&
+                 ((offst_freq - inc) < car_max) &&
+                 ((offst_freq + inc) > -car_max) &&
+                 (cpt_step < steps_max));
+
+       reg = STV090x_READ_DEMOD(state, PDELCTRL1);
+       STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0);
+       if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0)
+                       goto err;
+
+       return lock;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_sw_algo(struct stv090x_state *state)
+{
+       int no_signal, zigzag, lock = 0;
+       u32 reg;
+
+       s32 dvbs2_fly_wheel;
+       s32 inc, timeout_step, trials, steps_max;
+
+       /* get params */
+       stv090x_get_loop_params(state, &inc, &timeout_step, &steps_max);
+
+       switch (state->search_mode) {
+       case STV090x_SEARCH_DVBS1:
+       case STV090x_SEARCH_DSS:
+               /* accelerate the frequency detector */
+               if (state->dev_ver >= 0x20) {
+                       if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x3B) < 0)
+                               goto err;
+               }
+
+               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0x49) < 0)
+                       goto err;
+               zigzag = 0;
+               break;
+
+       case STV090x_SEARCH_DVBS2:
+               if (state->dev_ver >= 0x20) {
+                       if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0)
+                               goto err;
+               }
+
+               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0x89) < 0)
+                       goto err;
+               zigzag = 1;
+               break;
+
+       case STV090x_SEARCH_AUTO:
+       default:
+               /* accelerate the frequency detector */
+               if (state->dev_ver >= 0x20) {
+                       if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x3b) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0)
+                               goto err;
+               }
+
+               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0xc9) < 0)
+                       goto err;
+               zigzag = 0;
+               break;
+       }
+
+       trials = 0;
+       do {
+               lock = stv090x_search_car_loop(state, inc, timeout_step, zigzag, steps_max);
+               no_signal = stv090x_chk_signal(state);
+               trials++;
+
+               /*run the SW search 2 times maximum*/
+               if (lock || no_signal || (trials == 2)) {
+                       /*Check if the demod is not losing lock in DVBS2*/
+                       if (state->dev_ver >= 0x20) {
+                               if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0)
+                                       goto err;
+                               if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x9e) < 0)
+                                       goto err;
+                       }
+
+                       reg = STV090x_READ_DEMOD(state, DMDSTATE);
+                       if ((lock) && (STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD) == STV090x_DVBS2)) {
+                               /*Check if the demod is not losing lock in DVBS2*/
+                               msleep(timeout_step);
+                               reg = STV090x_READ_DEMOD(state, DMDFLYW);
+                               dvbs2_fly_wheel = STV090x_GETFIELD_Px(reg, FLYWHEEL_CPT_FIELD);
+                               if (dvbs2_fly_wheel < 0xd) {     /*if correct frames is decrementing */
+                                       msleep(timeout_step);
+                                       reg = STV090x_READ_DEMOD(state, DMDFLYW);
+                                       dvbs2_fly_wheel = STV090x_GETFIELD_Px(reg, FLYWHEEL_CPT_FIELD);
+                               }
+                               if (dvbs2_fly_wheel < 0xd) {
+                                       /*FALSE lock, The demod is loosing lock */
+                                       lock = 0;
+                                       if (trials < 2) {
+                                               if (state->dev_ver >= 0x20) {
+                                                       if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x79) < 0)
+                                                               goto err;
+                                               }
+
+                                               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, 0x89) < 0)
+                                                       goto err;
+                                       }
+                               }
+                       }
+               }
+       } while ((!lock) && (trials < 2) && (!no_signal));
+
+       return lock;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static enum stv090x_delsys stv090x_get_std(struct stv090x_state *state)
+{
+       u32 reg;
+       enum stv090x_delsys delsys;
+
+       reg = STV090x_READ_DEMOD(state, DMDSTATE);
+       if (STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD) == 2)
+               delsys = STV090x_DVBS2;
+       else if (STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD) == 3) {
+               reg = STV090x_READ_DEMOD(state, FECM);
+               if (STV090x_GETFIELD_Px(reg, DSS_DVB_FIELD) == 1)
+                       delsys = STV090x_DSS;
+               else
+                       delsys = STV090x_DVBS1;
+       } else {
+               delsys = STV090x_ERROR;
+       }
+
+       return delsys;
+}
+
+/* in Hz */
+static s32 stv090x_get_car_freq(struct stv090x_state *state, u32 mclk)
+{
+       s32 derot, int_1, int_2, tmp_1, tmp_2;
+
+       derot  = STV090x_READ_DEMOD(state, CFR2) << 16;
+       derot |= STV090x_READ_DEMOD(state, CFR1) <<  8;
+       derot |= STV090x_READ_DEMOD(state, CFR0);
+
+       derot = comp2(derot, 24);
+       int_1 = state->mclk >> 12;
+       int_2 = derot >> 12;
+
+       /* carrier_frequency = MasterClock * Reg / 2^24 */
+       tmp_1 = state->mclk % 0x1000;
+       tmp_2 = derot % 0x1000;
+
+       derot = (int_1 * int_2) +
+               ((int_1 * tmp_2) >> 12) +
+               ((int_1 * tmp_1) >> 12);
+
+       return derot;
+}
+
+static int stv090x_get_viterbi(struct stv090x_state *state)
+{
+       u32 reg, rate;
+
+       reg = STV090x_READ_DEMOD(state, VITCURPUN);
+       rate = STV090x_GETFIELD_Px(reg, VIT_CURPUN_FIELD);
+
+       switch (rate) {
+       case 13:
+               state->fec = STV090x_PR12;
+               break;
+
+       case 18:
+               state->fec = STV090x_PR23;
+               break;
+
+       case 21:
+               state->fec = STV090x_PR34;
+               break;
+
+       case 24:
+               state->fec = STV090x_PR56;
+               break;
+
+       case 25:
+               state->fec = STV090x_PR67;
+               break;
+
+       case 26:
+               state->fec = STV090x_PR78;
+               break;
+
+       default:
+               state->fec = STV090x_PRERR;
+               break;
+       }
+
+       return 0;
+}
+
+static enum stv090x_signal_state stv090x_get_sig_params(struct stv090x_state *state)
+{
+       struct dvb_frontend *fe = &state->frontend;
+
+       u8 tmg;
+       u32 reg;
+       s32 i = 0, offst_freq;
+
+       msleep(5);
+
+       if (state->algo == STV090x_BLIND_SEARCH) {
+               tmg = STV090x_READ_DEMOD(state, TMGREG2);
+               STV090x_WRITE_DEMOD(state, SFRSTEP, 0x5c);
+               while ((i <= 50) && (tmg != 0) && (tmg != 0xff)) {
+                       tmg = STV090x_READ_DEMOD(state, TMGREG2);
+                       msleep(5);
+                       i += 5;
+               }
+       }
+       state->delsys = stv090x_get_std(state);
+
+       if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+               goto err;
+
+       if (state->config->tuner_get_frequency) {
+               if (state->config->tuner_get_frequency(fe, &state->frequency) < 0)
+                       goto err;
+       }
+
+       if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+               goto err;
+
+       offst_freq = stv090x_get_car_freq(state, state->mclk) / 1000;
+       state->frequency += offst_freq;
+
+       if (stv090x_get_viterbi(state) < 0)
+               goto err;
+
+       reg = STV090x_READ_DEMOD(state, DMDMODCOD);
+       state->modcod = STV090x_GETFIELD_Px(reg, DEMOD_MODCOD_FIELD);
+       state->pilots = STV090x_GETFIELD_Px(reg, DEMOD_TYPE_FIELD) & 0x01;
+       state->frame_len = STV090x_GETFIELD_Px(reg, DEMOD_TYPE_FIELD) >> 1;
+       reg = STV090x_READ_DEMOD(state, TMGOBS);
+       state->rolloff = STV090x_GETFIELD_Px(reg, ROLLOFF_STATUS_FIELD);
+       reg = STV090x_READ_DEMOD(state, FECM);
+       state->inversion = STV090x_GETFIELD_Px(reg, IQINV_FIELD);
+
+       if ((state->algo == STV090x_BLIND_SEARCH) || (state->srate < 10000000)) {
+
+               if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+                       goto err;
+
+               if (state->config->tuner_get_frequency) {
+                       if (state->config->tuner_get_frequency(fe, &state->frequency) < 0)
+                               goto err;
+               }
+
+               if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+                       goto err;
+
+               if (abs(offst_freq) <= ((state->search_range / 2000) + 500))
+                       return STV090x_RANGEOK;
+               else if (abs(offst_freq) <= (stv090x_car_width(state->srate, state->rolloff) / 2000))
+                       return STV090x_RANGEOK;
+               else
+                       return STV090x_OUTOFRANGE; /* Out of Range */
+       } else {
+               if (abs(offst_freq) <= ((state->search_range / 2000) + 500))
+                       return STV090x_RANGEOK;
+               else
+                       return STV090x_OUTOFRANGE;
+       }
+
+       return STV090x_OUTOFRANGE;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static u32 stv090x_get_tmgoffst(struct stv090x_state *state, u32 srate)
+{
+       s32 offst_tmg;
+
+       offst_tmg  = STV090x_READ_DEMOD(state, TMGREG2) << 16;
+       offst_tmg |= STV090x_READ_DEMOD(state, TMGREG1) <<  8;
+       offst_tmg |= STV090x_READ_DEMOD(state, TMGREG0);
+
+       offst_tmg = comp2(offst_tmg, 24); /* 2's complement */
+       if (!offst_tmg)
+               offst_tmg = 1;
+
+       offst_tmg  = ((s32) srate * 10) / ((s32) 0x1000000 / offst_tmg);
+       offst_tmg /= 320;
+
+       return offst_tmg;
+}
+
+static u8 stv090x_optimize_carloop(struct stv090x_state *state, enum stv090x_modcod modcod, s32 pilots)
+{
+       u8 aclc = 0x29;
+       s32 i;
+       struct stv090x_long_frame_crloop *car_loop, *car_loop_qpsk_low, *car_loop_apsk_low;
+
+       if (state->dev_ver == 0x20) {
+               car_loop                = stv090x_s2_crl_cut20;
+               car_loop_qpsk_low       = stv090x_s2_lowqpsk_crl_cut20;
+               car_loop_apsk_low       = stv090x_s2_apsk_crl_cut20;
+       } else {
+               /* >= Cut 3 */
+               car_loop                = stv090x_s2_crl_cut30;
+               car_loop_qpsk_low       = stv090x_s2_lowqpsk_crl_cut30;
+               car_loop_apsk_low       = stv090x_s2_apsk_crl_cut30;
+       }
+
+       if (modcod < STV090x_QPSK_12) {
+               i = 0;
+               while ((i < 3) && (modcod != car_loop_qpsk_low[i].modcod))
+                       i++;
+
+               if (i >= 3)
+                       i = 2;
+
+       } else {
+               i = 0;
+               while ((i < 14) && (modcod != car_loop[i].modcod))
+                       i++;
+
+               if (i >= 14) {
+                       i = 0;
+                       while ((i < 11) && (modcod != car_loop_apsk_low[i].modcod))
+                               i++;
+
+                       if (i >= 11)
+                               i = 10;
+               }
+       }
+
+       if (modcod <= STV090x_QPSK_25) {
+               if (pilots) {
+                       if (state->srate <= 3000000)
+                               aclc = car_loop_qpsk_low[i].crl_pilots_on_2;
+                       else if (state->srate <= 7000000)
+                               aclc = car_loop_qpsk_low[i].crl_pilots_on_5;
+                       else if (state->srate <= 15000000)
+                               aclc = car_loop_qpsk_low[i].crl_pilots_on_10;
+                       else if (state->srate <= 25000000)
+                               aclc = car_loop_qpsk_low[i].crl_pilots_on_20;
+                       else
+                               aclc = car_loop_qpsk_low[i].crl_pilots_on_30;
+               } else {
+                       if (state->srate <= 3000000)
+                               aclc = car_loop_qpsk_low[i].crl_pilots_off_2;
+                       else if (state->srate <= 7000000)
+                               aclc = car_loop_qpsk_low[i].crl_pilots_off_5;
+                       else if (state->srate <= 15000000)
+                               aclc = car_loop_qpsk_low[i].crl_pilots_off_10;
+                       else if (state->srate <= 25000000)
+                               aclc = car_loop_qpsk_low[i].crl_pilots_off_20;
+                       else
+                               aclc = car_loop_qpsk_low[i].crl_pilots_off_30;
+               }
+
+       } else if (modcod <= STV090x_8PSK_910) {
+               if (pilots) {
+                       if (state->srate <= 3000000)
+                               aclc = car_loop[i].crl_pilots_on_2;
+                       else if (state->srate <= 7000000)
+                               aclc = car_loop[i].crl_pilots_on_5;
+                       else if (state->srate <= 15000000)
+                               aclc = car_loop[i].crl_pilots_on_10;
+                       else if (state->srate <= 25000000)
+                               aclc = car_loop[i].crl_pilots_on_20;
+                       else
+                               aclc = car_loop[i].crl_pilots_on_30;
+               } else {
+                       if (state->srate <= 3000000)
+                               aclc = car_loop[i].crl_pilots_off_2;
+                       else if (state->srate <= 7000000)
+                               aclc = car_loop[i].crl_pilots_off_5;
+                       else if (state->srate <= 15000000)
+                               aclc = car_loop[i].crl_pilots_off_10;
+                       else if (state->srate <= 25000000)
+                               aclc = car_loop[i].crl_pilots_off_20;
+                       else
+                               aclc = car_loop[i].crl_pilots_off_30;
+               }
+       } else { /* 16APSK and 32APSK */
+               if (state->srate <= 3000000)
+                       aclc = car_loop_apsk_low[i].crl_pilots_on_2;
+               else if (state->srate <= 7000000)
+                       aclc = car_loop_apsk_low[i].crl_pilots_on_5;
+               else if (state->srate <= 15000000)
+                       aclc = car_loop_apsk_low[i].crl_pilots_on_10;
+               else if (state->srate <= 25000000)
+                       aclc = car_loop_apsk_low[i].crl_pilots_on_20;
+               else
+                       aclc = car_loop_apsk_low[i].crl_pilots_on_30;
+       }
+
+       return aclc;
+}
+
+static u8 stv090x_optimize_carloop_short(struct stv090x_state *state)
+{
+       struct stv090x_short_frame_crloop *short_crl;
+       s32 index = 0;
+       u8 aclc = 0x0b;
+
+       switch (state->modulation) {
+       case STV090x_QPSK:
+       default:
+               index = 0;
+               break;
+       case STV090x_8PSK:
+               index = 1;
+               break;
+       case STV090x_16APSK:
+               index = 2;
+               break;
+       case STV090x_32APSK:
+               index = 3;
+               break;
+       }
+
+       if (state->dev_ver >= 0x30)
+               short_crl = stv090x_s2_short_crl_cut20;
+       else if (state->dev_ver >= 0x20)
+               short_crl = stv090x_s2_short_crl_cut30;
+
+       if (state->srate <= 3000000)
+               aclc = short_crl[index].crl_2;
+       else if (state->srate <= 7000000)
+               aclc = short_crl[index].crl_5;
+       else if (state->srate <= 15000000)
+               aclc = short_crl[index].crl_10;
+       else if (state->srate <= 25000000)
+               aclc = short_crl[index].crl_20;
+       else
+               aclc = short_crl[index].crl_30;
+
+       return aclc;
+}
+
+static int stv090x_optimize_track(struct stv090x_state *state)
+{
+       struct dvb_frontend *fe = &state->frontend;
+
+       enum stv090x_rolloff rolloff;
+       enum stv090x_modcod modcod;
+
+       s32 srate, pilots, aclc, f_1, f_0, i = 0, blind_tune = 0;
+       u32 reg;
+
+       srate  = stv090x_get_srate(state, state->mclk);
+       srate += stv090x_get_tmgoffst(state, srate);
+
+       switch (state->delsys) {
+       case STV090x_DVBS1:
+       case STV090x_DSS:
+               if (state->algo == STV090x_SEARCH_AUTO) {
+                       reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+                       STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
+                       STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 0);
+                       if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+                               goto err;
+               }
+               reg = STV090x_READ_DEMOD(state, DEMOD);
+               STV090x_SETFIELD_Px(reg, ROLLOFF_CONTROL_FIELD, state->rolloff);
+               STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 0x01);
+               if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
+                       goto err;
+
+               if (state->dev_ver >= 0x30) {
+                       if (stv090x_get_viterbi(state) < 0)
+                               goto err;
+
+                       if (state->fec == STV090x_PR12) {
+                               if (STV090x_WRITE_DEMOD(state, GAUSSR0, 0x98) < 0)
+                                       goto err;
+                               if (STV090x_WRITE_DEMOD(state, CCIR0, 0x18) < 0)
+                                       goto err;
+                       } else {
+                               if (STV090x_WRITE_DEMOD(state, GAUSSR0, 0x18) < 0)
+                                       goto err;
+                               if (STV090x_WRITE_DEMOD(state, CCIR0, 0x18) < 0)
+                                       goto err;
+                       }
+               }
+
+               if (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x75) < 0)
+                       goto err;
+               break;
+
+       case STV090x_DVBS2:
+               reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+               STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 0);
+               STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
+               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, ACLC, 0) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, BCLC, 0) < 0)
+                       goto err;
+               if (state->frame_len == STV090x_LONG_FRAME) {
+                       reg = STV090x_READ_DEMOD(state, DMDMODCOD);
+                       modcod = STV090x_GETFIELD_Px(reg, DEMOD_MODCOD_FIELD);
+                       pilots = STV090x_GETFIELD_Px(reg, DEMOD_TYPE_FIELD) & 0x01;
+                       aclc = stv090x_optimize_carloop(state, modcod, pilots);
+                       if (modcod <= STV090x_QPSK_910) {
+                               STV090x_WRITE_DEMOD(state, ACLC2S2Q, aclc);
+                       } else if (modcod <= STV090x_8PSK_910) {
+                               if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
+                                       goto err;
+                               if (STV090x_WRITE_DEMOD(state, ACLC2S28, aclc) < 0)
+                                       goto err;
+                       }
+                       if ((state->demod_mode == STV090x_SINGLE) && (modcod > STV090x_8PSK_910)) {
+                               if (modcod <= STV090x_16APSK_910) {
+                                       if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
+                                               goto err;
+                                       if (STV090x_WRITE_DEMOD(state, ACLC2S216A, aclc) < 0)
+                                               goto err;
+                               } else {
+                                       if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
+                                               goto err;
+                                       if (STV090x_WRITE_DEMOD(state, ACLC2S232A, aclc) < 0)
+                                               goto err;
+                               }
+                       }
+               } else {
+                       /*Carrier loop setting for short frame*/
+                       aclc = stv090x_optimize_carloop_short(state);
+                       if (state->modulation == STV090x_QPSK) {
+                               if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, aclc) < 0)
+                                       goto err;
+                       } else if (state->modulation == STV090x_8PSK) {
+                               if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
+                                       goto err;
+                               if (STV090x_WRITE_DEMOD(state, ACLC2S28, aclc) < 0)
+                                       goto err;
+                       } else if (state->modulation == STV090x_16APSK) {
+                               if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
+                                       goto err;
+                               if (STV090x_WRITE_DEMOD(state, ACLC2S216A, aclc) < 0)
+                                       goto err;
+                       } else if (state->modulation == STV090x_32APSK)  {
+                               if (STV090x_WRITE_DEMOD(state, ACLC2S2Q, 0x2a) < 0)
+                                       goto err;
+                               if (STV090x_WRITE_DEMOD(state, ACLC2S232A, aclc) < 0)
+                                       goto err;
+                       }
+               }
+
+               STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x67); /* PER */
+               break;
+
+       case STV090x_UNKNOWN:
+       default:
+               reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+               STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
+               STV090x_SETFIELD_Px(reg, DVBS2_ENABLE_FIELD, 1);
+               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+                       goto err;
+               break;
+       }
+
+       f_1 = STV090x_READ_DEMOD(state, CFR2);
+       f_0 = STV090x_READ_DEMOD(state, CFR1);
+       reg = STV090x_READ_DEMOD(state, TMGOBS);
+       rolloff = STV090x_GETFIELD_Px(reg, ROLLOFF_STATUS_FIELD);
+
+       if (state->algo == STV090x_BLIND_SEARCH) {
+               STV090x_WRITE_DEMOD(state, SFRSTEP, 0x00);
+               reg = STV090x_READ_DEMOD(state, DMDCFGMD);
+               STV090x_SETFIELD_Px(reg, SCAN_ENABLE_FIELD, 0x00);
+               STV090x_SETFIELD_Px(reg, CFR_AUTOSCAN_FIELD, 0x00);
+               if (STV090x_WRITE_DEMOD(state, DMDCFGMD, reg) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc1) < 0)
+                       goto err;
+
+               if (stv090x_set_srate(state, srate) < 0)
+                       goto err;
+               blind_tune = 1;
+       }
+
+       if (state->dev_ver >= 0x20) {
+               if ((state->search_mode == STV090x_SEARCH_DVBS1)        ||
+                   (state->search_mode == STV090x_SEARCH_DSS)          ||
+                   (state->search_mode == STV090x_SEARCH_AUTO)) {
+
+                       if (STV090x_WRITE_DEMOD(state, VAVSRVIT, 0x0a) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x00) < 0)
+                               goto err;
+               }
+       }
+
+       if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
+               goto err;
+
+       /* AUTO tracking MODE */
+       if (STV090x_WRITE_DEMOD(state, SFRUP1, 0x80) < 0)
+               goto err;
+       /* AUTO tracking MODE */
+       if (STV090x_WRITE_DEMOD(state, SFRLOW1, 0x80) < 0)
+               goto err;
+
+       if ((state->dev_ver >= 0x20) || (blind_tune == 1) || (state->srate < 10000000)) {
+               /* update initial carrier freq with the found freq offset */
+               if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, CFRINIT0, f_0) < 0)
+                       goto err;
+               state->tuner_bw = stv090x_car_width(srate, state->rolloff) + 10000000;
+
+               if ((state->dev_ver >= 0x20) || (blind_tune == 1)) {
+
+                       if (state->algo != STV090x_WARM_SEARCH) {
+
+                               if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+                                       goto err;
+
+                               if (state->config->tuner_set_bandwidth) {
+                                       if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
+                                               goto err;
+                               }
+
+                               if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+                                       goto err;
+
+                       }
+               }
+               if ((state->algo == STV090x_BLIND_SEARCH) || (state->srate < 10000000))
+                       msleep(50); /* blind search: wait 50ms for SR stabilization */
+               else
+                       msleep(5);
+
+               stv090x_get_lock_tmg(state);
+
+               if (!(stv090x_get_dmdlock(state, (state->DemodTimeout / 2)))) {
+                       if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, CFRINIT0, f_0) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0)
+                               goto err;
+
+                       i = 0;
+
+                       while ((!(stv090x_get_dmdlock(state, (state->DemodTimeout / 2)))) && (i <= 2)) {
+
+                               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+                                       goto err;
+                               if (STV090x_WRITE_DEMOD(state, CFRINIT1, f_1) < 0)
+                                       goto err;
+                               if (STV090x_WRITE_DEMOD(state, CFRINIT0, f_0) < 0)
+                                       goto err;
+                               if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x18) < 0)
+                                       goto err;
+                               i++;
+                       }
+               }
+
+       }
+
+       if (state->dev_ver >= 0x20) {
+               if (STV090x_WRITE_DEMOD(state, CARFREQ, 0x49) < 0)
+                       goto err;
+       }
+
+       if ((state->delsys == STV090x_DVBS1) || (state->delsys == STV090x_DSS))
+               stv090x_set_vit_thtracq(state);
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_get_feclock(struct stv090x_state *state, s32 timeout)
+{
+       s32 timer = 0, lock = 0, stat;
+       u32 reg;
+
+       while ((timer < timeout) && (!lock)) {
+               reg = STV090x_READ_DEMOD(state, DMDSTATE);
+               stat = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD);
+
+               switch (stat) {
+               case 0: /* searching */
+               case 1: /* first PLH detected */
+               default:
+                       lock = 0;
+                       break;
+
+               case 2: /* DVB-S2 mode */
+                       reg = STV090x_READ_DEMOD(state, PDELSTATUS1);
+                       lock = STV090x_GETFIELD_Px(reg, PKTDELIN_LOCK_FIELD);
+                       break;
+
+               case 3: /* DVB-S1/legacy mode */
+                       reg = STV090x_READ_DEMOD(state, VSTATUSVIT);
+                       lock = STV090x_GETFIELD_Px(reg, LOCKEDVIT_FIELD);
+                       break;
+               }
+               if (!lock) {
+                       msleep(10);
+                       timer += 10;
+               }
+       }
+       return lock;
+}
+
+static int stv090x_get_lock(struct stv090x_state *state, s32 timeout_dmd, s32 timeout_fec)
+{
+       u32 reg;
+       s32 timer = 0;
+       int lock;
+
+       lock = stv090x_get_dmdlock(state, timeout_dmd);
+       if (lock)
+               lock = stv090x_get_feclock(state, timeout_fec);
+
+       if (lock) {
+               lock = 0;
+
+               while ((timer < timeout_fec) && (!lock)) {
+                       reg = STV090x_READ_DEMOD(state, TSSTATUS);
+                       lock = STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD);
+                       msleep(1);
+                       timer++;
+               }
+       }
+
+       return lock;
+}
+
+static int stv090x_set_s2rolloff(struct stv090x_state *state)
+{
+       u32 reg;
+
+       if (state->dev_ver <= 0x20) {
+               /* rolloff to auto mode if DVBS2 */
+               reg = STV090x_READ_DEMOD(state, DEMOD);
+               STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 0x00);
+               if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
+                       goto err;
+       } else {
+               /* DVB-S2 rolloff to auto mode if DVBS2 */
+               reg = STV090x_READ_DEMOD(state, DEMOD);
+               STV090x_SETFIELD_Px(reg, MANUAL_S2ROLLOFF_FIELD, 0x00);
+               if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
+                       goto err;
+       }
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+
+static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
+{
+       struct dvb_frontend *fe = &state->frontend;
+       enum stv090x_signal_state signal_state = STV090x_NOCARRIER;
+       u32 reg;
+       s32 timeout_dmd = 500, timeout_fec = 50, agc1_power, power_iq = 0, i;
+       int lock = 0, low_sr = 0, no_signal = 0;
+
+       reg = STV090x_READ_DEMOD(state, TSCFGH);
+       STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 1); /* Stop path 1 stream merger */
+       if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0)
+               goto err;
+
+       if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Demod stop */
+               goto err;
+
+       if (state->dev_ver >= 0x20) {
+               if (STV090x_WRITE_DEMOD(state, CORRELABS, 0x9e) < 0) /* cut 2.0 */
+                       goto err;
+       }
+
+       stv090x_get_lock_tmg(state);
+
+       if (state->algo == STV090x_BLIND_SEARCH) {
+               state->tuner_bw = 2 * 36000000; /* wide bw for unknown srate */
+               if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc0) < 0) /* wider srate scan */
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, CORRELMANT, 0x70) < 0)
+                       goto err;
+               if (stv090x_set_srate(state, 1000000) < 0) /* inital srate = 1Msps */
+                       goto err;
+       } else {
+               /* known srate */
+               if (STV090x_WRITE_DEMOD(state, DMDTOM, 0x20) < 0)
+                       goto err;
+               if (STV090x_WRITE_DEMOD(state, TMGCFG, 0xd2) < 0)
+                       goto err;
+
+               if (state->srate < 2000000) {
+                       /* SR < 2MSPS */
+                       if (STV090x_WRITE_DEMOD(state, CORRELMANT, 0x63) < 0)
+                               goto err;
+               } else {
+                       /* SR >= 2Msps */
+                       if (STV090x_WRITE_DEMOD(state, CORRELMANT, 0x70) < 0)
+                               goto err;
+               }
+
+               if (STV090x_WRITE_DEMOD(state, AGC2REF, 0x38) < 0)
+                       goto err;
+
+               if (state->dev_ver >= 0x20) {
+                       if (STV090x_WRITE_DEMOD(state, KREFTMG, 0x5a) < 0)
+                               goto err;
+                       if (state->algo == STV090x_COLD_SEARCH)
+                               state->tuner_bw = (15 * (stv090x_car_width(state->srate, state->rolloff) + 10000000)) / 10;
+                       else if (state->algo == STV090x_WARM_SEARCH)
+                               state->tuner_bw = stv090x_car_width(state->srate, state->rolloff) + 10000000;
+               }
+
+               /* if cold start or warm  (Symbolrate is known)
+                * use a Narrow symbol rate scan range
+                */
+               if (STV090x_WRITE_DEMOD(state, TMGCFG2, 0xc1) < 0) /* narrow srate scan */
+                       goto err;
+
+               if (stv090x_set_srate(state, state->srate) < 0)
+                       goto err;
+
+               if (stv090x_set_max_srate(state, state->mclk, state->srate) < 0)
+                       goto err;
+               if (stv090x_set_min_srate(state, state->mclk, state->srate) < 0)
+                       goto err;
+
+               if (state->srate >= 10000000)
+                       low_sr = 0;
+               else
+                       low_sr = 1;
+       }
+
+       /* Setup tuner */
+       if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+               goto err;
+
+       if (state->config->tuner_set_bbgain) {
+               if (state->config->tuner_set_bbgain(fe, 10) < 0) /* 10dB */
+                       goto err;
+       }
+
+       if (state->config->tuner_set_frequency) {
+               if (state->config->tuner_set_frequency(fe, state->frequency) < 0)
+                       goto err;
+       }
+
+       if (state->config->tuner_set_bandwidth) {
+               if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
+                       goto err;
+       }
+
+       if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+               goto err;
+
+       msleep(50);
+
+       if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+               goto err;
+
+       if (state->config->tuner_get_status) {
+               if (state->config->tuner_get_status(fe, &reg) < 0)
+                       goto err;
+       }
+
+       if (reg)
+               dprintk(FE_DEBUG, 1, "Tuner phase locked");
+       else
+               dprintk(FE_DEBUG, 1, "Tuner unlocked");
+
+       if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+               goto err;
+
+       msleep(10);
+       agc1_power = MAKEWORD16(STV090x_READ_DEMOD(state, AGCIQIN1),
+                               STV090x_READ_DEMOD(state, AGCIQIN0));
+
+       if (agc1_power == 0) {
+               /* If AGC1 integrator value is 0
+                * then read POWERI, POWERQ
+                */
+               for (i = 0; i < 5; i++) {
+                       power_iq += (STV090x_READ_DEMOD(state, POWERI) +
+                                    STV090x_READ_DEMOD(state, POWERQ)) >> 1;
+               }
+               power_iq /= 5;
+       }
+
+       if ((agc1_power == 0) && (power_iq < STV090x_IQPOWER_THRESHOLD)) {
+               dprintk(FE_ERROR, 1, "No Signal: POWER_IQ=0x%02x", power_iq);
+               lock = 0;
+
+       } else {
+               reg = STV090x_READ_DEMOD(state, DEMOD);
+               STV090x_SETFIELD_Px(reg, SPECINV_CONTROL_FIELD, state->inversion);
+
+               if (state->dev_ver <= 0x20) {
+                       /* rolloff to auto mode if DVBS2 */
+                       STV090x_SETFIELD_Px(reg, MANUAL_SXROLLOFF_FIELD, 1);
+               } else {
+                       /* DVB-S2 rolloff to auto mode if DVBS2 */
+                       STV090x_SETFIELD_Px(reg, MANUAL_S2ROLLOFF_FIELD, 1);
+               }
+               if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
+                       goto err;
+
+               if (stv090x_delivery_search(state) < 0)
+                       goto err;
+
+               if (state->algo != STV090x_BLIND_SEARCH) {
+                       if (stv090x_start_search(state) < 0)
+                               goto err;
+               }
+       }
+
+       /* need to check for AGC1 state */
+
+
+
+       if (state->algo == STV090x_BLIND_SEARCH)
+               lock = stv090x_blind_search(state);
+
+       else if (state->algo == STV090x_COLD_SEARCH)
+               lock = stv090x_get_coldlock(state, timeout_dmd);
+
+       else if (state->algo == STV090x_WARM_SEARCH)
+               lock = stv090x_get_dmdlock(state, timeout_dmd);
+
+       if ((!lock) && (state->algo == STV090x_COLD_SEARCH)) {
+               if (!low_sr) {
+                       if (stv090x_chk_tmg(state))
+                               lock = stv090x_sw_algo(state);
+               }
+       }
+
+       if (lock)
+               signal_state = stv090x_get_sig_params(state);
+
+       if ((lock) && (signal_state == STV090x_RANGEOK)) { /* signal within Range */
+               stv090x_optimize_track(state);
+
+               if (state->dev_ver >= 0x20) {
+                       /* >= Cut 2.0 :release TS reset after
+                        * demod lock and optimized Tracking
+                        */
+                       reg = STV090x_READ_DEMOD(state, TSCFGH);
+                       STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0); /* release merger reset */
+                       if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0)
+                               goto err;
+
+                       msleep(3);
+
+                       STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 1); /* merger reset */
+                       if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0)
+                               goto err;
+
+                       STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0); /* release merger reset */
+                       if (STV090x_WRITE_DEMOD(state, TSCFGH, reg) < 0)
+                               goto err;
+               }
+
+               if (stv090x_get_lock(state, timeout_fec, timeout_fec)) {
+                       lock = 1;
+                       if (state->delsys == STV090x_DVBS2) {
+                               stv090x_set_s2rolloff(state);
+
+                               reg = STV090x_READ_DEMOD(state, PDELCTRL2);
+                               STV090x_SETFIELD_Px(reg, RESET_UPKO_COUNT, 1);
+                               if (STV090x_WRITE_DEMOD(state, PDELCTRL2, reg) < 0)
+                                       goto err;
+                               /* Reset DVBS2 packet delinator error counter */
+                               reg = STV090x_READ_DEMOD(state, PDELCTRL2);
+                               STV090x_SETFIELD_Px(reg, RESET_UPKO_COUNT, 0);
+                               if (STV090x_WRITE_DEMOD(state, PDELCTRL2, reg) < 0)
+                                       goto err;
+
+                               if (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x67) < 0) /* PER */
+                                       goto err;
+                       } else {
+                               if (STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x75) < 0)
+                                       goto err;
+                       }
+                       /* Reset the Total packet counter */
+                       if (STV090x_WRITE_DEMOD(state, FBERCPT4, 0x00) < 0)
+                               goto err;
+                       /* Reset the packet Error counter2 */
+                       if (STV090x_WRITE_DEMOD(state, ERRCTRL2, 0xc1) < 0)
+                               goto err;
+               } else {
+                       lock = 0;
+                       signal_state = STV090x_NODATA;
+                       no_signal = stv090x_chk_signal(state);
+               }
+       }
+       return signal_state;
+
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static enum dvbfe_search stv090x_search(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *props = &fe->dtv_property_cache;
+
+       state->delsys = props->delivery_system;
+       state->frequency = p->frequency;
+       state->srate = p->u.qpsk.symbol_rate;
+       state->search_mode = STV090x_SEARCH_AUTO;
+       state->algo = STV090x_COLD_SEARCH;
+       state->fec = STV090x_PRERR;
+       state->search_range = 2000000;
+
+       if (stv090x_algo(state) == STV090x_RANGEOK) {
+               dprintk(FE_DEBUG, 1, "Search success!");
+               return DVBFE_ALGO_SEARCH_SUCCESS;
+       } else {
+               dprintk(FE_DEBUG, 1, "Search failed!");
+               return DVBFE_ALGO_SEARCH_FAILED;
+       }
+
+       return DVBFE_ALGO_SEARCH_ERROR;
+}
+
+/* FIXME! */
+static int stv090x_read_status(struct dvb_frontend *fe, enum fe_status *status)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       u32 reg;
+       u8 search_state;
+
+       reg = STV090x_READ_DEMOD(state, DMDSTATE);
+       search_state = STV090x_GETFIELD_Px(reg, HEADER_MODE_FIELD);
+
+       switch (search_state) {
+       case 0: /* searching */
+       case 1: /* first PLH detected */
+       default:
+               dprintk(FE_DEBUG, 1, "Status: Unlocked (Searching ..)");
+               *status = 0;
+               break;
+
+       case 2: /* DVB-S2 mode */
+               dprintk(FE_DEBUG, 1, "Delivery system: DVB-S2");
+               reg = STV090x_READ_DEMOD(state, DSTATUS);
+               if (STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD)) {
+                       reg = STV090x_READ_DEMOD(state, TSSTATUS);
+                       if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) {
+                               *status = FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+                       }
+               }
+               break;
+
+       case 3: /* DVB-S1/legacy mode */
+               dprintk(FE_DEBUG, 1, "Delivery system: DVB-S");
+               reg = STV090x_READ_DEMOD(state, DSTATUS);
+               if (STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD)) {
+                       reg = STV090x_READ_DEMOD(state, VSTATUSVIT);
+                       if (STV090x_GETFIELD_Px(reg, LOCKEDVIT_FIELD)) {
+                               reg = STV090x_READ_DEMOD(state, TSSTATUS);
+                               if (STV090x_GETFIELD_Px(reg, TSFIFO_LINEOK_FIELD)) {
+                                       *status = FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+                               }
+                       }
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static int stv090x_read_per(struct dvb_frontend *fe, u32 *per)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+
+       s32 count_4, count_3, count_2, count_1, count_0, count;
+       u32 reg, h, m, l;
+       enum fe_status status;
+
+       stv090x_read_status(fe, &status);
+       if (!(status & FE_HAS_LOCK)) {
+               *per = 1 << 23; /* Max PER */
+       } else {
+               /* Counter 2 */
+               reg = STV090x_READ_DEMOD(state, ERRCNT22);
+               h = STV090x_GETFIELD_Px(reg, ERR_CNT2_FIELD);
+
+               reg = STV090x_READ_DEMOD(state, ERRCNT21);
+               m = STV090x_GETFIELD_Px(reg, ERR_CNT21_FIELD);
+
+               reg = STV090x_READ_DEMOD(state, ERRCNT20);
+               l = STV090x_GETFIELD_Px(reg, ERR_CNT20_FIELD);
+
+               *per = ((h << 16) | (m << 8) | l);
+
+               count_4 = STV090x_READ_DEMOD(state, FBERCPT4);
+               count_3 = STV090x_READ_DEMOD(state, FBERCPT3);
+               count_2 = STV090x_READ_DEMOD(state, FBERCPT2);
+               count_1 = STV090x_READ_DEMOD(state, FBERCPT1);
+               count_0 = STV090x_READ_DEMOD(state, FBERCPT0);
+
+               if ((!count_4) && (!count_3)) {
+                       count  = (count_2 & 0xff) << 16;
+                       count |= (count_1 & 0xff) <<  8;
+                       count |=  count_0 & 0xff;
+               } else {
+                       count = 1 << 24;
+               }
+               if (count == 0)
+                       *per = 1;
+       }
+       if (STV090x_WRITE_DEMOD(state, FBERCPT4, 0) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, ERRCTRL2, 0xc1) < 0)
+               goto err;
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_table_lookup(const struct stv090x_tab *tab, int max, int val)
+{
+       int res = 0;
+       int min = 0, med;
+
+       if (val < tab[min].read)
+               res = tab[min].real;
+       else if (val >= tab[max].read)
+               res = tab[max].real;
+       else {
+               while ((max - min) > 1) {
+                       med = (max + min) / 2;
+                       if (val >= tab[min].read && val < tab[med].read)
+                               max = med;
+                       else
+                               min = med;
+               }
+               res = ((val - tab[min].read) *
+                      (tab[max].real - tab[min].real) /
+                      (tab[max].read - tab[min].read)) +
+                       tab[min].real;
+       }
+
+       return res;
+}
+
+static int stv090x_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       u32 reg;
+       s32 agc;
+
+       reg = STV090x_READ_DEMOD(state, AGCIQIN1);
+       agc = STV090x_GETFIELD_Px(reg, AGCIQ_VALUE_FIELD);
+
+       *strength = stv090x_table_lookup(stv090x_rf_tab, ARRAY_SIZE(stv090x_rf_tab) - 1, agc);
+       if (agc > stv090x_rf_tab[0].read)
+               *strength = 5;
+       else if (agc < stv090x_rf_tab[ARRAY_SIZE(stv090x_rf_tab) - 1].read)
+               *strength = -100;
+
+       return 0;
+}
+
+static int stv090x_read_cnr(struct dvb_frontend *fe, u16 *cnr)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       u32 reg_0, reg_1, reg, i;
+       s32 val_0, val_1, val = 0;
+       u8 lock_f;
+
+       switch (state->delsys) {
+       case STV090x_DVBS2:
+               reg = STV090x_READ_DEMOD(state, DSTATUS);
+               lock_f = STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD);
+               if (lock_f) {
+                       msleep(5);
+                       for (i = 0; i < 16; i++) {
+                               reg_1 = STV090x_READ_DEMOD(state, NNOSPLHT1);
+                               val_1 = STV090x_GETFIELD_Px(reg_1, NOSPLHT_NORMED_FIELD);
+                               reg_0 = STV090x_READ_DEMOD(state, NNOSPLHT0);
+                               val_0 = STV090x_GETFIELD_Px(reg_1, NOSPLHT_NORMED_FIELD);
+                               val  += MAKEWORD16(val_1, val_0);
+                               msleep(1);
+                       }
+                       val /= 16;
+                       *cnr = stv090x_table_lookup(stv090x_s2cn_tab, ARRAY_SIZE(stv090x_s2cn_tab) - 1, val);
+                       if (val < stv090x_s2cn_tab[ARRAY_SIZE(stv090x_s2cn_tab) - 1].read)
+                               *cnr = 1000;
+               }
+               break;
+
+       case STV090x_DVBS1:
+       case STV090x_DSS:
+               reg = STV090x_READ_DEMOD(state, DSTATUS);
+               lock_f = STV090x_GETFIELD_Px(reg, LOCK_DEFINITIF_FIELD);
+               if (lock_f) {
+                       msleep(5);
+                       for (i = 0; i < 16; i++) {
+                               reg_1 = STV090x_READ_DEMOD(state, NOSDATAT1);
+                               val_1 = STV090x_GETFIELD_Px(reg_1, NOSDATAT_UNNORMED_FIELD);
+                               reg_0 = STV090x_READ_DEMOD(state, NOSDATAT0);
+                               val_0 = STV090x_GETFIELD_Px(reg_1, NOSDATAT_UNNORMED_FIELD);
+                               val  += MAKEWORD16(val_1, val_0);
+                               msleep(1);
+                       }
+                       val /= 16;
+                       *cnr = stv090x_table_lookup(stv090x_s1cn_tab, ARRAY_SIZE(stv090x_s1cn_tab) - 1, val);
+                       if (val < stv090x_s2cn_tab[ARRAY_SIZE(stv090x_s1cn_tab) - 1].read)
+                               *cnr = 1000;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int stv090x_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       u32 reg;
+
+       reg = STV090x_READ_DEMOD(state, DISTXCTL);
+       switch (tone) {
+       case SEC_TONE_ON:
+               STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, 0);
+               STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1);
+               if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+                       goto err;
+               STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 0);
+               if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+                       goto err;
+               break;
+
+       case SEC_TONE_OFF:
+               STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, 0);
+               STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1);
+               if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+                       goto err;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+
+static enum dvbfe_algo stv090x_frontend_algo(struct dvb_frontend *fe)
+{
+       return DVBFE_ALGO_CUSTOM;
+}
+
+static int stv090x_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       u32 reg, idle = 0, fifo_full = 1;
+       int i;
+
+       reg = STV090x_READ_DEMOD(state, DISTXCTL);
+
+       STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, 2);
+       STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1);
+       if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+               goto err;
+       STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 0);
+       if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+               goto err;
+
+       STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 1);
+       if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+               goto err;
+
+       for (i = 0; i < cmd->msg_len; i++) {
+
+               while (fifo_full) {
+                       reg = STV090x_READ_DEMOD(state, DISTXSTATUS);
+                       fifo_full = STV090x_GETFIELD_Px(reg, FIFO_FULL_FIELD);
+               }
+
+               if (STV090x_WRITE_DEMOD(state, DISTXDATA, cmd->msg[i]) < 0)
+                       goto err;
+       }
+       reg = STV090x_READ_DEMOD(state, DISTXCTL);
+       STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 0);
+       if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+               goto err;
+
+       i = 0;
+
+       while ((!idle) && (i < 10)) {
+               reg = STV090x_READ_DEMOD(state, DISTXSTATUS);
+               idle = STV090x_GETFIELD_Px(reg, TX_IDLE_FIELD);
+               msleep(10);
+               i++;
+       }
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t burst)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       u32 reg, idle = 0, fifo_full = 1;
+       u8 mode, value;
+       int i;
+
+       reg = STV090x_READ_DEMOD(state, DISTXCTL);
+
+       if (burst == SEC_MINI_A) {
+               mode = 3;
+               value = 0x00;
+       } else {
+               mode = 2;
+               value = 0xFF;
+       }
+
+       STV090x_SETFIELD_Px(reg, DISTX_MODE_FIELD, mode);
+       STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 1);
+       if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+               goto err;
+       STV090x_SETFIELD_Px(reg, DISEQC_RESET_FIELD, 0);
+       if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+               goto err;
+
+       STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 1);
+       if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+               goto err;
+
+       while (fifo_full) {
+               reg = STV090x_READ_DEMOD(state, DISTXSTATUS);
+               fifo_full = STV090x_GETFIELD_Px(reg, FIFO_FULL_FIELD);
+       }
+
+       if (STV090x_WRITE_DEMOD(state, DISTXDATA, value) < 0)
+               goto err;
+
+       reg = STV090x_READ_DEMOD(state, DISTXCTL);
+       STV090x_SETFIELD_Px(reg, DIS_PRECHARGE_FIELD, 0);
+       if (STV090x_WRITE_DEMOD(state, DISTXCTL, reg) < 0)
+               goto err;
+
+       i = 0;
+
+       while ((!idle) && (i < 10)) {
+               reg = STV090x_READ_DEMOD(state, DISTXSTATUS);
+               idle = STV090x_GETFIELD_Px(reg, TX_IDLE_FIELD);
+               msleep(10);
+               i++;
+       }
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_recv_slave_reply(struct dvb_frontend *fe, struct dvb_diseqc_slave_reply *reply)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       u32 reg = 0, i = 0, rx_end = 0;
+
+       while ((rx_end != 1) && (i < 10)) {
+               msleep(10);
+               i++;
+               reg = STV090x_READ_DEMOD(state, DISRX_ST0);
+               rx_end = STV090x_GETFIELD_Px(reg, RX_END_FIELD);
+       }
+
+       if (rx_end) {
+               reply->msg_len = STV090x_GETFIELD_Px(reg, FIFO_BYTENBR_FIELD);
+               for (i = 0; i < reply->msg_len; i++)
+                       reply->msg[i] = STV090x_READ_DEMOD(state, DISRXDATA);
+       }
+
+       return 0;
+}
+
+static int stv090x_sleep(struct dvb_frontend *fe)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       u32 reg;
+
+       dprintk(FE_DEBUG, 1, "Set %s to sleep",
+               state->device == STV0900 ? "STV0900" : "STV0903");
+
+       reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
+       STV090x_SETFIELD(reg, STANDBY_FIELD, 0x01);
+       if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0)
+               goto err;
+
+       reg = stv090x_read_reg(state, STV090x_TSTTNR1);
+       STV090x_SETFIELD(reg, ADC1_PON_FIELD, 0);
+       if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0)
+               goto err;
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_wakeup(struct dvb_frontend *fe)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       u32 reg;
+
+       dprintk(FE_DEBUG, 1, "Wake %s from standby",
+               state->device == STV0900 ? "STV0900" : "STV0903");
+
+       reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
+       STV090x_SETFIELD(reg, STANDBY_FIELD, 0x00);
+       if (stv090x_write_reg(state, STV090x_SYNTCTRL, reg) < 0)
+               goto err;
+
+       reg = stv090x_read_reg(state, STV090x_TSTTNR1);
+       STV090x_SETFIELD(reg, ADC1_PON_FIELD, 1);
+       if (stv090x_write_reg(state, STV090x_TSTTNR1, reg) < 0)
+               goto err;
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static void stv090x_release(struct dvb_frontend *fe)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+
+       kfree(state);
+}
+
+static int stv090x_ldpc_mode(struct stv090x_state *state, enum stv090x_mode ldpc_mode)
+{
+       u32 reg = 0;
+
+       switch (ldpc_mode) {
+       case STV090x_DUAL:
+       default:
+               if ((state->demod_mode != STV090x_DUAL) || (STV090x_GETFIELD(reg, DDEMOD_FIELD) != 1)) {
+                       /* set LDPC to dual mode */
+                       if (stv090x_write_reg(state, STV090x_GENCFG, 0x1d) < 0)
+                               goto err;
+
+                       state->demod_mode = STV090x_DUAL;
+
+                       reg = stv090x_read_reg(state, STV090x_TSTRES0);
+                       STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x1);
+                       if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0)
+                               goto err;
+                       STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x0);
+                       if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0)
+                               goto err;
+
+                       if (STV090x_WRITE_DEMOD(state, MODCODLST0, 0xff) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLST1, 0xff) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLST2, 0xff) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLST3, 0xff) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLST4, 0xff) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLST5, 0xff) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLST6, 0xff) < 0)
+                               goto err;
+
+                       if (STV090x_WRITE_DEMOD(state, MODCODLST7, 0xcc) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLST8, 0xcc) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLST9, 0xcc) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLSTA, 0xcc) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLSTB, 0xcc) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLSTC, 0xcc) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLSTD, 0xcc) < 0)
+                               goto err;
+
+                       if (STV090x_WRITE_DEMOD(state, MODCODLSTE, 0xff) < 0)
+                               goto err;
+                       if (STV090x_WRITE_DEMOD(state, MODCODLSTF, 0xcf) < 0)
+                               goto err;
+               }
+               break;
+
+       case STV090x_SINGLE:
+               if (stv090x_stop_modcod(state) < 0)
+                       goto err;
+               if (stv090x_activate_modcod_single(state) < 0)
+                       goto err;
+
+               if (state->demod == STV090x_DEMODULATOR_1) {
+                       if (stv090x_write_reg(state, STV090x_GENCFG, 0x06) < 0) /* path 2 */
+                               goto err;
+               } else {
+                       if (stv090x_write_reg(state, STV090x_GENCFG, 0x04) < 0) /* path 1 */
+                               goto err;
+               }
+
+               reg = stv090x_read_reg(state, STV090x_TSTRES0);
+               STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x1);
+               if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0)
+                       goto err;
+               STV090x_SETFIELD(reg, FRESFEC_FIELD, 0x0);
+               if (stv090x_write_reg(state, STV090x_TSTRES0, reg) < 0)
+                       goto err;
+
+               reg = STV090x_READ_DEMOD(state, PDELCTRL1);
+               STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0x01);
+               if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0)
+                       goto err;
+               STV090x_SETFIELD_Px(reg, ALGOSWRST_FIELD, 0x00);
+               if (STV090x_WRITE_DEMOD(state, PDELCTRL1, reg) < 0)
+                       goto err;
+               break;
+       }
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+/* return (Hz), clk in Hz*/
+static u32 stv090x_get_mclk(struct stv090x_state *state)
+{
+       const struct stv090x_config *config = state->config;
+       u32 div, reg;
+       u8 ratio;
+
+       div = stv090x_read_reg(state, STV090x_NCOARSE);
+       reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
+       ratio = STV090x_GETFIELD(reg, SELX1RATIO_FIELD) ? 4 : 6;
+
+       return (div + 1) * config->xtal / ratio; /* kHz */
+}
+
+static int stv090x_set_mclk(struct stv090x_state *state, u32 mclk, u32 clk)
+{
+       const struct stv090x_config *config = state->config;
+       u32 reg, div, clk_sel;
+
+       reg = stv090x_read_reg(state, STV090x_SYNTCTRL);
+       clk_sel = ((STV090x_GETFIELD(reg, SELX1RATIO_FIELD) == 1) ? 4 : 6);
+
+       div = ((clk_sel * mclk) / config->xtal) - 1;
+
+       reg = stv090x_read_reg(state, STV090x_NCOARSE);
+       STV090x_SETFIELD(reg, M_DIV_FIELD, div);
+       if (stv090x_write_reg(state, STV090x_NCOARSE, reg) < 0)
+               goto err;
+
+       state->mclk = stv090x_get_mclk(state);
+
+       /*Set the DiseqC frequency to 22KHz */
+       div = state->mclk / 704000;
+       if (STV090x_WRITE_DEMOD(state, F22TX, div) < 0)
+               goto err;
+       if (STV090x_WRITE_DEMOD(state, F22RX, div) < 0)
+               goto err;
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_set_tspath(struct stv090x_state *state)
+{
+       u32 reg;
+
+       if (state->dev_ver >= 0x20) {
+               switch (state->config->ts1_mode) {
+               case STV090x_TSMODE_PARALLEL_PUNCTURED:
+               case STV090x_TSMODE_DVBCI:
+                       switch (state->config->ts2_mode) {
+                       case STV090x_TSMODE_SERIAL_PUNCTURED:
+                       case STV090x_TSMODE_SERIAL_CONTINUOUS:
+                       default:
+                               stv090x_write_reg(state, STV090x_TSGENERAL, 0x00);
+                               break;
+
+                       case STV090x_TSMODE_PARALLEL_PUNCTURED:
+                       case STV090x_TSMODE_DVBCI:
+                               if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x06) < 0) /* Mux'd stream mode */
+                                       goto err;
+                               reg = stv090x_read_reg(state, STV090x_P1_TSCFGM);
+                               STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3);
+                               if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0)
+                                       goto err;
+                               reg = stv090x_read_reg(state, STV090x_P2_TSCFGM);
+                               STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3);
+                               if (stv090x_write_reg(state, STV090x_P2_TSCFGM, reg) < 0)
+                                       goto err;
+                               if (stv090x_write_reg(state, STV090x_P1_TSSPEED, 0x14) < 0)
+                                       goto err;
+                               if (stv090x_write_reg(state, STV090x_P2_TSSPEED, 0x28) < 0)
+                                       goto err;
+                               break;
+                       }
+                       break;
+
+               case STV090x_TSMODE_SERIAL_PUNCTURED:
+               case STV090x_TSMODE_SERIAL_CONTINUOUS:
+               default:
+                       switch (state->config->ts2_mode) {
+                       case STV090x_TSMODE_SERIAL_PUNCTURED:
+                       case STV090x_TSMODE_SERIAL_CONTINUOUS:
+                       default:
+                               if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0c) < 0)
+                                       goto err;
+                               break;
+
+                       case STV090x_TSMODE_PARALLEL_PUNCTURED:
+                       case STV090x_TSMODE_DVBCI:
+                               if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0a) < 0)
+                                       goto err;
+                               break;
+                       }
+                       break;
+               }
+       } else {
+               switch (state->config->ts1_mode) {
+               case STV090x_TSMODE_PARALLEL_PUNCTURED:
+               case STV090x_TSMODE_DVBCI:
+                       switch (state->config->ts2_mode) {
+                       case STV090x_TSMODE_SERIAL_PUNCTURED:
+                       case STV090x_TSMODE_SERIAL_CONTINUOUS:
+                       default:
+                               stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x10);
+                               break;
+
+                       case STV090x_TSMODE_PARALLEL_PUNCTURED:
+                       case STV090x_TSMODE_DVBCI:
+                               stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x16);
+                               reg = stv090x_read_reg(state, STV090x_P1_TSCFGM);
+                               STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 3);
+                               if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0)
+                                       goto err;
+                               reg = stv090x_read_reg(state, STV090x_P1_TSCFGM);
+                               STV090x_SETFIELD_Px(reg, TSFIFO_MANSPEED_FIELD, 0);
+                               if (stv090x_write_reg(state, STV090x_P1_TSCFGM, reg) < 0)
+                                       goto err;
+                               if (stv090x_write_reg(state, STV090x_P1_TSSPEED, 0x14) < 0)
+                                       goto err;
+                               if (stv090x_write_reg(state, STV090x_P2_TSSPEED, 0x28) < 0)
+                                       goto err;
+                               break;
+                       }
+                       break;
+
+               case STV090x_TSMODE_SERIAL_PUNCTURED:
+               case STV090x_TSMODE_SERIAL_CONTINUOUS:
+               default:
+                       switch (state->config->ts2_mode) {
+                       case STV090x_TSMODE_SERIAL_PUNCTURED:
+                       case STV090x_TSMODE_SERIAL_CONTINUOUS:
+                       default:
+                               stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x14);
+                               break;
+
+                       case STV090x_TSMODE_PARALLEL_PUNCTURED:
+                       case STV090x_TSMODE_DVBCI:
+                               stv090x_write_reg(state, STV090x_TSGENERAL1X, 0x12);
+                               break;
+                       }
+                       break;
+               }
+       }
+
+       switch (state->config->ts1_mode) {
+       case STV090x_TSMODE_PARALLEL_PUNCTURED:
+               reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+               STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
+               STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
+               if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+                       goto err;
+               break;
+
+       case STV090x_TSMODE_DVBCI:
+               reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+               STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
+               STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
+               if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+                       goto err;
+               break;
+
+       case STV090x_TSMODE_SERIAL_PUNCTURED:
+               reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+               STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
+               STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
+               if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+                       goto err;
+               break;
+
+       case STV090x_TSMODE_SERIAL_CONTINUOUS:
+               reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+               STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
+               STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
+               if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+                       goto err;
+               break;
+
+       default:
+               break;
+       }
+
+       switch (state->config->ts2_mode) {
+       case STV090x_TSMODE_PARALLEL_PUNCTURED:
+               reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
+               STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
+               STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
+               if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
+                       goto err;
+               break;
+
+       case STV090x_TSMODE_DVBCI:
+               reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
+               STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x00);
+               STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
+               if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
+                       goto err;
+               break;
+
+       case STV090x_TSMODE_SERIAL_PUNCTURED:
+               reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
+               STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
+               STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x00);
+               if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
+                       goto err;
+               break;
+
+       case STV090x_TSMODE_SERIAL_CONTINUOUS:
+               reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
+               STV090x_SETFIELD_Px(reg, TSFIFO_SERIAL_FIELD, 0x01);
+               STV090x_SETFIELD_Px(reg, TSFIFO_DVBCI_FIELD, 0x01);
+               if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
+                       goto err;
+               break;
+
+       default:
+               break;
+       }
+       reg = stv090x_read_reg(state, STV090x_P2_TSCFGH);
+       STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x01);
+       if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
+               goto err;
+       STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x00);
+       if (stv090x_write_reg(state, STV090x_P2_TSCFGH, reg) < 0)
+               goto err;
+
+       reg = stv090x_read_reg(state, STV090x_P1_TSCFGH);
+       STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x01);
+       if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+               goto err;
+       STV090x_SETFIELD_Px(reg, RST_HWARE_FIELD, 0x00);
+       if (stv090x_write_reg(state, STV090x_P1_TSCFGH, reg) < 0)
+               goto err;
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_init(struct dvb_frontend *fe)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       const struct stv090x_config *config = state->config;
+       u32 reg;
+
+       if (stv090x_wakeup(fe) < 0) {
+               dprintk(FE_ERROR, 1, "Error waking device");
+               goto err;
+       }
+
+       if (stv090x_ldpc_mode(state, state->demod_mode) < 0)
+               goto err;
+
+       reg = STV090x_READ_DEMOD(state, TNRCFG2);
+       STV090x_SETFIELD_Px(reg, TUN_IQSWAP_FIELD, state->inversion);
+       if (STV090x_WRITE_DEMOD(state, TNRCFG2, reg) < 0)
+               goto err;
+       reg = STV090x_READ_DEMOD(state, DEMOD);
+       STV090x_SETFIELD_Px(reg, ROLLOFF_CONTROL_FIELD, state->rolloff);
+       if (STV090x_WRITE_DEMOD(state, DEMOD, reg) < 0)
+               goto err;
+
+       if (stv090x_i2c_gate_ctrl(fe, 1) < 0)
+               goto err;
+
+       if (config->tuner_set_mode) {
+               if (config->tuner_set_mode(fe, TUNER_WAKE) < 0)
+                       goto err;
+       }
+
+       if (config->tuner_init) {
+               if (config->tuner_init(fe) < 0)
+                       goto err;
+       }
+
+       if (stv090x_i2c_gate_ctrl(fe, 0) < 0)
+               goto err;
+
+       if (stv090x_set_tspath(state) < 0)
+               goto err;
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static int stv090x_setup(struct dvb_frontend *fe)
+{
+       struct stv090x_state *state = fe->demodulator_priv;
+       const struct stv090x_config *config = state->config;
+       const struct stv090x_reg *stv090x_initval = NULL;
+       const struct stv090x_reg *stv090x_cut20_val = NULL;
+       unsigned long t1_size = 0, t2_size = 0;
+       u32 reg = 0;
+
+       int i;
+
+       if (state->device == STV0900) {
+               dprintk(FE_DEBUG, 1, "Initializing STV0900");
+               stv090x_initval = stv0900_initval;
+               t1_size = ARRAY_SIZE(stv0900_initval);
+               stv090x_cut20_val = stv0900_cut20_val;
+               t2_size = ARRAY_SIZE(stv0900_cut20_val);
+       } else if (state->device == STV0903) {
+               dprintk(FE_DEBUG, 1, "Initializing STV0903");
+               stv090x_initval = stv0903_initval;
+               t1_size = ARRAY_SIZE(stv0903_initval);
+               stv090x_cut20_val = stv0903_cut20_val;
+               t2_size = ARRAY_SIZE(stv0903_cut20_val);
+       }
+
+       /* STV090x init */
+       if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x5c) < 0) /* Stop Demod */
+               goto err;
+
+       msleep(5);
+
+       if (STV090x_WRITE_DEMOD(state, TNRCFG, 0x6c) < 0) /* check register ! (No Tuner Mode) */
+               goto err;
+
+       STV090x_SETFIELD_Px(reg, ENARPT_LEVEL_FIELD, config->repeater_level);
+       if (STV090x_WRITE_DEMOD(state, I2CRPT, reg) < 0) /* repeater OFF */
+               goto err;
+
+       if (stv090x_write_reg(state, STV090x_NCOARSE, 0x13) < 0) /* set PLL divider */
+               goto err;
+       msleep(5);
+       if (stv090x_write_reg(state, STV090x_I2CCFG, 0x08) < 0) /* 1/41 oversampling */
+               goto err;
+       if (stv090x_write_reg(state, STV090x_SYNTCTRL, 0x20 | config->clk_mode) < 0) /* enable PLL */
+               goto err;
+       msleep(5);
+
+       /* write initval */
+       dprintk(FE_DEBUG, 1, "Setting up initial values");
+       for (i = 0; i < t1_size; i++) {
+               if (stv090x_write_reg(state, stv090x_initval[i].addr, stv090x_initval[i].data) < 0)
+                       goto err;
+       }
+
+       state->dev_ver = stv090x_read_reg(state, STV090x_MID);
+       if (state->dev_ver >= 0x20) {
+               if (stv090x_write_reg(state, STV090x_TSGENERAL, 0x0c) < 0)
+                       goto err;
+
+               /* write cut20_val*/
+               dprintk(FE_DEBUG, 1, "Setting up Cut 2.0 initial values");
+               for (i = 0; i < t2_size; i++) {
+                       if (stv090x_write_reg(state, stv090x_cut20_val[i].addr, stv090x_cut20_val[i].data) < 0)
+                               goto err;
+               }
+
+       } else if (state->dev_ver < 0x20) {
+               dprintk(FE_ERROR, 1, "ERROR: Unsupported Cut: 0x%02x!",
+                       state->dev_ver);
+
+               goto err;
+       } else if (state->dev_ver > 0x30) {
+               /* we shouldn't bail out from here */
+               dprintk(FE_ERROR, 1, "INFO: Cut: 0x%02x probably incomplete support!",
+                       state->dev_ver);
+       }
+
+       if (stv090x_write_reg(state, STV090x_TSTRES0, 0x80) < 0)
+               goto err;
+       if (stv090x_write_reg(state, STV090x_TSTRES0, 0x00) < 0)
+               goto err;
+
+       stv090x_set_mclk(state, 135000000, config->xtal); /* 135 Mhz */
+       msleep(5);
+       if (stv090x_write_reg(state, STV090x_SYNTCTRL, 0x20 | config->clk_mode) < 0)
+               goto err;
+       stv090x_get_mclk(state);
+
+       return 0;
+err:
+       dprintk(FE_ERROR, 1, "I/O error");
+       return -1;
+}
+
+static struct dvb_frontend_ops stv090x_ops = {
+
+       .info = {
+               .name                   = "STV090x Multistandard",
+               .type                   = FE_QPSK,
+               .frequency_min          = 950000,
+               .frequency_max          = 2150000,
+               .frequency_stepsize     = 0,
+               .frequency_tolerance    = 0,
+               .symbol_rate_min        = 1000000,
+               .symbol_rate_max        = 45000000,
+               .caps                   = FE_CAN_INVERSION_AUTO |
+                                         FE_CAN_FEC_AUTO       |
+                                         FE_CAN_QPSK           |
+                                         FE_CAN_2G_MODULATION
+       },
+
+       .release                        = stv090x_release,
+       .init                           = stv090x_init,
+
+       .sleep                          = stv090x_sleep,
+       .get_frontend_algo              = stv090x_frontend_algo,
+
+       .i2c_gate_ctrl                  = stv090x_i2c_gate_ctrl,
+
+       .diseqc_send_master_cmd         = stv090x_send_diseqc_msg,
+       .diseqc_send_burst              = stv090x_send_diseqc_burst,
+       .diseqc_recv_slave_reply        = stv090x_recv_slave_reply,
+       .set_tone                       = stv090x_set_tone,
+
+       .search                         = stv090x_search,
+       .read_status                    = stv090x_read_status,
+       .read_ber                       = stv090x_read_per,
+       .read_signal_strength           = stv090x_read_signal_strength,
+       .read_snr                       = stv090x_read_cnr
+};
+
+
+struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
+                                   struct i2c_adapter *i2c,
+                                   enum stv090x_demodulator demod)
+{
+       struct stv090x_state *state = NULL;
+
+       state = kzalloc(sizeof (struct stv090x_state), GFP_KERNEL);
+       if (state == NULL)
+               goto error;
+
+       state->verbose                          = &verbose;
+       state->config                           = config;
+       state->i2c                              = i2c;
+       state->frontend.ops                     = stv090x_ops;
+       state->frontend.demodulator_priv        = state;
+       state->demod                            = demod;
+       state->demod_mode                       = config->demod_mode; /* Single or Dual mode */
+       state->device                           = config->device;
+       state->rolloff                          = STV090x_RO_35; /* default */
+
+       if (state->demod == STV090x_DEMODULATOR_0)
+               mutex_init(&demod_lock);
+
+       if (stv090x_sleep(&state->frontend) < 0) {
+               dprintk(FE_ERROR, 1, "Error putting device to sleep");
+               goto error;
+       }
+
+       if (stv090x_setup(&state->frontend) < 0) {
+               dprintk(FE_ERROR, 1, "Error setting up device");
+               goto error;
+       }
+       if (stv090x_wakeup(&state->frontend) < 0) {
+               dprintk(FE_ERROR, 1, "Error waking device");
+               goto error;
+       }
+
+       dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x\n",
+              state->device == STV0900 ? "STV0900" : "STV0903",
+              demod,
+              state->dev_ver);
+
+       return &state->frontend;
+
+error:
+       kfree(state);
+       return NULL;
+}
+EXPORT_SYMBOL(stv090x_attach);
+MODULE_PARM_DESC(verbose, "Set Verbosity level");
+MODULE_AUTHOR("Manu Abraham");
+MODULE_DESCRIPTION("STV090x Multi-Std Broadcast frontend");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/stv090x.h b/drivers/media/dvb/frontends/stv090x.h
new file mode 100644 (file)
index 0000000..e968c98
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+       STV0900/0903 Multistandard Broadcast Frontend driver
+       Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+       Copyright (C) ST Microelectronics
+
+       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 __STV090x_H
+#define __STV090x_H
+
+enum stv090x_demodulator {
+       STV090x_DEMODULATOR_0 = 1,
+       STV090x_DEMODULATOR_1
+};
+
+enum stv090x_device {
+       STV0903 =  0,
+       STV0900,
+};
+
+enum stv090x_mode {
+       STV090x_DUAL = 0,
+       STV090x_SINGLE
+};
+
+enum stv090x_tsmode {
+       STV090x_TSMODE_SERIAL_PUNCTURED = 1,
+       STV090x_TSMODE_SERIAL_CONTINUOUS,
+       STV090x_TSMODE_PARALLEL_PUNCTURED,
+       STV090x_TSMODE_DVBCI
+};
+
+enum stv090x_clkmode {
+       STV090x_CLK_INT = 0, /* Clk i/p = CLKI */
+       STV090x_CLK_EXT = 2 /* Clk i/p = XTALI */
+};
+
+enum stv090x_i2crpt {
+       STV090x_RPTLEVEL_256    = 0,
+       STV090x_RPTLEVEL_128    = 1,
+       STV090x_RPTLEVEL_64     = 2,
+       STV090x_RPTLEVEL_32     = 3,
+       STV090x_RPTLEVEL_16     = 4,
+       STV090x_RPTLEVEL_8      = 5,
+       STV090x_RPTLEVEL_4      = 6,
+       STV090x_RPTLEVEL_2      = 7,
+};
+
+struct stv090x_config {
+       enum stv090x_device     device;
+       enum stv090x_mode       demod_mode;
+       enum stv090x_clkmode    clk_mode;
+
+       u32 xtal; /* default: 8000000 */
+       u8 address; /* default: 0x68 */
+
+       u32 ref_clk; /* default: 16000000 FIXME to tuner config */
+
+       u8 ts1_mode;
+       u8 ts2_mode;
+
+       enum stv090x_i2crpt     repeater_level;
+
+       int (*tuner_init) (struct dvb_frontend *fe);
+       int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode);
+       int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency);
+       int (*tuner_get_frequency) (struct dvb_frontend *fe, u32 *frequency);
+       int (*tuner_set_bandwidth) (struct dvb_frontend *fe, u32 bandwidth);
+       int (*tuner_get_bandwidth) (struct dvb_frontend *fe, u32 *bandwidth);
+       int (*tuner_set_bbgain) (struct dvb_frontend *fe, u32 gain);
+       int (*tuner_get_bbgain) (struct dvb_frontend *fe, u32 *gain);
+       int (*tuner_set_refclk)  (struct dvb_frontend *fe, u32 refclk);
+       int (*tuner_get_status) (struct dvb_frontend *fe, u32 *status);
+};
+
+#if defined(CONFIG_DVB_STV090x) || (defined(CONFIG_DVB_STV090x_MODULE) && defined(MODULE))
+
+extern struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
+                                          struct i2c_adapter *i2c,
+                                          enum stv090x_demodulator demod);
+#else
+
+static inline struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
+                                                 struct i2c_adapter *i2c,
+                                                 enum stv090x_demodulator demod)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif /* CONFIG_DVB_STV090x */
+
+#endif /* __STV090x_H */
diff --git a/drivers/media/dvb/frontends/stv090x_priv.h b/drivers/media/dvb/frontends/stv090x_priv.h
new file mode 100644 (file)
index 0000000..5a4a017
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+       STV0900/0903 Multistandard Broadcast Frontend driver
+       Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+       Copyright (C) ST Microelectronics
+
+       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 __STV090x_PRIV_H
+#define __STV090x_PRIV_H
+
+#include "dvb_frontend.h"
+
+#define FE_ERROR                               0
+#define FE_NOTICE                              1
+#define FE_INFO                                        2
+#define FE_DEBUG                               3
+#define FE_DEBUGREG                            4
+
+#define dprintk(__y, __z, format, arg...) do {                                         \
+       if (__z) {                                                                      \
+               if      ((verbose > FE_ERROR) && (verbose > __y))                       \
+                       printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);          \
+               else if ((verbose > FE_NOTICE) && (verbose > __y))                      \
+                       printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);       \
+               else if ((verbose > FE_INFO) && (verbose > __y))                        \
+                       printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);         \
+               else if ((verbose > FE_DEBUG) && (verbose > __y))                       \
+                       printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);        \
+       } else {                                                                        \
+               if (verbose > __y)                                                      \
+                       printk(format, ##arg);                                          \
+       }                                                                               \
+} while (0)
+
+#define STV090x_READ_DEMOD(__state, __reg) ((                  \
+       (__state)->demod == STV090x_DEMODULATOR_1)      ?       \
+       stv090x_read_reg(__state, STV090x_P2_##__reg) :         \
+       stv090x_read_reg(__state, STV090x_P1_##__reg))
+
+#define STV090x_WRITE_DEMOD(__state, __reg, __data) ((         \
+       (__state)->demod == STV090x_DEMODULATOR_1)      ?       \
+       stv090x_write_reg(__state, STV090x_P2_##__reg, __data) :\
+       stv090x_write_reg(__state, STV090x_P1_##__reg, __data))
+
+#define STV090x_ADDR_OFFST(__state, __x) ((                    \
+       (__state->demod) == STV090x_DEMODULATOR_1)      ?       \
+               STV090x_P1_##__x :                              \
+               STV090x_P2_##__x)
+
+
+#define STV090x_SETFIELD(mask, bitf, val)      (mask = (mask & (~(((1 << STV090x_WIDTH_##bitf) - 1) <<\
+                                                        STV090x_OFFST_##bitf))) | \
+                                                        (val << STV090x_OFFST_##bitf))
+
+#define STV090x_GETFIELD(val, bitf)            ((val >> STV090x_OFFST_##bitf) & ((1 << STV090x_WIDTH_##bitf) - 1))
+
+
+#define STV090x_SETFIELD_Px(mask, bitf, val)   (mask = (mask & (~(((1 << STV090x_WIDTH_Px_##bitf) - 1) <<\
+                                                        STV090x_OFFST_Px_##bitf))) | \
+                                                        (val << STV090x_OFFST_Px_##bitf))
+
+#define STV090x_GETFIELD_Px(val, bitf)         ((val >> STV090x_OFFST_Px_##bitf) & ((1 << STV090x_WIDTH_Px_##bitf) - 1))
+
+#define MAKEWORD16(__a, __b)                   (((__a) << 8) | (__b))
+
+#define MSB(__x)                               ((__x >> 8) & 0xff)
+#define LSB(__x)                               (__x & 0xff)
+
+
+#define STV090x_IQPOWER_THRESHOLD        30
+#define STV090x_SEARCH_AGC2_TH_CUT20    700
+#define STV090x_SEARCH_AGC2_TH_CUT30   1200
+
+#define STV090x_SEARCH_AGC2_TH(__ver)  \
+       ((__ver <= 0x20) ?              \
+       STV090x_SEARCH_AGC2_TH_CUT20 :  \
+       STV090x_SEARCH_AGC2_TH_CUT30)
+
+enum stv090x_signal_state {
+       STV090x_NOCARRIER,
+       STV090x_NODATA,
+       STV090x_DATAOK,
+       STV090x_RANGEOK,
+       STV090x_OUTOFRANGE
+};
+
+enum stv090x_fec {
+       STV090x_PR12 = 0,
+       STV090x_PR23,
+       STV090x_PR34,
+       STV090x_PR45,
+       STV090x_PR56,
+       STV090x_PR67,
+       STV090x_PR78,
+       STV090x_PR89,
+       STV090x_PR910,
+       STV090x_PRERR
+};
+
+enum stv090x_modulation {
+       STV090x_QPSK,
+       STV090x_8PSK,
+       STV090x_16APSK,
+       STV090x_32APSK,
+       STV090x_UNKNOWN
+};
+
+enum stv090x_frame {
+       STV090x_LONG_FRAME,
+       STV090x_SHORT_FRAME
+};
+
+enum stv090x_pilot {
+       STV090x_PILOTS_OFF,
+       STV090x_PILOTS_ON
+};
+
+enum stv090x_rolloff {
+       STV090x_RO_35,
+       STV090x_RO_25,
+       STV090x_RO_20
+};
+
+enum stv090x_inversion {
+       STV090x_IQ_AUTO,
+       STV090x_IQ_NORMAL,
+       STV090x_IQ_SWAP
+};
+
+enum stv090x_modcod {
+       STV090x_DUMMY_PLF = 0,
+       STV090x_QPSK_14,
+       STV090x_QPSK_13,
+       STV090x_QPSK_25,
+       STV090x_QPSK_12,
+       STV090x_QPSK_35,
+       STV090x_QPSK_23,
+       STV090x_QPSK_34,
+       STV090x_QPSK_45,
+       STV090x_QPSK_56,
+       STV090x_QPSK_89,
+       STV090x_QPSK_910,
+       STV090x_8PSK_35,
+       STV090x_8PSK_23,
+       STV090x_8PSK_34,
+       STV090x_8PSK_56,
+       STV090x_8PSK_89,
+       STV090x_8PSK_910,
+       STV090x_16APSK_23,
+       STV090x_16APSK_34,
+       STV090x_16APSK_45,
+       STV090x_16APSK_56,
+       STV090x_16APSK_89,
+       STV090x_16APSK_910,
+       STV090x_32APSK_34,
+       STV090x_32APSK_45,
+       STV090x_32APSK_56,
+       STV090x_32APSK_89,
+       STV090x_32APSK_910,
+       STV090x_MODCODE_UNKNOWN
+};
+
+enum stv090x_search {
+       STV090x_SEARCH_DSS = 0,
+       STV090x_SEARCH_DVBS1,
+       STV090x_SEARCH_DVBS2,
+       STV090x_SEARCH_AUTO
+};
+
+enum stv090x_algo {
+       STV090x_BLIND_SEARCH,
+       STV090x_COLD_SEARCH,
+       STV090x_WARM_SEARCH
+};
+
+enum stv090x_delsys {
+       STV090x_ERROR = 0,
+       STV090x_DVBS1 = 1,
+       STV090x_DVBS2,
+       STV090x_DSS
+};
+
+struct stv090x_long_frame_crloop {
+       enum stv090x_modcod     modcod;
+
+       u8 crl_pilots_on_2;
+       u8 crl_pilots_off_2;
+       u8 crl_pilots_on_5;
+       u8 crl_pilots_off_5;
+       u8 crl_pilots_on_10;
+       u8 crl_pilots_off_10;
+       u8 crl_pilots_on_20;
+       u8 crl_pilots_off_20;
+       u8 crl_pilots_on_30;
+       u8 crl_pilots_off_30;
+};
+
+struct stv090x_short_frame_crloop {
+       enum stv090x_modulation modulation;
+
+       u8 crl_2;  /*      SR <   3M */
+       u8 crl_5;  /*  3 < SR <=  7M */
+       u8 crl_10; /*  7 < SR <= 15M */
+       u8 crl_20; /* 10 < SR <= 25M */
+       u8 crl_30; /* 10 < SR <= 45M */
+};
+
+struct stv090x_reg {
+       u16 addr;
+       u8  data;
+};
+
+struct stv090x_tab {
+       s32 real;
+       s32 read;
+};
+
+struct stv090x_state {
+       enum stv090x_device             device;
+       enum stv090x_demodulator        demod;
+       enum stv090x_mode               demod_mode;
+       u32                             dev_ver;
+
+       struct i2c_adapter              *i2c;
+       const struct stv090x_config     *config;
+       struct dvb_frontend             frontend;
+
+       u32                             *verbose; /* Cached module verbosity */
+
+       enum stv090x_delsys             delsys;
+       enum stv090x_fec                fec;
+       enum stv090x_modulation         modulation;
+       enum stv090x_modcod             modcod;
+       enum stv090x_search             search_mode;
+       enum stv090x_frame              frame_len;
+       enum stv090x_pilot              pilots;
+       enum stv090x_rolloff            rolloff;
+       enum stv090x_inversion          inversion;
+       enum stv090x_algo               algo;
+
+       u32                             frequency;
+       u32                             srate;
+
+       s32                             mclk; /* Masterclock Divider factor */
+       s32                             tuner_bw;
+
+       u32                             tuner_refclk;
+
+       s32                             search_range;
+
+       s32                             DemodTimeout;
+       s32                             FecTimeout;
+};
+
+#endif /* __STV090x_PRIV_H */
diff --git a/drivers/media/dvb/frontends/stv090x_reg.h b/drivers/media/dvb/frontends/stv090x_reg.h
new file mode 100644 (file)
index 0000000..57b6abb
--- /dev/null
@@ -0,0 +1,2373 @@
+/*
+       STV0900/0903 Multistandard Broadcast Frontend driver
+       Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+       Copyright (C) ST Microelectronics
+
+       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 __STV090x_REG_H
+#define __STV090x_REG_H
+
+#define STV090x_MID                            0xf100
+#define STV090x_OFFST_MCHIP_IDENT_FIELD                4
+#define STV090x_WIDTH_MCHIP_IDENT_FIELD                4
+#define STV090x_OFFST_MRELEASE_FIELD           0
+#define STV090x_WIDTH_MRELEASE_FIELD           4
+
+#define STV090x_DACR1                          0xf113
+#define STV090x_OFFST_DACR1_MODE_FIELD         5
+#define STV090x_WIDTH_DACR1_MODE_FIELD         3
+#define STV090x_OFFST_DACR1_VALUE_FIELD                0
+#define STV090x_WIDTH_DACR1_VALUE_FIELD                4
+
+#define STV090x_DACR2                          0xf114
+#define STV090x_OFFST_DACR2_VALUE_FIELD                0
+#define STV090x_WIDTH_DACR2_VALUE_FIELD                8
+
+#define STV090x_OUTCFG                         0xf11c
+#define STV090x_OFFST_OUTSERRS1_HZ_FIELD       6
+#define STV090x_WIDTH_OUTSERRS1_HZ_FIELD       1
+#define STV090x_OFFST_OUTSERRS2_HZ_FIELD       5
+#define STV090x_WIDTH_OUTSERRS2_HZ_FIELD       1
+#define STV090x_OFFST_OUTSERRS3_HZ_FIELD       4
+#define STV090x_WIDTH_OUTPARRS3_HZ_FIELD       1
+#define STV090x_OFFST_OUTPARRS3_HZ_FIELD       3
+#define STV090x_WIDTH_OUTPARRS3_HZ_FIELD       1
+
+#define STV090x_MODECFG                                0xf11d
+
+#define STV090x_IRQSTATUS3                     0xf120
+#define STV090x_OFFST_SPLL_LOCK_FIELD          5
+#define STV090x_WIDTH_SPLL_LOCK_FIELD          1
+#define STV090x_OFFST_SSTREAM_LCK_3_FIELD      4
+#define STV090x_WIDTH_SSTREAM_LCK_3_FIELD      1
+#define STV090x_OFFST_SSTREAM_LCK_2_FIELD      3
+#define STV090x_WIDTH_SSTREAM_LCK_2_FIELD      1
+#define STV090x_OFFST_SSTREAM_LCK_1_FIELD      2
+#define STV090x_WIDTH_SSTREAM_LCK_1_FIELD      1
+#define STV090x_OFFST_SDVBS1_PRF_2_FIELD       1
+#define STV090x_WIDTH_SDVBS1_PRF_2_FIELD       1
+#define STV090x_OFFST_SDVBS1_PRF_1_FIELD       0
+#define STV090x_WIDTH_SDVBS1_PRF_1_FIELD       1
+
+#define STV090x_IRQSTATUS2                     0xf121
+#define STV090x_OFFST_SSPY_ENDSIM_3_FIELD      7
+#define STV090x_WIDTH_SSPY_ENDSIM_3_FIELD      1
+#define STV090x_OFFST_SSPY_ENDSIM_2_FIELD      6
+#define STV090x_WIDTH_SSPY_ENDSIM_2_FIELD      1
+#define STV090x_OFFST_SSPY_ENDSIM_1_FIELD      5
+#define STV090x_WIDTH_SSPY_ENDSIM_1_FIELD      1
+#define STV090x_OFFST_SPKTDEL_ERROR_2_FIELD    4
+#define STV090x_WIDTH_SPKTDEL_ERROR_2_FIELD    1
+#define STV090x_OFFST_SPKTDEL_LOCKB_2_FIELD    3
+#define STV090x_WIDTH_SPKTDEL_LOCKB_2_FIELD    1
+#define STV090x_OFFST_SPKTDEL_LOCK_2_FIELD     2
+#define STV090x_WIDTH_SPKTDEL_LOCK_2_FIELD     1
+#define STV090x_OFFST_SPKTDEL_ERROR_1_FIELD    1
+#define STV090x_WIDTH_SPKTDEL_ERROR_1_FIELD    1
+#define STV090x_OFFST_SPKTDEL_LOCKB_1_FIELD    0
+#define STV090x_WIDTH_SPKTDEL_LOCKB_1_FIELD    1
+
+#define STV090x_IRQSTATUS1                     0xf122
+#define STV090x_OFFST_SPKTDEL_LOCK_1_FIELD     7
+#define STV090x_WIDTH_SPKTDEL_LOCK_1_FIELD     1
+#define STV090x_OFFST_SDEMOD_LOCKB_2_FIELD     2
+#define STV090x_WIDTH_SDEMOD_LOCKB_2_FIELD     1
+#define STV090x_OFFST_SDEMOD_LOCK_2_FIELD      1
+#define STV090x_WIDTH_SDEMOD_LOCK_2_FIELD      1
+#define STV090x_OFFST_SDEMOD_IRQ_2_FIELD       0
+#define STV090x_WIDTH_SDEMOD_IRQ_2_FIELD       1
+
+#define STV090x_IRQSTATUS0                     0xf123
+#define STV090x_OFFST_SDEMOD_LOCKB_1_FIELD     7
+#define STV090x_WIDTH_SDEMOD_LOCKB_1_FIELD     1
+#define STV090x_OFFST_SDEMOD_LOCK_1_FIELD      6
+#define STV090x_WIDTH_SDEMOD_LOCK_1_FIELD      1
+#define STV090x_OFFST_SDEMOD_IRQ_1_FIELD       5
+#define STV090x_WIDTH_SDEMOD_IRQ_1_FIELD       1
+#define STV090x_OFFST_SBCH_ERRFLAG_FIELD       4
+#define STV090x_WIDTH_SBCH_ERRFLAG_FIELD       1
+#define STV090x_OFFST_SDISEQC2RX_IRQ_FIELD     3
+#define STV090x_WIDTH_SDISEQC2RX_IRQ_FIELD     1
+#define STV090x_OFFST_SDISEQC2TX_IRQ_FIELD     2
+#define STV090x_WIDTH_SDISEQC2TX_IRQ_FIELD     1
+#define STV090x_OFFST_SDISEQC1RX_IRQ_FIELD     1
+#define STV090x_WIDTH_SDISEQC1RX_IRQ_FIELD     1
+#define STV090x_OFFST_SDISEQC1TX_IRQ_FIELD     0
+#define STV090x_WIDTH_SDISEQC1TX_IRQ_FIELD     1
+
+#define STV090x_IRQMASK3                       0xf124
+#define STV090x_OFFST_MPLL_LOCK_FIELD          5
+#define STV090x_WIDTH_MPLL_LOCK_FIELD          1
+#define STV090x_OFFST_MSTREAM_LCK_3_FIELD      2
+#define STV090x_WIDTH_MSTREAM_LCK_3_FIELD      3
+#define STV090x_OFFST_MSTREAM_LCK_2_FIELD      2
+#define STV090x_WIDTH_MSTREAM_LCK_2_FIELD      3
+#define STV090x_OFFST_MSTREAM_LCK_1_FIELD      2
+#define STV090x_WIDTH_MSTREAM_LCK_1_FIELD      3
+#define STV090x_OFFST_MDVBS1_PRF_2_FIELD       1
+#define STV090x_WIDTH_MDVBS1_PRF_2_FIELD       1
+#define STV090x_OFFST_MDVBS1_PRF_1_FIELD       0
+#define STV090x_WIDTH_MDVBS1_PRF_1_FIELD       1
+
+#define STV090x_IRQMASK2                       0xf125
+#define STV090x_OFFST_MSPY_ENDSIM_3_FIELD      5
+#define STV090x_WIDTH_MSPY_ENDSIM_3_FIELD      3
+#define STV090x_OFFST_MSPY_ENDSIM_2_FIELD      5
+#define STV090x_WIDTH_MSPY_ENDSIM_2_FIELD      3
+#define STV090x_OFFST_MSPY_ENDSIM_1_FIELD      5
+#define STV090x_WIDTH_MSPY_ENDSIM_1_FIELD      3
+#define STV090x_OFFST_MPKTDEL_ERROR_2_FIELD    4
+#define STV090x_WIDTH_MPKTDEL_ERROR_2_FIELD    1
+#define STV090x_OFFST_MPKTDEL_LOCKB_2_FIELD    3
+#define STV090x_WIDTH_MPKTDEL_LOCKB_2_FIELD    1
+#define STV090x_OFFST_MPKTDEL_LOCK_2_FIELD     2
+#define STV090x_WIDTH_MPKTDEL_LOCK_2_FIELD     1
+#define STV090x_OFFST_MPKTDEL_ERROR_1_FIELD    1
+#define STV090x_WIDTH_MPKTDEL_ERROR_1_FIELD    1
+#define STV090x_OFFST_MPKTDEL_LOCKB_1_FIELD    0
+#define STV090x_WIDTH_MPKTDEL_LOCKB_1_FIELD    1
+
+#define STV090x_IRQMASK1                       0xf126
+#define STV090x_OFFST_MPKTDEL_LOCK_1_FIELD     7
+#define STV090x_WIDTH_MPKTDEL_LOCK_1_FIELD     1
+#define STV090x_OFFST_MEXTPINB2_FIELD          6
+#define STV090x_WIDTH_MEXTPINB2_FIELD          1
+#define STV090x_OFFST_MEXTPIN2_FIELD           5
+#define STV090x_WIDTH_MEXTPIN2_FIELD           1
+#define STV090x_OFFST_MEXTPINB1_FIELD          4
+#define STV090x_WIDTH_MEXTPINB1_FIELD          1
+#define STV090x_OFFST_MEXTPIN1_FIELD           3
+#define STV090x_WIDTH_MEXTPIN1_FIELD           1
+#define STV090x_OFFST_MDEMOD_LOCKB_2_FIELD     2
+#define STV090x_WIDTH_MDEMOD_LOCKB_2_FIELD     1
+#define STV090x_OFFST_MDEMOD_LOCK_2_FIELD      1
+#define STV090x_WIDTH_MDEMOD_LOCK_2_FIELD      1
+#define STV090x_OFFST_MDEMOD_IRQ_2_FIELD       0
+#define STV090x_WIDTH_MDEMOD_IRQ_2_FIELD       1
+
+#define STV090x_IRQMASK0                       0xf127
+#define STV090x_OFFST_MDEMOD_LOCKB_1_FIELD     7
+#define STV090x_WIDTH_MDEMOD_LOCKB_1_FIELD     1
+#define STV090x_OFFST_MDEMOD_LOCK_1_FIELD      6
+#define STV090x_WIDTH_MDEMOD_LOCK_1_FIELD      1
+#define STV090x_OFFST_MDEMOD_IRQ_1_FIELD       5
+#define STV090x_WIDTH_MDEMOD_IRQ_1_FIELD       1
+#define STV090x_OFFST_MBCH_ERRFLAG_FIELD       4
+#define STV090x_WIDTH_MBCH_ERRFLAG_FIELD       1
+#define STV090x_OFFST_MDISEQC2RX_IRQ_FIELD     3
+#define STV090x_WIDTH_MDISEQC2RX_IRQ_FIELD     1
+#define STV090x_OFFST_MDISEQC2TX_IRQ_FIELD     2
+#define STV090x_WIDTH_MDISEQC2TX_IRQ_FIELD     1
+#define STV090x_OFFST_MDISEQC1RX_IRQ_FIELD     1
+#define STV090x_WIDTH_MDISEQC1RX_IRQ_FIELD     1
+#define STV090x_OFFST_MDISEQC1TX_IRQ_FIELD     0
+#define STV090x_WIDTH_MDISEQC1TX_IRQ_FIELD     1
+
+#define STV090x_I2CCFG                         0xf129
+#define STV090x_OFFST_12C_FASTMODE_FIELD       3
+#define STV090x_WIDTH_12C_FASTMODE_FIELD       1
+#define STV090x_OFFST_12CADDR_INC_FIELD                0
+#define STV090x_WIDTH_12CADDR_INC_FIELD                2
+
+#define STV090x_Px_I2CRPT(__x)                 (0xf12a + (__x - 1) * 0x1)
+#define STV090x_P1_I2CRPT                      STV090x_Px_I2CRPT(1)
+#define STV090x_P2_I2CRPT                      STV090x_Px_I2CRPT(2)
+#define STV090x_OFFST_Px_I2CT_ON_FIELD         7
+#define STV090x_WIDTH_Px_I2CT_ON_FIELD         1
+#define STV090x_OFFST_Px_ENARPT_LEVEL_FIELD    4
+#define STV090x_WIDTH_Px_ENARPT_LEVEL_FIELD    3
+#define STV090x_OFFST_Px_SCLT_DELAY_FIELD      3
+#define STV090x_WIDTH_Px_SCLT_DELAY_FIELD      1
+#define STV090x_OFFST_Px_STOP_ENABLE_FIELD     2
+#define STV090x_WIDTH_Px_STOP_ENABLE_FIELD     1
+#define STV090x_OFFST_Px_STOP_SDAT2SDA_FIELD   1
+#define STV090x_WIDTH_Px_STOP_SDAT2SDA_FIELD   1
+
+#define STV090x_CLKI2CFG                       0xf140
+#define STV090x_OFFST_CLKI2_OPD_FIELD          7
+#define STV090x_WIDTH_CLKI2_OPD_FIELD          1
+#define STV090x_OFFST_CLKI2_CONFIG_FIELD       1
+#define STV090x_WIDTH_CLKI2_CONFIG_FIELD       6
+#define STV090x_OFFST_CLKI2_XOR_FIELD          0
+#define STV090x_WIDTH_CLKI2_XOR_FIELD          1
+
+#define STV090x_GPIOxCFG(__x)                  (0xf141 + (__x - 1))
+#define STV090x_GPIO1CFG                       STV090x_GPIOxCFG(1)
+#define STV090x_GPIO2CFG                       STV090x_GPIOxCFG(2)
+#define STV090x_GPIO3CFG                       STV090x_GPIOxCFG(3)
+#define STV090x_GPIO4CFG                       STV090x_GPIOxCFG(4)
+#define STV090x_GPIO5CFG                       STV090x_GPIOxCFG(5)
+#define STV090x_GPIO6CFG                       STV090x_GPIOxCFG(6)
+#define STV090x_GPIO7CFG                       STV090x_GPIOxCFG(7)
+#define STV090x_GPIO8CFG                       STV090x_GPIOxCFG(8)
+#define STV090x_GPIO9CFG                       STV090x_GPIOxCFG(9)
+#define STV090x_GPIO10CFG                      STV090x_GPIOxCFG(10)
+#define STV090x_GPIO11CFG                      STV090x_GPIOxCFG(11)
+#define STV090x_GPIO12CFG                      STV090x_GPIOxCFG(12)
+#define STV090x_GPIO13CFG                      STV090x_GPIOxCFG(13)
+#define STV090x_OFFST_GPIOx_OPD_FIELD          7
+#define STV090x_WIDTH_GPIOx_OPD_FIELD          1
+#define STV090x_OFFST_GPIOx_CONFIG_FIELD       1
+#define STV090x_WIDTH_GPIOx_CONFIG_FIELD       6
+#define STV090x_OFFST_GPIOx_XOR_FIELD          0
+#define STV090x_WIDTH_GPIOx_XOR_FIELD          1
+
+#define STV090x_CSxCFG(__x)                    (0xf14e + __x * 0x1)
+#define STV090x_CS0CFG                         STV090x_CSxCFG(0)
+#define STV090x_CS1CFG                         STV090x_CSxCFG(1)
+#define STV090x_OFFST_CSX_OPD_FIELD            7
+#define STV090x_WIDTH_CSX_OPD_FIELD            1
+#define STV090x_OFFST_CSX_CONFIG_FIELD         1
+#define STV090x_WIDTH_CSX_CONFIG_FIELD         6
+#define STV090x_OFFST_CSX_XOR_FIELD            0
+#define STV090x_WIDTH_CSX_XOR_FIELD            1
+
+
+#define STV090x_STDBYCFG                       0xf150
+#define STV090x_OFFST_STDBY_OPD_FIELD          7
+#define STV090x_WIDTH_STDBY_OPD_FIELD          1
+#define STV090x_OFFST_STDBY_CONFIG_FIELD       1
+#define STV090x_WIDTH_STDBY_CONFIG_FIELD       6
+#define STV090x_OFFST_STDBY_XOR_FIELD          0
+#define STV090x_WIDTH_STDBY_XOR_FIELD          1
+
+#define STV090x_DIRCLKCFG                      0xf151
+#define STV090x_OFFST_DIRCLK_OPD_FIELD         7
+#define STV090x_WIDTH_DIRCLK_OPD_FIELD         1
+#define STV090x_OFFST_DIRCLK_CONFIG_FIELD      1
+#define STV090x_WIDTH_DIRCLK_CONFIG_FIELD      6
+#define STV090x_OFFST_DIRCLK_XOR_FIELD         0
+#define STV090x_WIDTH_DIRCLK_XOR_FIELD         1
+
+
+#define STV090x_AGCRFxCFG(__x)                 (0xf152 + (__x - 1) * 0x4)
+#define STV090x_AGCRF1CFG                      STV090x_AGCRFxCFG(1)
+#define STV090x_AGCRF2CFG                      STV090x_AGCRFxCFG(2)
+#define STV090x_OFFST_AGCRFx_OPD_FIELD         7
+#define STV090x_WIDTH_AGCRFx_OPD_FIELD         1
+#define STV090x_OFFST_AGCRFx_CONFIG_FIELD      1
+#define STV090x_WIDTH_AGCRFx_CONFIG_FIELD      6
+#define STV090x_OFFST_AGCRFx_XOR_FIELD         0
+#define STV090x_WIDTH_AGCRFx_XOR_FIELD         1
+
+#define STV090x_SDATxCFG(__x)                  (0xf153 + (__x - 1) * 0x4)
+#define STV090x_SDAT1CFG                       STV090x_SDATxCFG(1)
+#define STV090x_SDAT2CFG                       STV090x_SDATxCFG(2)
+#define STV090x_OFFST_SDATx_OPD_FIELD          7
+#define STV090x_WIDTH_SDATx_OPD_FIELD          1
+#define STV090x_OFFST_SDATx_CONFIG_FIELD       1
+#define STV090x_WIDTH_SDATx_CONFIG_FIELD       6
+#define STV090x_OFFST_SDATx_XOR_FIELD          0
+#define STV090x_WIDTH_SDATx_XOR_FIELD          1
+
+#define STV090x_SCLTxCFG(__x)                  (0xf154 + (__x - 1) * 0x4)
+#define STV090x_SCLT1CFG                       STV090x_SCLTxCFG(1)
+#define STV090x_SCLT2CFG                       STV090x_SCLTxCFG(2)
+#define STV090x_OFFST_SCLTx_OPD_FIELD          7
+#define STV090x_WIDTH_SCLTx_OPD_FIELD          1
+#define STV090x_OFFST_SCLTx_CONFIG_FIELD       1
+#define STV090x_WIDTH_SCLTx_CONFIG_FIELD       6
+#define STV090x_OFFST_SCLTx_XOR_FIELD          0
+#define STV090x_WIDTH_SCLTx_XOR_FIELD          1
+
+#define STV090x_DISEQCOxCFG(__x)               (0xf155 + (__x - 1) * 0x4)
+#define STV090x_DISEQCO1CFG                    STV090x_DISEQCOxCFG(1)
+#define STV090x_DISEQCO2CFG                    STV090x_DISEQCOxCFG(2)
+#define STV090x_OFFST_DISEQCOx_OPD_FIELD       7
+#define STV090x_WIDTH_DISEQCOx_OPD_FIELD       1
+#define STV090x_OFFST_DISEQCOx_CONFIG_FIELD    1
+#define STV090x_WIDTH_DISEQCOx_CONFIG_FIELD    6
+#define STV090x_OFFST_DISEQCOx_XOR_FIELD       0
+#define STV090x_WIDTH_DISEQCOx_XOR_FIELD       1
+
+#define STV090x_CLKOUT27CFG                    0xf15a
+#define STV090x_OFFST_CLKOUT27_OPD_FIELD       7
+#define STV090x_WIDTH_CLKOUT27_OPD_FIELD       1
+#define STV090x_OFFST_CLKOUT27_CONFIG_FIELD    1
+#define STV090x_WIDTH_CLKOUT27_CONFIG_FIELD    6
+#define STV090x_OFFST_CLKOUT27_XOR_FIELD       0
+#define STV090x_WIDTH_CLKOUT27_XOR_FIELD       1
+
+#define STV090x_ERRORxCFG(__x)                 (0xf15b + (__x - 1) * 0x5)
+#define STV090x_ERROR1CFG                      STV090x_ERRORxCFG(1)
+#define STV090x_ERROR2CFG                      STV090x_ERRORxCFG(2)
+#define STV090x_ERROR3CFG                      STV090x_ERRORxCFG(3)
+#define STV090x_OFFST_ERRORx_OPD_FIELD         7
+#define STV090x_WIDTH_ERRORx_OPD_FIELD         1
+#define STV090x_OFFST_ERRORx_CONFIG_FIELD      1
+#define STV090x_WIDTH_ERRORx_CONFIG_FIELD      6
+#define STV090x_OFFST_ERRORx_XOR_FIELD         0
+#define STV090x_WIDTH_ERRORx_XOR_FIELD         1
+
+#define STV090x_DPNxCFG(__x)                   (0xf15c + (__x - 1) * 0x5)
+#define STV090x_DPN1CFG                                STV090x_DPNxCFG(1)
+#define STV090x_DPN2CFG                                STV090x_DPNxCFG(2)
+#define STV090x_DPN3CFG                                STV090x_DPNxCFG(3)
+#define STV090x_OFFST_DPNx_OPD_FIELD           7
+#define STV090x_WIDTH_DPNx_OPD_FIELD           1
+#define STV090x_OFFST_DPNx_CONFIG_FIELD                1
+#define STV090x_WIDTH_DPNx_CONFIG_FIELD                6
+#define STV090x_OFFST_DPNx_XOR_FIELD           0
+#define STV090x_WIDTH_DPNx_XOR_FIELD           1
+
+#define STV090x_STROUTxCFG(__x)                        (0xf15d + (__x - 1) * 0x5)
+#define STV090x_STROUT1CFG                     STV090x_STROUTxCFG(1)
+#define STV090x_STROUT2CFG                     STV090x_STROUTxCFG(2)
+#define STV090x_STROUT3CFG                     STV090x_STROUTxCFG(3)
+#define STV090x_OFFST_STROUTx_OPD_FIELD                7
+#define STV090x_WIDTH_STROUTx_OPD_FIELD                1
+#define STV090x_OFFST_STROUTx_CONFIG_FIELD     1
+#define STV090x_WIDTH_STROUTx_CONFIG_FIELD     6
+#define STV090x_OFFST_STROUTx_XOR_FIELD                0
+#define STV090x_WIDTH_STROUTx_XOR_FIELD                1
+
+#define STV090x_CLKOUTxCFG(__x)                        (0xf15e + (__x - 1) * 0x5)
+#define STV090x_CLKOUT1CFG                     STV090x_CLKOUTxCFG(1)
+#define STV090x_CLKOUT2CFG                     STV090x_CLKOUTxCFG(2)
+#define STV090x_CLKOUT3CFG                     STV090x_CLKOUTxCFG(3)
+#define STV090x_OFFST_CLKOUTx_OPD_FIELD                7
+#define STV090x_WIDTH_CLKOUTx_OPD_FIELD                1
+#define STV090x_OFFST_CLKOUTx_CONFIG_FIELD     1
+#define STV090x_WIDTH_CLKOUTx_CONFIG_FIELD     6
+#define STV090x_OFFST_CLKOUTx_XOR_FIELD                0
+#define STV090x_WIDTH_CLKOUTx_XOR_FIELD                1
+
+#define STV090x_DATAxCFG(__x)                  (0xf15f + (__x - 71) * 0x5)
+#define STV090x_DATA71CFG                      STV090x_DATAxCFG(71)
+#define STV090x_DATA72CFG                      STV090x_DATAxCFG(72)
+#define STV090x_DATA73CFG                      STV090x_DATAxCFG(73)
+#define STV090x_OFFST_DATAx_OPD_FIELD          7
+#define STV090x_WIDTH_DATAx_OPD_FIELD          1
+#define STV090x_OFFST_DATAx_CONFIG_FIELD       1
+#define STV090x_WIDTH_DATAx_CONFIG_FIELD       6
+#define STV090x_OFFST_DATAx_XOR_FIELD          0
+#define STV090x_WIDTH_DATAx_XOR_FIELD          1
+
+#define STV090x_NCOARSE                                0xf1b3
+#define STV090x_OFFST_M_DIV_FIELD              0
+#define STV090x_WIDTH_M_DIV_FIELD              8
+
+#define STV090x_SYNTCTRL                       0xf1b6
+#define STV090x_OFFST_STANDBY_FIELD            7
+#define STV090x_WIDTH_STANDBY_FIELD            1
+#define STV090x_OFFST_BYPASSPLLCORE_FIELD      6
+#define STV090x_WIDTH_BYPASSPLLCORE_FIELD      1
+#define STV090x_OFFST_SELX1RATIO_FIELD         5
+#define STV090x_WIDTH_SELX1RATIO_FIELD         1
+#define STV090x_OFFST_STOP_PLL_FIELD           3
+#define STV090x_WIDTH_SELX1RATIO_FIELD         1
+#define STV090x_OFFST_BYPASSPLLFSK_FIELD       2
+#define STV090x_WIDTH_BYPASSPLLFSK_FIELD       1
+#define STV090x_OFFST_SELOSCI_FIELD            1
+#define STV090x_WIDTH_SELOSCI_FIELD            1
+#define STV090x_OFFST_BYPASSPLLADC_FIELD       0
+#define STV090x_WIDTH_BYPASSPLLADC_FIELD       1
+
+#define STV090x_FILTCTRL                       0xf1b7
+#define STV090x_OFFST_INV_CLK135_FIELD         7
+#define STV090x_WIDTH_INV_CLK135_FIELD         1
+#define STV090x_OFFST_SEL_FSKCKDIV_FIELD       2
+#define STV090x_WIDTH_SEL_FSKCKDIV_FIELD       1
+#define STV090x_OFFST_INV_CLKFSK_FIELD         1
+#define STV090x_WIDTH_INV_CLKFSK_FIELD         1
+#define STV090x_OFFST_BYPASS_APPLI_FIELD       0
+#define STV090x_WIDTH_BYPASS_APPLI_FIELD       1
+
+#define STV090x_PLLSTAT                                0xf1b8
+#define STV090x_OFFST_PLLLOCK_FIELD            0
+#define STV090x_WIDTH_PLLLOCK_FIELD            1
+
+#define STV090x_STOPCLK1                       0xf1c2
+#define STV090x_OFFST_STOP_CLKPKDT2_FIELD      6
+#define STV090x_WIDTH_STOP_CLKPKDT2_FIELD      1
+#define STV090x_OFFST_STOP_CLKPKDT1_FIELD      5
+#define STV090x_WIDTH_STOP_CLKPKDT1_FIELD      1
+#define STV090x_OFFST_STOP_CLKFEC_FIELD                4
+#define STV090x_WIDTH_STOP_CLKFEC_FIELD                1
+#define STV090x_OFFST_STOP_CLKADCI2_FIELD      3
+#define STV090x_WIDTH_STOP_CLKADCI2_FIELD      1
+#define STV090x_OFFST_INV_CLKADCI2_FIELD       2
+#define STV090x_WIDTH_INV_CLKADCI2_FIELD       1
+#define STV090x_OFFST_STOP_CLKADCI1_FIELD      1
+#define STV090x_WIDTH_STOP_CLKADCI1_FIELD      1
+#define STV090x_OFFST_INV_CLKADCI1_FIELD       0
+#define STV090x_WIDTH_INV_CLKADCI1_FIELD       1
+
+#define STV090x_STOPCLK2                       0xf1c3
+#define STV090x_OFFST_STOP_CLKSAMP2_FIELD      4
+#define STV090x_WIDTH_STOP_CLKSAMP2_FIELD      1
+#define STV090x_OFFST_STOP_CLKSAMP1_FIELD      3
+#define STV090x_WIDTH_STOP_CLKSAMP1_FIELD      1
+#define STV090x_OFFST_STOP_CLKVIT2_FIELD       2
+#define STV090x_WIDTH_STOP_CLKVIT2_FIELD       1
+#define STV090x_OFFST_STOP_CLKVIT1_FIELD       1
+#define STV090x_WIDTH_STOP_CLKVIT1_FIELD       1
+#define STV090x_OFFST_STOP_CLKTS_FIELD         0
+#define STV090x_WIDTH_STOP_CLKTS_FIELD         1
+
+#define STV090x_TSTTNR0                                0xf1df
+#define STV090x_OFFST_SEL_FSK_FIELD            7
+#define STV090x_WIDTH_SEL_FSK_FIELD            1
+#define STV090x_OFFST_FSK_PON_FIELD            2
+#define STV090x_WIDTH_FSK_PON_FIELD            1
+
+#define STV090x_TSTTNR1                                0xf1e0
+#define STV090x_OFFST_ADC1_PON_FIELD           1
+#define STV090x_WIDTH_ADC1_PON_FIELD           1
+#define STV090x_OFFST_ADC1_INMODE_FIELD                0
+#define STV090x_WIDTH_ADC1_INMODE_FIELD                1
+
+#define STV090x_TSTTNR2                                0xf1e1
+#define STV090x_OFFST_DISEQC1_PON_FIELD                5
+#define STV090x_WIDTH_DISEQC1_PON_FIELD                1
+
+#define STV090x_TSTTNR3                                0xf1e2
+#define STV090x_OFFST_ADC2_PON_FIELD           1
+#define STV090x_WIDTH_ADC2_PON_FIELD           1
+#define STV090x_OFFST_ADC2_INMODE_FIELD                0
+#define STV090x_WIDTH_ADC2_INMODE_FIELD                1
+
+#define STV090x_TSTTNR4                                0xf1e3
+#define STV090x_OFFST_DISEQC2_PON_FIELD                5
+#define STV090x_WIDTH_DISEQC2_PON_FIELD                1
+
+#define STV090x_FSKTFC2                                0xf170
+#define STV090x_OFFST_FSKT_KMOD_FIELD          2
+#define STV090x_WIDTH_FSKT_KMOD_FIELD          6
+#define STV090x_OFFST_FSKT_CAR_FIELD           0
+#define STV090x_WIDTH_FSKT_CAR_FIELD           2
+
+#define STV090x_FSKTFC1                                0xf171
+#define STV090x_OFFST_FSKTC1_CAR_FIELD         0
+#define STV090x_WIDTH_FSKTC1_CAR_FIELD         8
+
+#define STV090x_FSKTFC0                                0xf172
+#define STV090x_OFFST_FSKTC0_CAR_FIELD         0
+#define STV090x_WIDTH_FSKTC0_CAR_FIELD         8
+
+#define STV090x_FSKTDELTAF1                    0xf173
+#define STV090x_OFFST_FSKTF1_DELTAF_FIELD      0
+#define STV090x_WIDTH_FSKTF1_DELTAF_FIELD      4
+
+#define STV090x_FSKTDELTAF0                    0xf174
+#define STV090x_OFFST_FSKTF0_DELTAF_FIELD      0
+#define STV090x_WIDTH_FSKTF0_DELTAF_FIELD      8
+
+#define STV090x_FSKTCTRL                       0xf175
+#define STV090x_OFFST_FSKT_EN_SGN_FIELD                6
+#define STV090x_WIDTH_FSKT_EN_SGN_FIELD                1
+#define STV090x_OFFST_FSKT_MOD_SGN_FIELD       5
+#define STV090x_WIDTH_FSKT_MOD_SGN_FIELD       1
+#define STV090x_OFFST_FSKT_MOD_EN_FIELD                2
+#define STV090x_WIDTH_FSKT_MOD_EN_FIELD                3
+#define STV090x_OFFST_FSKT_DACMODE_FIELD       0
+#define STV090x_WIDTH_FSKT_DACMODE_FIELD       2
+
+#define STV090x_FSKRFC2                                0xf176
+#define STV090x_OFFST_FSKRC2_DETSGN_FIELD      6
+#define STV090x_WIDTH_FSKRC2_DETSGN_FIELD      1
+#define STV090x_OFFST_FSKRC2_OUTSGN_FIELD      5
+#define STV090x_WIDTH_FSKRC2_OUTSGN_FIELD      1
+#define STV090x_OFFST_FSKRC2_KAGC_FIELD                2
+#define STV090x_WIDTH_FSKRC2_KAGC_FIELD                3
+#define STV090x_OFFST_FSKRC2_CAR_FIELD         0
+#define STV090x_WIDTH_FSKRC2_CAR_FIELD         2
+
+#define STV090x_FSKRFC1                                0xf177
+#define STV090x_OFFST_FSKRC1_CAR_FIELD         0
+#define STV090x_WIDTH_FSKRC1_CAR_FIELD         8
+
+#define STV090x_FSKRFC0                                0xf178
+#define STV090x_OFFST_FSKRC0_CAR_FIELD         0
+#define STV090x_WIDTH_FSKRC0_CAR_FIELD         8
+
+#define STV090x_FSKRK1                         0xf179
+#define STV090x_OFFST_FSKR_K1_EXP_FIELD                5
+#define STV090x_WIDTH_FSKR_K1_EXP_FIELD                3
+#define STV090x_OFFST_FSKR_K1_MANT_FIELD       0
+#define STV090x_WIDTH_FSKR_K1_MANT_FIELD       5
+
+#define STV090x_FSKRK2                         0xf17a
+#define STV090x_OFFST_FSKR_K2_EXP_FIELD                5
+#define STV090x_WIDTH_FSKR_K2_EXP_FIELD                3
+#define STV090x_OFFST_FSKR_K2_MANT_FIELD       0
+#define STV090x_WIDTH_FSKR_K2_MANT_FIELD       5
+
+#define STV090x_FSKRAGCR                       0xf17b
+#define STV090x_OFFST_FSKR_OUTCTL_FIELD                6
+#define STV090x_WIDTH_FSKR_OUTCTL_FIELD                2
+#define STV090x_OFFST_FSKR_AGC_REF_FIELD       0
+#define STV090x_WIDTH_FSKR_AGC_REF_FIELD       6
+
+#define STV090x_FSKRAGC                                0xf17c
+#define STV090x_OFFST_FSKR_AGC_ACCU_FIELD      0
+#define STV090x_WIDTH_FSKR_AGC_ACCU_FIELD      8
+
+#define STV090x_FSKRALPHA                      0xf17d
+#define STV090x_OFFST_FSKR_ALPHA_EXP_FIELD     2
+#define STV090x_WIDTH_FSKR_ALPHA_EXP_FIELD     3
+#define STV090x_OFFST_FSKR_ALPHA_M_FIELD       0
+#define STV090x_WIDTH_FSKR_ALPHA_M_FIELD       2
+
+#define STV090x_FSKRPLTH1                      0xf17e
+#define STV090x_OFFST_FSKR_BETA_FIELD          4
+#define STV090x_WIDTH_FSKR_BETA_FIELD          4
+#define STV090x_OFFST_FSKR_PLL_TRESH1_FIELD    0
+#define STV090x_WIDTH_FSKR_PLL_TRESH1_FIELD    4
+
+#define STV090x_FSKRPLTH0                      0xf17f
+#define STV090x_OFFST_FSKR_PLL_TRESH0_FIELD    0
+#define STV090x_WIDTH_FSKR_PLL_TRESH0_FIELD    8
+
+#define STV090x_FSKRDF1                                0xf180
+#define STV090x_OFFST_FSKR_DELTAF1_FIELD       0
+#define STV090x_WIDTH_FSKR_DELTAF1_FIELD       5
+
+#define STV090x_FSKRDF0                                0xf181
+#define STV090x_OFFST_FSKR_DELTAF0_FIELD       0
+#define STV090x_WIDTH_FSKR_DELTAF0_FIELD       8
+
+#define STV090x_FSKRSTEPP                      0xf182
+#define STV090x_OFFST_FSKR_STEP_PLUS_FIELD     0
+#define STV090x_WIDTH_FSKR_STEP_PLUS_FIELD     8
+
+#define STV090x_FSKRSTEPM                      0xf183
+#define STV090x_OFFST_FSKR_STEP_MINUS_FIELD    0
+#define STV090x_WIDTH_FSKR_STEP_MINUS_FIELD    8
+
+#define STV090x_FSKRDET1                       0xf184
+#define STV090x_OFFST_FSKR_CARDET1_ACCU_FIELD  0
+#define STV090x_WIDTH_FSKR_CARDET1_ACCU_FIELD  4
+
+#define STV090x_FSKRDET0                       0xf185
+#define STV090x_OFFST_FSKR_CARDET0_ACCU_FIELD  0
+#define STV090x_WIDTH_FSKR_CARDET0_ACCU_FIELD  8
+
+#define STV090x_FSKRDTH1                               0xf186
+#define STV090x_OFFST_FSKR_CARLOSS_THRESH1_FIELD       4
+#define STV090x_WIDTH_FSKR_CARLOSS_THRESH1_FIELD       4
+#define STV090x_OFFST_FSKR_CARDET_THRESH1_FIELD                0
+#define STV090x_WIDTH_FSKR_CARDET_THRESH1_FIELD                4
+
+#define STV090x_FSKRDTH0                       0xf187
+#define STV090x_OFFST_FSKR_CARDET_THRESH0_FIELD        0
+#define STV090x_WIDTH_FSKR_CARDET_THRESH0_FIELD        8
+
+#define STV090x_FSKRLOSS                       0xf188
+#define STV090x_OFFST_FSKR_CARLOSS_THRESH_FIELD        0
+#define STV090x_WIDTH_FSKR_CARLOSS_THRESH_FIELD        8
+
+#define STV090x_Px_DISTXCTL(__x)               (0xF1A0 - (__x - 1) * 0x10)
+#define STV090x_P1_DISTXCTL                    STV090x_Px_DISTXCTL(1)
+#define STV090x_P2_DISTXCTL                    STV090x_Px_DISTXCTL(2)
+#define STV090x_OFFST_Px_TIM_OFF_FIELD         7
+#define STV090x_WIDTH_Px_TIM_OFF_FIELD         1
+#define STV090x_OFFST_Px_DISEQC_RESET_FIELD    6
+#define STV090x_WIDTH_Px_DISEQC_RESET_FIELD    1
+#define STV090x_OFFST_Px_TIM_CMD_FIELD         4
+#define STV090x_WIDTH_Px_TIM_CMD_FIELD         2
+#define STV090x_OFFST_Px_DIS_PRECHARGE_FIELD   3
+#define STV090x_WIDTH_Px_DIS_PRECHARGE_FIELD   1
+#define STV090x_OFFST_Px_DISTX_MODE_FIELD      0
+#define STV090x_WIDTH_Px_DISTX_MODE_FIELD      3
+
+#define STV090x_Px_DISRXCTL(__x)               (0xf1a1 - (__x - 1) * 0x10)
+#define STV090x_P1_DISRXCTL                    STV090x_Px_DISRXCTL(1)
+#define STV090x_P2_DISRXCTL                    STV090x_Px_DISRXCTL(2)
+#define STV090x_OFFST_Px_RECEIVER_ON_FIELD     7
+#define STV090x_WIDTH_Px_RECEIVER_ON_FIELD     1
+#define STV090x_OFFST_Px_IGNO_SHORT22K_FIELD   6
+#define STV090x_WIDTH_Px_IGNO_SHORT22K_FIELD   1
+#define STV090x_OFFST_Px_ONECHIP_TRX_FIELD     5
+#define STV090x_WIDTH_Px_ONECHIP_TRX_FIELD     1
+#define STV090x_OFFST_Px_EXT_ENVELOP_FIELD     4
+#define STV090x_WIDTH_Px_EXT_ENVELOP_FIELD     1
+#define STV090x_OFFST_Px_PIN_SELECT_FIELD      2
+#define STV090x_WIDTH_Px_PIN_SELECT_FIELD      2
+#define STV090x_OFFST_Px_IRQ_RXEND_FIELD       1
+#define STV090x_WIDTH_Px_IRQ_RXEND_FIELD       1
+#define STV090x_OFFST_Px_IRQ_4NBYTES_FIELD     0
+#define STV090x_WIDTH_Px_IRQ_4NBYTES_FIELD     1
+
+#define STV090x_Px_DISRX_ST0(__x)              (0xf1a4 - (__x - 1) * 0x10)
+#define STV090x_P1_DISRX_ST0                   STV090x_Px_DISRX_ST0(1)
+#define STV090x_P2_DISRX_ST0                   STV090x_Px_DISRX_ST0(2)
+#define STV090x_OFFST_Px_RX_END_FIELD          7
+#define STV090x_WIDTH_Px_RX_END_FIELD          1
+#define STV090x_OFFST_Px_RX_ACTIVE_FIELD       6
+#define STV090x_WIDTH_Px_RX_ACTIVE_FIELD       1
+#define STV090x_OFFST_Px_SHORT_22KHZ_FIELD     5
+#define STV090x_WIDTH_Px_SHORT_22KHZ_FIELD     1
+#define STV090x_OFFST_Px_CONT_TONE_FIELD       4
+#define STV090x_WIDTH_Px_CONT_TONE_FIELD       1
+#define STV090x_OFFST_Px_FIFO_4BREADY_FIELD    3
+#define STV090x_WIDTH_Px_FIFO_4BREADY_FIELD    2
+#define STV090x_OFFST_Px_FIFO_EMPTY_FIELD      2
+#define STV090x_WIDTH_Px_FIFO_EMPTY_FIELD      1
+#define STV090x_OFFST_Px_ABORT_DISRX_FIELD     0
+#define STV090x_WIDTH_Px_ABORT_DISRX_FIELD     1
+
+#define STV090x_Px_DISRX_ST1(__x)              (0xf1a5 - (__x - 1) * 0x10)
+#define STV090x_P1_DISRX_ST1                   STV090x_Px_DISRX_ST1(1)
+#define STV090x_P2_DISRX_ST1                   STV090x_Px_DISRX_ST1(2)
+#define STV090x_OFFST_Px_RX_FAIL_FIELD         7
+#define STV090x_WIDTH_Px_RX_FAIL_FIELD         1
+#define STV090x_OFFST_Px_FIFO_PARITYFAIL_FIELD 6
+#define STV090x_WIDTH_Px_FIFO_PARITYFAIL_FIELD 1
+#define STV090x_OFFST_Px_RX_NONBYTE_FIELD      5
+#define STV090x_WIDTH_Px_RX_NONBYTE_FIELD      1
+#define STV090x_OFFST_Px_FIFO_OVERFLOW_FIELD   4
+#define STV090x_WIDTH_Px_FIFO_OVERFLOW_FIELD   1
+#define STV090x_OFFST_Px_FIFO_BYTENBR_FIELD    0
+#define STV090x_WIDTH_Px_FIFO_BYTENBR_FIELD    4
+
+#define STV090x_Px_DISRXDATA(__x)              (0xf1a6 - (__x - 1) * 0x10)
+#define STV090x_P1_DISRXDATA                   STV090x_Px_DISRXDATA(1)
+#define STV090x_P2_DISRXDATA                   STV090x_Px_DISRXDATA(2)
+#define STV090x_OFFST_Px_DISRX_DATA_FIELD      0
+#define STV090x_WIDTH_Px_DISRX_DATA_FIELD      8
+
+#define STV090x_Px_DISTXDATA(__x)              (0xf1a7 - (__x - 1) * 0x10)
+#define STV090x_P1_DISTXDATA                   STV090x_Px_DISTXDATA(1)
+#define STV090x_P2_DISTXDATA                   STV090x_Px_DISTXDATA(2)
+#define STV090x_OFFST_Px_DISEQC_FIFO_FIELD     0
+#define STV090x_WIDTH_Px_DISEQC_FIFO_FIELD     8
+
+#define STV090x_Px_DISTXSTATUS(__x)            (0xf1a8 - (__x - 1) * 0x10)
+#define STV090x_P1_DISTXSTATUS                 STV090x_Px_DISTXSTATUS(1)
+#define STV090x_P2_DISTXSTATUS                 STV090x_Px_DISTXSTATUS(2)
+#define STV090x_OFFST_Px_TX_FAIL_FIELD         7
+#define STV090x_WIDTH_Px_TX_FAIL_FIELD         1
+#define STV090x_OFFST_Px_FIFO_FULL_FIELD       6
+#define STV090x_WIDTH_Px_FIFO_FULL_FIELD       1
+#define STV090x_OFFST_Px_TX_IDLE_FIELD         5
+#define STV090x_WIDTH_Px_TX_IDLE_FIELD         1
+#define STV090x_OFFST_Px_GAP_BURST_FIELD       4
+#define STV090x_WIDTH_Px_GAP_BURST_FIELD       1
+#define STV090x_OFFST_Px_TXFIFO_BYTES_FIELD    0
+#define STV090x_WIDTH_Px_TXFIFO_BYTES_FIELD    4
+
+#define STV090x_Px_F22TX(__x)                  (0xf1a9 - (__x - 1) * 0x10)
+#define STV090x_P1_F22TX                       STV090x_Px_F22TX(1)
+#define STV090x_P2_F22TX                       STV090x_Px_F22TX(2)
+#define STV090x_OFFST_Px_F22_REG_FIELD         0
+#define STV090x_WIDTH_Px_F22_REG_FIELD         8
+
+#define STV090x_Px_F22RX(__x)                  (0xf1aa - (__x - 1) * 0x10)
+#define STV090x_P1_F22RX                       STV090x_Px_F22RX(1)
+#define STV090x_P2_F22RX                       STV090x_Px_F22RX(2)
+#define STV090x_OFFST_Px_F22RX_REG_FIELD       0
+#define STV090x_WIDTH_Px_F22RX_REG_FIELD       8
+
+#define STV090x_Px_ACRPRESC(__x)               (0xf1ac - (__x - 1) * 0x10)
+#define STV090x_P1_ACRPRESC                    STV090x_Px_ACRPRESC(1)
+#define STV090x_P2_ACRPRESC                    STV090x_Px_ACRPRESC(2)
+#define STV090x_OFFST_Px_ACR_PRESC_FIELD       0
+#define STV090x_WIDTH_Px_ACR_PRESC_FIELD       3
+
+#define STV090x_Px_ACRDIV(__x)                 (0xf1ad - (__x - 1) * 0x10)
+#define STV090x_P1_ACRDIV                      STV090x_Px_ACRDIV(1)
+#define STV090x_P2_ACRDIV                      STV090x_Px_ACRDIV(2)
+#define STV090x_OFFST_Px_ACR_DIV_FIELD         0
+#define STV090x_WIDTH_Px_ACR_DIV_FIELD         8
+
+#define STV090x_Px_IQCONST(__x)                        (0xF400 - (__x - 1) * 0x200)
+#define STV090x_P1_IQCONST                     STV090x_Px_IQCONST(1)
+#define STV090x_P2_IQCONST                     STV090x_Px_IQCONST(2)
+#define STV090x_OFFST_Px_CONSTEL_SELECT_FIELD  5
+#define STV090x_WIDTH_Px_CONSTEL_SELECT_FIELD  2
+
+#define STV090x_Px_NOSCFG(__x)                 (0xF401 - (__x - 1) * 0x200)
+#define STV090x_P1_NOSCFG                      STV090x_Px_NOSCFG(1)
+#define STV090x_P2_NOSCFG                      STV090x_Px_NOSCFG(2)
+#define STV090x_OFFST_Px_NOSPLH_BETA_FIELD     3
+#define STV090x_WIDTH_Px_NOSPLH_BETA_FIELD     2
+#define STV090x_OFFST_Px_NOSDATA_BETA_FIELD    0
+#define STV090x_WIDTH_Px_NOSDATA_BETA_FIELD    3
+
+#define STV090x_Px_ISYMB(__x)                  (0xF402 - (__x - 1) * 0x200)
+#define STV090x_P1_ISYMB                       STV090x_Px_ISYMB(1)
+#define STV090x_P2_ISYMB                       STV090x_Px_ISYMB(2)
+#define STV090x_OFFST_Px_I_SYMBOL_FIELD                0
+#define STV090x_WIDTH_Px_I_SYMBOL_FIELD                8
+
+#define STV090x_Px_QSYMB(__x)                  (0xF403 - (__x - 1) * 0x200)
+#define STV090x_P1_QSYMB                       STV090x_Px_QSYMB(1)
+#define STV090x_P2_QSYMB                       STV090x_Px_QSYMB(2)
+#define STV090x_OFFST_Px_Q_SYMBOL_FIELD                0
+#define STV090x_WIDTH_Px_Q_SYMBOL_FIELD                8
+
+#define STV090x_Px_AGC1CFG(__x)                        (0xF404 - (__x - 1) * 0x200)
+#define STV090x_P1_AGC1CFG                     STV090x_Px_AGC1CFG(1)
+#define STV090x_P2_AGC1CFG                     STV090x_Px_AGC1CFG(2)
+#define STV090x_OFFST_Px_DC_FROZEN_FIELD       7
+#define STV090x_WIDTH_Px_DC_FROZEN_FIELD       1
+#define STV090x_OFFST_Px_DC_CORRECT_FIELD      6
+#define STV090x_WIDTH_Px_DC_CORRECT_FIELD      1
+#define STV090x_OFFST_Px_AMM_FROZEN_FIELD      5
+#define STV090x_WIDTH_Px_AMM_FROZEN_FIELD      1
+#define STV090x_OFFST_Px_AMM_CORRECT_FIELD     4
+#define STV090x_WIDTH_Px_AMM_CORRECT_FIELD     1
+#define STV090x_OFFST_Px_QUAD_FROZEN_FIELD     3
+#define STV090x_WIDTH_Px_QUAD_FROZEN_FIELD     1
+#define STV090x_OFFST_Px_QUAD_CORRECT_FIELD    2
+#define STV090x_WIDTH_Px_QUAD_CORRECT_FIELD    1
+
+#define STV090x_Px_AGC1CN(__x)                 (0xF406 - (__x - 1) * 0x200)
+#define STV090x_P1_AGC1CN                      STV090x_Px_AGC1CN(1)
+#define STV090x_P2_AGC1CN                      STV090x_Px_AGC1CN(2)
+#define STV090x_WIDTH_Px_AGC1_LOCKED_FIELD     7
+#define STV090x_OFFST_Px_AGC1_LOCKED_FIELD     1
+#define STV090x_OFFST_Px_AGC1_MINPOWER_FIELD   4
+#define STV090x_WIDTH_Px_AGC1_MINPOWER_FIELD   1
+#define STV090x_OFFST_Px_AGCOUT_FAST_FIELD     3
+#define STV090x_WIDTH_Px_AGCOUT_FAST_FIELD     1
+#define STV090x_OFFST_Px_AGCIQ_BETA_FIELD      0
+#define STV090x_WIDTH_Px_AGCIQ_BETA_FIELD      3
+
+#define STV090x_Px_AGC1REF(__x)                        (0xF407 - (__x - 1) * 0x200)
+#define STV090x_P1_AGC1REF                     STV090x_Px_AGC1REF(1)
+#define STV090x_P2_AGC1REF                     STV090x_Px_AGC1REF(2)
+#define STV090x_OFFST_Px_AGCIQ_REF_FIELD       0
+#define STV090x_WIDTH_Px_AGCIQ_REF_FIELD       8
+
+#define STV090x_Px_IDCCOMP(__x)                        (0xF408 - (__x - 1) * 0x200)
+#define STV090x_P1_IDCCOMP                     STV090x_Px_IDCCOMP(1)
+#define STV090x_P2_IDCCOMP                     STV090x_Px_IDCCOMP(2)
+#define STV090x_OFFST_Px_IAVERAGE_ADJ_FIELD    0
+#define STV090x_WIDTH_Px_IAVERAGE_ADJ_FIELD    8
+
+#define STV090x_Px_QDCCOMP(__x)                        (0xF409 - (__x - 1) * 0x200)
+#define STV090x_P1_QDCCOMP                     STV090x_Px_QDCCOMP(1)
+#define STV090x_P2_QDCCOMP                     STV090x_Px_QDCCOMP(2)
+#define STV090x_OFFST_Px_QAVERAGE_ADJ_FIELD    0
+#define STV090x_WIDTH_Px_QAVERAGE_ADJ_FIELD    8
+
+#define STV090x_Px_POWERI(__x)                 (0xF40A - (__x - 1) * 0x200)
+#define STV090x_P1_POWERI                      STV090x_Px_POWERI(1)
+#define STV090x_P2_POWERI                      STV090x_Px_POWERI(2)
+#define STV090x_OFFST_Px_POWER_I_FIELD         0
+#define STV090x_WIDTH_Px_POWER_I_FIELD         8
+
+#define STV090x_Px_POWERQ(__x)                 (0xF40B - (__x - 1) * 0x200)
+#define STV090x_P1_POWERQ                      STV090x_Px_POWERQ(1)
+#define STV090x_P2_POWERQ                      STV090x_Px_POWERQ(2)
+#define STV090x_OFFST_Px_POWER_Q_FIELD         0
+#define STV090x_WIDTH_Px_POWER_Q_FIELD         8
+
+#define STV090x_Px_AGC1AMM(__x)                        (0xF40C - (__x - 1) * 0x200)
+#define STV090x_P1_AGC1AMM                     STV090x_Px_AGC1AMM(1)
+#define STV090x_P2_AGC1AMM                     STV090x_Px_AGC1AMM(2)
+#define STV090x_OFFST_Px_AMM_VALUE_FIELD       0
+#define STV090x_WIDTH_Px_AMM_VALUE_FIELD       8
+
+#define STV090x_Px_AGC1QUAD(__x)               (0xF40D - (__x - 1) * 0x200)
+#define STV090x_P1_AGC1QUAD                    STV090x_Px_AGC1QUAD(1)
+#define STV090x_P2_AGC1QUAD                    STV090x_Px_AGC1QUAD(2)
+#define STV090x_OFFST_Px_QUAD_VALUE_FIELD      0
+#define STV090x_WIDTH_Px_QUAD_VALUE_FIELD      8
+
+#define STV090x_Px_AGCIQINy(__x, __y)          (0xF40F - (__x-1) * 0x200 - __y * 0x1)
+#define STV090x_P1_AGCIQIN0                    STV090x_Px_AGCIQINy(1, 0)
+#define STV090x_P1_AGCIQIN1                    STV090x_Px_AGCIQINy(1, 1)
+#define STV090x_P2_AGCIQIN0                    STV090x_Px_AGCIQINy(2, 0)
+#define STV090x_P2_AGCIQIN1                    STV090x_Px_AGCIQINy(2, 1)
+#define STV090x_OFFST_Px_AGCIQ_VALUE_FIELD     0
+#define STV090x_WIDTH_Px_AGCIQ_VALUE_FIELD     8
+
+#define STV090x_Px_DEMOD(__x)                  (0xF410 - (__x - 1) * 0x200)
+#define STV090x_P1_DEMOD                       STV090x_Px_DEMOD(1)
+#define STV090x_P2_DEMOD                       STV090x_Px_DEMOD(2)
+#define STV090x_OFFST_Px_MANUAL_S2ROLLOFF_FIELD        7
+#define STV090x_WIDTH_Px_MANUAL_S2ROLLOFF_FIELD        1
+#define STV090x_OFFST_Px_DEMOD_STOP_FIELD      6
+#define STV090x_WIDTH_Px_DEMOD_STOP_FIELD      1
+#define STV090x_OFFST_Px_SPECINV_CONTROL_FIELD 4
+#define STV090x_WIDTH_Px_SPECINV_CONTROL_FIELD 2
+#define STV090x_OFFST_Px_FORCE_ENASAMP_FIELD   3
+#define STV090x_WIDTH_Px_FORCE_ENASAMP_FIELD   1
+#define STV090x_OFFST_Px_MANUAL_SXROLLOFF_FIELD        2
+#define STV090x_WIDTH_Px_MANUAL_SXROLLOFF_FIELD        1
+#define STV090x_OFFST_Px_ROLLOFF_CONTROL_FIELD 0
+#define STV090x_WIDTH_Px_ROLLOFF_CONTROL_FIELD 2
+
+#define STV090x_Px_DMDMODCOD(__x)              (0xF411 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDMODCOD                   STV090x_Px_DMDMODCOD(1)
+#define STV090x_P2_DMDMODCOD                   STV090x_Px_DMDMODCOD(2)
+#define STV090x_OFFST_Px_MANUAL_MODCOD_FIELD   7
+#define STV090x_WIDTH_Px_MANUAL_MODCOD_FIELD   1
+#define STV090x_OFFST_Px_DEMOD_MODCOD_FIELD    2
+#define STV090x_WIDTH_Px_DEMOD_MODCOD_FIELD    5
+#define STV090x_OFFST_Px_DEMOD_TYPE_FIELD      0
+#define STV090x_WIDTH_Px_DEMOD_TYPE_FIELD      2
+
+#define STV090x_Px_DSTATUS(__x)                        (0xF412 - (__x - 1) * 0x200)
+#define STV090x_P1_DSTATUS                     STV090x_Px_DSTATUS(1)
+#define STV090x_P2_DSTATUS                     STV090x_Px_DSTATUS(2)
+#define STV090x_OFFST_Px_CAR_LOCK_FIELD                7
+#define STV090x_WIDTH_Px_CAR_LOCK_FIELD                1
+#define STV090x_OFFST_Px_TMGLOCK_QUALITY_FIELD 5
+#define STV090x_WIDTH_Px_TMGLOCK_QUALITY_FIELD 2
+#define STV090x_OFFST_Px_LOCK_DEFINITIF_FIELD  3
+#define STV090x_WIDTH_Px_LOCK_DEFINITIF_FIELD  1
+
+#define STV090x_Px_DSTATUS2(__x)               (0xF413 - (__x - 1) * 0x200)
+#define STV090x_P1_DSTATUS2                    STV090x_Px_DSTATUS2(1)
+#define STV090x_P2_DSTATUS2                    STV090x_Px_DSTATUS2(2)
+#define STV090x_OFFST_Px_DEMOD_DELOCK_FIELD    7
+#define STV090x_WIDTH_Px_DEMOD_DELOCK_FIELD    1
+#define STV090x_OFFST_Px_AGC1_NOSIGNALACK_FIELD        3
+#define STV090x_WIDTH_Px_AGC1_NOSIGNALACK_FIELD        1
+#define STV090x_OFFST_Px_AGC2_OVERFLOW_FIELD   2
+#define STV090x_WIDTH_Px_AGC2_OVERFLOW_FIELD   1
+#define STV090x_OFFST_Px_CFR_OVERFLOW_FIELD    1
+#define STV090x_WIDTH_Px_CFR_OVERFLOW_FIELD    1
+#define STV090x_OFFST_Px_GAMMA_OVERUNDER_FIELD 0
+#define STV090x_WIDTH_Px_GAMMA_OVERUNDER_FIELD 1
+
+#define STV090x_Px_DMDCFGMD(__x)               (0xF414 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDCFGMD                    STV090x_Px_DMDCFGMD(1)
+#define STV090x_P2_DMDCFGMD                    STV090x_Px_DMDCFGMD(2)
+#define STV090x_OFFST_Px_DVBS2_ENABLE_FIELD    7
+#define STV090x_WIDTH_Px_DVBS2_ENABLE_FIELD    1
+#define STV090x_OFFST_Px_DVBS1_ENABLE_FIELD    6
+#define STV090x_WIDTH_Px_DVBS1_ENABLE_FIELD    1
+#define STV090x_OFFST_Px_CFR_AUTOSCAN_FIELD    5 /* check */
+#define STV090x_WIDTH_Px_CFR_AUTOSCAN_FIELD    1
+#define STV090x_OFFST_Px_SCAN_ENABLE_FIELD     4 /* check */
+#define STV090x_WIDTH_Px_SCAN_ENABLE_FIELD     1
+#define STV090x_OFFST_Px_TUN_AUTOSCAN_FIELD    3
+#define STV090x_WIDTH_Px_TUN_AUTOSCAN_FIELD    1
+#define STV090x_OFFST_Px_NOFORCE_RELOCK_FIELD  2
+#define STV090x_WIDTH_Px_NOFORCE_RELOCK_FIELD  1
+#define STV090x_OFFST_Px_TUN_RNG_FIELD         0
+#define STV090x_WIDTH_Px_TUN_RNG_FIELD         2
+
+#define STV090x_Px_DMDCFG2(__x)                        (0xF415 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDCFG2                     STV090x_Px_DMDCFG2(1)
+#define STV090x_P2_DMDCFG2                     STV090x_Px_DMDCFG2(2)
+#define STV090x_OFFST_Px_S1S2_SEQUENTIAL_FIELD 6
+#define STV090x_WIDTH_Px_S1S2_SEQUENTIAL_FIELD 1
+
+#define STV090x_Px_DMDISTATE(__x)              (0xF416 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDISTATE                   STV090x_Px_DMDISTATE(1)
+#define STV090x_P2_DMDISTATE                   STV090x_Px_DMDISTATE(2)
+#define STV090x_OFFST_Px_I2C_DEMOD_MODE_FIELD  0
+#define STV090x_WIDTH_Px_I2C_DEMOD_MODE_FIELD  5
+
+#define STV090x_Px_DMDTOM(__x)                 (0xF417 - (__x - 1) * 0x200) /* check */
+#define STV090x_P1_DMDTOM                      STV090x_Px_DMDTOM(1)
+#define STV090x_P2_DMDTOM                      STV090x_Px_DMDTOM(2)
+
+#define STV090x_Px_DMDSTATE(__x)               (0xF41B - (__x - 1) * 0x200)
+#define STV090x_P1_DMDSTATE                    STV090x_Px_DMDSTATE(1)
+#define STV090x_P2_DMDSTATE                    STV090x_Px_DMDSTATE(2)
+#define STV090x_OFFST_Px_HEADER_MODE_FIELD     5
+#define STV090x_WIDTH_Px_HEADER_MODE_FIELD     2
+
+#define STV090x_Px_DMDFLYW(__x)                        (0xF41C - (__x - 1) * 0x200)
+#define STV090x_P1_DMDFLYW                     STV090x_Px_DMDFLYW(1)
+#define STV090x_P2_DMDFLYW                     STV090x_Px_DMDFLYW(2)
+#define STV090x_OFFST_Px_I2C_IRQVAL_FIELD      4
+#define STV090x_WIDTH_Px_I2C_IRQVAL_FIELD      4
+#define STV090x_OFFST_Px_FLYWHEEL_CPT_FIELD    0 /* check */
+#define STV090x_WIDTH_Px_FLYWHEEL_CPT_FIELD    4
+
+#define STV090x_Px_DSTATUS3(__x)               (0xF41D - (__x - 1) * 0x200)
+#define STV090x_P1_DSTATUS3                    STV090x_Px_DSTATUS3(1)
+#define STV090x_P2_DSTATUS3                    STV090x_Px_DSTATUS3(2)
+#define STV090x_OFFST_Px_DEMOD_CFGMODE_FIELD   5
+#define STV090x_WIDTH_Px_DEMOD_CFGMODE_FIELD   2
+
+#define STV090x_Px_DMDCFG3(__x)                        (0xF41E - (__x - 1) * 0x200)
+#define STV090x_P1_DMDCFG3                     STV090x_Px_DMDCFG3(1)
+#define STV090x_P2_DMDCFG3                     STV090x_Px_DMDCFG3(2)
+#define STV090x_OFFST_Px_NOSTOP_FIFOFULL_FIELD 3
+#define STV090x_WIDTH_Px_NOSTOP_FIFOFULL_FIELD 1
+
+#define STV090x_Px_DMDCFG4(__x)                        (0xf41f - (__x - 1) * 0x200)
+#define STV090x_P1_DMDCFG4                     STV090x_Px_DMDCFG4(1)
+#define STV090x_P2_DMDCFG4                     STV090x_Px_DMDCFG4(2)
+
+#define STV090x_Px_CORRELMANT(__x)             (0xF420 - (__x - 1) * 0x200)
+#define STV090x_P1_CORRELMANT                  STV090x_Px_CORRELMANT(1)
+#define STV090x_P2_CORRELMANT                  STV090x_Px_CORRELMANT(2)
+#define STV090x_OFFST_Px_CORREL_MANT_FIELD     0
+#define STV090x_WIDTH_Px_CORREL_MANT_FIELD     8
+
+#define STV090x_Px_CORRELABS(__x)              (0xF421 - (__x - 1) * 0x200)
+#define STV090x_P1_CORRELABS                   STV090x_Px_CORRELABS(1)
+#define STV090x_P2_CORRELABS                   STV090x_Px_CORRELABS(2)
+#define STV090x_OFFST_Px_CORREL_ABS_FIELD      0
+#define STV090x_WIDTH_Px_CORREL_ABS_FIELD      8
+
+#define STV090x_Px_CORRELEXP(__x)              (0xF422 - (__x - 1) * 0x200)
+#define STV090x_P1_CORRELEXP                   STV090x_Px_CORRELEXP(1)
+#define STV090x_P2_CORRELEXP                   STV090x_Px_CORRELEXP(2)
+#define STV090x_OFFST_Px_CORREL_ABSEXP_FIELD   4
+#define STV090x_WIDTH_Px_CORREL_ABSEXP_FIELD   4
+#define STV090x_OFFST_Px_CORREL_EXP_FIELD      0
+#define STV090x_WIDTH_Px_CORREL_EXP_FIELD      4
+
+#define STV090x_Px_PLHMODCOD(__x)              (0xF424 - (__x - 1) * 0x200)
+#define STV090x_P1_PLHMODCOD                   STV090x_Px_PLHMODCOD(1)
+#define STV090x_P2_PLHMODCOD                   STV090x_Px_PLHMODCOD(2)
+#define STV090x_OFFST_Px_SPECINV_DEMOD_FIELD   7
+#define STV090x_WIDTH_Px_SPECINV_DEMOD_FIELD   1
+#define STV090x_OFFST_Px_PLH_MODCOD_FIELD      2
+#define STV090x_WIDTH_Px_PLH_MODCOD_FIELD      5
+#define STV090x_OFFST_Px_PLH_TYPE_FIELD                0
+#define STV090x_WIDTH_Px_PLH_TYPE_FIELD                2
+
+#define STV090x_Px_AGCK32(__x)                 (0xf42b - (__x - 1) * 0x200)
+#define STV090x_P1_AGCK32                      STV090x_Px_AGCK32(1)
+#define STV090x_P2_AGCK32                      STV090x_Px_AGCK32(2)
+
+#define STV090x_Px_AGC2O(__x)                  (0xF42C - (__x - 1) * 0x200)
+#define STV090x_P1_AGC2O                       STV090x_Px_AGC2O(1)
+#define STV090x_P2_AGC2O                       STV090x_Px_AGC2O(2)
+
+#define STV090x_Px_AGC2REF(__x)                        (0xF42D - (__x - 1) * 0x200)
+#define STV090x_P1_AGC2REF                     STV090x_Px_AGC2REF(1)
+#define STV090x_P2_AGC2REF                     STV090x_Px_AGC2REF(2)
+#define STV090x_OFFST_Px_AGC2_REF_FIELD                0
+#define STV090x_WIDTH_Px_AGC2_REF_FIELD                8
+
+#define STV090x_Px_AGC1ADJ(__x)                        (0xF42E - (__x - 1) * 0x200)
+#define STV090x_P1_AGC1ADJ                     STV090x_Px_AGC1ADJ(1)
+#define STV090x_P2_AGC1ADJ                     STV090x_Px_AGC1ADJ(2)
+#define STV090x_OFFST_Px_AGC1_ADJUSTED_FIELD   0
+#define STV090x_WIDTH_Px_AGC1_ADJUSTED_FIELD   7
+
+#define STV090x_Px_AGC2Iy(__x, __y)            (0xF437 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_AGC2I0                      STV090x_Px_AGC2Iy(1, 0)
+#define STV090x_P1_AGC2I1                      STV090x_Px_AGC2Iy(1, 1)
+#define STV090x_P2_AGC2I0                      STV090x_Px_AGC2Iy(2, 0)
+#define STV090x_P2_AGC2I1                      STV090x_Px_AGC2Iy(2, 1)
+#define STV090x_OFFST_Px_AGC2_INTEGRATOR_FIELD 0
+#define STV090x_WIDTH_Px_AGC2_INTEGRATOR_FIELD 8
+
+#define STV090x_Px_CARCFG(__x)                 (0xF438 - (__x - 1) * 0x200)
+#define STV090x_P1_CARCFG                      STV090x_Px_CARCFG(1)
+#define STV090x_P2_CARCFG                      STV090x_Px_CARCFG(2)
+#define STV090x_OFFST_Px_EN_CAR2CENTER_FIELD   5
+#define STV090x_WIDTH_Px_EN_CAR2CENTER_FIELD   1
+#define STV090x_OFFST_Px_ROTATON_FIELD         2
+#define STV090x_WIDTH_Px_ROTATON_FIELD         1
+#define STV090x_OFFST_Px_PH_DET_ALGO_FIELD     0
+#define STV090x_WIDTH_Px_PH_DET_ALGO_FIELD     2
+
+#define STV090x_Px_ACLC(__x)                   (0xF439 - (__x - 1) * 0x200)
+#define STV090x_P1_ACLC                                STV090x_Px_ACLC(1)
+#define STV090x_P2_ACLC                                STV090x_Px_ACLC(2)
+#define STV090x_OFFST_Px_CAR_ALPHA_MANT_FIELD  4
+#define STV090x_WIDTH_Px_CAR_ALPHA_MANT_FIELD  2
+#define STV090x_OFFST_Px_CAR_ALPHA_EXP_FIELD   0
+#define STV090x_WIDTH_Px_CAR_ALPHA_EXP_FIELD   4
+
+#define STV090x_Px_BCLC(__x)                   (0xF43A - (__x - 1) * 0x200)
+#define STV090x_P1_BCLC                                STV090x_Px_BCLC(1)
+#define STV090x_P2_BCLC                                STV090x_Px_BCLC(2)
+#define STV090x_OFFST_Px_CAR_BETA_MANT_FIELD   4
+#define STV090x_WIDTH_Px_CAR_BETA_MANT_FIELD   2
+#define STV090x_OFFST_Px_CAR_BETA_EXP_FIELD    0
+#define STV090x_WIDTH_Px_CAR_BETA_EXP_FIELD    4
+
+#define STV090x_Px_CARFREQ(__x)                        (0xF43D - (__x - 1) * 0x200)
+#define STV090x_P1_CARFREQ                     STV090x_Px_CARFREQ(1)
+#define STV090x_P2_CARFREQ                     STV090x_Px_CARFREQ(2)
+#define STV090x_OFFST_Px_KC_COARSE_EXP_FIELD   4
+#define STV090x_WIDTH_Px_KC_COARSE_EXP_FIELD   4
+#define STV090x_OFFST_Px_BETA_FREQ_FIELD       0
+#define STV090x_WIDTH_Px_BETA_FREQ_FIELD       4
+
+#define STV090x_Px_CARHDR(__x)                 (0xF43E - (__x - 1) * 0x200)
+#define STV090x_P1_CARHDR                      STV090x_Px_CARHDR(1)
+#define STV090x_P2_CARHDR                      STV090x_Px_CARHDR(2)
+#define STV090x_OFFST_Px_FREQ_HDR_FIELD                0
+#define STV090x_WIDTH_Px_FREQ_HDR_FIELD                8
+
+#define STV090x_Px_LDT(__x)                    (0xF43F - (__x - 1) * 0x200)
+#define STV090x_P1_LDT                         STV090x_Px_LDT(1)
+#define STV090x_P2_LDT                         STV090x_Px_LDT(2)
+#define STV090x_OFFST_Px_CARLOCK_THRES_FIELD   0
+#define STV090x_WIDTH_Px_CARLOCK_THRES_FIELD   8
+
+#define STV090x_Px_LDT2(__x)                   (0xF440 - (__x - 1) * 0x200)
+#define STV090x_P1_LDT2                                STV090x_Px_LDT2(1)
+#define STV090x_P2_LDT2                                STV090x_Px_LDT2(2)
+#define STV090x_OFFST_Px_CARLOCK_THRES2_FIELD  0
+#define STV090x_WIDTH_Px_CARLOCK_THRES2_FIELD  8
+
+#define STV090x_Px_CFRICFG(__x)                        (0xF441 - (__x - 1) * 0x200)
+#define STV090x_P1_CFRICFG                     STV090x_Px_CFRICFG(1)
+#define STV090x_P2_CFRICFG                     STV090x_Px_CFRICFG(2)
+#define STV090x_OFFST_Px_NEG_CFRSTEP_FIELD     0
+#define STV090x_WIDTH_Px_NEG_CFRSTEP_FIELD     1
+
+#define STV090x_Pn_CFRUPy(__x, __y)            (0xF443 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_CFRUP0                      STV090x_Pn_CFRUPy(1, 0)
+#define STV090x_P1_CFRUP1                      STV090x_Pn_CFRUPy(1, 1)
+#define STV090x_P2_CFRUP0                      STV090x_Pn_CFRUPy(2, 0)
+#define STV090x_P2_CFRUP1                      STV090x_Pn_CFRUPy(2, 1)
+#define STV090x_OFFST_Px_CFR_UP_FIELD          0
+#define STV090x_WIDTH_Px_CFR_UP_FIELD          8
+
+#define STV090x_Pn_CFRLOWy(__x, __y)           (0xF447 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_CFRLOW0                     STV090x_Pn_CFRLOWy(1, 0)
+#define STV090x_P1_CFRLOW1                     STV090x_Pn_CFRLOWy(1, 1)
+#define STV090x_P2_CFRLOW0                     STV090x_Pn_CFRLOWy(2, 0)
+#define STV090x_P2_CFRLOW1                     STV090x_Pn_CFRLOWy(2, 1)
+#define STV090x_OFFST_Px_CFR_LOW_FIELD         0
+#define STV090x_WIDTH_Px_CFR_LOW_FIELD         8
+
+#define STV090x_Pn_CFRINITy(__x, __y)          (0xF449 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_CFRINIT0                    STV090x_Pn_CFRINITy(1, 0)
+#define STV090x_P1_CFRINIT1                    STV090x_Pn_CFRINITy(1, 1)
+#define STV090x_P2_CFRINIT0                    STV090x_Pn_CFRINITy(2, 0)
+#define STV090x_P2_CFRINIT1                    STV090x_Pn_CFRINITy(2, 1)
+#define STV090x_OFFST_Px_CFR_INIT_FIELD                0
+#define STV090x_WIDTH_Px_CFR_INIT_FIELD                8
+
+#define STV090x_Px_CFRINC1(__x)                        (0xF44A - (__x - 1) * 0x200)
+#define STV090x_P1_CFRINC1                     STV090x_Px_CFRINC1(1)
+#define STV090x_P2_CFRINC1                     STV090x_Px_CFRINC1(2)
+#define STV090x_OFFST_Px_CFR_INC1_FIELD                0
+#define STV090x_WIDTH_Px_CFR_INC1_FIELD                7
+
+#define STV090x_Px_CFRINC0(__x)                        (0xF44B - (__x - 1) * 0x200)
+#define STV090x_P1_CFRINC0                     STV090x_Px_CFRINC0(1)
+#define STV090x_P2_CFRINC0                     STV090x_Px_CFRINC0(2)
+#define STV090x_OFFST_Px_CFR_INC0_FIELD                4
+#define STV090x_WIDTH_Px_CFR_INC0_FIELD                4
+
+#define STV090x_Pn_CFRy(__x, __y)              (0xF44E - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_CFR0                                STV090x_Pn_CFRy(1, 0)
+#define STV090x_P1_CFR1                                STV090x_Pn_CFRy(1, 1)
+#define STV090x_P1_CFR2                                STV090x_Pn_CFRy(1, 2)
+#define STV090x_P2_CFR0                                STV090x_Pn_CFRy(2, 0)
+#define STV090x_P2_CFR1                                STV090x_Pn_CFRy(2, 1)
+#define STV090x_P2_CFR2                                STV090x_Pn_CFRy(2, 2)
+#define STV090x_OFFST_Px_CAR_FREQ_FIELD                0
+#define STV090x_WIDTH_Px_CAR_FREQ_FIELD                8
+
+#define STV090x_Px_LDI(__x)                    (0xF44F - (__x - 1) * 0x200)
+#define STV090x_P1_LDI                         STV090x_Px_LDI(1)
+#define STV090x_P2_LDI                         STV090x_Px_LDI(2)
+#define STV090x_OFFST_Px_LOCK_DET_INTEGR_FIELD 0
+#define STV090x_WIDTH_Px_LOCK_DET_INTEGR_FIELD 8
+
+#define STV090x_Px_TMGCFG(__x)                 (0xF450 - (__x - 1) * 0x200)
+#define STV090x_P1_TMGCFG                      STV090x_Px_TMGCFG(1)
+#define STV090x_P2_TMGCFG                      STV090x_Px_TMGCFG(2)
+#define STV090x_OFFST_Px_TMGLOCK_BETA_FIELD    6
+#define STV090x_WIDTH_Px_TMGLOCK_BETA_FIELD    2
+#define STV090x_OFFST_Px_DO_TIMING_FIELD       4
+#define STV090x_WIDTH_Px_DO_TIMING_FIELD       1
+#define STV090x_OFFST_Px_TMG_MINFREQ_FIELD     0
+#define STV090x_WIDTH_Px_TMG_MINFREQ_FIELD     2
+
+#define STV090x_Px_RTC(__x)                    (0xF451 - (__x - 1) * 0x200)
+#define STV090x_P1_RTC                         STV090x_Px_RTC(1)
+#define STV090x_P2_RTC                         STV090x_Px_RTC(2)
+#define STV090x_OFFST_Px_TMGALPHA_EXP_FIELD    4
+#define STV090x_WIDTH_Px_TMGALPHA_EXP_FIELD    4
+#define STV090x_OFFST_Px_TMGBETA_EXP_FIELD     0
+#define STV090x_WIDTH_Px_TMGBETA_EXP_FIELD     4
+
+#define STV090x_Px_RTCS2(__x)                  (0xF452 - (__x - 1) * 0x200)
+#define STV090x_P1_RTCS2                       STV090x_Px_RTCS2(1)
+#define STV090x_P2_RTCS2                       STV090x_Px_RTCS2(2)
+#define STV090x_OFFST_Px_TMGALPHAS2_EXP_FIELD  4
+#define STV090x_WIDTH_Px_TMGALPHAS2_EXP_FIELD  4
+#define STV090x_OFFST_Px_TMGBETAS2_EXP_FIELD   0
+#define STV090x_WIDTH_Px_TMGBETAS2_EXP_FIELD   4
+
+#define STV090x_Px_TMGTHRISE(__x)              (0xF453 - (__x - 1) * 0x200)
+#define STV090x_P1_TMGTHRISE                   STV090x_Px_TMGTHRISE(1)
+#define STV090x_P2_TMGTHRISE                   STV090x_Px_TMGTHRISE(2)
+#define STV090x_OFFST_Px_TMGLOCK_THRISE_FIELD  0
+#define STV090x_WIDTH_Px_TMGLOCK_THRISE_FIELD  8
+
+#define STV090x_Px_TMGTHFALL(__x)              (0xF454 - (__x - 1) * 0x200)
+#define STV090x_P1_TMGTHFALL                   STV090x_Px_TMGTHFALL(1)
+#define STV090x_P2_TMGTHFALL                   STV090x_Px_TMGTHFALL(2)
+#define STV090x_OFFST_Px_TMGLOCK_THFALL_FIELD  0
+#define STV090x_WIDTH_Px_TMGLOCK_THFALL_FIELD  8
+
+#define STV090x_Px_SFRUPRATIO(__x)             (0xF455 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRUPRATIO                  STV090x_Px_SFRUPRATIO(1)
+#define STV090x_P2_SFRUPRATIO                  STV090x_Px_SFRUPRATIO(2)
+#define STV090x_OFFST_Px_SFR_UPRATIO_FIELD     0
+#define STV090x_WIDTH_Px_SFR_UPRATIO_FIELD     8
+
+#define STV090x_Px_SFRLOWRATIO(__x)            (0xF456 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRLOWRATIO                 STV090x_Px_SFRLOWRATIO(1)
+#define STV090x_P2_SFRLOWRATIO                 STV090x_Px_SFRLOWRATIO(2)
+#define STV090x_OFFST_Px_SFR_LOWRATIO_FIELD    0
+#define STV090x_WIDTH_Px_SFR_LOWRATIO_FIELD    8
+
+#define STV090x_Px_KREFTMG(__x)                        (0xF458 - (__x - 1) * 0x200)
+#define STV090x_P1_KREFTMG                     STV090x_Px_KREFTMG(1)
+#define STV090x_P2_KREFTMG                     STV090x_Px_KREFTMG(2)
+#define STV090x_OFFST_Px_KREF_TMG_FIELD                0
+#define STV090x_WIDTH_Px_KREF_TMG_FIELD                8
+
+#define STV090x_Px_SFRSTEP(__x)                        (0xF459 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRSTEP                     STV090x_Px_SFRSTEP(1)
+#define STV090x_P2_SFRSTEP                     STV090x_Px_SFRSTEP(2)
+#define STV090x_OFFST_Px_SFR_SCANSTEP_FIELD    4
+#define STV090x_WIDTH_Px_SFR_SCANSTEP_FIELD    4
+#define STV090x_OFFST_Px_SFR_CENTERSTEP_FIELD  0
+#define STV090x_WIDTH_Px_SFR_CENTERSTEP_FIELD  4
+
+#define STV090x_Px_TMGCFG2(__x)                        (0xF45A - (__x - 1) * 0x200)
+#define STV090x_P1_TMGCFG2                     STV090x_Px_TMGCFG2(1)
+#define STV090x_P2_TMGCFG2                     STV090x_Px_TMGCFG2(2)
+#define STV090x_OFFST_Px_SFRRATIO_FINE_FIELD   0
+#define STV090x_WIDTH_Px_SFRRATIO_FINE_FIELD   1
+
+#define STV090x_Px_SFRINIT1(__x)               (0xF45E - (__x - 1) * 0x200)
+#define STV090x_P1_SFRINIT1                    STV090x_Px_SFRINIT1(1)
+#define STV090x_P2_SFRINIT1                    STV090x_Px_SFRINIT1(2)
+#define STV090x_OFFST_Px_SFR_INIT_FIELD                0
+#define STV090x_WIDTH_Px_SFR_INIT_FIELD                8
+
+#define STV090x_Px_SFRINIT0(__x)               (0xF45F - (__x - 1) * 0x200)
+#define STV090x_P1_SFRINIT0                    STV090x_Px_SFRINIT0(1)
+#define STV090x_P2_SFRINIT0                    STV090x_Px_SFRINIT0(2)
+#define STV090x_OFFST_Px_SFR_INIT_FIELD                0
+#define STV090x_WIDTH_Px_SFR_INIT_FIELD                8
+
+#define STV090x_Px_SFRUP1(__x)                 (0xF460 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRUP1                      STV090x_Px_SFRUP1(1)
+#define STV090x_P2_SFRUP1                      STV090x_Px_SFRUP1(2)
+#define STV090x_OFFST_Px_SYMB_FREQ_UP1_FIELD   0
+#define STV090x_WIDTH_Px_SYMB_FREQ_UP1_FIELD   7
+
+#define STV090x_Px_SFRUP0(__x)                 (0xF461 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRUP0                      STV090x_Px_SFRUP0(1)
+#define STV090x_P2_SFRUP0                      STV090x_Px_SFRUP0(2)
+#define STV090x_OFFST_Px_SYMB_FREQ_UP0_FIELD   0
+#define STV090x_WIDTH_Px_SYMB_FREQ_UP0_FIELD   8
+
+#define STV090x_Px_SFRLOW1(__x)                        (0xF462 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRLOW1                     STV090x_Px_SFRLOW1(1)
+#define STV090x_P2_SFRLOW1                     STV090x_Px_SFRLOW1(2)
+#define STV090x_OFFST_Px_SYMB_FREQ_LOW1_FIELD  0
+#define STV090x_WIDTH_Px_SYMB_FREQ_LOW1_FIELD  7
+
+#define STV090x_Px_SFRLOW0(__x)                        (0xF463 - (__x - 1) * 0x200)
+#define STV090x_P1_SFRLOW0                     STV090x_Px_SFRLOW0(1)
+#define STV090x_P2_SFRLOW0                     STV090x_Px_SFRLOW0(2)
+#define STV090x_OFFST_Px_SYMB_FREQ_LOW0_FIELD  0
+#define STV090x_WIDTH_Px_SYMB_FREQ_LOW0_FIELD  8
+
+#define STV090x_Px_SFRy(__x, __y)              (0xF464 - (__x-1) * 0x200 + (3 - __y))
+#define STV090x_P1_SFR0                                STV090x_Px_SFRy(1, 0)
+#define STV090x_P1_SFR1                                STV090x_Px_SFRy(1, 1)
+#define STV090x_P1_SFR2                                STV090x_Px_SFRy(1, 2)
+#define STV090x_P1_SFR3                                STV090x_Px_SFRy(1, 3)
+#define STV090x_P2_SFR0                                STV090x_Px_SFRy(2, 0)
+#define STV090x_P2_SFR1                                STV090x_Px_SFRy(2, 1)
+#define STV090x_P2_SFR2                                STV090x_Px_SFRy(2, 2)
+#define STV090x_P2_SFR3                                STV090x_Px_SFRy(2, 3)
+#define STV090x_OFFST_Px_SYMB_FREQ_FIELD       0
+#define STV090x_WIDTH_Px_SYMB_FREQ_FIELD       32
+
+#define STV090x_Px_TMGREG2(__x)                        (0xF468 - (__x - 1) * 0x200)
+#define STV090x_P1_TMGREG2                     STV090x_Px_TMGREG2(1)
+#define STV090x_P2_TMGREG2                     STV090x_Px_TMGREG2(2)
+#define STV090x_OFFST_Px_TMGREG_FIELD          0
+#define STV090x_WIDTH_Px_TMGREG_FIELD          8
+
+#define STV090x_Px_TMGREG1(__x)                        (0xF469 - (__x - 1) * 0x200)
+#define STV090x_P1_TMGREG1                     STV090x_Px_TMGREG1(1)
+#define STV090x_P2_TMGREG1                             STV090x_Px_TMGREG1(2)
+#define STV090x_OFFST_Px_TMGREG_FIELD          0
+#define STV090x_WIDTH_Px_TMGREG_FIELD          8
+
+#define STV090x_Px_TMGREG0(__x)                        (0xF46A - (__x - 1) * 0x200)
+#define STV090x_P1_TMGREG0                     STV090x_Px_TMGREG0(1)
+#define STV090x_P2_TMGREG0                     STV090x_Px_TMGREG0(2)
+#define STV090x_OFFST_Px_TMGREG_FIELD          0
+#define STV090x_WIDTH_Px_TMGREG_FIELD          8
+
+#define STV090x_Px_TMGLOCKy(__x, __y)          (0xF46C - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_TMGLOCK0                    STV090x_Px_TMGLOCKy(1, 0)
+#define STV090x_P1_TMGLOCK1                    STV090x_Px_TMGLOCKy(1, 1)
+#define STV090x_P2_TMGLOCK0                    STV090x_Px_TMGLOCKy(2, 0)
+#define STV090x_P2_TMGLOCK1                    STV090x_Px_TMGLOCKy(2, 1)
+#define STV090x_OFFST_Px_TMGLOCK_LEVEL_FIELD   0
+#define STV090x_WIDTH_Px_TMGLOCK_LEVEL_FIELD   8
+
+#define STV090x_Px_TMGOBS(__x)                 (0xF46D - (__x - 1) * 0x200)
+#define STV090x_P1_TMGOBS                      STV090x_Px_TMGOBS(1)
+#define STV090x_P2_TMGOBS                      STV090x_Px_TMGOBS(2)
+#define STV090x_OFFST_Px_ROLLOFF_STATUS_FIELD  6
+#define STV090x_WIDTH_Px_ROLLOFF_STATUS_FIELD  2
+
+#define STV090x_Px_EQUALCFG(__x)               (0xF46F - (__x - 1) * 0x200)
+#define STV090x_P1_EQUALCFG                    STV090x_Px_EQUALCFG(1)
+#define STV090x_P2_EQUALCFG                    STV090x_Px_EQUALCFG(2)
+#define STV090x_OFFST_Px_EQUAL_ON_FIELD                6
+#define STV090x_WIDTH_Px_EQUAL_ON_FIELD                1
+#define STV090x_OFFST_Px_MU_EQUALDFE_FIELD     0
+#define STV090x_WIDTH_Px_MU_EQUALDFE_FIELD     3
+
+#define STV090x_Px_EQUAIy(__x, __y)            (0xf470 - (__x - 1) * 0x200 + (__y - 1))
+#define STV090x_P1_EQUAI1                      STV090x_Px_EQUAIy(1, 1)
+#define STV090x_P1_EQUAI2                      STV090x_Px_EQUAIy(1, 2)
+#define STV090x_P1_EQUAI3                      STV090x_Px_EQUAIy(1, 3)
+#define STV090x_P1_EQUAI4                      STV090x_Px_EQUAIy(1, 4)
+#define STV090x_P1_EQUAI5                      STV090x_Px_EQUAIy(1, 5)
+#define STV090x_P1_EQUAI6                      STV090x_Px_EQUAIy(1, 6)
+#define STV090x_P1_EQUAI7                      STV090x_Px_EQUAIy(1, 7)
+#define STV090x_P1_EQUAI8                      STV090x_Px_EQUAIy(1, 8)
+
+#define STV090x_P2_EQUAI1                      STV090x_Px_EQUAIy(2, 1)
+#define STV090x_P2_EQUAI2                      STV090x_Px_EQUAIy(2, 2)
+#define STV090x_P2_EQUAI3                      STV090x_Px_EQUAIy(2, 3)
+#define STV090x_P2_EQUAI4                      STV090x_Px_EQUAIy(2, 4)
+#define STV090x_P2_EQUAI5                      STV090x_Px_EQUAIy(2, 5)
+#define STV090x_P2_EQUAI6                      STV090x_Px_EQUAIy(2, 6)
+#define STV090x_P2_EQUAI7                      STV090x_Px_EQUAIy(2, 7)
+#define STV090x_P2_EQUAI8                      STV090x_Px_EQUAIy(2, 8)
+#define STV090x_OFFST_Px_EQUA_ACCIy_FIELD      0
+#define STV090x_WIDTH_Px_EQUA_ACCIy_FIELD      8
+
+#define STV090x_Px_EQUAQy(__x, __y)            (0xf471 - (__x - 1) * 0x200 + (__y - 1))
+#define STV090x_P1_EQUAQ1                      STV090x_Px_EQUAQy(1, 1)
+#define STV090x_P1_EQUAQ2                      STV090x_Px_EQUAQy(1, 2)
+#define STV090x_P1_EQUAQ3                      STV090x_Px_EQUAQy(1, 3)
+#define STV090x_P1_EQUAQ4                      STV090x_Px_EQUAQy(1, 4)
+#define STV090x_P1_EQUAQ5                      STV090x_Px_EQUAQy(1, 5)
+#define STV090x_P1_EQUAQ6                      STV090x_Px_EQUAQy(1, 6)
+#define STV090x_P1_EQUAQ7                      STV090x_Px_EQUAQy(1, 7)
+#define STV090x_P1_EQUAQ8                      STV090x_Px_EQUAQy(1, 8)
+
+#define STV090x_P2_EQUAQ1                      STV090x_Px_EQUAQy(2, 1)
+#define STV090x_P2_EQUAQ2                      STV090x_Px_EQUAQy(2, 2)
+#define STV090x_P2_EQUAQ3                      STV090x_Px_EQUAQy(2, 3)
+#define STV090x_P2_EQUAQ4                      STV090x_Px_EQUAQy(2, 4)
+#define STV090x_P2_EQUAQ5                      STV090x_Px_EQUAQy(2, 5)
+#define STV090x_P2_EQUAQ6                      STV090x_Px_EQUAQy(2, 6)
+#define STV090x_P2_EQUAQ7                      STV090x_Px_EQUAQy(2, 7)
+#define STV090x_P2_EQUAQ8                      STV090x_Px_EQUAQy(2, 8)
+#define STV090x_OFFST_Px_EQUA_ACCQy_FIELD      0
+#define STV090x_WIDTH_Px_EQUA_ACCQy_FIELD      8
+
+#define STV090x_Px_NNOSDATATy(__x, __y)                (0xf481 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NNOSDATAT0                  STV090x_Px_NNOSDATATy(1, 0)
+#define STV090x_P1_NNOSDATAT1                  STV090x_Px_NNOSDATATy(1, 1)
+#define STV090x_P2_NNOSDATAT0                  STV090x_Px_NNOSDATATy(2, 0)
+#define STV090x_P2_NNOSDATAT1                  STV090x_Px_NNOSDATATy(2, 1)
+#define STV090x_OFFST_Px_NOSDATAT_NORMED_FIELD 0
+#define STV090x_WIDTH_Px_NOSDATAT_NORMED_FIELD 8
+
+#define STV090x_Px_NNOSDATAy(__x, __y)         (0xf483 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NNOSDATA0                   STV090x_Px_NNOSDATAy(1, 0)
+#define STV090x_P1_NNOSDATA1                   STV090x_Px_NNOSDATAy(1, 1)
+#define STV090x_P2_NNOSDATA0                   STV090x_Px_NNOSDATAy(2, 0)
+#define STV090x_P2_NNOSDATA1                   STV090x_Px_NNOSDATAy(2, 1)
+#define STV090x_OFFST_Px_NOSDATA_NORMED_FIELD  0
+#define STV090x_WIDTH_Px_NOSDATA_NORMED_FIELD  8
+
+#define STV090x_Px_NNOSPLHTy(__x, __y)         (0xf485 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NNOSPLHT0                   STV090x_Px_NNOSPLHTy(1, 0)
+#define STV090x_P1_NNOSPLHT1                   STV090x_Px_NNOSPLHTy(1, 1)
+#define STV090x_P2_NNOSPLHT0                   STV090x_Px_NNOSPLHTy(2, 0)
+#define STV090x_P2_NNOSPLHT1                   STV090x_Px_NNOSPLHTy(2, 1)
+#define STV090x_OFFST_Px_NOSPLHT_NORMED_FIELD  0
+#define STV090x_WIDTH_Px_NOSPLHT_NORMED_FIELD  8
+
+#define STV090x_Px_NNOSPLHy(__x, __y)          (0xf487 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NNOSPLH0                    STV090x_Px_NNOSPLHy(1, 0)
+#define STV090x_P1_NNOSPLH1                    STV090x_Px_NNOSPLHy(1, 1)
+#define STV090x_P2_NNOSPLH0                    STV090x_Px_NNOSPLHy(2, 0)
+#define STV090x_P2_NNOSPLH1                    STV090x_Px_NNOSPLHy(2, 1)
+#define STV090x_OFFST_Px_NOSPLH_NORMED_FIELD   0
+#define STV090x_WIDTH_Px_NOSPLH_NORMED_FIELD   8
+
+#define STV090x_Px_NOSDATATy(__x, __y)                 (0xf489 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NOSDATAT0                           STV090x_Px_NOSDATATy(1, 0)
+#define STV090x_P1_NOSDATAT1                           STV090x_Px_NOSDATATy(1, 1)
+#define STV090x_P2_NOSDATAT0                           STV090x_Px_NOSDATATy(2, 0)
+#define STV090x_P2_NOSDATAT1                           STV090x_Px_NOSDATATy(2, 1)
+#define STV090x_OFFST_Px_NOSDATAT_UNNORMED_FIELD       0
+#define STV090x_WIDTH_Px_NOSDATAT_UNNORMED_FIELD       8
+
+#define STV090x_Px_NOSDATAy(__x, __y)          (0xf48b - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NOSDATA0                    STV090x_Px_NOSDATAy(1, 0)
+#define STV090x_P1_NOSDATA1                    STV090x_Px_NOSDATAy(1, 1)
+#define STV090x_P2_NOSDATA0                    STV090x_Px_NOSDATAy(2, 0)
+#define STV090x_P2_NOSDATA1                    STV090x_Px_NOSDATAy(2, 1)
+#define STV090x_OFFST_Px_NOSDATA_UNNORMED_FIELD        0
+#define STV090x_WIDTH_Px_NOSDATA_UNNORMED_FIELD        8
+
+#define STV090x_Px_NOSPLHTy(__x, __y)          (0xf48d - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_NOSPLHT0                    STV090x_Px_NOSPLHTy(1, 0)
+#define STV090x_P1_NOSPLHT1                    STV090x_Px_NOSPLHTy(1, 1)
+#define STV090x_P2_NOSPLHT0                    STV090x_Px_NOSPLHTy(2, 0)
+#define STV090x_P2_NOSPLHT1                    STV090x_Px_NOSPLHTy(2, 1)
+#define STV090x_OFFST_Px_NOSPLHT_UNNORMED_FIELD        0
+#define STV090x_WIDTH_Px_NOSPLHT_UNNORMED_FIELD        8
+
+#define STV090x_Px_NOSPLHy(__x, __y)           (0xf48f - (__x - 1) * 0x200 - __y * 0x1)
+#define STv090x_P1_NOSPLH0                     STV090x_Px_NOSPLHy(1, 0)
+#define STv090x_P1_NOSPLH1                     STV090x_Px_NOSPLHy(1, 1)
+#define STv090x_P2_NOSPLH0                     STV090x_Px_NOSPLHy(2, 0)
+#define STv090x_P2_NOSPLH1                     STV090x_Px_NOSPLHy(2, 1)
+#define STV090x_OFFST_Px_NOSPLH_UNNORMED_FIELD 0
+#define STV090x_WIDTH_Px_NOSPLH_UNNORMED_FIELD 8
+
+#define STV090x_Px_CAR2CFG(__x)                        (0xf490 - (__x - 1) * 0x200)
+#define STV090x_P1_CAR2CFG                     STV090x_Px_CAR2CFG(1)
+#define STV090x_P2_CAR2CFG                     STV090x_Px_CAR2CFG(2)
+#define STV090x_OFFST_Px_PN4_SELECT_FIELD      6
+#define STV090x_WIDTH_Px_PN4_SELECT_FIELD      1
+#define STV090x_OFFST_Px_CFR2_STOPDVBS1_FIELD  5
+#define STV090x_WIDTH_Px_CFR2_STOPDVBS1_FIELD  1
+#define STV090x_OFFST_Px_ROTA2ON_FIELD         2
+#define STV090x_WIDTH_Px_ROTA2ON_FIELD         1
+#define STV090x_OFFST_Px_PH_DET_ALGO2_FIELD    0
+#define STV090x_WIDTH_Px_PH_DET_ALGO2_FIELD    2
+
+#define STV090x_Px_ACLC2(__x)                  (0xf491 - (__x - 1) * 0x200)
+#define STV090x_P1_ACLC2                       STV090x_Px_ACLC2(1)
+#define STV090x_P2_ACLC2                       STV090x_Px_ACLC2(2)
+#define STV090x_OFFST_Px_CAR2_ALPHA_MANT_FIELD 4
+#define STV090x_WIDTH_Px_CAR2_ALPHA_MANT_FIELD 2
+#define STV090x_OFFST_Px_CAR2_ALPHA_EXP_FIELD  0
+#define STV090x_WIDTH_Px_CAR2_ALPHA_EXP_FIELD  4
+
+#define STV090x_Px_BCLC2(__x)                  (0xf492 - (__x - 1) * 0x200)
+#define STV090x_P1_BCLC2                       STV090x_Px_BCLC2(1)
+#define STV090x_P2_BCLC2                       STV090x_Px_BCLC2(2)
+#define STV090x_OFFST_Px_CAR2_BETA_MANT_FIELD  4
+#define STV090x_WIDTH_Px_CAR2_BETA_MANT_FIELD  2
+#define STV090x_OFFST_Px_CAR2_BETA_EXP_FIELD   0
+#define STV090x_WIDTH_Px_CAR2_BETA_EXP_FIELD   4
+
+#define STV090x_Px_ACLC2S2Q(__x)               (0xf497 - (__x - 1) * 0x200)
+#define STV090x_P1_ACLC2S2Q                    STV090x_Px_ACLC2S2Q(1)
+#define STV090x_P2_ACLC2S2Q                    STV090x_Px_ACLC2S2Q(2)
+#define STV090x_OFFST_Px_ENAB_SPSKSYMB_FIELD   7
+#define STV090x_WIDTH_Px_ENAB_SPSKSYMB_FIELD   1
+#define STV090x_OFFST_Px_CAR2S2_Q_ALPH_M_FIELD 4
+#define STV090x_WIDTH_Px_CAR2S2_Q_ALPH_M_FIELD 2
+#define STV090x_OFFST_Px_CAR2S2_Q_ALPH_E_FIELD 0
+#define STV090x_WIDTH_Px_CAR2S2_Q_ALPH_E_FIELD 4
+
+#define STV090x_Px_ACLC2S28(__x)               (0xf498 - (__x - 1) * 0x200)
+#define STV090x_P1_ACLC2S28                    STV090x_Px_ACLC2S28(1)
+#define STV090x_P2_ACLC2S28                    STV090x_Px_ACLC2S28(2)
+#define STV090x_OFFST_Px_CAR2S2_8_ALPH_M_FIELD 4
+#define STV090x_WIDTH_Px_CAR2S2_8_ALPH_M_FIELD 2
+#define STV090x_OFFST_Px_CAR2S2_8_ALPH_E_FIELD 0
+#define STV090x_WIDTH_Px_CAR2S2_8_ALPH_E_FIELD 4
+
+#define STV090x_Px_ACLC2S216A(__x)             (0xf499 - (__x - 1) * 0x200)
+#define STV090x_P1_ACLC2S216A                  STV090x_Px_ACLC2S216A(1)
+#define STV090x_P2_ACLC2S216A                  STV090x_Px_ACLC2S216A(2)
+#define STV090x_OFFST_Px_CAR2S2_16A_ALPH_M_FIELD       4
+#define STV090x_WIDTH_Px_CAR2S2_16A_ALPH_M_FIELD       2
+#define STV090x_OFFST_Px_CAR2S2_16A_ALPH_E_FIELD       0
+#define STV090x_WIDTH_Px_CAR2S2_16A_ALPH_E_FIELD       4
+
+#define STV090x_Px_ACLC2S232A(__x)             (0xf499 - (__x - 1) * 0x200)
+#define STV090x_P1_ACLC2S232A                  STV090x_Px_ACLC2S232A(1)
+#define STV090x_P2_ACLC2S232A                  STV090x_Px_ACLC2S232A(2)
+#define STV090x_OFFST_Px_CAR2S2_32A_ALPH_M_FIELD       4
+#define STV090x_WIDTH_Px_CAR2S2_32A_ALPH_M_FIELD       2
+#define STV090x_OFFST_Px_CAR2S2_32A_ALPH_E_FIELD       0
+#define STV090x_WIDTH_Px_CAR2S2_32A_ALPH_E_FIELD       4
+
+#define STV090x_Px_BCLC2S2Q(__x)               (0xf49c - (__x - 1) * 0x200)
+#define STV090x_P1_BCLC2S2Q                    STV090x_Px_BCLC2S2Q(1)
+#define STV090x_P2_BCLC2S2Q                    STV090x_Px_BCLC2S2Q(2)
+#define STV090x_OFFST_Px_CAR2S2_Q_BETA_M_FIELD 4
+#define STV090x_WIDTH_Px_CAR2S2_Q_BETA_M_FIELD 2
+#define STV090x_OFFST_Px_CAR2S2_Q_BETA_E_FIELD 0
+#define STV090x_WIDTH_Px_CAR2S2_Q_BETA_E_FIELD 4
+
+#define STV090x_Px_BCLC2S28(__x)               (0xf49d - (__x - 1) * 0x200)
+#define STV090x_P1_BCLC2S28                    STV090x_Px_BCLC2S28(1)
+#define STV090x_P2_BCLC2S28                    STV090x_Px_BCLC2S28(1)
+#define STV090x_OFFST_Px_CAR2S2_8_BETA_M_FIELD 4
+#define STV090x_WIDTH_Px_CAR2S2_8_BETA_M_FIELD 2
+#define STV090x_OFFST_Px_CAR2S2_8_BETA_E_FIELD 0
+#define STV090x_WIDTH_Px_CAR2S2_8_BETA_E_FIELD 4
+
+#define STV090x_Px_BCLC2S216A(__x)             (0xf49d - (__x - 1) * 0x200)
+#define STV090x_P1_BCLC2S216A                  STV090x_Px_BCLC2S216A(1)
+#define STV090x_P2_BCLC2S216A                  STV090x_Px_BCLC2S216A(1)
+#define STV090x_OFFST_Px_CAR2S2_16A_BETA_M_FIELD       4
+#define STV090x_WIDTH_Px_CAR2S2_16A_BETA_M_FIELD       2
+#define STV090x_OFFST_Px_CAR2S2_16A_BETA_E_FIELD       0
+#define STV090x_WIDTH_Px_CAR2S2_16A_BETA_E_FIELD       4
+
+#define STV090x_Px_BCLC2S232A(__x)             (0xf49d - (__x - 1) * 0x200)
+#define STV090x_P1_BCLC2S232A                  STV090x_Px_BCLC2S232A(1)
+#define STV090x_P2_BCLC2S232A                  STV090x_Px_BCLC2S232A(1)
+#define STV090x_OFFST_Px_CAR2S2_32A_BETA_M_FIELD       4
+#define STV090x_WIDTH_Px_CAR2S2_32A_BETA_M_FIELD       2
+#define STV090x_OFFST_Px_CAR2S2_32A_BETA_E_FIELD       0
+#define STV090x_WIDTH_Px_CAR2S2_32A_BETA_E_FIELD       4
+
+#define STV090x_Px_PLROOT2(__x)                        (0xf4ac - (__x - 1) * 0x200)
+#define STV090x_P1_PLROOT2                     STV090x_Px_PLROOT2(1)
+#define STV090x_P2_PLROOT2                     STV090x_Px_PLROOT2(2)
+#define STV090x_OFFST_Px_PLSCRAMB_MODE_FIELD   2
+#define STV090x_WIDTH_Px_PLSCRAMB_MODE_FIELD   2
+#define STV090x_OFFST_Px_PLSCRAMB_ROOT_FIELD   0
+#define STV090x_WIDTH_Px_PLSCRAMB_ROOT_FIELD   2
+
+#define STV090x_Px_PLROOT1(__x)                        (0xf4ad - (__x - 1) * 0x200)
+#define STV090x_P1_PLROOT1                     STV090x_Px_PLROOT1(1)
+#define STV090x_P2_PLROOT1                     STV090x_Px_PLROOT1(2)
+#define STV090x_OFFST_Px_PLSCRAMB_ROOT1_FIELD  0
+#define STV090x_WIDTH_Px_PLSCRAMB_ROOT1_FIELD  8
+
+#define STV090x_Px_PLROOT0(__x)                        (0xf4ae - (__x - 1) * 0x200)
+#define STV090x_P1_PLROOT0                     STV090x_Px_PLROOT0(1)
+#define STV090x_P2_PLROOT0                     STV090x_Px_PLROOT0(2)
+#define STV090x_OFFST_Px_PLSCRAMB_ROOT0_FIELD  0
+#define STV090x_WIDTH_Px_PLSCRAMB_ROOT0_FIELD  8
+
+#define STV090x_Px_MODCODLST0(__x)             (0xf4b0 - (__x - 1) * 0x200) /* check */
+#define STV090x_P1_MODCODLST0                  STV090x_Px_MODCODLST0(1)
+#define STV090x_P2_MODCODLST0                  STV090x_Px_MODCODLST0(2)
+
+#define STV090x_Px_MODCODLST1(__x)             (0xf4b1 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST1                  STV090x_Px_MODCODLST1(1)
+#define STV090x_P2_MODCODLST1                  STV090x_Px_MODCODLST1(2)
+#define STV090x_OFFST_Px_DIS_MODCOD29_FIELD    4
+#define STV090x_WIDTH_Px_DIS_MODCOD29T_FIELD   4
+#define STV090x_OFFST_Px_DIS_32PSK_9_10_FIELD  0
+#define STV090x_WIDTH_Px_DIS_32PSK_9_10_FIELD  4
+
+#define STV090x_Px_MODCODLST2(__x)             (0xf4b2 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST2                  STV090x_Px_MODCODLST2(1)
+#define STV090x_P2_MODCODLST2                  STV090x_Px_MODCODLST2(2)
+#define STV090x_OFFST_Px_DIS_32PSK_8_9_FIELD   4
+#define STV090x_WIDTH_Px_DIS_32PSK_8_9_FIELD   4
+#define STV090x_OFFST_Px_DIS_32PSK_5_6_FIELD   0
+#define STV090x_WIDTH_Px_DIS_32PSK_5_6_FIELD   4
+
+#define STV090x_Px_MODCODLST3(__x)             (0xf4b3 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST3                  STV090x_Px_MODCODLST3(1)
+#define STV090x_P2_MODCODLST3                  STV090x_Px_MODCODLST3(2)
+#define STV090x_OFFST_Px_DIS_32PSK_4_5_FIELD   4
+#define STV090x_WIDTH_Px_DIS_32PSK_4_5_FIELD   4
+#define STV090x_OFFST_Px_DIS_32PSK_3_4_FIELD   0
+#define STV090x_WIDTH_Px_DIS_32PSK_3_4_FIELD   4
+
+#define STV090x_Px_MODCODLST4(__x)             (0xf4b4 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST4                  STV090x_Px_MODCODLST4(1)
+#define STV090x_P2_MODCODLST4                  STV090x_Px_MODCODLST4(2)
+#define STV090x_OFFST_Px_DIS_16PSK_9_10_FIELD  4
+#define STV090x_WIDTH_Px_DIS_16PSK_9_10_FIELD  4
+#define STV090x_OFFST_Px_DIS_16PSK_8_9_FIELD   0
+#define STV090x_WIDTH_Px_DIS_16PSK_8_9_FIELD   4
+
+#define STV090x_Px_MODCODLST5(__x)             (0xf4b5 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST5                  STV090x_Px_MODCODLST5(1)
+#define STV090x_P2_MODCODLST5                  STV090x_Px_MODCODLST5(2)
+#define STV090x_OFFST_Px_DIS_16PSK_5_6_FIELD   4
+#define STV090x_WIDTH_Px_DIS_16PSK_5_6_FIELD   4
+#define STV090x_OFFST_Px_DIS_16PSK_4_5_FIELD   0
+#define STV090x_WIDTH_Px_DIS_16PSK_4_5_FIELD   4
+
+#define STV090x_Px_MODCODLST6(__x)             (0xf4b6 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST6                  STV090x_Px_MODCODLST6(1)
+#define STV090x_P2_MODCODLST6                  STV090x_Px_MODCODLST6(2)
+#define STV090x_OFFST_Px_DIS_16PSK_3_4_FIELD   4
+#define STV090x_WIDTH_Px_DIS_16PSK_3_4_FIELD   4
+#define STV090x_OFFST_Px_DIS_16PSK_2_3_FIELD   0
+#define STV090x_WIDTH_Px_DIS_16PSK_2_3_FIELD   4
+
+#define STV090x_Px_MODCODLST7(__x)             (0xf4b7 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST7                  STV090x_Px_MODCODLST7(1)
+#define STV090x_P2_MODCODLST7                  STV090x_Px_MODCODLST7(2)
+#define STV090x_OFFST_Px_DIS_8P_9_10_FIELD     4
+#define STV090x_WIDTH_Px_DIS_8P_9_10_FIELD     4
+#define STV090x_OFFST_Px_DIS_8P_8_9_FIELD      0
+#define STV090x_WIDTH_Px_DIS_8P_8_9_FIELD      4
+
+#define STV090x_Px_MODCODLST8(__x)             (0xf4b8 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST8                  STV090x_Px_MODCODLST8(1)
+#define STV090x_P2_MODCODLST8                  STV090x_Px_MODCODLST8(2)
+#define STV090x_OFFST_Px_DIS_8P_5_6_FIELD      4
+#define STV090x_WIDTH_Px_DIS_8P_5_6_FIELD      4
+#define STV090x_OFFST_Px_DIS_8P_3_4_FIELD      0
+#define STV090x_WIDTH_Px_DIS_8P_3_4_FIELD      4
+
+#define STV090x_Px_MODCODLST9(__x)             (0xf4b9 - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLST9                  STV090x_Px_MODCODLST9(1)
+#define STV090x_P2_MODCODLST9                  STV090x_Px_MODCODLST9(2)
+#define STV090x_OFFST_Px_DIS_8P_2_3_FIELD      4
+#define STV090x_WIDTH_Px_DIS_8P_2_3_FIELD      4
+#define STV090x_OFFST_Px_DIS_8P_3_5_FIELD      0
+#define STV090x_WIDTH_Px_DIS_8P_3_5_FIELD      4
+
+#define STV090x_Px_MODCODLSTA(__x)             (0xf4ba - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLSTA                  STV090x_Px_MODCODLSTA(1)
+#define STV090x_P2_MODCODLSTA                  STV090x_Px_MODCODLSTA(2)
+#define STV090x_OFFST_Px_DIS_QP_9_10_FIELD     4
+#define STV090x_WIDTH_Px_DIS_QP_9_10_FIELD     4
+#define STV090x_OFFST_Px_DIS_QP_8_9_FIELD      0
+#define STV090x_WIDTH_Px_DIS_QP_8_9_FIELD      4
+
+#define STV090x_Px_MODCODLSTB(__x)             (0xf4bb - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLSTB                  STV090x_Px_MODCODLSTB(1)
+#define STV090x_P2_MODCODLSTB                  STV090x_Px_MODCODLSTB(2)
+#define STV090x_OFFST_Px_DIS_QP_5_6_FIELD      4
+#define STV090x_WIDTH_Px_DIS_QP_5_6_FIELD      4
+#define STV090x_OFFST_Px_DIS_QP_4_5_FIELD      0
+#define STV090x_WIDTH_Px_DIS_QP_4_5_FIELD      4
+
+#define STV090x_Px_MODCODLSTC(__x)             (0xf4bc - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLSTC                  STV090x_Px_MODCODLSTC(1)
+#define STV090x_P2_MODCODLSTC                  STV090x_Px_MODCODLSTC(2)
+#define STV090x_OFFST_Px_DIS_QP_3_4_FIELD      4
+#define STV090x_WIDTH_Px_DIS_QP_3_4_FIELD      4
+#define STV090x_OFFST_Px_DIS_QP_2_3_FIELD      0
+#define STV090x_WIDTH_Px_DIS_QP_2_3_FIELD      4
+
+#define STV090x_Px_MODCODLSTD(__x)             (0xf4bd - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLSTD                  STV090x_Px_MODCODLSTD(1)
+#define STV090x_P2_MODCODLSTD                  STV090x_Px_MODCODLSTD(2)
+#define STV090x_OFFST_Px_DIS_QP_3_5_FIELD      4
+#define STV090x_WIDTH_Px_DIS_QP_3_5_FIELD      4
+#define STV090x_OFFST_Px_DIS_QP_1_2_FIELD      0
+#define STV090x_WIDTH_Px_DIS_QP_1_2_FIELD      4
+
+#define STV090x_Px_MODCODLSTE(__x)             (0xf4be - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLSTE                  STV090x_Px_MODCODLSTE(1)
+#define STV090x_P2_MODCODLSTE                  STV090x_Px_MODCODLSTE(2)
+#define STV090x_OFFST_Px_DIS_QP_2_5_FIELD      4
+#define STV090x_WIDTH_Px_DIS_QP_2_5_FIELD      4
+#define STV090x_OFFST_Px_DIS_QP_1_3_FIELD      0
+#define STV090x_WIDTH_Px_DIS_QP_1_3_FIELD      4
+
+#define STV090x_Px_MODCODLSTF(__x)             (0xf4bf - (__x - 1) * 0x200)
+#define STV090x_P1_MODCODLSTF                  STV090x_Px_MODCODLSTF(1)
+#define STV090x_P2_MODCODLSTF                  STV090x_Px_MODCODLSTF(2)
+#define STV090x_OFFST_Px_DIS_QP_1_4_FIELD      4
+#define STV090x_WIDTH_Px_DIS_QP_1_4_FIELD      4
+
+#define STV090x_Px_GAUSSR0(__x)                        (0xf4c0 - (__x - 1) * 0x200)
+#define STV090x_P1_GAUSSR0                     STV090x_Px_GAUSSR0(1)
+#define STV090x_P2_GAUSSR0                     STV090x_Px_GAUSSR0(2)
+#define STV090x_OFFST_Px_EN_CCIMODE_FIELD      7
+#define STV090x_WIDTH_Px_EN_CCIMODE_FIELD      1
+#define STV090x_OFFST_Px_R0_GAUSSIEN_FIELD     0
+#define STV090x_WIDTH_Px_R0_GAUSSIEN_FIELD     7
+
+#define STV090x_Px_CCIR0(__x)                  (0xf4c1 - (__x - 1) * 0x200)
+#define STV090x_P1_CCIR0                       STV090x_Px_CCIR0(1)
+#define STV090x_P2_CCIR0                       STV090x_Px_CCIR0(2)
+#define STV090x_OFFST_Px_CCIDETECT_PLH_FIELD   7
+#define STV090x_WIDTH_Px_CCIDETECT_PLH_FIELD   1
+#define STV090x_OFFST_Px_R0_CCI_FIELD          0
+#define STV090x_WIDTH_Px_R0_CCI_FIELD          7
+
+#define STV090x_Px_CCIQUANT(__x)               (0xf4c2 - (__x - 1) * 0x200)
+#define STV090x_P1_CCIQUANT                    STV090x_Px_CCIQUANT(1)
+#define STV090x_P2_CCIQUANT                    STV090x_Px_CCIQUANT(2)
+#define STV090x_OFFST_Px_CCI_BETA_FIELD                5
+#define STV090x_WIDTH_Px_CCI_BETA_FIELD                3
+#define STV090x_OFFST_Px_CCI_QUANT_FIELD       0
+#define STV090x_WIDTH_Px_CCI_QUANT_FIELD       5
+
+#define STV090x_Px_CCITHRESH(__x)              (0xf4c3 - (__x - 1) * 0x200)
+#define STV090x_P1_CCITHRESH                   STV090x_Px_CCITHRESH(1)
+#define STV090x_P2_CCITHRESH                   STV090x_Px_CCITHRESH(2)
+#define STV090x_OFFST_Px_CCI_THRESHOLD_FIELD   0
+#define STV090x_WIDTH_Px_CCI_THRESHOLD_FIELD   8
+
+#define STV090x_Px_CCIACC(__x)                 (0xf4c4 - (__x - 1) * 0x200)
+#define STV090x_P1_CCIACC                      STV090x_Px_CCIACC(1)
+#define STV090x_P2_CCIACC                      STV090x_Px_CCIACC(1)
+#define STV090x_OFFST_Px_CCI_VALUE_FIELD       0
+#define STV090x_WIDTH_Px_CCI_VALUE_FIELD       8
+
+#define STV090x_Px_DMDRESCFG(__x)              (0xF4C6 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDRESCFG                   STV090x_Px_DMDRESCFG(1)
+#define STV090x_P2_DMDRESCFG                   STV090x_Px_DMDRESCFG(2)
+#define STV090x_OFFST_Px_DMDRES_RESET_FIELD    7
+#define STV090x_WIDTH_Px_DMDRES_RESET_FIELD    1
+
+#define STV090x_Px_DMDRESADR(__x)              (0xF4C7 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDRESADR                   STV090x_Px_DMDRESADR(1)
+#define STV090x_P2_DMDRESADR                   STV090x_Px_DMDRESADR(2)
+#define STV090x_OFFST_Px_DMDRES_RESNBR_FIELD   0
+#define STV090x_WIDTH_Px_DMDRES_RESNBR_FIELD   4
+
+#define STV090x_Px_DMDRESDATAy(__x, __y)       (0xF4C8 - (__x - 1) * 0x200 + (7 - __y))
+#define STV090x_P1_DMDRESDATA0                 STV090x_Px_DMDRESDATAy(1, 0)
+#define STV090x_P1_DMDRESDATA1                 STV090x_Px_DMDRESDATAy(1, 1)
+#define STV090x_P1_DMDRESDATA2                 STV090x_Px_DMDRESDATAy(1, 2)
+#define STV090x_P1_DMDRESDATA3                 STV090x_Px_DMDRESDATAy(1, 3)
+#define STV090x_P1_DMDRESDATA4                 STV090x_Px_DMDRESDATAy(1, 4)
+#define STV090x_P1_DMDRESDATA5                 STV090x_Px_DMDRESDATAy(1, 5)
+#define STV090x_P1_DMDRESDATA6                 STV090x_Px_DMDRESDATAy(1, 6)
+#define STV090x_P1_DMDRESDATA7                 STV090x_Px_DMDRESDATAy(1, 7)
+#define STV090x_P2_DMDRESDATA0                 STV090x_Px_DMDRESDATAy(2, 0)
+#define STV090x_P2_DMDRESDATA1                 STV090x_Px_DMDRESDATAy(2, 1)
+#define STV090x_P2_DMDRESDATA2                 STV090x_Px_DMDRESDATAy(2, 2)
+#define STV090x_P2_DMDRESDATA3                 STV090x_Px_DMDRESDATAy(2, 3)
+#define STV090x_P2_DMDRESDATA4                 STV090x_Px_DMDRESDATAy(2, 4)
+#define STV090x_P2_DMDRESDATA5                 STV090x_Px_DMDRESDATAy(2, 5)
+#define STV090x_P2_DMDRESDATA6                 STV090x_Px_DMDRESDATAy(2, 6)
+#define STV090x_P2_DMDRESDATA7                 STV090x_Px_DMDRESDATAy(2, 7)
+#define STV090x_OFFST_Px_DMDRES_DATA_FIELD     0
+#define STV090x_WIDTH_Px_DMDRES_DATA_FIELD     8
+
+#define STV090x_Px_FFEIy(__x, __y)             (0xf4d0 - (__x - 1) * 0x200 + 0x2 * (__y - 1))
+#define STV090x_P1_FFEI1                       STV090x_Px_FFEIy(1, 1)
+#define STV090x_P1_FFEI2                       STV090x_Px_FFEIy(1, 2)
+#define STV090x_P1_FFEI3                       STV090x_Px_FFEIy(1, 3)
+#define STV090x_P1_FFEI4                       STV090x_Px_FFEIy(1, 4)
+#define STV090x_P2_FFEI1                       STV090x_Px_FFEIy(2, 1)
+#define STV090x_P2_FFEI2                       STV090x_Px_FFEIy(2, 2)
+#define STV090x_P2_FFEI3                       STV090x_Px_FFEIy(2, 3)
+#define STV090x_P2_FFEI4                       STV090x_Px_FFEIy(2, 4)
+#define STV090x_OFFST_Px_FFE_ACCIy_FIELD       0
+#define STV090x_WIDTH_Px_FFE_ACCIy_FIELD       8
+
+#define STV090x_Px_FFEQy(__x, __y)             (0xf4d1 - (__x - 1) * 0x200 + 0x2 * (__y - 1))
+#define STV090x_P1_FFEQ1                       STV090x_Px_FFEQy(1, 1)
+#define STV090x_P1_FFEQ2                       STV090x_Px_FFEQy(1, 2)
+#define STV090x_P1_FFEQ3                       STV090x_Px_FFEQy(1, 3)
+#define STV090x_P1_FFEQ4                       STV090x_Px_FFEQy(1, 4)
+#define STV090x_P2_FFEQ1                       STV090x_Px_FFEQy(2, 1)
+#define STV090x_P2_FFEQ2                       STV090x_Px_FFEQy(2, 2)
+#define STV090x_P2_FFEQ3                       STV090x_Px_FFEQy(2, 3)
+#define STV090x_P2_FFEQ4                       STV090x_Px_FFEQy(2, 4)
+#define STV090x_OFFST_Px_FFE_ACCQy_FIELD       0
+#define STV090x_WIDTH_Px_FFE_ACCQy_FIELD       8
+
+#define STV090x_Px_FFECFG(__x)                 (0xf4d8 - (__x - 1) * 0x200)
+#define STV090x_P1_FFECFG                      STV090x_Px_FFECFG(1)
+#define STV090x_P2_FFECFG                      STV090x_Px_FFECFG(2)
+#define STV090x_OFFST_Px_EQUALFFE_ON_FIELD     6
+#define STV090x_WIDTH_Px_EQUALFFE_ON_FIELD     1
+
+#define STV090x_Px_SMAPCOEF7(__x)              (0xf500 - (__x - 1) * 0x200)
+#define STV090x_P1_SMAPCOEF7                   STV090x_Px_SMAPCOEF7(1)
+#define STV090x_P2_SMAPCOEF7                   STV090x_Px_SMAPCOEF7(2)
+#define STV090x_OFFST_Px_DIS_QSCALE_FIELD      7
+#define STV090x_WIDTH_Px_DIS_QSCALE_FIELD      1
+#define STV090x_OFFST_Px_SMAPCOEF_Q_LLR12_FIELD        0
+#define STV090x_WIDTH_Px_SMAPCOEF_Q_LLR12_FIELD        7
+
+#define STV090x_Px_SMAPCOEF6(__x)              (0xf501 - (__x - 1) * 0x200)
+#define STV090x_P1_SMAPCOEF6                   STV090x_Px_SMAPCOEF6(1)
+#define STV090x_P2_SMAPCOEF6                   STV090x_Px_SMAPCOEF6(2)
+#define STV090x_OFFST_Px_ADJ_8PSKLLR1_FIELD    2
+#define STV090x_WIDTH_Px_ADJ_8PSKLLR1_FIELD    1
+#define STV090x_OFFST_Px_OLD_8PSKLLR1_FIELD    1
+#define STV090x_WIDTH_Px_OLD_8PSKLLR1_FIELD    1
+#define STV090x_OFFST_Px_DIS_AB8PSK_FIELD      0
+#define STV090x_WIDTH_Px_DIS_AB8PSK_FIELD      1
+
+#define STV090x_Px_SMAPCOEF5(__x)                      (0xf502 - (__x - 1) * 0x200)
+#define STV090x_P1_SMAPCOEF5                           STV090x_Px_SMAPCOEF5(1)
+#define STV090x_P2_SMAPCOEF5                           STV090x_Px_SMAPCOEF5(2)
+#define STV090x_OFFST_Px_DIS_8SCALE_FIELD              7
+#define STV090x_WIDTH_Px_DIS_8SCALE_FIELD              1
+#define STV090x_OFFST_Px_SMAPCOEF_8P_LLR23_FIELD       0
+#define STV090x_WIDTH_Px_SMAPCOEF_8P_LLR23_FIELD       7
+
+#define STV090x_Px_DMDPLHSTAT(__x)             (0xF520 - (__x - 1) * 0x200)
+#define STV090x_P1_DMDPLHSTAT                  STV090x_Px_DMDPLHSTAT(1)
+#define STV090x_P2_DMDPLHSTAT                  STV090x_Px_DMDPLHSTAT(2)
+#define STV090x_OFFST_Px_PLH_STATISTIC_FIELD   0
+#define STV090x_WIDTH_Px_PLH_STATISTIC_FIELD   8
+
+#define STV090x_Px_LOCKTIMEy(__x, __y)         (0xF525 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_LOCKTIME0                   STV090x_Px_LOCKTIMEy(1, 0)
+#define STV090x_P1_LOCKTIME1                   STV090x_Px_LOCKTIMEy(1, 1)
+#define STV090x_P1_LOCKTIME2                   STV090x_Px_LOCKTIMEy(1, 2)
+#define STV090x_P1_LOCKTIME3                   STV090x_Px_LOCKTIMEy(1, 3)
+#define STV090x_P2_LOCKTIME0                   STV090x_Px_LOCKTIMEy(2, 0)
+#define STV090x_P2_LOCKTIME1                   STV090x_Px_LOCKTIMEy(2, 1)
+#define STV090x_P2_LOCKTIME2                   STV090x_Px_LOCKTIMEy(2, 2)
+#define STV090x_P2_LOCKTIME3                   STV090x_Px_LOCKTIMEy(2, 3)
+#define STV090x_OFFST_Px_DEMOD_LOCKTIME_FIELD  0
+#define STV090x_WIDTH_Px_DEMOD_LOCKTIME_FIELD  8
+
+#define STV090x_Px_TNRCFG(__x)                 (0xf4e0 - (__x - 1) * 0x200) /* check */
+#define STV090x_P1_TNRCFG                      STV090x_Px_TNRCFG(1)
+#define STV090x_P2_TNRCFG                      STV090x_Px_TNRCFG(2)
+
+#define STV090x_Px_TNRCFG2(__x)                        (0xf4e1 - (__x - 1) * 0x200)
+#define STV090x_P1_TNRCFG2                     STV090x_Px_TNRCFG2(1)
+#define STV090x_P2_TNRCFG2                     STV090x_Px_TNRCFG2(2)
+#define STV090x_OFFST_Px_TUN_IQSWAP_FIELD      7
+#define STV090x_WIDTH_Px_TUN_IQSWAP_FIELD      1
+
+#define STV090x_Px_VITSCALE(__x)               (0xf532 - (__x - 1) * 0x200)
+#define STV090x_P1_VITSCALE                    STV090x_Px_VITSCALE(1)
+#define STV090x_P2_VITSCALE                    STV090x_Px_VITSCALE(2)
+#define STV090x_OFFST_Px_NVTH_NOSRANGE_FIELD   7
+#define STV090x_WIDTH_Px_NVTH_NOSRANGE_FIELD   1
+#define STV090x_OFFST_Px_VERROR_MAXMODE_FIELD  6
+#define STV090x_WIDTH_Px_VERROR_MAXMODE_FIELD  1
+#define STV090x_OFFST_Px_NSLOWSN_LOCKED_FIELD  3
+#define STV090x_WIDTH_Px_NSLOWSN_LOCKED_FIELD  1
+#define STV090x_OFFST_Px_DIS_RSFLOCK_FIELD     1
+#define STV090x_WIDTH_Px_DIS_RSFLOCK_FIELD     1
+
+#define STV090x_Px_FECM(__x)                   (0xf533 - (__x - 1) * 0x200)
+#define STV090x_P1_FECM                                STV090x_Px_FECM(1)
+#define STV090x_P2_FECM                                STV090x_Px_FECM(2)
+#define STV090x_OFFST_Px_DSS_DVB_FIELD         7
+#define STV090x_WIDTH_Px_DSS_DVB_FIELD         1
+#define STV090x_OFFST_Px_DSS_SRCH_FIELD                4
+#define STV090x_WIDTH_Px_DSS_SRCH_FIELD                1
+#define STV090x_OFFST_Px_SYNCVIT_FIELD         1
+#define STV090x_WIDTH_Px_SYNCVIT_FIELD         1
+#define STV090x_OFFST_Px_IQINV_FIELD           0
+#define STV090x_WIDTH_Px_IQINV_FIELD           1
+
+#define STV090x_Px_VTH12(__x)                  (0xf534 - (__x - 1) * 0x200)
+#define STV090x_P1_VTH12                       STV090x_Px_VTH12(1)
+#define STV090x_P2_VTH12                       STV090x_Px_VTH12(2)
+#define STV090x_OFFST_Px_VTH12_FIELD           0
+#define STV090x_WIDTH_Px_VTH12_FIELD           8
+
+#define STV090x_Px_VTH23(__x)                  (0xf535 - (__x - 1) * 0x200)
+#define STV090x_P1_VTH23                       STV090x_Px_VTH23(1)
+#define STV090x_P2_VTH23                       STV090x_Px_VTH23(2)
+#define STV090x_OFFST_Px_VTH23_FIELD           0
+#define STV090x_WIDTH_Px_VTH23_FIELD           8
+
+#define STV090x_Px_VTH34(__x)                  (0xf536 - (__x - 1) * 0x200)
+#define STV090x_P1_VTH34                       STV090x_Px_VTH34(1)
+#define STV090x_P2_VTH34                       STV090x_Px_VTH34(2)
+#define STV090x_OFFST_Px_VTH34_FIELD           0
+#define STV090x_WIDTH_Px_VTH34_FIELD           8
+
+#define STV090x_Px_VTH56(__x)                  (0xf537 - (__x - 1) * 0x200)
+#define STV090x_P1_VTH56                       STV090x_Px_VTH56(1)
+#define STV090x_P2_VTH56                       STV090x_Px_VTH56(2)
+#define STV090x_OFFST_Px_VTH56_FIELD           0
+#define STV090x_WIDTH_Px_VTH56_FIELD           8
+
+#define STV090x_Px_VTH67(__x)                  (0xf538 - (__x - 1) * 0x200)
+#define STV090x_P1_VTH67                       STV090x_Px_VTH67(1)
+#define STV090x_P2_VTH67                       STV090x_Px_VTH67(2)
+#define STV090x_OFFST_Px_VTH67_FIELD           0
+#define STV090x_WIDTH_Px_VTH67_FIELD           8
+
+#define STV090x_Px_VTH78(__x)                  (0xf539 - (__x - 1) * 0x200)
+#define STV090x_P1_VTH78                       STV090x_Px_VTH78(1)
+#define STV090x_P2_VTH78                       STV090x_Px_VTH78(2)
+#define STV090x_OFFST_Px_VTH78_FIELD           0
+#define STV090x_WIDTH_Px_VTH78_FIELD           8
+
+#define STV090x_Px_VITCURPUN(__x)              (0xf53a - (__x - 1) * 0x200)
+#define STV090x_P1_VITCURPUN                   STV090x_Px_VITCURPUN(1)
+#define STV090x_P2_VITCURPUN                   STV090x_Px_VITCURPUN(2)
+#define STV090x_OFFST_Px_VIT_CURPUN_FIELD      0
+#define STV090x_WIDTH_Px_VIT_CURPUN_FIELD      5
+
+#define STV090x_Px_VERROR(__x)                 (0xf53b - (__x - 1) * 0x200)
+#define STV090x_P1_VERROR                      STV090x_Px_VERROR(1)
+#define STV090x_P2_VERROR                      STV090x_Px_VERROR(2)
+#define STV090x_OFFST_Px_REGERR_VIT_FIELD      0
+#define STV090x_WIDTH_Px_REGERR_VIT_FIELD      8
+
+#define STV090x_Px_PRVIT(__x)                  (0xf53c - (__x - 1) * 0x200)
+#define STV090x_P1_PRVIT                       STV090x_Px_PRVIT(1)
+#define STV090x_P2_PRVIT                       STV090x_Px_PRVIT(2)
+#define STV090x_OFFST_Px_DIS_VTHLOCK_FIELD     6
+#define STV090x_WIDTH_Px_DIS_VTHLOCK_FIELD     1
+#define STV090x_OFFST_Px_E7_8VIT_FIELD         5
+#define STV090x_WIDTH_Px_E7_8VIT_FIELD         1
+#define STV090x_OFFST_Px_E6_7VIT_FIELD         4
+#define STV090x_WIDTH_Px_E6_7VIT_FIELD         1
+#define STV090x_OFFST_Px_E5_6VIT_FIELD         3
+#define STV090x_WIDTH_Px_E5_6VIT_FIELD         1
+#define STV090x_OFFST_Px_E3_4VIT_FIELD         2
+#define STV090x_WIDTH_Px_E3_4VIT_FIELD         1
+#define STV090x_OFFST_Px_E2_3VIT_FIELD         1
+#define STV090x_WIDTH_Px_E2_3VIT_FIELD         1
+#define STV090x_OFFST_Px_E1_2VIT_FIELD         0
+#define STV090x_WIDTH_Px_E1_2VIT_FIELD         1
+
+#define STV090x_Px_VAVSRVIT(__x)               (0xf53d - (__x - 1) * 0x200)
+#define STV090x_P1_VAVSRVIT                    STV090x_Px_VAVSRVIT(1)
+#define STV090x_P2_VAVSRVIT                    STV090x_Px_VAVSRVIT(2)
+#define STV090x_OFFST_Px_SNVIT_FIELD           4
+#define STV090x_WIDTH_Px_SNVIT_FIELD           2
+#define STV090x_OFFST_Px_TOVVIT_FIELD          2
+#define STV090x_WIDTH_Px_TOVVIT_FIELD          2
+#define STV090x_OFFST_Px_HYPVIT_FIELD          0
+#define STV090x_WIDTH_Px_HYPVIT_FIELD          2
+
+#define STV090x_Px_VSTATUSVIT(__x)             (0xf53e - (__x - 1) * 0x200)
+#define STV090x_P1_VSTATUSVIT                  STV090x_Px_VSTATUSVIT(1)
+#define STV090x_P2_VSTATUSVIT                  STV090x_Px_VSTATUSVIT(2)
+#define STV090x_OFFST_Px_PRFVIT_FIELD          4
+#define STV090x_WIDTH_Px_PRFVIT_FIELD          1
+#define STV090x_OFFST_Px_LOCKEDVIT_FIELD       3
+#define STV090x_WIDTH_Px_LOCKEDVIT_FIELD       1
+
+#define STV090x_Px_VTHINUSE(__x)               (0xf53f - (__x - 1) * 0x200)
+#define STV090x_P1_VTHINUSE                    STV090x_Px_VTHINUSE(1)
+#define STV090x_P2_VTHINUSE                    STV090x_Px_VTHINUSE(2)
+#define STV090x_OFFST_Px_VIT_INUSE_FIELD       0
+#define STV090x_WIDTH_Px_VIT_INUSE_FIELD       8
+
+#define STV090x_Px_KDIV12(__x)                 (0xf540 - (__x - 1) * 0x200)
+#define STV090x_P1_KDIV12                      STV090x_Px_KDIV12(1)
+#define STV090x_P2_KDIV12                      STV090x_Px_KDIV12(2)
+#define STV090x_OFFST_Px_K_DIVIDER_12_FIELD    0
+#define STV090x_WIDTH_Px_K_DIVIDER_12_FIELD    7
+
+#define STV090x_Px_KDIV23(__x)                 (0xf541 - (__x - 1) * 0x200)
+#define STV090x_P1_KDIV23                      STV090x_Px_KDIV23(1)
+#define STV090x_P2_KDIV23                      STV090x_Px_KDIV23(2)
+#define STV090x_OFFST_Px_K_DIVIDER_23_FIELD    0
+#define STV090x_WIDTH_Px_K_DIVIDER_23_FIELD    7
+
+#define STV090x_Px_KDIV34(__x)                 (0xf542 - (__x - 1) * 0x200)
+#define STV090x_P1_KDIV34                      STV090x_Px_KDIV34(1)
+#define STV090x_P2_KDIV34                      STV090x_Px_KDIV34(2)
+#define STV090x_OFFST_Px_K_DIVIDER_34_FIELD    0
+#define STV090x_WIDTH_Px_K_DIVIDER_34_FIELD    7
+
+#define STV090x_Px_KDIV56(__x)                 (0xf543 - (__x - 1) * 0x200)
+#define STV090x_P1_KDIV56                      STV090x_Px_KDIV56(1)
+#define STV090x_P2_KDIV56                      STV090x_Px_KDIV56(2)
+#define STV090x_OFFST_Px_K_DIVIDER_56_FIELD    0
+#define STV090x_WIDTH_Px_K_DIVIDER_56_FIELD    7
+
+#define STV090x_Px_KDIV67(__x)                 (0xf544 - (__x - 1) * 0x200)
+#define STV090x_P1_KDIV67                      STV090x_Px_KDIV67(1)
+#define STV090x_P2_KDIV67                      STV090x_Px_KDIV67(2)
+#define STV090x_OFFST_Px_K_DIVIDER_67_FIELD    0
+#define STV090x_WIDTH_Px_K_DIVIDER_67_FIELD    7
+
+#define STV090x_Px_KDIV78(__x)                 (0xf545 - (__x - 1) * 0x200)
+#define STV090x_P1_KDIV78                      STV090x_Px_KDIV78(1)
+#define STV090x_P2_KDIV78                      STV090x_Px_KDIV78(2)
+#define STV090x_OFFST_Px_K_DIVIDER_78_FIELD    0
+#define STV090x_WIDTH_Px_K_DIVIDER_78_FIELD    7
+
+#define STV090x_Px_PDELCTRL1(__x)              (0xf550 - (__x - 1) * 0x200)
+#define STV090x_P1_PDELCTRL1                   STV090x_Px_PDELCTRL1(1)
+#define STV090x_P2_PDELCTRL1                   STV090x_Px_PDELCTRL1(2)
+#define STV090x_OFFST_Px_INV_MISMASK_FIELD     7
+#define STV090x_WIDTH_Px_INV_MISMASK_FIELD     1
+#define STV090x_OFFST_Px_FILTER_EN_FIELD       5
+#define STV090x_WIDTH_Px_FILTER_EN_FIELD       1
+#define STV090x_OFFST_Px_EN_MIS00_FIELD                1
+#define STV090x_WIDTH_Px_EN_MIS00_FIELD                1
+#define STV090x_OFFST_Px_ALGOSWRST_FIELD       0
+#define STV090x_WIDTH_Px_ALGOSWRST_FIELD       1
+
+#define STV090x_Px_PDELCTRL2(__x)              (0xf551 - (__x - 1) * 0x200)
+#define STV090x_P1_PDELCTRL2                   STV090x_Px_PDELCTRL2(1)
+#define STV090x_P2_PDELCTRL2                   STV090x_Px_PDELCTRL2(2)
+#define STV090x_OFFST_Px_FORCE_CONTINUOUS      7
+#define STV090x_WIDTH_Px_FORCE_CONTINUOUS      1
+#define STV090x_OFFST_Px_RESET_UPKO_COUNT      6
+#define STV090x_WIDTH_Px_RESET_UPKO_COUNT      1
+#define STV090x_OFFST_Px_USER_PKTDELIN_NB      5
+#define STV090x_WIDTH_Px_USER_PKTDELIN_NB      1
+#define STV090x_OFFST_Px_FORCE_LOCKED          4
+#define STV090x_WIDTH_Px_FORCE_LOCKED          1
+#define STV090x_OFFST_Px_DATA_UNBBSCRAM                3
+#define STV090x_WIDTH_Px_DATA_UNBBSCRAM                1
+#define STV090x_OFFST_Px_FORCE_LONGPACKET      2
+#define STV090x_WIDTH_Px_FORCE_LONGPACKET      1
+#define STV090x_OFFST_Px_FRAME_MODE_FIELD      1
+#define STV090x_WIDTH_Px_FRAME_MODE_FIELD      1
+
+#define STV090x_Px_HYSTTHRESH(__x)             (0xf554 - (__x - 1) * 0x200)
+#define STV090x_P1_HYSTTHRESH                  STV090x_Px_HYSTTHRESH(1)
+#define STV090x_P2_HYSTTHRESH                  STV090x_Px_HYSTTHRESH(2)
+#define STV090x_OFFST_Px_UNLCK_THRESH_FIELD    4
+#define STV090x_WIDTH_Px_UNLCK_THRESH_FIELD    4
+#define STV090x_OFFST_Px_DELIN_LCK_THRESH_FIELD        0
+#define STV090x_WIDTH_Px_DELIN_LCK_THRESH_FIELD        4
+
+#define STV090x_Px_ISIENTRY(__x)               (0xf55e - (__x - 1) * 0x200)
+#define STV090x_P1_ISIENTRY                    STV090x_Px_ISIENTRY(1)
+#define STV090x_P2_ISIENTRY                    STV090x_Px_ISIENTRY(2)
+#define STV090x_OFFST_Px_ISI_ENTRY_FIELD       0
+#define STV090x_WIDTH_Px_ISI_ENTRY_FIELD       8
+
+#define STV090x_Px_ISIBITENA(__x)              (0xf55f - (__x - 1) * 0x200)
+#define STV090x_P1_ISIBITENA                   STV090x_Px_ISIBITENA(1)
+#define STV090x_P2_ISIBITENA                   STV090x_Px_ISIBITENA(2)
+#define STV090x_OFFST_Px_ISI_BIT_EN_FIELD      0
+#define STV090x_WIDTH_Px_ISI_BIT_EN_FIELD      8
+
+#define STV090x_Px_MATSTRy(__x, __y)           (0xf561 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_MATSTR0                     STV090x_Px_MATSTRy(1, 0)
+#define STV090x_P1_MATSTR1                     STV090x_Px_MATSTRy(1, 1)
+#define STV090x_P2_MATSTR0                     STV090x_Px_MATSTRy(2, 0)
+#define STV090x_P2_MATSTR1                     STV090x_Px_MATSTRy(2, 1)
+#define STV090x_OFFST_Px_MATYPE_CURRENT_FIELD  0
+#define STV090x_WIDTH_Px_MATYPE_CURRENT_FIELD  8
+
+#define STV090x_Px_UPLSTRy(__x, __y)           (0xf563 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_UPLSTR0                     STV090x_Px_UPLSTRy(1, 0)
+#define STV090x_P1_UPLSTR1                     STV090x_Px_UPLSTRy(1, 1)
+#define STV090x_P2_UPLSTR0                     STV090x_Px_UPLSTRy(2, 0)
+#define STV090x_P2_UPLSTR1                     STV090x_Px_UPLSTRy(2, 1)
+#define STV090x_OFFST_Px_UPL_CURRENT_FIELD     0
+#define STV090x_WIDTH_Px_UPL_CURRENT_FIELD     8
+
+#define STV090x_Px_DFLSTRy(__x, __y)           (0xf565 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_DFLSTR0                     STV090x_Px_DFLSTRy(1, 0)
+#define STV090x_P1_DFLSTR1                     STV090x_Px_DFLSTRy(1, 1)
+#define STV090x_P2_DFLSTR0                     STV090x_Px_DFLSTRy(2, 0)
+#define STV090x_P2_DFLSTR1                     STV090x_Px_DFLSTRy(2, 1)
+#define STV090x_OFFST_Px_DFL_CURRENT_FIELD     0
+#define STV090x_WIDTH_Px_DFL_CURRENT_FIELD     8
+
+#define STV090x_Px_SYNCSTR(__x)                        (0xf566 - (__x - 1) * 0x200)
+#define STV090x_P1_SYNCSTR                     STV090x_Px_SYNCSTR(1)
+#define STV090x_P2_SYNCSTR                     STV090x_Px_SYNCSTR(2)
+#define STV090x_OFFST_Px_SYNC_CURRENT_FIELD    0
+#define STV090x_WIDTH_Px_SYNC_CURRENT_FIELD    8
+
+#define STV090x_Px_SYNCDSTRy(__x, __y)         (0xf568 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_SYNCDSTR0                   STV090x_Px_SYNCDSTRy(1, 0)
+#define STV090x_P1_SYNCDSTR1                   STV090x_Px_SYNCDSTRy(1, 1)
+#define STV090x_P2_SYNCDSTR0                   STV090x_Px_SYNCDSTRy(2, 0)
+#define STV090x_P2_SYNCDSTR1                   STV090x_Px_SYNCDSTRy(2, 1)
+#define STV090x_OFFST_Px_SYNCD_CURRENT_FIELD   0
+#define STV090x_WIDTH_Px_SYNCD_CURRENT_FIELD   8
+
+#define STV090x_Px_PDELSTATUS1(__x)            (0xf569 - (__x - 1) * 0x200)
+#define STV090x_P1_PDELSTATUS1                 STV090x_Px_PDELSTATUS1(1)
+#define STV090x_P2_PDELSTATUS1                 STV090x_Px_PDELSTATUS1(2)
+#define STV090x_OFFST_Px_PKTDELIN_LOCK_FIELD   1
+#define STV090x_WIDTH_Px_PKTDELIN_LOCK_FIELD   1
+#define STV090x_OFFST_Px_FIRST_LOCK_FIELD      0
+#define STV090x_WIDTH_Px_FIRST_LOCK_FIELD      1
+
+#define STV090x_Px_PDELSTATUS2(__x)            (0xf56a - (__x - 1) * 0x200)
+#define STV090x_P1_PDELSTATUS2                 STV090x_Px_PDELSTATUS2(1)
+#define STV090x_P2_PDELSTATUS2                 STV090x_Px_PDELSTATUS2(2)
+#define STV090x_OFFST_Px_FRAME_MODCOD_FIELD    2
+#define STV090x_WIDTH_Px_FRAME_MODCOD_FIELD    5
+#define STV090x_OFFST_Px_FRAME_TYPE_FIELD      0
+#define STV090x_WIDTH_Px_FRAME_TYPE_FIELD      2
+
+#define STV090x_Px_BBFCRCKO1(__x)              (0xf56b - (__x - 1) * 0x200)
+#define STV090x_P1_BBFCRCKO1                   STV090x_Px_BBFCRCKO1(1)
+#define STV090x_P2_BBFCRCKO1                   STV090x_Px_BBFCRCKO1(2)
+#define STV090x_OFFST_Px_BBHCRC_KOCNT_FIELD    0
+#define STV090x_WIDTH_Px_BBHCRC_KOCNT_FIELD    8
+
+#define STV090x_Px_BBFCRCKO0(__x)              (0xf56c - (__x - 1) * 0x200)
+#define STV090x_P1_BBFCRCKO0                   STV090x_Px_BBFCRCKO0(1)
+#define STV090x_P2_BBFCRCKO0                   STV090x_Px_BBFCRCKO0(2)
+#define STV090x_OFFST_Px_BBHCRC_KOCNT_FIELD    0
+#define STV090x_WIDTH_Px_BBHCRC_KOCNT_FIELD    8
+
+#define STV090x_Px_UPCRCKO1(__x)               (0xf56d - (__x - 1) * 0x200)
+#define STV090x_P1_UPCRCKO1                    STV090x_Px_UPCRCKO1(1)
+#define STV090x_P2_UPCRCKO1                    STV090x_Px_UPCRCKO1(2)
+#define STV090x_OFFST_Px_PKTCRC_KOCNT_FIELD    0
+#define STV090x_WIDTH_Px_PKTCRC_KOCNT_FIELD    8
+
+#define STV090x_Px_UPCRCKO0(__x)               (0xf56e - (__x - 1) * 0x200)
+#define STV090x_P1_UPCRCKO0                    STV090x_Px_UPCRCKO0(1)
+#define STV090x_P2_UPCRCKO0                    STV090x_Px_UPCRCKO0(2)
+#define STV090x_OFFST_Px_PKTCRC_KOCNT_FIELD    0
+#define STV090x_WIDTH_Px_PKTCRC_KOCNT_FIELD    8
+
+#define STV090x_NBITER_NFx(__x)                                (0xFA03 + (__x - 4) * 0x1)
+#define STV090x_NBITER_NF4                             STV090x_NBITER_NFx(4)
+#define STV090x_NBITER_NF5                             STV090x_NBITER_NFx(5)
+#define STV090x_NBITER_NF6                             STV090x_NBITER_NFx(6)
+#define STV090x_NBITER_NF7                             STV090x_NBITER_NFx(7)
+#define STV090x_NBITER_NF8                             STV090x_NBITER_NFx(8)
+#define STV090x_NBITER_NF9                             STV090x_NBITER_NFx(9)
+#define STV090x_NBITER_NF10                            STV090x_NBITER_NFx(10)
+#define STV090x_NBITER_NF11                            STV090x_NBITER_NFx(11)
+#define STV090x_NBITER_NF12                            STV090x_NBITER_NFx(12)
+#define STV090x_NBITER_NF13                            STV090x_NBITER_NFx(13)
+#define STV090x_NBITER_NF14                            STV090x_NBITER_NFx(14)
+#define STV090x_NBITER_NF15                            STV090x_NBITER_NFx(15)
+#define STV090x_NBITER_NF16                            STV090x_NBITER_NFx(16)
+#define STV090x_NBITER_NF17                            STV090x_NBITER_NFx(17)
+
+#define STV090x_NBITERNOERR                            0xFA3F
+#define STV090x_OFFST_NBITER_STOP_CRIT_FIELD           0
+#define STV090x_WIDTH_NBITER_STOP_CRIT_FIELD           4
+
+#define STV090x_GAINLLR_NFx(__x)                       (0xFA43 + (__x - 4) * 0x1)
+#define STV090x_GAINLLR_NF4                            STV090x_GAINLLR_NFx(4)
+#define STV090x_OFFST_GAINLLR_NF_QP_1_2_FIELD          0
+#define STV090x_WIDTH_GAINLLR_NF_QP_1_2_FIELD          7
+
+#define STV090x_GAINLLR_NF5                            STV090x_GAINLLR_NFx(5)
+#define STV090x_OFFST_GAINLLR_NF_QP_3_5_FIELD          0
+#define STV090x_WIDTH_GAINLLR_NF_QP_3_5_FIELD          7
+
+#define STV090x_GAINLLR_NF6                            STV090x_GAINLLR_NFx(6)
+#define STV090x_OFFST_GAINLLR_NF_QP_2_3_FIELD          0
+#define STV090x_WIDTH_GAINLLR_NF_QP_2_3_FIELD          7
+
+#define STV090x_GAINLLR_NF7                            STV090x_GAINLLR_NFx(7)
+#define STV090x_OFFST_GAINLLR_NF_QP_3_4_FIELD          0
+#define STV090x_WIDTH_GAINLLR_NF_QP_3_4_FIELD          7
+
+#define STV090x_GAINLLR_NF8                            STV090x_GAINLLR_NFx(8)
+#define STV090x_OFFST_GAINLLR_NF_QP_4_5_FIELD          0
+#define STV090x_WIDTH_GAINLLR_NF_QP_4_5_FIELD          7
+
+#define STV090x_GAINLLR_NF9                            STV090x_GAINLLR_NFx(9)
+#define STV090x_OFFST_GAINLLR_NF_QP_5_6_FIELD          0
+#define STV090x_WIDTH_GAINLLR_NF_QP_5_6_FIELD          7
+
+#define STV090x_GAINLLR_NF10                           STV090x_GAINLLR_NFx(10)
+#define STV090x_OFFST_GAINLLR_NF_QP_8_9_FIELD          0
+#define STV090x_WIDTH_GAINLLR_NF_QP_8_9_FIELD          7
+
+#define STV090x_GAINLLR_NF11                           STV090x_GAINLLR_NFx(11)
+#define STV090x_OFFST_GAINLLR_NF_QP_9_10_FIELD         0
+#define STV090x_WIDTH_GAINLLR_NF_QP_9_10_FIELD         7
+
+#define STV090x_GAINLLR_NF12                           STV090x_GAINLLR_NFx(12)
+#define STV090x_OFFST_GAINLLR_NF_8P_3_5_FIELD          0
+#define STV090x_WIDTH_GAINLLR_NF_8P_3_5_FIELD          7
+
+#define STV090x_GAINLLR_NF13                           STV090x_GAINLLR_NFx(13)
+#define STV090x_OFFST_GAINLLR_NF_8P_2_3_FIELD          0
+#define STV090x_WIDTH_GAINLLR_NF_8P_2_3_FIELD          7
+
+#define STV090x_GAINLLR_NF14                           STV090x_GAINLLR_NFx(14)
+#define STV090x_OFFST_GAINLLR_NF_8P_3_4_FIELD          0
+#define STV090x_WIDTH_GAINLLR_NF_8P_3_4_FIELD          7
+
+#define STV090x_GAINLLR_NF15                           STV090x_GAINLLR_NFx(15)
+#define STV090x_OFFST_GAINLLR_NF_8P_5_6_FIELD          0
+#define STV090x_WIDTH_GAINLLR_NF_8P_5_6_FIELD          7
+
+#define STV090x_GAINLLR_NF16                           STV090x_GAINLLR_NFx(16)
+#define STV090x_OFFST_GAINLLR_NF_8P_8_9_FIELD          0
+#define STV090x_WIDTH_GAINLLR_NF_8P_8_9_FIELD          7
+
+#define STV090x_GAINLLR_NF17                           STV090x_GAINLLR_NFx(17)
+#define STV090x_OFFST_GAINLLR_NF_8P_9_10_FIELD         0
+#define STV090x_WIDTH_GAINLLR_NF_8P_9_10_FIELD         7
+
+#define STV090x_GENCFG                                 0xFA86
+#define STV090x_OFFST_BROADCAST_FIELD                  4
+#define STV090x_WIDTH_BROADCAST_FIELD                  1
+#define STV090x_OFFST_PRIORITY_FIELD                   1
+#define STV090x_WIDTH_PRIORITY_FIELD                   1
+#define STV090x_OFFST_DDEMOD_FIELD                     0
+#define STV090x_WIDTH_DDEMOD_FIELD                     1
+
+#define STV090x_LDPCERRx(__x)                          (0xFA97 - (__x  * 0x1))
+#define STV090x_LDPCERR0                               STV090x_LDPCERRx(0)
+#define STV090x_LDPCERR1                               STV090x_LDPCERRx(1)
+#define STV090x_OFFST_Px_LDPC_ERRORS_COUNTER_FIELD     0
+#define STV090x_WIDTH_Px_LDPC_ERRORS_COUNTER_FIELD     8
+
+#define STV090x_BCHERR                                 0xFA98
+#define STV090x_OFFST_Px_ERRORFLAG_FIELD               4
+#define STV090x_WIDTH_Px_ERRORFLAG_FIELD               1
+#define STV090x_OFFST_Px_BCH_ERRORS_COUNTER_FIELD      0
+#define STV090x_WIDTH_Px_BCH_ERRORS_COUNTER_FIELD      4
+
+#define STV090x_Px_TSSTATEM(__x)                       (0xF570 - (__x - 1) * 0x200)
+#define STV090x_P1_TSSTATEM                            STV090x_Px_TSSTATEM(1)
+#define STV090x_P2_TSSTATEM                            STV090x_Px_TSSTATEM(2)
+#define STV090x_OFFST_Px_TSDIL_ON_FIELD                        7
+#define STV090x_WIDTH_Px_TSDIL_ON_FIELD                        1
+#define STV090x_OFFST_Px_TSRS_ON_FIELD                 5
+#define STV090x_WIDTH_Px_TSRS_ON_FIELD                 1
+
+#define STV090x_Px_TSCFGH(__x)                         (0xF572 - (__x - 1) * 0x200)
+#define STV090x_P1_TSCFGH                              STV090x_Px_TSCFGH(1)
+#define STV090x_P2_TSCFGH                              STV090x_Px_TSCFGH(2)
+#define STV090x_OFFST_Px_TSFIFO_DVBCI_FIELD            7
+#define STV090x_WIDTH_Px_TSFIFO_DVBCI_FIELD            1
+#define STV090x_OFFST_Px_TSFIFO_SERIAL_FIELD           6
+#define STV090x_WIDTH_Px_TSFIFO_SERIAL_FIELD           1
+#define STV090x_OFFST_Px_TSFIFO_TEIUPDATE_FIELD                5
+#define STV090x_WIDTH_Px_TSFIFO_TEIUPDATE_FIELD                1
+#define STV090x_OFFST_Px_TSFIFO_DUTY50_FIELD           4
+#define STV090x_WIDTH_Px_TSFIFO_DUTY50_FIELD           1
+#define STV090x_OFFST_Px_TSFIFO_HSGNLOUT_FIELD         3
+#define STV090x_WIDTH_Px_TSFIFO_HSGNLOUT_FIELD         1
+#define STV090x_OFFST_Px_TSFIFO_ERRORMODE_FIELD                1
+#define STV090x_WIDTH_Px_TSFIFO_ERRORMODE_FIELD                2
+#define STV090x_OFFST_Px_RST_HWARE_FIELD               0
+#define STV090x_WIDTH_Px_RST_HWARE_FIELD               1
+
+#define STV090x_Px_TSCFGM(__x)                         (0xF573 - (__x - 1) * 0x200)
+#define STV090x_P1_TSCFGM                              STV090x_Px_TSCFGM(1)
+#define STV090x_P2_TSCFGM                              STV090x_Px_TSCFGM(2)
+#define STV090x_OFFST_Px_TSFIFO_MANSPEED_FIELD         6
+#define STV090x_WIDTH_Px_TSFIFO_MANSPEED_FIELD         2
+#define STV090x_OFFST_Px_TSFIFO_PERMDATA_FIELD         5
+#define STV090x_WIDTH_Px_TSFIFO_PERMDATA_FIELD         1
+#define STV090x_OFFST_Px_TSFIFO_INVDATA_FIELD          0
+#define STV090x_WIDTH_Px_TSFIFO_INVDATA_FIELD          1
+
+#define STV090x_Px_TSCFGL(__x)                         (0xF574 - (__x - 1) * 0x200)
+#define STV090x_P1_TSCFGL                              STV090x_Px_TSCFGL(1)
+#define STV090x_P2_TSCFGL                              STV090x_Px_TSCFGL(2)
+#define STV090x_OFFST_Px_TSFIFO_BCLKDEL1CK_FIELD       6
+#define STV090x_WIDTH_Px_TSFIFO_BCLKDEL1CK_FIELD       2
+#define STV090x_OFFST_Px_BCHERROR_MODE_FIELD           4
+#define STV090x_WIDTH_Px_BCHERROR_MODE_FIELD           2
+#define STV090x_OFFST_Px_TSFIFO_NSGNL2DATA_FIELD       3
+#define STV090x_WIDTH_Px_TSFIFO_NSGNL2DATA_FIELD       1
+#define STV090x_OFFST_Px_TSFIFO_EMBINDVB_FIELD         2
+#define STV090x_WIDTH_Px_TSFIFO_EMBINDVB_FIELD         1
+#define STV090x_OFFST_Px_TSFIFO_DPUNACT_FIELD          1
+#define STV090x_WIDTH_Px_TSFIFO_DPUNACT_FIELD          1
+
+#define STV090x_Px_TSINSDELH(__x)                      (0xF576 - (__x - 1) * 0x200)
+#define STV090x_P1_TSINSDELH                           STV090x_Px_TSINSDELH(1)
+#define STV090x_P2_TSINSDELH                           STV090x_Px_TSINSDELH(2)
+#define STV090x_OFFST_Px_TSDEL_SYNCBYTE_FIELD          7
+#define STV090x_WIDTH_Px_TSDEL_SYNCBYTE_FIELD          1
+#define STV090x_OFFST_Px_TSDEL_XXHEADER_FIELD          6
+#define STV090x_WIDTH_Px_TSDEL_XXHEADER_FIELD          1
+
+#define STV090x_Px_TSSPEED(__x)                                (0xF580 - (__x - 1) * 0x200)
+#define STV090x_P1_TSSPEED                             STV090x_Px_TSSPEED(1)
+#define STV090x_P2_TSSPEED                             STV090x_Px_TSSPEED(2)
+#define STV090x_OFFST_Px_TSFIFO_OUTSPEED_FIELD         0
+#define STV090x_WIDTH_Px_TSFIFO_OUTSPEED_FIELD         8
+
+#define STV090x_Px_TSSTATUS(__x)                       (0xF581 - (__x - 1) * 0x200)
+#define STV090x_P1_TSSTATUS                            STV090x_Px_TSSTATUS(1)
+#define STV090x_P2_TSSTATUS                            STV090x_Px_TSSTATUS(2)
+#define STV090x_OFFST_Px_TSFIFO_LINEOK_FIELD           7
+#define STV090x_WIDTH_Px_TSFIFO_LINEOK_FIELD           1
+#define STV090x_OFFST_Px_TSFIFO_ERROR_FIELD            6
+#define STV090x_WIDTH_Px_TSFIFO_ERROR_FIELD            1
+
+#define STV090x_Px_TSSTATUS2(__x)                      (0xF582 - (__x - 1) * 0x200)
+#define STV090x_P1_TSSTATUS2                           STV090x_Px_TSSTATUS2(1)
+#define STV090x_P2_TSSTATUS2                           STV090x_Px_TSSTATUS2(2)
+#define STV090x_OFFST_Px_TSFIFO_DEMODSEL_FIELD         7
+#define STV090x_WIDTH_Px_TSFIFO_DEMODSEL_FIELD         1
+#define STV090x_OFFST_Px_TSFIFOSPEED_STORE_FIELD       6
+#define STV090x_WIDTH_Px_TSFIFOSPEED_STORE_FIELD       1
+#define STV090x_OFFST_Px_DILXX_RESET_FIELD             5
+#define STV090x_WIDTH_Px_DILXX_RESET_FIELD             1
+#define STV090x_OFFST_Px_TSSERIAL_IMPOS_FIELD          5
+#define STV090x_WIDTH_Px_TSSERIAL_IMPOS_FIELD          1
+#define STV090x_OFFST_Px_SCRAMBDETECT_FIELD            1
+#define STV090x_WIDTH_Px_SCRAMBDETECT_FIELD            1
+
+#define STV090x_Px_TSBITRATEy(__x, __y)                        (0xF584 - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_TSBITRATE0                          STV090x_Px_TSBITRATEy(1, 0)
+#define STV090x_P1_TSBITRATE1                          STV090x_Px_TSBITRATEy(1, 1)
+#define STV090x_P2_TSBITRATE0                          STV090x_Px_TSBITRATEy(2, 0)
+#define STV090x_P2_TSBITRATE1                          STV090x_Px_TSBITRATEy(2, 1)
+#define STV090x_OFFST_Px_TSFIFO_BITRATE_FIELD          7
+#define STV090x_WIDTH_Px_TSFIFO_BITRATE_FIELD          8
+
+#define STV090x_Px_ERRCTRL1(__x)                       (0xF598 - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCTRL1                            STV090x_Px_ERRCTRL1(1)
+#define STV090x_P2_ERRCTRL1                            STV090x_Px_ERRCTRL1(2)
+#define STV090x_OFFST_Px_ERR_SOURCE_FIELD              4
+#define STV090x_WIDTH_Px_ERR_SOURCE_FIELD              4
+#define STV090x_OFFST_Px_NUM_EVENT_FIELD               0
+#define STV090x_WIDTH_Px_NUM_EVENT_FIELD               3
+
+#define STV090x_Px_ERRCNT12(__x)                       (0xF599 - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCNT12                            STV090x_Px_ERRCNT12(1)
+#define STV090x_P2_ERRCNT12                            STV090x_Px_ERRCNT12(2)
+#define STV090x_OFFST_Px_ERRCNT1_OLDVALUE_FIELD                7
+#define STV090x_WIDTH_Px_ERRCNT1_OLDVALUE_FIELD                1
+#define STV090x_OFFST_Px_ERR_CNT12_FIELD               0
+#define STV090x_WIDTH_Px_ERR_CNT12_FIELD               7
+
+#define STV090x_Px_ERRCNT11(__x)                       (0xF59A - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCNT11                            STV090x_Px_ERRCNT11(1)
+#define STV090x_P2_ERRCNT11                            STV090x_Px_ERRCNT11(2)
+#define STV090x_OFFST_Px_ERR_CNT11_FIELD               0
+#define STV090x_WIDTH_Px_ERR_CNT11_FIELD               8
+
+#define STV090x_Px_ERRCNT10(__x)                       (0xF59B - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCNT10                            STV090x_Px_ERRCNT10(1)
+#define STV090x_P2_ERRCNT10                            STV090x_Px_ERRCNT10(2)
+#define STV090x_OFFST_Px_ERR_CNT10_FIELD               0
+#define STV090x_WIDTH_Px_ERR_CNT10_FIELD               8
+
+#define STV090x_Px_ERRCTRL2(__x)                       (0xF59C - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCTRL2                            STV090x_Px_ERRCTRL2(1)
+#define STV090x_P2_ERRCTRL2                            STV090x_Px_ERRCTRL2(2)
+#define STV090x_OFFST_Px_ERR_SOURCE2_FIELD             4
+#define STV090x_WIDTH_Px_ERR_SOURCE2_FIELD             4
+#define STV090x_OFFST_Px_NUM_EVENT2_FIELD              0
+#define STV090x_WIDTH_Px_NUM_EVENT2_FIELD              3
+
+#define STV090x_Px_ERRCNT22(__x)                       (0xF59D - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCNT22                            STV090x_Px_ERRCNT22(1)
+#define STV090x_P2_ERRCNT22                            STV090x_Px_ERRCNT22(2)
+#define STV090x_OFFST_Px_ERRCNT2_OLDVALUE_FIELD                7
+#define STV090x_WIDTH_Px_ERRCNT2_OLDVALUE_FIELD                1
+#define STV090x_OFFST_Px_ERR_CNT2_FIELD                        0
+#define STV090x_WIDTH_Px_ERR_CNT2_FIELD                        7
+
+#define STV090x_Px_ERRCNT21(__x)                       (0xF59E - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCNT21                            STV090x_Px_ERRCNT21(1)
+#define STV090x_P2_ERRCNT21                            STV090x_Px_ERRCNT21(2)
+#define STV090x_OFFST_Px_ERR_CNT21_FIELD               0
+#define STV090x_WIDTH_Px_ERR_CNT21_FIELD               8
+
+#define STV090x_Px_ERRCNT20(__x)                       (0xF59F - (__x - 1) * 0x200)
+#define STV090x_P1_ERRCNT20                            STV090x_Px_ERRCNT20(1)
+#define STV090x_P2_ERRCNT20                            STV090x_Px_ERRCNT20(2)
+#define STV090x_OFFST_Px_ERR_CNT20_FIELD               0
+#define STV090x_WIDTH_Px_ERR_CNT20_FIELD               8
+
+#define STV090x_Px_FECSPY(__x)                         (0xF5A0 - (__x - 1) * 0x200)
+#define STV090x_P1_FECSPY                              STV090x_Px_FECSPY(1)
+#define STV090x_P2_FECSPY                              STV090x_Px_FECSPY(2)
+#define STV090x_OFFST_Px_SPY_ENABLE_FIELD              7
+#define STV090x_WIDTH_Px_SPY_ENABLE_FIELD              1
+#define STV090x_OFFST_Px_BERMETER_DATAMAODE_FIELD      2
+#define STV090x_WIDTH_Px_BERMETER_DATAMAODE_FIELD      2
+
+#define STV090x_Px_FSPYCFG(__x)                                (0xF5A1 - (__x - 1) * 0x200)
+#define STV090x_P1_FSPYCFG                             STV090x_Px_FSPYCFG(1)
+#define STV090x_P2_FSPYCFG                             STV090x_Px_FSPYCFG(2)
+#define STV090x_OFFST_Px_RST_ON_ERROR_FIELD            5
+#define STV090x_WIDTH_Px_RST_ON_ERROR_FIELD            1
+#define STV090x_OFFST_Px_ONE_SHOT_FIELD                        4
+#define STV090x_WIDTH_Px_ONE_SHOT_FIELD                        1
+#define STV090x_OFFST_Px_I2C_MODE_FIELD                        2
+#define STV090x_WIDTH_Px_I2C_MODE_FIELD                        2
+
+#define STV090x_Px_FSPYDATA(__x)                       (0xF5A2 - (__x - 1) * 0x200)
+#define STV090x_P1_FSPYDATA                            STV090x_Px_FSPYDATA(1)
+#define STV090x_P2_FSPYDATA                            STV090x_Px_FSPYDATA(2)
+#define STV090x_OFFST_Px_SPY_STUFFING_FIELD            7
+#define STV090x_WIDTH_Px_SPY_STUFFING_FIELD            1
+#define STV090x_OFFST_Px_SPY_CNULLPKT_FIELD            5
+#define STV090x_WIDTH_Px_SPY_CNULLPKT_FIELD            1
+#define STV090x_OFFST_Px_SPY_OUTDATA_MODE_FIELD                0
+#define STV090x_WIDTH_Px_SPY_OUTDATA_MODE_FIELD                5
+
+#define STV090x_Px_FSPYOUT(__x)                                (0xF5A3 - (__x - 1) * 0x200)
+#define STV090x_P1_FSPYOUT                             STV090x_Px_FSPYOUT(1)
+#define STV090x_P2_FSPYOUT                             STV090x_Px_FSPYOUT(2)
+#define STV090x_OFFST_Px_FSPY_DIRECT_FIELD             7
+#define STV090x_WIDTH_Px_FSPY_DIRECT_FIELD             1
+#define STV090x_OFFST_Px_STUFF_MODE_FIELD              0
+#define STV090x_WIDTH_Px_STUFF_MODE_FIELD              3
+
+#define STV090x_Px_FSTATUS(__x)                                (0xF5A4 - (__x - 1) * 0x200)
+#define STV090x_P1_FSTATUS                             STV090x_Px_FSTATUS(1)
+#define STV090x_P2_FSTATUS                             STV090x_Px_FSTATUS(2)
+#define STV090x_OFFST_Px_SPY_ENDSIM_FIELD              7
+#define STV090x_WIDTH_Px_SPY_ENDSIM_FIELD              1
+#define STV090x_OFFST_Px_VALID_SIM_FIELD               6
+#define STV090x_WIDTH_Px_VALID_SIM_FIELD               1
+#define STV090x_OFFST_Px_FOUND_SIGNAL_FIELD            5
+#define STV090x_WIDTH_Px_FOUND_SIGNAL_FIELD            1
+#define STV090x_OFFST_Px_DSS_SYNCBYTE_FIELD            4
+#define STV090x_WIDTH_Px_DSS_SYNCBYTE_FIELD            1
+#define STV090x_OFFST_Px_RESULT_STATE_FIELD            0
+#define STV090x_WIDTH_Px_RESULT_STATE_FIELD            4
+
+#define STV090x_Px_FBERCPT4(__x)                       (0xF5A8 - (__x - 1) * 0x200)
+#define STV090x_P1_FBERCPT4                            STV090x_Px_FBERCPT4(1)
+#define STV090x_P2_FBERCPT4                            STV090x_Px_FBERCPT4(2)
+#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD           0
+#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD           8
+
+#define STV090x_Px_FBERCPT3(__x)                       (0xF5A9 - (__x - 1) * 0x200)
+#define STV090x_P1_FBERCPT3                            STV090x_Px_FBERCPT3(1)
+#define STV090x_P2_FBERCPT3                            STV090x_Px_FBERCPT3(2)
+#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD           0
+#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD           8
+
+#define STV090x_Px_FBERCPT2(__x)                       (0xF5AA - (__x - 1) * 0x200)
+#define STV090x_P1_FBERCPT2                            STV090x_Px_FBERCPT2(1)
+#define STV090x_P2_FBERCPT2                            STV090x_Px_FBERCPT2(2)
+#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD           0
+#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD           8
+
+#define STV090x_Px_FBERCPT1(__x)                       (0xF5AB - (__x - 1) * 0x200)
+#define STV090x_P1_FBERCPT1                            STV090x_Px_FBERCPT1(1)
+#define STV090x_P2_FBERCPT1                            STV090x_Px_FBERCPT1(2)
+#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD           0
+#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD           8
+
+#define STV090x_Px_FBERCPT0(__x)                       (0xF5AC - (__x - 1) * 0x200)
+#define STV090x_P1_FBERCPT0                            STV090x_Px_FBERCPT0(1)
+#define STV090x_P2_FBERCPT0                            STV090x_Px_FBERCPT0(2)
+#define STV090x_OFFST_Px_FBERMETER_CPT_FIELD           0
+#define STV090x_WIDTH_Px_FBERMETER_CPT_FIELD           8
+
+#define STV090x_Px_FBERERRy(__x, __y)                  (0xF5AF - (__x - 1) * 0x200 - __y * 0x1)
+#define STV090x_P1_FBERERR0                            STV090x_Px_FBERERRy(1, 0)
+#define STV090x_P1_FBERERR1                            STV090x_Px_FBERERRy(1, 1)
+#define STV090x_P1_FBERERR2                            STV090x_Px_FBERERRy(1, 2)
+#define STV090x_P2_FBERERR0                            STV090x_Px_FBERERRy(2, 0)
+#define STV090x_P2_FBERERR1                            STV090x_Px_FBERERRy(2, 1)
+#define STV090x_P2_FBERERR2                            STV090x_Px_FBERERRy(2, 2)
+#define STV090x_OFFST_Px_FBERMETER_CPT_ERR_FIELD       0
+#define STV090x_WIDTH_Px_FBERMETER_CPT_ERR_FIELD       8
+
+#define STV090x_Px_FSPYBER(__x)                                (0xF5B2 - (__x - 1) * 0x200)
+#define STV090x_P1_FSPYBER                             STV090x_Px_FSPYBER(1)
+#define STV090x_P2_FSPYBER                             STV090x_Px_FSPYBER(2)
+#define STV090x_OFFST_Px_FSPYBER_SYNCBYTE_FIELD                4
+#define STV090x_WIDTH_Px_FSPYBER_SYNCBYTE_FIELD                1
+#define STV090x_OFFST_Px_FSPYBER_UNSYNC_FIELD          3
+#define STV090x_WIDTH_Px_FSPYBER_UNSYNC_FIELD          1
+#define STV090x_OFFST_Px_FSPYBER_CTIME_FIELD           0
+#define STV090x_WIDTH_Px_FSPYBER_CTIME_FIELD           3
+
+#define STV090x_RCCFGH                                 0xf600
+
+#define STV090x_TSGENERAL                              0xF630
+#define STV090x_OFFST_Px_MUXSTREAM_OUT_FIELD           3
+#define STV090x_WIDTH_Px_MUXSTREAM_OUT_FIELD           1
+#define STV090x_OFFST_Px_TSFIFO_PERMPARAL_FIELD                1
+#define STV090x_WIDTH_Px_TSFIFO_PERMPARAL_FIELD                2
+
+#define STV090x_TSGENERAL1X                            0xf670
+#define STV090x_CFGEXT                                 0xfa80
+
+#define STV090x_TSTRES0                                        0xFF11
+#define STV090x_OFFST_FRESFEC_FIELD                    7
+#define STV090x_WIDTH_FRESFEC_FIELD                    1
+
+#define STV090x_Px_TSTDISRX(__x)                       (0xFF67 - (__x - 1) * 0x2)
+#define STV090x_P1_TSTDISRX                            STV090x_Px_TSTDISRX(1)
+#define STV090x_P2_TSTDISRX                            STV090x_Px_TSTDISRX(2)
+#define STV090x_OFFST_Px_TSTDISRX_SELECT_FIELD         3
+#define STV090x_WIDTH_Px_TSTDISRX_SELECT_FIELD         1
+
+#endif /* __STV090x_REG_H */
diff --git a/drivers/media/dvb/frontends/stv6110x.c b/drivers/media/dvb/frontends/stv6110x.c
new file mode 100644 (file)
index 0000000..3d8a2e0
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+       STV6110(A) Silicon tuner driver
+
+       Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+       Copyright (C) ST Microelectronics
+
+       This program is free software; you can redistribute it and/or modify
+       it under the terms of the GNU General Public License as published by
+       the Free Software Foundation; either version 2 of the License, or
+       (at your option) any later version.
+
+       This program is distributed in the hope that it will be useful,
+       but WITHOUT ANY WARRANTY; without even the implied warranty of
+       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+       GNU General Public License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with this program; if not, write to the Free Software
+       Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+
+#include "dvb_frontend.h"
+
+#include "stv6110x_reg.h"
+#include "stv6110x.h"
+#include "stv6110x_priv.h"
+
+static unsigned int verbose;
+module_param(verbose, int, 0644);
+MODULE_PARM_DESC(verbose, "Set Verbosity level");
+
+static u8 stv6110x_regs[] = {0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e};
+
+static int stv6110x_read_reg(struct stv6110x_state *stv6110x, u8 reg, u8 *data)
+{
+       int ret;
+       const struct stv6110x_config *config = stv6110x->config;
+       u8 b0[] = { reg };
+       u8 b1[] = { 0 };
+       struct i2c_msg msg[] = {
+               { .addr = config->addr, .flags = 0,        .buf = b0, .len = 1 },
+               { .addr = config->addr, .flags = I2C_M_RD, .buf = b1, .len = 1 }
+       };
+
+       ret = i2c_transfer(stv6110x->i2c, msg, 2);
+       if (ret != 2) {
+               dprintk(FE_ERROR, 1, "I/O Error");
+               return -EREMOTEIO;
+       }
+       *data = b1[0];
+
+       return 0;
+}
+
+static int stv6110x_write_reg(struct stv6110x_state *stv6110x, u8 reg, u8 data)
+{
+       int ret;
+       const struct stv6110x_config *config = stv6110x->config;
+       u8 buf[] = { reg, data };
+       struct i2c_msg msg = { .addr = config->addr, .flags = 0, . buf = buf, .len = 2 };
+
+       ret = i2c_transfer(stv6110x->i2c, &msg, 1);
+       if (ret != 1) {
+               dprintk(FE_ERROR, 1, "I/O Error");
+               return -EREMOTEIO;
+       }
+
+       return 0;
+}
+
+static int stv6110x_init(struct dvb_frontend *fe)
+{
+       struct stv6110x_state *stv6110x = fe->tuner_priv;
+       int ret;
+       u8 i;
+
+       for (i = 0; i < ARRAY_SIZE(stv6110x_regs); i++) {
+               ret = stv6110x_write_reg(stv6110x, i, stv6110x_regs[i]);
+               if (ret < 0) {
+                       dprintk(FE_ERROR, 1, "Initialization failed");
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static int stv6110x_set_frequency(struct dvb_frontend *fe, u32 frequency)
+{
+       struct stv6110x_state *stv6110x = fe->tuner_priv;
+       u32 rDiv, divider;
+       s32 pVal, pCalc, rDivOpt = 0;
+       u8 i;
+
+       STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_K, (REFCLOCK_MHz - 16));
+
+       if (frequency <= 1023000) {
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 1);
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0);
+               pVal = 40;
+       } else if (frequency <= 1300000) {
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 1);
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1);
+               pVal = 40;
+       } else if (frequency <= 2046000) {
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 0);
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 0);
+               pVal = 20;
+       } else {
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_DIV4SEL, 0);
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_PRESC32_ON, 1);
+               pVal = 20;
+       }
+
+       for (rDiv = 0; rDiv <= 3; rDiv++) {
+               pCalc = (REFCLOCK_kHz / 100) / R_DIV(rDiv);
+
+               if ((abs((s32)(pCalc - pVal))) < (abs((s32)(1000 - pVal))))
+                       rDivOpt = rDiv;
+       }
+
+       divider = (frequency * R_DIV(rDivOpt) * pVal) / REFCLOCK_kHz;
+       divider = (divider + 5) / 10;
+
+       STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_R_DIV, rDivOpt);
+       STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG1], TNG1_N_DIV_11_8, MSB(divider));
+       STV6110x_SETFIELD(stv6110x_regs[STV6110x_TNG0], TNG0_N_DIV_7_0, LSB(divider));
+
+       /* VCO Auto calibration */
+       STV6110x_SETFIELD(stv6110x_regs[STV6110x_STAT1], STAT1_CALVCO_STRT, 1);
+
+       stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x_regs[STV6110x_CTRL1]);
+       stv6110x_write_reg(stv6110x, STV6110x_TNG1, stv6110x_regs[STV6110x_TNG1]);
+       stv6110x_write_reg(stv6110x, STV6110x_TNG0, stv6110x_regs[STV6110x_TNG0]);
+       stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x_regs[STV6110x_STAT1]);
+
+       for (i = 0; i < TRIALS; i++) {
+               stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x_regs[STV6110x_STAT1]);
+               if (!STV6110x_GETFIELD(STAT1_CALVCO_STRT, stv6110x_regs[STV6110x_STAT1]))
+                               break;
+               msleep(1);
+       }
+
+       return 0;
+}
+
+static int stv6110x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+       stv6110x_read_reg(stv6110x, STV6110x_TNG1, &stv6110x_regs[STV6110x_TNG1]);
+       stv6110x_read_reg(stv6110x, STV6110x_TNG0, &stv6110x_regs[STV6110x_TNG0]);
+
+       *frequency = (MAKEWORD16(STV6110x_GETFIELD(TNG1_N_DIV_11_8, stv6110x_regs[STV6110x_TNG1]),
+                                STV6110x_GETFIELD(TNG0_N_DIV_7_0, stv6110x_regs[STV6110x_TNG0]))) * REFCLOCK_kHz;
+
+       *frequency /= (1 << (STV6110x_GETFIELD(TNG1_R_DIV, stv6110x_regs[STV6110x_TNG1]) +
+                            STV6110x_GETFIELD(TNG1_DIV4SEL, stv6110x_regs[STV6110x_TNG1])));
+
+       *frequency >>= 2;
+
+       return 0;
+}
+
+static int stv6110x_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
+{
+       struct stv6110x_state *stv6110x = fe->tuner_priv;
+       u32 halfbw;
+       u8 i;
+
+       halfbw = bandwidth >> 1;
+
+       if (halfbw > 36000000)
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_CF, 31); /* LPF */
+       else if (halfbw < 5000000)
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_CF, 0); /* LPF */
+       else
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_CF, ((halfbw / 1000000) - 5)); /* LPF */
+
+
+       STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x0); /* cal. clk activated */
+       STV6110x_SETFIELD(stv6110x_regs[STV6110x_STAT1], STAT1_CALRC_STRT, 0x1); /* LPF auto cal */
+
+       stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x_regs[STV6110x_CTRL3]);
+       stv6110x_write_reg(stv6110x, STV6110x_STAT1, stv6110x_regs[STV6110x_STAT1]);
+
+       for (i = 0; i < TRIALS; i++) {
+               stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x_regs[STV6110x_STAT1]);
+               if (!STV6110x_GETFIELD(STAT1_CALRC_STRT, stv6110x_regs[STV6110x_STAT1]))
+                       break;
+               msleep(1);
+       }
+       STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL3], CTRL3_RCCLK_OFF, 0x1); /* cal. done */
+       stv6110x_write_reg(stv6110x, STV6110x_CTRL3, stv6110x_regs[STV6110x_CTRL3]);
+
+       return 0;
+}
+
+static int stv6110x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+       struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+       stv6110x_read_reg(stv6110x, STV6110x_CTRL3, &stv6110x_regs[STV6110x_CTRL3]);
+       *bandwidth = (STV6110x_GETFIELD(CTRL3_CF, stv6110x_regs[STV6110x_CTRL3]) + 5) * 2000000;
+
+       return 0;
+}
+
+static int stv6110x_set_refclock(struct dvb_frontend *fe, u32 refclock)
+{
+       struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+       /* setup divider */
+       switch (refclock) {
+       default:
+       case 1:
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 0);
+               break;
+       case 2:
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 1);
+               break;
+       case 4:
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 2);
+               break;
+       case 8:
+       case 0:
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_CO_DIV, 3);
+               break;
+       }
+       stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x_regs[STV6110x_CTRL2]);
+
+       return 0;
+}
+
+static int stv6110x_get_bbgain(struct dvb_frontend *fe, u32 *gain)
+{
+       struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+       stv6110x_read_reg(stv6110x, STV6110x_CTRL2, &stv6110x_regs[STV6110x_CTRL2]);
+       *gain = 2 * STV6110x_GETFIELD(CTRL2_BBGAIN, stv6110x_regs[STV6110x_CTRL2]);
+
+       return 0;
+}
+
+static int stv6110x_set_bbgain(struct dvb_frontend *fe, u32 gain)
+{
+       struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+       STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL2], CTRL2_BBGAIN, gain / 2);
+       stv6110x_write_reg(stv6110x, STV6110x_CTRL2, stv6110x_regs[STV6110x_CTRL2]);
+
+       return 0;
+}
+
+static int stv6110x_set_mode(struct dvb_frontend *fe, enum tuner_mode mode)
+{
+       struct stv6110x_state *stv6110x = fe->tuner_priv;
+       int ret;
+
+       switch (mode) {
+       case TUNER_SLEEP:
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_SYN, 0);
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_RX, 0);
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_LPT, 0);
+               break;
+
+       case TUNER_WAKE:
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_SYN, 1);
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_RX, 1);
+               STV6110x_SETFIELD(stv6110x_regs[STV6110x_CTRL1], CTRL1_LPT, 1);
+               break;
+       }
+
+       ret = stv6110x_write_reg(stv6110x, STV6110x_CTRL1, stv6110x_regs[STV6110x_CTRL1]);
+       if (ret < 0) {
+               dprintk(FE_ERROR, 1, "I/O Error");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int stv6110x_sleep(struct dvb_frontend *fe)
+{
+       return stv6110x_set_mode(fe, TUNER_SLEEP);
+}
+
+static int stv6110x_get_status(struct dvb_frontend *fe, u32 *status)
+{
+       struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+       stv6110x_read_reg(stv6110x, STV6110x_STAT1, &stv6110x_regs[STV6110x_STAT1]);
+
+       if (STV6110x_GETFIELD(STAT1_LOCK, stv6110x_regs[STV6110x_STAT1]))
+               *status = TUNER_PHASELOCKED;
+       else
+               *status = 0;
+
+       return 0;
+}
+
+
+static int stv6110x_release(struct dvb_frontend *fe)
+{
+       struct stv6110x_state *stv6110x = fe->tuner_priv;
+
+       fe->tuner_priv = NULL;
+       kfree(stv6110x);
+
+       return 0;
+}
+
+static struct dvb_tuner_ops stv6110x_ops = {
+       .info = {
+               .name           = "STV6110(A) Silicon Tuner",
+               .frequency_min  =  950000,
+               .frequency_max  = 2150000,
+               .frequency_step = 0,
+       },
+
+       .init                   = stv6110x_init,
+       .sleep                  = stv6110x_sleep,
+       .release                = stv6110x_release
+};
+
+static struct stv6110x_devctl stv6110x_ctl = {
+       .tuner_init             = stv6110x_init,
+       .tuner_set_mode         = stv6110x_set_mode,
+       .tuner_set_frequency    = stv6110x_set_frequency,
+       .tuner_get_frequency    = stv6110x_get_frequency,
+       .tuner_set_bandwidth    = stv6110x_set_bandwidth,
+       .tuner_get_bandwidth    = stv6110x_get_bandwidth,
+       .tuner_set_bbgain       = stv6110x_set_bbgain,
+       .tuner_get_bbgain       = stv6110x_get_bbgain,
+       .tuner_set_refclk       = stv6110x_set_refclock,
+       .tuner_get_status       = stv6110x_get_status,
+};
+
+struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
+                                       const struct stv6110x_config *config,
+                                       struct i2c_adapter *i2c)
+{
+       struct stv6110x_state *stv6110x;
+
+       stv6110x = kzalloc(sizeof (struct stv6110x_state), GFP_KERNEL);
+       if (stv6110x == NULL)
+               goto error;
+
+       stv6110x->i2c           = i2c;
+       stv6110x->config        = config;
+       stv6110x->devctl        = &stv6110x_ctl;
+
+       fe->tuner_priv          = stv6110x;
+       fe->ops.tuner_ops       = stv6110x_ops;
+
+       printk("%s: Attaching STV6110x \n", __func__);
+       return stv6110x->devctl;
+
+error:
+       kfree(stv6110x);
+       return NULL;
+}
+EXPORT_SYMBOL(stv6110x_attach);
+
+MODULE_AUTHOR("Manu Abraham");
+MODULE_DESCRIPTION("STV6110x Silicon tuner");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/stv6110x.h b/drivers/media/dvb/frontends/stv6110x.h
new file mode 100644 (file)
index 0000000..a382570
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+       STV6110(A) Silicon tuner driver
+
+       Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+       Copyright (C) ST Microelectronics
+
+       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 __STV6110x_H
+#define __STV6110x_H
+
+struct stv6110x_config {
+       u8      addr;
+       u32     refclk;
+};
+
+enum tuner_mode {
+       TUNER_SLEEP = 1,
+       TUNER_WAKE,
+};
+
+enum tuner_status {
+       TUNER_PHASELOCKED = 1,
+};
+
+struct stv6110x_devctl {
+       int (*tuner_init) (struct dvb_frontend *fe);
+       int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode);
+       int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency);
+       int (*tuner_get_frequency) (struct dvb_frontend *fe, u32 *frequency);
+       int (*tuner_set_bandwidth) (struct dvb_frontend *fe, u32 bandwidth);
+       int (*tuner_get_bandwidth) (struct dvb_frontend *fe, u32 *bandwidth);
+       int (*tuner_set_bbgain) (struct dvb_frontend *fe, u32 gain);
+       int (*tuner_get_bbgain) (struct dvb_frontend *fe, u32 *gain);
+       int (*tuner_set_refclk)  (struct dvb_frontend *fe, u32 refclk);
+       int (*tuner_get_status) (struct dvb_frontend *fe, u32 *status);
+};
+
+
+#if defined(CONFIG_DVB_STV6110x) || (defined(CONFIG_DVB_STV6110x_MODULE) && defined(MODULE))
+
+extern struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
+                                              const struct stv6110x_config *config,
+                                              struct i2c_adapter *i2c);
+
+#else
+static inline struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe,
+                                                     const struct stv6110x_config *config,
+                                                     struct i2c_adapter *i2c)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+
+#endif /* CONFIG_DVB_STV6110x */
+
+#endif /* __STV6110x_H */
diff --git a/drivers/media/dvb/frontends/stv6110x_priv.h b/drivers/media/dvb/frontends/stv6110x_priv.h
new file mode 100644 (file)
index 0000000..7260da6
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+       STV6110(A) Silicon tuner driver
+
+       Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+       Copyright (C) ST Microelectronics
+
+       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 __STV6110x_PRIV_H
+#define __STV6110x_PRIV_H
+
+#define FE_ERROR                               0
+#define FE_NOTICE                              1
+#define FE_INFO                                        2
+#define FE_DEBUG                               3
+#define FE_DEBUGREG                            4
+
+#define dprintk(__y, __z, format, arg...) do {                                         \
+       if (__z) {                                                                      \
+               if      ((verbose > FE_ERROR) && (verbose > __y))                       \
+                       printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);          \
+               else if ((verbose > FE_NOTICE) && (verbose > __y))                      \
+                       printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);       \
+               else if ((verbose > FE_INFO) && (verbose > __y))                        \
+                       printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);         \
+               else if ((verbose > FE_DEBUG) && (verbose > __y))                       \
+                       printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);        \
+       } else {                                                                        \
+               if (verbose > __y)                                                      \
+                       printk(format, ##arg);                                          \
+       }                                                                               \
+} while (0)
+
+
+#define STV6110x_SETFIELD(mask, bitf, val)                             \
+       (mask = (mask & (~(((1 << STV6110x_WIDTH_##bitf) - 1) <<        \
+                                 STV6110x_OFFST_##bitf))) |            \
+                         (val << STV6110x_OFFST_##bitf))
+
+#define STV6110x_GETFIELD(bitf, val)                                   \
+       ((val >> STV6110x_OFFST_##bitf) &                               \
+       ((1 << STV6110x_WIDTH_##bitf) - 1))
+
+#define MAKEWORD16(a, b)                       (((a) << 8) | (b))
+
+#define LSB(x)                                 ((x & 0xff))
+#define MSB(y)                                 ((y >> 8) & 0xff)
+
+#define TRIALS                                 10
+#define R_DIV(__div)                           (1 << (__div + 1))
+#define REFCLOCK_kHz                           (stv6110x->config->refclk /    1000)
+#define REFCLOCK_MHz                           (stv6110x->config->refclk / 1000000)
+
+struct stv6110x_state {
+       struct i2c_adapter              *i2c;
+       const struct stv6110x_config    *config;
+
+       struct stv6110x_devctl          *devctl;
+};
+
+#endif /* __STV6110x_PRIV_H */
diff --git a/drivers/media/dvb/frontends/stv6110x_reg.h b/drivers/media/dvb/frontends/stv6110x_reg.h
new file mode 100644 (file)
index 0000000..93e5c70
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+       STV6110(A) Silicon tuner driver
+
+       Copyright (C) Manu Abraham <abraham.manu@gmail.com>
+
+       Copyright (C) ST Microelectronics
+
+       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 __STV6110x_REG_H
+#define __STV6110x_REG_H
+
+#define STV6110x_CTRL1                         0x00
+#define STV6110x_OFFST_CTRL1_K                 3
+#define STV6110x_WIDTH_CTRL1_K                 5
+#define STV6110x_OFFST_CTRL1_LPT               2
+#define STV6110x_WIDTH_CTRL1_LPT               1
+#define STV6110x_OFFST_CTRL1_RX                        1
+#define STV6110x_WIDTH_CTRL1_RX                        1
+#define STV6110x_OFFST_CTRL1_SYN               0
+#define STV6110x_WIDTH_CTRL1_SYN               1
+
+#define STV6110x_CTRL2                         0x01
+#define STV6110x_OFFST_CTRL2_CO_DIV            6
+#define STV6110x_WIDTH_CTRL2_CO_DIV            2
+#define STV6110x_OFFST_CTRL2_RSVD              5
+#define STV6110x_WIDTH_CTRL2_RSVD              1
+#define STV6110x_OFFST_CTRL2_REFOUT_SEL                4
+#define STV6110x_WIDTH_CTRL2_REFOUT_SEL                1
+#define STV6110x_OFFST_CTRL2_BBGAIN            0
+#define STV6110x_WIDTH_CTRL2_BBGAIN            4
+
+#define STV6110x_TNG0                          0x02
+#define STV6110x_OFFST_TNG0_N_DIV_7_0          0
+#define STV6110x_WIDTH_TNG0_N_DIV_7_0          8
+
+#define STV6110x_TNG1                          0x03
+#define STV6110x_OFFST_TNG1_R_DIV              6
+#define STV6110x_WIDTH_TNG1_R_DIV              2
+#define STV6110x_OFFST_TNG1_PRESC32_ON         5
+#define STV6110x_WIDTH_TNG1_PRESC32_ON         1
+#define STV6110x_OFFST_TNG1_DIV4SEL            4
+#define STV6110x_WIDTH_TNG1_DIV4SEL            1
+#define STV6110x_OFFST_TNG1_N_DIV_11_8         0
+#define STV6110x_WIDTH_TNG1_N_DIV_11_8         4
+
+
+#define STV6110x_CTRL3                         0x04
+#define STV6110x_OFFST_CTRL3_DCLOOP_OFF                7
+#define STV6110x_WIDTH_CTRL3_DCLOOP_OFF                1
+#define STV6110x_OFFST_CTRL3_RCCLK_OFF         6
+#define STV6110x_WIDTH_CTRL3_RCCLK_OFF         1
+#define STV6110x_OFFST_CTRL3_ICP               5
+#define STV6110x_WIDTH_CTRL3_ICP               1
+#define STV6110x_OFFST_CTRL3_CF                        0
+#define STV6110x_WIDTH_CTRL3_CF                        5
+
+#define STV6110x_STAT1                         0x05
+#define STV6110x_OFFST_STAT1_CALVCO_STRT       2
+#define STV6110x_WIDTH_STAT1_CALVCO_STRT       1
+#define STV6110x_OFFST_STAT1_CALRC_STRT                1
+#define STV6110x_WIDTH_STAT1_CALRC_STRT                1
+#define STV6110x_OFFST_STAT1_LOCK              0
+#define STV6110x_WIDTH_STAT1_LOCK              1
+
+#define STV6110x_STAT2                         0x06
+#define STV6110x_STAT3                         0x07
+
+#endif /* __STV6110x_REG_H */
index 2a8bbcd44cd02a40f86921eac66bcf5455076391..4302c563a6b8950f6bdf045ee55a8adbbf2ea7e7 100644 (file)
@@ -1,7 +1,7 @@
 /*
     NXP TDA10048HN DVB OFDM demodulator driver
 
-    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
+    Copyright (C) 2009 Steven Toth <stoth@kernellabs.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -25,6 +25,7 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <asm/div64.h>
 #include "dvb_frontend.h"
 #include "dvb_math.h"
 #include "tda10048.h"
@@ -138,11 +139,20 @@ struct tda10048_state {
 
        struct i2c_adapter *i2c;
 
-       /* configuration settings */
-       const struct tda10048_config *config;
+       /* We'll cache and update the attach config settings */
+       struct tda10048_config config;
        struct dvb_frontend frontend;
 
        int fwloaded;
+
+       u32 freq_if_hz;
+       u32 xtal_hz;
+       u32 pll_mfactor;
+       u32 pll_nfactor;
+       u32 pll_pfactor;
+       u32 sample_freq;
+
+       enum fe_bandwidth bandwidth;
 };
 
 static struct init_tab {
@@ -192,12 +202,26 @@ static struct init_tab {
        { TDA10048_CONF_C4_2, 0x04 },
 };
 
+static struct pll_tab {
+       u32     clk_freq_khz;
+       u32     if_freq_khz;
+       u8      m, n, p;
+} pll_tab[] = {
+       { TDA10048_CLK_4000,  TDA10048_IF_36130, 10, 0, 0 },
+       { TDA10048_CLK_16000, TDA10048_IF_3300,  10, 3, 0 },
+       { TDA10048_CLK_16000, TDA10048_IF_3500,  10, 3, 0 },
+       { TDA10048_CLK_16000, TDA10048_IF_4000,  10, 3, 0 },
+       { TDA10048_CLK_16000, TDA10048_IF_4300,  10, 3, 0 },
+       { TDA10048_CLK_16000, TDA10048_IF_36130, 10, 3, 0 },
+};
+
 static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data)
 {
+       struct tda10048_config *config = &state->config;
        int ret;
        u8 buf[] = { reg, data };
        struct i2c_msg msg = {
-               .addr = state->config->demod_address,
+               .addr = config->demod_address,
                .flags = 0, .buf = buf, .len = 2 };
 
        dprintk(2, "%s(reg = 0x%02x, data = 0x%02x)\n", __func__, reg, data);
@@ -212,13 +236,14 @@ static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data)
 
 static u8 tda10048_readreg(struct tda10048_state *state, u8 reg)
 {
+       struct tda10048_config *config = &state->config;
        int ret;
        u8 b0[] = { reg };
        u8 b1[] = { 0 };
        struct i2c_msg msg[] = {
-               { .addr = state->config->demod_address,
+               { .addr = config->demod_address,
                        .flags = 0, .buf = b0, .len = 1 },
-               { .addr = state->config->demod_address,
+               { .addr = config->demod_address,
                        .flags = I2C_M_RD, .buf = b1, .len = 1 } };
 
        dprintk(2, "%s(reg = 0x%02x)\n", __func__, reg);
@@ -235,6 +260,7 @@ static u8 tda10048_readreg(struct tda10048_state *state, u8 reg)
 static int tda10048_writeregbulk(struct tda10048_state *state, u8 reg,
                                 const u8 *data, u16 len)
 {
+       struct tda10048_config *config = &state->config;
        int ret = -EREMOTEIO;
        struct i2c_msg msg;
        u8 *buf;
@@ -250,7 +276,7 @@ static int tda10048_writeregbulk(struct tda10048_state *state, u8 reg,
        *buf = reg;
        memcpy(buf + 1, data, len);
 
-       msg.addr = state->config->demod_address;
+       msg.addr = config->demod_address;
        msg.flags = 0;
        msg.buf = buf;
        msg.len = len + 1;
@@ -271,14 +297,206 @@ error:
        return ret;
 }
 
+static int tda10048_set_phy2(struct dvb_frontend *fe, u32 sample_freq_hz,
+                            u32 if_hz)
+{
+       struct tda10048_state *state = fe->demodulator_priv;
+       u64 t;
+
+       dprintk(1, "%s()\n", __func__);
+
+       if (sample_freq_hz == 0)
+               return -EINVAL;
+
+       if (if_hz < (sample_freq_hz / 2)) {
+               /* PHY2 = (if2/fs) * 2^15 */
+               t = if_hz;
+               t *= 10;
+               t *= 32768;
+               do_div(t, sample_freq_hz);
+               t += 5;
+               do_div(t, 10);
+       } else {
+               /* PHY2 = ((IF1-fs)/fs) * 2^15 */
+               t = sample_freq_hz - if_hz;
+               t *= 10;
+               t *= 32768;
+               do_div(t, sample_freq_hz);
+               t += 5;
+               do_div(t, 10);
+               t = ~t + 1;
+       }
+
+       tda10048_writereg(state, TDA10048_FREQ_PHY2_LSB, (u8)t);
+       tda10048_writereg(state, TDA10048_FREQ_PHY2_MSB, (u8)(t >> 8));
+
+       return 0;
+}
+
+static int tda10048_set_wref(struct dvb_frontend *fe, u32 sample_freq_hz,
+                            u32 bw)
+{
+       struct tda10048_state *state = fe->demodulator_priv;
+       u64 t, z;
+       u32 b = 8000000;
+
+       dprintk(1, "%s()\n", __func__);
+
+       if (sample_freq_hz == 0)
+               return -EINVAL;
+
+       if (bw == BANDWIDTH_6_MHZ)
+               b = 6000000;
+       else
+       if (bw == BANDWIDTH_7_MHZ)
+               b = 7000000;
+
+       /* WREF = (B / (7 * fs)) * 2^31 */
+       t = b * 10;
+       /* avoid warning: this decimal constant is unsigned only in ISO C90 */
+       /* t *= 2147483648 on 32bit platforms */
+       t *= (2048 * 1024);
+       t *= 1024;
+       z = 7 * sample_freq_hz;
+       do_div(t, z);
+       t += 5;
+       do_div(t, 10);
+
+       tda10048_writereg(state, TDA10048_TIME_WREF_LSB, (u8)t);
+       tda10048_writereg(state, TDA10048_TIME_WREF_MID1, (u8)(t >> 8));
+       tda10048_writereg(state, TDA10048_TIME_WREF_MID2, (u8)(t >> 16));
+       tda10048_writereg(state, TDA10048_TIME_WREF_MSB, (u8)(t >> 24));
+
+       return 0;
+}
+
+static int tda10048_set_invwref(struct dvb_frontend *fe, u32 sample_freq_hz,
+                               u32 bw)
+{
+       struct tda10048_state *state = fe->demodulator_priv;
+       u64 t;
+       u32 b = 8000000;
+
+       dprintk(1, "%s()\n", __func__);
+
+       if (sample_freq_hz == 0)
+               return -EINVAL;
+
+       if (bw == BANDWIDTH_6_MHZ)
+               b = 6000000;
+       else
+       if (bw == BANDWIDTH_7_MHZ)
+               b = 7000000;
+
+       /* INVWREF = ((7 * fs) / B) * 2^5 */
+       t = sample_freq_hz;
+       t *= 7;
+       t *= 32;
+       t *= 10;
+       do_div(t, b);
+       t += 5;
+       do_div(t, 10);
+
+       tda10048_writereg(state, TDA10048_TIME_INVWREF_LSB, (u8)t);
+       tda10048_writereg(state, TDA10048_TIME_INVWREF_MSB, (u8)(t >> 8));
+
+       return 0;
+}
+
+static int tda10048_set_bandwidth(struct dvb_frontend *fe,
+       enum fe_bandwidth bw)
+{
+       struct tda10048_state *state = fe->demodulator_priv;
+       dprintk(1, "%s(bw=%d)\n", __func__, bw);
+
+       /* Bandwidth setting may need to be adjusted */
+       switch (bw) {
+       case BANDWIDTH_6_MHZ:
+       case BANDWIDTH_7_MHZ:
+       case BANDWIDTH_8_MHZ:
+               tda10048_set_wref(fe, state->sample_freq, bw);
+               tda10048_set_invwref(fe, state->sample_freq, bw);
+               break;
+       default:
+               printk(KERN_ERR "%s() invalid bandwidth\n", __func__);
+               return -EINVAL;
+       }
+
+       state->bandwidth = bw;
+
+       return 0;
+}
+
+static int tda10048_set_if(struct dvb_frontend *fe, enum fe_bandwidth bw)
+{
+       struct tda10048_state *state = fe->demodulator_priv;
+       struct tda10048_config *config = &state->config;
+       int i;
+       u32 if_freq_khz;
+
+       dprintk(1, "%s(bw = %d)\n", __func__, bw);
+
+       /* based on target bandwidth and clk we calculate pll factors */
+       switch (bw) {
+       case BANDWIDTH_6_MHZ:
+               if_freq_khz = config->dtv6_if_freq_khz;
+               break;
+       case BANDWIDTH_7_MHZ:
+               if_freq_khz = config->dtv7_if_freq_khz;
+               break;
+       case BANDWIDTH_8_MHZ:
+               if_freq_khz = config->dtv8_if_freq_khz;
+               break;
+       default:
+               printk(KERN_ERR "%s() no default\n", __func__);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(pll_tab); i++) {
+               if ((pll_tab[i].clk_freq_khz == config->clk_freq_khz) &&
+                       (pll_tab[i].if_freq_khz == if_freq_khz)) {
+
+                       state->freq_if_hz = pll_tab[i].if_freq_khz * 1000;
+                       state->xtal_hz = pll_tab[i].clk_freq_khz * 1000;
+                       state->pll_mfactor = pll_tab[i].m;
+                       state->pll_nfactor = pll_tab[i].n;
+                       state->pll_pfactor = pll_tab[i].p;
+                       break;
+               }
+       }
+       if (i == ARRAY_SIZE(pll_tab)) {
+               printk(KERN_ERR "%s() Incorrect attach settings\n",
+                       __func__);
+               return -EINVAL;
+       }
+
+       dprintk(1, "- freq_if_hz = %d\n", state->freq_if_hz);
+       dprintk(1, "- xtal_hz = %d\n", state->xtal_hz);
+       dprintk(1, "- pll_mfactor = %d\n", state->pll_mfactor);
+       dprintk(1, "- pll_nfactor = %d\n", state->pll_nfactor);
+       dprintk(1, "- pll_pfactor = %d\n", state->pll_pfactor);
+
+       /* Calculate the sample frequency */
+       state->sample_freq = state->xtal_hz * (state->pll_mfactor + 45);
+       state->sample_freq /= (state->pll_nfactor + 1);
+       state->sample_freq /= (state->pll_pfactor + 4);
+       dprintk(1, "- sample_freq = %d\n", state->sample_freq);
+
+       /* Update the I/F */
+       tda10048_set_phy2(fe, state->sample_freq, state->freq_if_hz);
+
+       return 0;
+}
+
 static int tda10048_firmware_upload(struct dvb_frontend *fe)
 {
        struct tda10048_state *state = fe->demodulator_priv;
+       struct tda10048_config *config = &state->config;
        const struct firmware *fw;
        int ret;
        int pos = 0;
        int cnt;
-       u8 wlen = state->config->fwbulkwritelen;
+       u8 wlen = config->fwbulkwritelen;
 
        if ((wlen != TDA10048_BULKWRITE_200) && (wlen != TDA10048_BULKWRITE_50))
                wlen = TDA10048_BULKWRITE_200;
@@ -289,7 +507,7 @@ static int tda10048_firmware_upload(struct dvb_frontend *fe)
                TDA10048_DEFAULT_FIRMWARE);
 
        ret = request_firmware(&fw, TDA10048_DEFAULT_FIRMWARE,
-               &state->i2c->dev);
+               state->i2c->dev.parent);
        if (ret) {
                printk(KERN_ERR "%s: Upload failed. (file not found?)\n",
                        __func__);
@@ -484,8 +702,12 @@ static int tda10048_get_tps(struct tda10048_state *state,
 static int tda10048_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
        struct tda10048_state *state = fe->demodulator_priv;
+       struct tda10048_config *config = &state->config;
        dprintk(1, "%s(%d)\n", __func__, enable);
 
+       if (config->disable_gate_access)
+               return 0;
+
        if (enable)
                return tda10048_writereg(state, TDA10048_CONF_C4_1,
                        tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x02);
@@ -523,6 +745,12 @@ static int tda10048_set_frontend(struct dvb_frontend *fe,
 
        dprintk(1, "%s(frequency=%d)\n", __func__, p->frequency);
 
+       /* Update the I/F pll's if the bandwidth changes */
+       if (p->u.ofdm.bandwidth != state->bandwidth) {
+               tda10048_set_if(fe, p->u.ofdm.bandwidth);
+               tda10048_set_bandwidth(fe, p->u.ofdm.bandwidth);
+       }
+
        if (fe->ops.tuner_ops.set_params) {
 
                if (fe->ops.i2c_gate_ctrl)
@@ -544,6 +772,7 @@ static int tda10048_set_frontend(struct dvb_frontend *fe,
 static int tda10048_init(struct dvb_frontend *fe)
 {
        struct tda10048_state *state = fe->demodulator_priv;
+       struct tda10048_config *config = &state->config;
        int ret = 0, i;
 
        dprintk(1, "%s()\n", __func__);
@@ -556,10 +785,14 @@ static int tda10048_init(struct dvb_frontend *fe)
                ret = tda10048_firmware_upload(fe);
 
        /* Set either serial or parallel */
-       tda10048_output_mode(fe, state->config->output_mode);
+       tda10048_output_mode(fe, config->output_mode);
+
+       /* Set inversion */
+       tda10048_set_inversion(fe, config->inversion);
 
-       /* set inversion */
-       tda10048_set_inversion(fe, state->config->inversion);
+       /* Establish default RF values */
+       tda10048_set_if(fe, BANDWIDTH_8_MHZ);
+       tda10048_set_bandwidth(fe, BANDWIDTH_8_MHZ);
 
        /* Ensure we leave the gate closed */
        tda10048_i2c_gate_ctrl(fe, 0);
@@ -812,6 +1045,45 @@ static void tda10048_release(struct dvb_frontend *fe)
        kfree(state);
 }
 
+static void tda10048_establish_defaults(struct dvb_frontend *fe)
+{
+       struct tda10048_state *state = fe->demodulator_priv;
+       struct tda10048_config *config = &state->config;
+
+       /* Validate/default the config */
+       if (config->dtv6_if_freq_khz == 0) {
+               config->dtv6_if_freq_khz = TDA10048_IF_4300;
+               printk(KERN_WARNING "%s() tda10048_config.dtv6_if_freq_khz "
+                       "is not set (defaulting to %d)\n",
+                       __func__,
+                       config->dtv6_if_freq_khz);
+       }
+
+       if (config->dtv7_if_freq_khz == 0) {
+               config->dtv7_if_freq_khz = TDA10048_IF_4300;
+               printk(KERN_WARNING "%s() tda10048_config.dtv7_if_freq_khz "
+                       "is not set (defaulting to %d)\n",
+                       __func__,
+                       config->dtv7_if_freq_khz);
+       }
+
+       if (config->dtv8_if_freq_khz == 0) {
+               config->dtv8_if_freq_khz = TDA10048_IF_4300;
+               printk(KERN_WARNING "%s() tda10048_config.dtv8_if_freq_khz "
+                       "is not set (defaulting to %d)\n",
+                       __func__,
+                       config->dtv8_if_freq_khz);
+       }
+
+       if (config->clk_freq_khz == 0) {
+               config->clk_freq_khz = TDA10048_CLK_16000;
+               printk(KERN_WARNING "%s() tda10048_config.clk_freq_khz "
+                       "is not set (defaulting to %d)\n",
+                       __func__,
+                       config->clk_freq_khz);
+       }
+}
+
 static struct dvb_frontend_ops tda10048_ops;
 
 struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
@@ -826,10 +1098,11 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
        if (state == NULL)
                goto error;
 
-       /* setup the state */
-       state->config = config;
+       /* setup the state and clone the config */
+       memcpy(&state->config, config, sizeof(*config));
        state->i2c = i2c;
        state->fwloaded = 0;
+       state->bandwidth = BANDWIDTH_8_MHZ;
 
        /* check if the demod is present */
        if (tda10048_readreg(state, TDA10048_IDENTITY) != 0x048)
@@ -840,6 +1113,17 @@ struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
                sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
 
+       /* Establish any defaults the the user didn't pass */
+       tda10048_establish_defaults(&state->frontend);
+
+       /* Set the xtal and freq defaults */
+       if (tda10048_set_if(&state->frontend, BANDWIDTH_8_MHZ) != 0)
+               goto error;
+
+       /* Default bandwidth */
+       if (tda10048_set_bandwidth(&state->frontend, BANDWIDTH_8_MHZ) != 0)
+               goto error;
+
        /* Leave the gate closed */
        tda10048_i2c_gate_ctrl(&state->frontend, 0);
 
index 0457b24601fa1239d34935811bbe165bf47428d3..8828ceaf74bb491dad21c12759d0a1b316ec8a0c 100644 (file)
@@ -1,7 +1,7 @@
 /*
     NXP TDA10048HN DVB OFDM demodulator driver
 
-    Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
+    Copyright (C) 2009 Steven Toth <stoth@kernellabs.com>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -43,6 +43,25 @@ struct tda10048_config {
 #define TDA10048_INVERSION_OFF 0
 #define TDA10048_INVERSION_ON  1
        u8 inversion;
+
+#define TDA10048_IF_3300  3300
+#define TDA10048_IF_3500  3500
+#define TDA10048_IF_3800  3800
+#define TDA10048_IF_4000  4000
+#define TDA10048_IF_4300  4300
+#define TDA10048_IF_4500  4500
+#define TDA10048_IF_4750  4750
+#define TDA10048_IF_36130 36130
+       u16 dtv6_if_freq_khz;
+       u16 dtv7_if_freq_khz;
+       u16 dtv8_if_freq_khz;
+
+#define TDA10048_CLK_4000  4000
+#define TDA10048_CLK_16000 16000
+       u16 clk_freq_khz;
+
+       /* Disable I2C gate access */
+       u8 disable_gate_access;
 };
 
 #if defined(CONFIG_DVB_TDA10048) || \
index bcf93f4828b28cbc7dace4c0b27d1bcc27db62e3..c6644d9094338ef252c2ca98ae4fd179199c67d7 100644 (file)
@@ -1,4 +1,4 @@
-sms1xxx-objs := smscoreapi.o sms-cards.o
+sms1xxx-objs := smscoreapi.o sms-cards.o smsendian.o smsir.o
 
 obj-$(CONFIG_DVB_SIANO_SMS1XXX) += sms1xxx.o
 obj-$(CONFIG_DVB_SIANO_SMS1XXX) += smsusb.o
index 63e4d0ec6583e95010ab8db2a5e853a1b81c79fb..d8b15d583bdeb2e662a3d336aabd7017d2414722 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include "sms-cards.h"
+#include "smsir.h"
 
 static int sms_dbg;
 module_param_named(cards_dbg, sms_dbg, int, 0644);
@@ -30,17 +31,14 @@ static struct sms_board sms_boards[] = {
        [SMS1XXX_BOARD_SIANO_STELLAR] = {
                .name   = "Siano Stellar Digital Receiver",
                .type   = SMS_STELLAR,
-               .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-stellar-dvbt-01.fw",
        },
        [SMS1XXX_BOARD_SIANO_NOVA_A] = {
                .name   = "Siano Nova A Digital Receiver",
                .type   = SMS_NOVA_A0,
-               .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-a-dvbt-01.fw",
        },
        [SMS1XXX_BOARD_SIANO_NOVA_B] = {
                .name   = "Siano Nova B Digital Receiver",
                .type   = SMS_NOVA_B0,
-               .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-nova-b-dvbt-01.fw",
        },
        [SMS1XXX_BOARD_SIANO_VEGA] = {
                .name   = "Siano Vega Digital Receiver",
@@ -65,6 +63,9 @@ static struct sms_board sms_boards[] = {
                .name   = "Hauppauge WinTV MiniStick",
                .type   = SMS_NOVA_B0,
                .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
+               .board_cfg.leds_power = 26,
+               .board_cfg.led0 = 27,
+               .board_cfg.led1 = 28,
                .led_power = 26,
                .led_lo    = 27,
                .led_hi    = 28,
@@ -74,7 +75,9 @@ static struct sms_board sms_boards[] = {
                .type   = SMS_NOVA_B0,
                .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
                .lna_ctrl  = 29,
+               .board_cfg.foreign_lna0_ctrl = 29,
                .rf_switch = 17,
+               .board_cfg.rf_switch_uhf = 17,
        },
        [SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = {
                .name   = "Hauppauge WinTV MiniCard",
@@ -82,6 +85,16 @@ static struct sms_board sms_boards[] = {
                .fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
                .lna_ctrl  = -1,
        },
+       [SMS1XXX_BOARD_SIANO_NICE] = {
+       /* 11 */
+               .name = "Siano Nice Digital Receiver",
+               .type = SMS_NOVA_B0,
+       },
+       [SMS1XXX_BOARD_SIANO_VENICE] = {
+       /* 12 */
+               .name = "Siano Venice Digital Receiver",
+               .type = SMS_VEGA,
+       },
 };
 
 struct sms_board *sms_get_board(int id)
@@ -91,12 +104,179 @@ struct sms_board *sms_get_board(int id)
        return &sms_boards[id];
 }
 EXPORT_SYMBOL_GPL(sms_get_board);
+static inline void sms_gpio_assign_11xx_default_led_config(
+               struct smscore_gpio_config *pGpioConfig) {
+       pGpioConfig->Direction = SMS_GPIO_DIRECTION_OUTPUT;
+       pGpioConfig->InputCharacteristics =
+               SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL;
+       pGpioConfig->OutputDriving = SMS_GPIO_OUTPUT_DRIVING_4mA;
+       pGpioConfig->OutputSlewRate = SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS;
+       pGpioConfig->PullUpDown = SMS_GPIO_PULL_UP_DOWN_NONE;
+}
+
+int sms_board_event(struct smscore_device_t *coredev,
+               enum SMS_BOARD_EVENTS gevent) {
+       int board_id = smscore_get_board_id(coredev);
+       struct sms_board *board = sms_get_board(board_id);
+       struct smscore_gpio_config MyGpioConfig;
+
+       sms_gpio_assign_11xx_default_led_config(&MyGpioConfig);
+
+       switch (gevent) {
+       case BOARD_EVENT_POWER_INIT: /* including hotplug */
+               switch (board_id) {
+               case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+                       /* set I/O and turn off all LEDs */
+                       smscore_gpio_configure(coredev,
+                                       board->board_cfg.leds_power,
+                                       &MyGpioConfig);
+                       smscore_gpio_set_level(coredev,
+                                       board->board_cfg.leds_power, 0);
+                       smscore_gpio_configure(coredev, board->board_cfg.led0,
+                                       &MyGpioConfig);
+                       smscore_gpio_set_level(coredev,
+                                       board->board_cfg.led0, 0);
+                       smscore_gpio_configure(coredev, board->board_cfg.led1,
+                                       &MyGpioConfig);
+                       smscore_gpio_set_level(coredev,
+                                       board->board_cfg.led1, 0);
+                       break;
+               case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+               case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+                       /* set I/O and turn off LNA */
+                       smscore_gpio_configure(coredev,
+                                       board->board_cfg.foreign_lna0_ctrl,
+                                       &MyGpioConfig);
+                       smscore_gpio_set_level(coredev,
+                                       board->board_cfg.foreign_lna0_ctrl,
+                                       0);
+                       break;
+               }
+               break; /* BOARD_EVENT_BIND */
+
+       case BOARD_EVENT_POWER_SUSPEND:
+               switch (board_id) {
+               case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.leds_power, 0);
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.led0, 0);
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.led1, 0);
+                       break;
+               case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+               case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+                       smscore_gpio_set_level(coredev,
+                                       board->board_cfg.foreign_lna0_ctrl,
+                                       0);
+                       break;
+               }
+               break; /* BOARD_EVENT_POWER_SUSPEND */
+
+       case BOARD_EVENT_POWER_RESUME:
+               switch (board_id) {
+               case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.leds_power, 1);
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.led0, 1);
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.led1, 0);
+                       break;
+               case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+               case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+                       smscore_gpio_set_level(coredev,
+                                       board->board_cfg.foreign_lna0_ctrl,
+                                       1);
+                       break;
+               }
+               break; /* BOARD_EVENT_POWER_RESUME */
+
+       case BOARD_EVENT_BIND:
+               switch (board_id) {
+               case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+                       smscore_gpio_set_level(coredev,
+                               board->board_cfg.leds_power, 1);
+                       smscore_gpio_set_level(coredev,
+                               board->board_cfg.led0, 1);
+                       smscore_gpio_set_level(coredev,
+                               board->board_cfg.led1, 0);
+                       break;
+               case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2:
+               case SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD:
+                       smscore_gpio_set_level(coredev,
+                                       board->board_cfg.foreign_lna0_ctrl,
+                                       1);
+                       break;
+               }
+               break; /* BOARD_EVENT_BIND */
+
+       case BOARD_EVENT_SCAN_PROG:
+               break; /* BOARD_EVENT_SCAN_PROG */
+       case BOARD_EVENT_SCAN_COMP:
+               break; /* BOARD_EVENT_SCAN_COMP */
+       case BOARD_EVENT_EMERGENCY_WARNING_SIGNAL:
+               break; /* BOARD_EVENT_EMERGENCY_WARNING_SIGNAL */
+       case BOARD_EVENT_FE_LOCK:
+               switch (board_id) {
+               case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+                       smscore_gpio_set_level(coredev,
+                       board->board_cfg.led1, 1);
+                       break;
+               }
+               break; /* BOARD_EVENT_FE_LOCK */
+       case BOARD_EVENT_FE_UNLOCK:
+               switch (board_id) {
+               case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.led1, 0);
+                       break;
+               }
+               break; /* BOARD_EVENT_FE_UNLOCK */
+       case BOARD_EVENT_DEMOD_LOCK:
+               break; /* BOARD_EVENT_DEMOD_LOCK */
+       case BOARD_EVENT_DEMOD_UNLOCK:
+               break; /* BOARD_EVENT_DEMOD_UNLOCK */
+       case BOARD_EVENT_RECEPTION_MAX_4:
+               break; /* BOARD_EVENT_RECEPTION_MAX_4 */
+       case BOARD_EVENT_RECEPTION_3:
+               break; /* BOARD_EVENT_RECEPTION_3 */
+       case BOARD_EVENT_RECEPTION_2:
+               break; /* BOARD_EVENT_RECEPTION_2 */
+       case BOARD_EVENT_RECEPTION_1:
+               break; /* BOARD_EVENT_RECEPTION_1 */
+       case BOARD_EVENT_RECEPTION_LOST_0:
+               break; /* BOARD_EVENT_RECEPTION_LOST_0 */
+       case BOARD_EVENT_MULTIPLEX_OK:
+               switch (board_id) {
+               case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.led1, 1);
+                       break;
+               }
+               break; /* BOARD_EVENT_MULTIPLEX_OK */
+       case BOARD_EVENT_MULTIPLEX_ERRORS:
+               switch (board_id) {
+               case SMS1XXX_BOARD_HAUPPAUGE_WINDHAM:
+                       smscore_gpio_set_level(coredev,
+                                               board->board_cfg.led1, 0);
+                       break;
+               }
+               break; /* BOARD_EVENT_MULTIPLEX_ERRORS */
+
+       default:
+               sms_err("Unknown SMS board event");
+               break;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(sms_board_event);
 
 static int sms_set_gpio(struct smscore_device_t *coredev, int pin, int enable)
 {
        int lvl, ret;
        u32 gpio;
-       struct smscore_gpio_config gpioconfig = {
+       struct smscore_config_gpio gpioconfig = {
                .direction            = SMS_GPIO_DIRECTION_OUTPUT,
                .pullupdown           = SMS_GPIO_PULLUPDOWN_NONE,
                .inputcharacteristics = SMS_GPIO_INPUTCHARACTERISTICS_NORMAL,
index 64d74c59c33f9503760207f9dcf1f1a775f1ac1d..38f062f6ad68a95c462a49afeb196ad37b580b07 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/usb.h>
 #include "smscoreapi.h"
+#include "smsir.h"
 
 #define SMS_BOARD_UNKNOWN 0
 #define SMS1XXX_BOARD_SIANO_STELLAR 1
 #define SMS1XXX_BOARD_HAUPPAUGE_WINDHAM 8
 #define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD 9
 #define SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2 10
+#define SMS1XXX_BOARD_SIANO_NICE       11
+#define SMS1XXX_BOARD_SIANO_VENICE     12
+
+struct sms_board_gpio_cfg {
+       int lna_vhf_exist;
+       int lna_vhf_ctrl;
+       int lna_uhf_exist;
+       int lna_uhf_ctrl;
+       int lna_uhf_d_ctrl;
+       int lna_sband_exist;
+       int lna_sband_ctrl;
+       int lna_sband_d_ctrl;
+       int foreign_lna0_ctrl;
+       int foreign_lna1_ctrl;
+       int foreign_lna2_ctrl;
+       int rf_switch_vhf;
+       int rf_switch_uhf;
+       int rf_switch_sband;
+       int leds_power;
+       int led0;
+       int led1;
+       int led2;
+       int led3;
+       int led4;
+       int ir;
+       int eeprom_wp;
+       int mrc_sense;
+       int mrc_pdn_resetn;
+       int mrc_gp0; /* mrcs spi int */
+       int mrc_gp1;
+       int mrc_gp2;
+       int mrc_gp3;
+       int mrc_gp4;
+       int host_spi_gsp_ts_int;
+};
 
 struct sms_board {
        enum sms_device_type_st type;
        char *name, *fw[DEVICE_MODE_MAX];
+       struct sms_board_gpio_cfg board_cfg;
+       enum ir_kb_type ir_kb_type;
 
        /* gpios */
        int led_power, led_hi, led_lo, lna_ctrl, rf_switch;
@@ -45,6 +83,32 @@ struct sms_board {
 
 struct sms_board *sms_get_board(int id);
 
+extern struct smscore_device_t *coredev;
+
+enum SMS_BOARD_EVENTS {
+       BOARD_EVENT_POWER_INIT,
+       BOARD_EVENT_POWER_SUSPEND,
+       BOARD_EVENT_POWER_RESUME,
+       BOARD_EVENT_BIND,
+       BOARD_EVENT_SCAN_PROG,
+       BOARD_EVENT_SCAN_COMP,
+       BOARD_EVENT_EMERGENCY_WARNING_SIGNAL,
+       BOARD_EVENT_FE_LOCK,
+       BOARD_EVENT_FE_UNLOCK,
+       BOARD_EVENT_DEMOD_LOCK,
+       BOARD_EVENT_DEMOD_UNLOCK,
+       BOARD_EVENT_RECEPTION_MAX_4,
+       BOARD_EVENT_RECEPTION_3,
+       BOARD_EVENT_RECEPTION_2,
+       BOARD_EVENT_RECEPTION_1,
+       BOARD_EVENT_RECEPTION_LOST_0,
+       BOARD_EVENT_MULTIPLEX_OK,
+       BOARD_EVENT_MULTIPLEX_ERRORS
+};
+
+int sms_board_event(struct smscore_device_t *coredev,
+               enum SMS_BOARD_EVENTS gevent);
+
 int sms_board_setup(struct smscore_device_t *coredev);
 
 #define SMS_LED_OFF 0
index 7bd4d1dee2b32022bf52ff5923b95f423bd81e45..32be382f0e97717f7c2f7c95c40f689374f4a994 100644 (file)
 #include <linux/io.h>
 
 #include <linux/firmware.h>
+#include <linux/wait.h>
+#include <asm/byteorder.h>
 
 #include "smscoreapi.h"
 #include "sms-cards.h"
+#include "smsir.h"
+#include "smsendian.h"
 
 static int sms_dbg;
 module_param_named(debug, sms_dbg, int, 0644);
@@ -58,42 +62,6 @@ struct smscore_client_t {
        onremove_t              onremove_handler;
 };
 
-struct smscore_device_t {
-       struct list_head entry;
-
-       struct list_head clients;
-       struct list_head subclients;
-       spinlock_t              clientslock;
-
-       struct list_head buffers;
-       spinlock_t              bufferslock;
-       int                             num_buffers;
-
-       void                    *common_buffer;
-       int                             common_buffer_size;
-       dma_addr_t              common_buffer_phys;
-
-       void                    *context;
-       struct device   *device;
-
-       char                    devpath[32];
-       unsigned long   device_flags;
-
-       setmode_t               setmode_handler;
-       detectmode_t    detectmode_handler;
-       sendrequest_t   sendrequest_handler;
-       preload_t               preload_handler;
-       postload_t              postload_handler;
-
-       int                             mode, modes_supported;
-
-       struct completion version_ex_done, data_download_done, trigger_done;
-       struct completion init_device_done, reload_start_done, resume_done;
-
-       int board_id;
-       int led_state;
-};
-
 void smscore_set_board_id(struct smscore_device_t *core, int id)
 {
        core->board_id = id;
@@ -384,6 +352,13 @@ int smscore_register_device(struct smsdevice_params_t *params,
        init_completion(&dev->init_device_done);
        init_completion(&dev->reload_start_done);
        init_completion(&dev->resume_done);
+       init_completion(&dev->gpio_configuration_done);
+       init_completion(&dev->gpio_set_level_done);
+       init_completion(&dev->gpio_get_level_done);
+       init_completion(&dev->ir_init_done);
+
+       /* Buffer management */
+       init_waitqueue_head(&dev->buffer_mng_waitq);
 
        /* alloc common buffer */
        dev->common_buffer_size = params->buffer_size * params->num_buffers;
@@ -439,6 +414,71 @@ int smscore_register_device(struct smsdevice_params_t *params,
 }
 EXPORT_SYMBOL_GPL(smscore_register_device);
 
+
+static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
+               void *buffer, size_t size, struct completion *completion) {
+       int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
+       if (rc < 0) {
+               sms_info("sendrequest returned error %d", rc);
+               return rc;
+       }
+
+       return wait_for_completion_timeout(completion,
+                       msecs_to_jiffies(SMS_PROTOCOL_MAX_RAOUNDTRIP_MS)) ?
+                       0 : -ETIME;
+}
+
+/**
+ * Starts & enables IR operations
+ *
+ * @return 0 on success, < 0 on error.
+ */
+static int smscore_init_ir(struct smscore_device_t *coredev)
+{
+       int ir_io;
+       int rc;
+       void *buffer;
+
+       coredev->ir.input_dev = NULL;
+       ir_io = sms_get_board(smscore_get_board_id(coredev))->board_cfg.ir;
+       if (ir_io) {/* only if IR port exist we use IR sub-module */
+               sms_info("IR loading");
+               rc = sms_ir_init(coredev);
+
+               if      (rc != 0)
+                       sms_err("Error initialization DTV IR sub-module");
+               else {
+                       buffer = kmalloc(sizeof(struct SmsMsgData_ST2) +
+                                               SMS_DMA_ALIGNMENT,
+                                               GFP_KERNEL | GFP_DMA);
+                       if (buffer) {
+                               struct SmsMsgData_ST2 *msg =
+                               (struct SmsMsgData_ST2 *)
+                               SMS_ALIGN_ADDRESS(buffer);
+
+                               SMS_INIT_MSG(&msg->xMsgHeader,
+                                               MSG_SMS_START_IR_REQ,
+                                               sizeof(struct SmsMsgData_ST2));
+                               msg->msgData[0] = coredev->ir.controller;
+                               msg->msgData[1] = coredev->ir.timeout;
+
+                               smsendian_handle_tx_message(
+                                       (struct SmsMsgHdr_ST2 *)msg);
+                               rc = smscore_sendrequest_and_wait(coredev, msg,
+                                               msg->xMsgHeader. msgLength,
+                                               &coredev->ir_init_done);
+
+                               kfree(buffer);
+                       } else
+                               sms_err
+                               ("Sending IR initialization message failed");
+               }
+       } else
+               sms_info("IR port has not been detected");
+
+       return 0;
+}
+
 /**
  * sets initial device mode and notifies client hotplugs that device is ready
  *
@@ -459,6 +499,7 @@ int smscore_start_device(struct smscore_device_t *coredev)
        kmutex_lock(&g_smscore_deviceslock);
 
        rc = smscore_notify_callbacks(coredev, coredev->device, 1);
+       smscore_init_ir(coredev);
 
        sms_info("device %p started, rc %d", coredev, rc);
 
@@ -468,29 +509,19 @@ int smscore_start_device(struct smscore_device_t *coredev)
 }
 EXPORT_SYMBOL_GPL(smscore_start_device);
 
-static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
-                                       void *buffer, size_t size,
-                                       struct completion *completion)
-{
-       int rc = coredev->sendrequest_handler(coredev->context, buffer, size);
-       if (rc < 0) {
-               sms_info("sendrequest returned error %d", rc);
-               return rc;
-       }
-
-       return wait_for_completion_timeout(completion,
-                                          msecs_to_jiffies(10000)) ?
-                                               0 : -ETIME;
-}
 
 static int smscore_load_firmware_family2(struct smscore_device_t *coredev,
                                         void *buffer, size_t size)
 {
        struct SmsFirmware_ST *firmware = (struct SmsFirmware_ST *) buffer;
        struct SmsMsgHdr_ST *msg;
-       u32 mem_address = firmware->StartAddress;
+       u32 mem_address;
        u8 *payload = firmware->Payload;
        int rc = 0;
+       firmware->StartAddress = le32_to_cpu(firmware->StartAddress);
+       firmware->Length = le32_to_cpu(firmware->Length);
+
+       mem_address = firmware->StartAddress;
 
        sms_info("loading FW to addr 0x%x size %d",
                 mem_address, firmware->Length);
@@ -657,6 +688,9 @@ void smscore_unregister_device(struct smscore_device_t *coredev)
 
        kmutex_lock(&g_smscore_deviceslock);
 
+       /* Release input device (IR) resources */
+       sms_ir_exit(coredev);
+
        smscore_notify_clients(coredev);
        smscore_notify_callbacks(coredev, NULL, 0);
 
@@ -664,7 +698,9 @@ void smscore_unregister_device(struct smscore_device_t *coredev)
         * onresponse must no longer be called */
 
        while (1) {
-               while ((cb = smscore_getbuffer(coredev))) {
+               while (!list_empty(&coredev->buffers)) {
+                       cb = (struct smscore_buffer_t *) coredev->buffers.next;
+                       list_del(&cb->entry);
                        kfree(cb);
                        num_buffers++;
                }
@@ -685,8 +721,10 @@ void smscore_unregister_device(struct smscore_device_t *coredev)
 
        if (coredev->common_buffer)
                dma_free_coherent(NULL, coredev->common_buffer_size,
-                                 coredev->common_buffer,
-                                 coredev->common_buffer_phys);
+                       coredev->common_buffer, coredev->common_buffer_phys);
+
+       if (coredev->fw_buf != NULL)
+               kfree(coredev->fw_buf);
 
        list_del(&coredev->entry);
        kfree(coredev);
@@ -746,7 +784,7 @@ static char *smscore_fw_lkup[][SMS_NUM_OF_DEVICE_TYPES] = {
        /*BDA*/
        {"none", "dvb_nova_12mhz.inp", "dvb_nova_12mhz_b0.inp", "none"},
        /*ISDBT*/
-       {"none", "isdbt_nova_12mhz.inp", "dvb_nova_12mhz.inp", "none"},
+       {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
        /*ISDBTBDA*/
        {"none", "isdbt_nova_12mhz.inp", "isdbt_nova_12mhz_b0.inp", "none"},
        /*CMMB*/
@@ -870,7 +908,7 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
                coredev->device_flags &= ~SMS_DEVICE_NOT_READY;
        }
 
-       if (rc != 0)
+       if (rc < 0)
                sms_err("return error code %d.", rc);
        return rc;
 }
@@ -940,14 +978,11 @@ smscore_client_t *smscore_find_client(struct smscore_device_t *coredev,
  *
  */
 void smscore_onresponse(struct smscore_device_t *coredev,
-                       struct smscore_buffer_t *cb)
-{
-       struct SmsMsgHdr_ST *phdr =
-               (struct SmsMsgHdr_ST *)((u8 *) cb->p + cb->offset);
-       struct smscore_client_t *client =
-               smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
+               struct smscore_buffer_t *cb) {
+       struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) ((u8 *) cb->p
+                       + cb->offset);
+       struct smscore_client_t *client;
        int rc = -EBUSY;
-
        static unsigned long last_sample_time; /* = 0; */
        static int data_total; /* = 0; */
        unsigned long time_now = jiffies_to_msecs(jiffies);
@@ -965,6 +1000,16 @@ void smscore_onresponse(struct smscore_device_t *coredev,
        }
 
        data_total += cb->size;
+       /* Do we need to re-route? */
+       if ((phdr->msgType == MSG_SMS_HO_PER_SLICES_IND) ||
+                       (phdr->msgType == MSG_SMS_TRANSMISSION_IND)) {
+               if (coredev->mode == DEVICE_MODE_DVBT_BDA)
+                       phdr->msgDstId = DVBT_BDA_CONTROL_MSG_ID;
+       }
+
+
+       client = smscore_find_client(coredev, phdr->msgType, phdr->msgDstId);
+
        /* If no client registered for type & id,
         * check for control client where type is not registered */
        if (client)
@@ -1009,6 +1054,35 @@ void smscore_onresponse(struct smscore_device_t *coredev,
                case MSG_SMS_SLEEP_RESUME_COMP_IND:
                        complete(&coredev->resume_done);
                        break;
+               case MSG_SMS_GPIO_CONFIG_EX_RES:
+                       sms_debug("MSG_SMS_GPIO_CONFIG_EX_RES");
+                       complete(&coredev->gpio_configuration_done);
+                       break;
+               case MSG_SMS_GPIO_SET_LEVEL_RES:
+                       sms_debug("MSG_SMS_GPIO_SET_LEVEL_RES");
+                       complete(&coredev->gpio_set_level_done);
+                       break;
+               case MSG_SMS_GPIO_GET_LEVEL_RES:
+               {
+                       u32 *msgdata = (u32 *) phdr;
+                       coredev->gpio_get_res = msgdata[1];
+                       sms_debug("MSG_SMS_GPIO_GET_LEVEL_RES gpio level %d",
+                                       coredev->gpio_get_res);
+                       complete(&coredev->gpio_get_level_done);
+                       break;
+               }
+               case MSG_SMS_START_IR_RES:
+                       complete(&coredev->ir_init_done);
+                       break;
+               case MSG_SMS_IR_SAMPLES_IND:
+                       sms_ir_event(coredev,
+                               (const char *)
+                               ((char *)phdr
+                               + sizeof(struct SmsMsgHdr_ST)),
+                               (int)phdr->msgLength
+                               - sizeof(struct SmsMsgHdr_ST));
+                       break;
+
                default:
                        break;
                }
@@ -1030,12 +1104,24 @@ struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
        struct smscore_buffer_t *cb = NULL;
        unsigned long flags;
 
+       DEFINE_WAIT(wait);
+
        spin_lock_irqsave(&coredev->bufferslock, flags);
 
-       if (!list_empty(&coredev->buffers)) {
-               cb = (struct smscore_buffer_t *) coredev->buffers.next;
-               list_del(&cb->entry);
-       }
+       /* This function must return a valid buffer, since the buffer list is
+        * finite, we check that there is an available buffer, if not, we wait
+        * until such buffer become available.
+        */
+
+       prepare_to_wait(&coredev->buffer_mng_waitq, &wait, TASK_INTERRUPTIBLE);
+
+       if (list_empty(&coredev->buffers))
+               schedule();
+
+       finish_wait(&coredev->buffer_mng_waitq, &wait);
+
+       cb = (struct smscore_buffer_t *) coredev->buffers.next;
+       list_del(&cb->entry);
 
        spin_unlock_irqrestore(&coredev->bufferslock, flags);
 
@@ -1052,8 +1138,8 @@ EXPORT_SYMBOL_GPL(smscore_getbuffer);
  *
  */
 void smscore_putbuffer(struct smscore_device_t *coredev,
-                      struct smscore_buffer_t *cb)
-{
+               struct smscore_buffer_t *cb) {
+       wake_up_interruptible(&coredev->buffer_mng_waitq);
        list_add_locked(&cb->entry, &coredev->buffers, &coredev->bufferslock);
 }
 EXPORT_SYMBOL_GPL(smscore_putbuffer);
@@ -1210,8 +1296,9 @@ int smsclient_sendrequest(struct smscore_client_t *client,
 EXPORT_SYMBOL_GPL(smsclient_sendrequest);
 
 
+/* old GPIO managments implementation */
 int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
-                          struct smscore_gpio_config *pinconfig)
+                          struct smscore_config_gpio *pinconfig)
 {
        struct {
                struct SmsMsgHdr_ST hdr;
@@ -1280,35 +1367,254 @@ int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level)
                                            &msg, sizeof(msg));
 }
 
-static int __init smscore_module_init(void)
-{
-       int rc = 0;
+/* new GPIO managment implementation */
+static int GetGpioPinParams(u32 PinNum, u32 *pTranslatedPinNum,
+               u32 *pGroupNum, u32 *pGroupCfg) {
+
+       *pGroupCfg = 1;
+
+       if (PinNum >= 0 && PinNum <= 1) {
+               *pTranslatedPinNum = 0;
+               *pGroupNum = 9;
+               *pGroupCfg = 2;
+       } else if (PinNum >= 2 && PinNum <= 6) {
+               *pTranslatedPinNum = 2;
+               *pGroupNum = 0;
+               *pGroupCfg = 2;
+       } else if (PinNum >= 7 && PinNum <= 11) {
+               *pTranslatedPinNum = 7;
+               *pGroupNum = 1;
+       } else if (PinNum >= 12 && PinNum <= 15) {
+               *pTranslatedPinNum = 12;
+               *pGroupNum = 2;
+               *pGroupCfg = 3;
+       } else if (PinNum == 16) {
+               *pTranslatedPinNum = 16;
+               *pGroupNum = 23;
+       } else if (PinNum >= 17 && PinNum <= 24) {
+               *pTranslatedPinNum = 17;
+               *pGroupNum = 3;
+       } else if (PinNum == 25) {
+               *pTranslatedPinNum = 25;
+               *pGroupNum = 6;
+       } else if (PinNum >= 26 && PinNum <= 28) {
+               *pTranslatedPinNum = 26;
+               *pGroupNum = 4;
+       } else if (PinNum == 29) {
+               *pTranslatedPinNum = 29;
+               *pGroupNum = 5;
+               *pGroupCfg = 2;
+       } else if (PinNum == 30) {
+               *pTranslatedPinNum = 30;
+               *pGroupNum = 8;
+       } else if (PinNum == 31) {
+               *pTranslatedPinNum = 31;
+               *pGroupNum = 17;
+       } else
+               return -1;
 
-       INIT_LIST_HEAD(&g_smscore_notifyees);
-       INIT_LIST_HEAD(&g_smscore_devices);
-       kmutex_init(&g_smscore_deviceslock);
+       *pGroupCfg <<= 24;
 
-       INIT_LIST_HEAD(&g_smscore_registry);
-       kmutex_init(&g_smscore_registrylock);
+       return 0;
+}
+
+int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
+               struct smscore_gpio_config *pGpioConfig) {
+
+       u32 totalLen;
+       u32 TranslatedPinNum;
+       u32 GroupNum;
+       u32 ElectricChar;
+       u32 groupCfg;
+       void *buffer;
+       int rc;
+
+       struct SetGpioMsg {
+               struct SmsMsgHdr_ST xMsgHeader;
+               u32 msgData[6];
+       } *pMsg;
+
+
+       if (PinNum > MAX_GPIO_PIN_NUMBER)
+               return -EINVAL;
+
+       if (pGpioConfig == NULL)
+               return -EINVAL;
+
+       totalLen = sizeof(struct SmsMsgHdr_ST) + (sizeof(u32) * 6);
+
+       buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
+                       GFP_KERNEL | GFP_DMA);
+       if (!buffer)
+               return -ENOMEM;
+
+       pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
+
+       pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+       pMsg->xMsgHeader.msgDstId = HIF_TASK;
+       pMsg->xMsgHeader.msgFlags = 0;
+       pMsg->xMsgHeader.msgLength = (u16) totalLen;
+       pMsg->msgData[0] = PinNum;
+
+       if (!(coredev->device_flags & SMS_DEVICE_FAMILY2)) {
+               pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_REQ;
+               if (GetGpioPinParams(PinNum, &TranslatedPinNum, &GroupNum,
+                               &groupCfg) != 0)
+                       return -EINVAL;
+
+               pMsg->msgData[1] = TranslatedPinNum;
+               pMsg->msgData[2] = GroupNum;
+               ElectricChar = (pGpioConfig->PullUpDown)
+                               | (pGpioConfig->InputCharacteristics << 2)
+                               | (pGpioConfig->OutputSlewRate << 3)
+                               | (pGpioConfig->OutputDriving << 4);
+               pMsg->msgData[3] = ElectricChar;
+               pMsg->msgData[4] = pGpioConfig->Direction;
+               pMsg->msgData[5] = groupCfg;
+       } else {
+               pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_CONFIG_EX_REQ;
+               pMsg->msgData[1] = pGpioConfig->PullUpDown;
+               pMsg->msgData[2] = pGpioConfig->OutputSlewRate;
+               pMsg->msgData[3] = pGpioConfig->OutputDriving;
+               pMsg->msgData[4] = pGpioConfig->Direction;
+               pMsg->msgData[5] = 0;
+       }
+
+       smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
+       rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
+                       &coredev->gpio_configuration_done);
+
+       if (rc != 0) {
+               if (rc == -ETIME)
+                       sms_err("smscore_gpio_configure timeout");
+               else
+                       sms_err("smscore_gpio_configure error");
+       }
+       kfree(buffer);
+
+       return rc;
+}
+
+int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
+               u8 NewLevel) {
+
+       u32 totalLen;
+       int rc;
+       void *buffer;
+
+       struct SetGpioMsg {
+               struct SmsMsgHdr_ST xMsgHeader;
+               u32 msgData[3]; /* keep it 3 ! */
+       } *pMsg;
+
+       if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER) ||
+                       (PinNum > MAX_GPIO_PIN_NUMBER))
+               return -EINVAL;
 
+       totalLen = sizeof(struct SmsMsgHdr_ST) +
+                       (3 * sizeof(u32)); /* keep it 3 ! */
 
+       buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
+                       GFP_KERNEL | GFP_DMA);
+       if (!buffer)
+               return -ENOMEM;
 
+       pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
 
+       pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+       pMsg->xMsgHeader.msgDstId = HIF_TASK;
+       pMsg->xMsgHeader.msgFlags = 0;
+       pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_SET_LEVEL_REQ;
+       pMsg->xMsgHeader.msgLength = (u16) totalLen;
+       pMsg->msgData[0] = PinNum;
+       pMsg->msgData[1] = NewLevel;
 
+       /* Send message to SMS */
+       smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
+       rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
+                       &coredev->gpio_set_level_done);
+
+       if (rc != 0) {
+               if (rc == -ETIME)
+                       sms_err("smscore_gpio_set_level timeout");
+               else
+                       sms_err("smscore_gpio_set_level error");
+       }
+       kfree(buffer);
 
        return rc;
-       sms_debug("rc %d", rc);
+}
+
+int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum,
+               u8 *level) {
+
+       u32 totalLen;
+       int rc;
+       void *buffer;
+
+       struct SetGpioMsg {
+               struct SmsMsgHdr_ST xMsgHeader;
+               u32 msgData[2];
+       } *pMsg;
+
+
+       if (PinNum > MAX_GPIO_PIN_NUMBER)
+               return -EINVAL;
+
+       totalLen = sizeof(struct SmsMsgHdr_ST) + (2 * sizeof(u32));
+
+       buffer = kmalloc(totalLen + SMS_DMA_ALIGNMENT,
+                       GFP_KERNEL | GFP_DMA);
+       if (!buffer)
+               return -ENOMEM;
+
+       pMsg = (struct SetGpioMsg *) SMS_ALIGN_ADDRESS(buffer);
+
+       pMsg->xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+       pMsg->xMsgHeader.msgDstId = HIF_TASK;
+       pMsg->xMsgHeader.msgFlags = 0;
+       pMsg->xMsgHeader.msgType = MSG_SMS_GPIO_GET_LEVEL_REQ;
+       pMsg->xMsgHeader.msgLength = (u16) totalLen;
+       pMsg->msgData[0] = PinNum;
+       pMsg->msgData[1] = 0;
+
+       /* Send message to SMS */
+       smsendian_handle_tx_message((struct SmsMsgHdr_ST *)pMsg);
+       rc = smscore_sendrequest_and_wait(coredev, pMsg, totalLen,
+                       &coredev->gpio_get_level_done);
+
+       if (rc != 0) {
+               if (rc == -ETIME)
+                       sms_err("smscore_gpio_get_level timeout");
+               else
+                       sms_err("smscore_gpio_get_level error");
+       }
+       kfree(buffer);
+
+       /* Its a race between other gpio_get_level() and the copy of the single
+        * global 'coredev->gpio_get_res' to  the function's variable 'level'
+        */
+       *level = coredev->gpio_get_res;
 
        return rc;
 }
 
-static void __exit smscore_module_exit(void)
+static int __init smscore_module_init(void)
 {
+       int rc = 0;
 
+       INIT_LIST_HEAD(&g_smscore_notifyees);
+       INIT_LIST_HEAD(&g_smscore_devices);
+       kmutex_init(&g_smscore_deviceslock);
 
+       INIT_LIST_HEAD(&g_smscore_registry);
+       kmutex_init(&g_smscore_registrylock);
 
+       return rc;
+}
 
-
+static void __exit smscore_module_exit(void)
+{
        kmutex_lock(&g_smscore_deviceslock);
        while (!list_empty(&g_smscore_notifyees)) {
                struct smscore_device_notifyee_t *notifyee =
index 548de9056e8b97b0f567d9cbf948ecb10891b6cc..f1108c64e895eb4ad2914aebb41cb6ef78a5ab3d 100644 (file)
@@ -1,26 +1,26 @@
-/*
- *  Driver for the Siano SMS1xxx USB dongle
- *
- *  author: Anatoly Greenblat
- *
- *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation;
- *
- *  Software distributed under the License is distributed on an "AS IS"
- *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
- *
- *  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 __smscoreapi_h__
-#define __smscoreapi_h__
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik, Anatoly Greenblat
+
+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, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+
+#ifndef __SMS_CORE_API_H__
+#define __SMS_CORE_API_H__
 
 #include <linux/version.h>
 #include <linux/device.h>
 #include <linux/mm.h>
 #include <linux/scatterlist.h>
 #include <linux/types.h>
-#include <asm/page.h>
 #include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/timer.h>
 
-#include "dmxdev.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dvb_frontend.h"
+#include <asm/page.h>
 
+#include "smsir.h"
 
 #define kmutex_init(_p_) mutex_init(_p_)
 #define kmutex_lock(_p_) mutex_lock(_p_)
 #define min(a, b) (((a) < (b)) ? (a) : (b))
 #endif
 
-#define SMS_ALLOC_ALIGNMENT                                    128
-#define SMS_DMA_ALIGNMENT                                      16
+#define SMS_PROTOCOL_MAX_RAOUNDTRIP_MS                 (10000)
+#define SMS_ALLOC_ALIGNMENT                            128
+#define SMS_DMA_ALIGNMENT                              16
 #define SMS_ALIGN_ADDRESS(addr) \
        ((((uintptr_t)(addr)) + (SMS_DMA_ALIGNMENT-1)) & ~(SMS_DMA_ALIGNMENT-1))
 
-#define SMS_DEVICE_FAMILY2                                     1
-#define SMS_ROM_NO_RESPONSE                                    2
+#define SMS_DEVICE_FAMILY2                             1
+#define SMS_ROM_NO_RESPONSE                            2
 #define SMS_DEVICE_NOT_READY                           0x8000000
 
 enum sms_device_type_st {
@@ -83,13 +83,13 @@ typedef void (*onremove_t)(void *context);
 struct smscore_buffer_t {
        /* public members, once passed to clients can be changed freely */
        struct list_head entry;
-       int                             size;
-       int                             offset;
+       int size;
+       int offset;
 
        /* private members, read-only for clients */
-       void                    *p;
-       dma_addr_t              phys;
-       unsigned long   offset_in_common;
+       void *p;
+       dma_addr_t phys;
+       unsigned long offset_in_common;
 };
 
 struct smsdevice_params_t {
@@ -116,10 +116,63 @@ struct smsclient_params_t {
        int                             data_type;
        onresponse_t    onresponse_handler;
        onremove_t              onremove_handler;
-
        void                    *context;
 };
 
+struct smscore_device_t {
+       struct list_head entry;
+
+       struct list_head clients;
+       struct list_head subclients;
+       spinlock_t clientslock;
+
+       struct list_head buffers;
+       spinlock_t bufferslock;
+       int num_buffers;
+
+       void *common_buffer;
+       int common_buffer_size;
+       dma_addr_t common_buffer_phys;
+
+       void *context;
+       struct device *device;
+
+       char devpath[32];
+       unsigned long device_flags;
+
+       setmode_t setmode_handler;
+       detectmode_t detectmode_handler;
+       sendrequest_t sendrequest_handler;
+       preload_t preload_handler;
+       postload_t postload_handler;
+
+       int mode, modes_supported;
+
+       /* host <--> device messages */
+       struct completion version_ex_done, data_download_done, trigger_done;
+       struct completion init_device_done, reload_start_done, resume_done;
+       struct completion gpio_configuration_done, gpio_set_level_done;
+       struct completion gpio_get_level_done, ir_init_done;
+
+       /* Buffer management */
+       wait_queue_head_t buffer_mng_waitq;
+
+       /* GPIO */
+       int gpio_get_res;
+
+       /* Target hardware board */
+       int board_id;
+
+       /* Firmware */
+       u8 *fw_buf;
+       u32 fw_buf_size;
+
+       /* Infrared (IR) */
+       struct ir_t ir;
+
+       int led_state;
+};
+
 /* GPIO definitions for antenna frequency domain control (SMS8021) */
 #define SMS_ANTENNA_GPIO_0                                     1
 #define SMS_ANTENNA_GPIO_1                                     0
@@ -154,18 +207,15 @@ struct smsclient_params_t {
 #define MSG_SMS_INIT_DEVICE_RES                                579
 #define MSG_SMS_ADD_PID_FILTER_REQ                     601
 #define MSG_SMS_ADD_PID_FILTER_RES                     602
-#define MSG_SMS_REMOVE_PID_FILTER_REQ          603
-#define MSG_SMS_REMOVE_PID_FILTER_RES          604
-#define MSG_SMS_DAB_CHANNEL                                    607
-#define MSG_SMS_GET_PID_FILTER_LIST_REQ                608
-#define MSG_SMS_GET_PID_FILTER_LIST_RES                609
-#define MSG_SMS_GET_STATISTICS_REQ                     615
-#define MSG_SMS_GET_STATISTICS_RES                     616
-#define MSG_SMS_SET_ANTENNA_CONFIG_REQ         651
-#define MSG_SMS_SET_ANTENNA_CONFIG_RES         652
-#define MSG_SMS_GET_STATISTICS_EX_REQ          653
-#define MSG_SMS_GET_STATISTICS_EX_RES          654
-#define MSG_SMS_SLEEP_RESUME_COMP_IND          655
+#define MSG_SMS_REMOVE_PID_FILTER_REQ                  603
+#define MSG_SMS_REMOVE_PID_FILTER_RES                  604
+#define MSG_SMS_DAB_CHANNEL                            607
+#define MSG_SMS_GET_PID_FILTER_LIST_REQ                        608
+#define MSG_SMS_GET_PID_FILTER_LIST_RES                        609
+#define MSG_SMS_HO_PER_SLICES_IND                      630
+#define MSG_SMS_SET_ANTENNA_CONFIG_REQ                 651
+#define MSG_SMS_SET_ANTENNA_CONFIG_RES                 652
+#define MSG_SMS_SLEEP_RESUME_COMP_IND                  655
 #define MSG_SMS_DATA_DOWNLOAD_REQ                      660
 #define MSG_SMS_DATA_DOWNLOAD_RES                      661
 #define MSG_SMS_SWDOWNLOAD_TRIGGER_REQ         664
@@ -190,14 +240,31 @@ struct smsclient_params_t {
 #define MSG_SMS_GPIO_CONFIG_EX_RES                     713
 #define MSG_SMS_ISDBT_TUNE_REQ                         776
 #define MSG_SMS_ISDBT_TUNE_RES                         777
+#define MSG_SMS_TRANSMISSION_IND                       782
+#define MSG_SMS_START_IR_REQ                           800
+#define MSG_SMS_START_IR_RES                           801
+#define MSG_SMS_IR_SAMPLES_IND                         802
+#define MSG_SMS_SIGNAL_DETECTED_IND                    827
+#define MSG_SMS_NO_SIGNAL_IND                          828
 
 #define SMS_INIT_MSG_EX(ptr, type, src, dst, len) do { \
        (ptr)->msgType = type; (ptr)->msgSrcId = src; (ptr)->msgDstId = dst; \
        (ptr)->msgLength = len; (ptr)->msgFlags = 0; \
 } while (0)
+
 #define SMS_INIT_MSG(ptr, type, len) \
        SMS_INIT_MSG_EX(ptr, type, 0, HIF_TASK, len)
 
+enum SMS_DVB3_EVENTS {
+       DVB3_EVENT_INIT = 0,
+       DVB3_EVENT_SLEEP,
+       DVB3_EVENT_HOTPLUG,
+       DVB3_EVENT_FE_LOCK,
+       DVB3_EVENT_FE_UNLOCK,
+       DVB3_EVENT_UNC_OK,
+       DVB3_EVENT_UNC_ERR
+};
+
 enum SMS_DEVICE_MODE {
        DEVICE_MODE_NONE = -1,
        DEVICE_MODE_DVBT = 0,
@@ -221,8 +288,13 @@ struct SmsMsgHdr_ST {
 };
 
 struct SmsMsgData_ST {
-       struct SmsMsgHdr_ST     xMsgHeader;
-       u32                     msgData[1];
+       struct SmsMsgHdr_ST xMsgHeader;
+       u32 msgData[1];
+};
+
+struct SmsMsgData_ST2 {
+       struct SmsMsgHdr_ST xMsgHeader;
+       u32 msgData[2];
 };
 
 struct SmsDataDownload_ST {
@@ -238,11 +310,12 @@ struct SmsVersionRes_ST {
        u8              Step; /* 0 - Step A */
        u8              MetalFix; /* 0 - Metal 0 */
 
-       u8              FirmwareId; /* 0xFF ï¿½ ROM, otherwise the
-                                    * value indicated by
-                                    * SMSHOSTLIB_DEVICE_MODES_E */
-       u8              SupportedProtocols; /* Bitwise OR combination of
+       /* FirmwareId 0xFF if ROM, otherwise the
+        * value indicated by SMSHOSTLIB_DEVICE_MODES_E */
+       u8 FirmwareId;
+       /* SupportedProtocols Bitwise OR combination of
                                             * supported protocols */
+       u8 SupportedProtocols;
 
        u8              VersionMajor;
        u8              VersionMinor;
@@ -264,86 +337,219 @@ struct SmsFirmware_ST {
        u8                      Payload[1];
 };
 
-struct SMSHOSTLIB_STATISTICS_ST {
-       u32 Reserved; /* Reserved */
+/* Statistics information returned as response for
+ * SmsHostApiGetStatistics_Req */
+struct SMSHOSTLIB_STATISTICS_S {
+       u32 Reserved;           /* Reserved */
 
        /* Common parameters */
-       u32 IsRfLocked; /* 0 - not locked, 1 - locked */
-       u32 IsDemodLocked; /* 0 - not locked, 1 - locked */
-       u32 IsExternalLNAOn; /* 0 - external LNA off, 1 - external LNA on */
+       u32 IsRfLocked;         /* 0 - not locked, 1 - locked */
+       u32 IsDemodLocked;      /* 0 - not locked, 1 - locked */
+       u32 IsExternalLNAOn;    /* 0 - external LNA off, 1 - external LNA on */
 
        /* Reception quality */
-       s32  SNR; /* dB */
-       u32 BER; /* Post Viterbi BER [1E-5] */
-       u32 FIB_CRC;    /* CRC errors percentage, valid only for DAB */
-       u32 TS_PER; /* Transport stream PER, 0xFFFFFFFF indicate N/A,
-                    * valid only for DVB-T/H */
-       u32 MFER; /* DVB-H frame error rate in percentage,
-                  * 0xFFFFFFFF indicate N/A, valid only for DVB-H */
-       s32  RSSI; /* dBm */
-       s32  InBandPwr; /* In band power in dBM */
-       s32  CarrierOffset; /* Carrier Offset in bin/1024 */
-
-       /* Transmission parameters, valid only for DVB-T/H */
-       u32 Frequency; /* Frequency in Hz */
-       u32 Bandwidth; /* Bandwidth in MHz */
-       u32 TransmissionMode; /* Transmission Mode, for DAB modes 1-4,
-                              * for DVB-T/H FFT mode carriers in Kilos */
-       u32 ModemState; /* from SMS_DvbModemState_ET */
-       u32 GuardInterval; /* Guard Interval, 1 divided by value */
-       u32 CodeRate; /* Code Rate from SMS_DvbModemState_ET */
-       u32 LPCodeRate; /* Low Priority Code Rate from SMS_DvbModemState_ET */
-       u32 Hierarchy; /* Hierarchy from SMS_Hierarchy_ET */
-       u32 Constellation; /* Constellation from SMS_Constellation_ET */
+       s32 SNR;                /* dB */
+       u32 BER;                /* Post Viterbi BER [1E-5] */
+       u32 FIB_CRC;            /* CRC errors percentage, valid only for DAB */
+       u32 TS_PER;             /* Transport stream PER,
+       0xFFFFFFFF indicate N/A, valid only for DVB-T/H */
+       u32 MFER;               /* DVB-H frame error rate in percentage,
+       0xFFFFFFFF indicate N/A, valid only for DVB-H */
+       s32 RSSI;               /* dBm */
+       s32 InBandPwr;          /* In band power in dBM */
+       s32 CarrierOffset;      /* Carrier Offset in bin/1024 */
+
+       /* Transmission parameters */
+       u32 Frequency;          /* Frequency in Hz */
+       u32 Bandwidth;          /* Bandwidth in MHz, valid only for DVB-T/H */
+       u32 TransmissionMode;   /* Transmission Mode, for DAB modes 1-4,
+       for DVB-T/H FFT mode carriers in Kilos */
+       u32 ModemState;         /* from SMSHOSTLIB_DVB_MODEM_STATE_ET,
+       valid only for DVB-T/H */
+       u32 GuardInterval;      /* Guard Interval from
+       SMSHOSTLIB_GUARD_INTERVALS_ET,  valid only for DVB-T/H */
+       u32 CodeRate;           /* Code Rate from SMSHOSTLIB_CODE_RATE_ET,
+       valid only for DVB-T/H */
+       u32 LPCodeRate;         /* Low Priority Code Rate from
+       SMSHOSTLIB_CODE_RATE_ET, valid only for DVB-T/H */
+       u32 Hierarchy;          /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET,
+       valid only for DVB-T/H */
+       u32 Constellation;      /* Constellation from
+       SMSHOSTLIB_CONSTELLATION_ET, valid only for DVB-T/H */
 
        /* Burst parameters, valid only for DVB-H */
-       u32 BurstSize; /* Current burst size in bytes */
-       u32 BurstDuration; /* Current burst duration in mSec */
-       u32 BurstCycleTime; /* Current burst cycle time in mSec */
-       u32 CalculatedBurstCycleTime; /* Current burst cycle time in mSec,
-                                      * as calculated by demodulator */
-       u32 NumOfRows; /* Number of rows in MPE table */
-       u32 NumOfPaddCols; /* Number of padding columns in MPE table */
-       u32 NumOfPunctCols; /* Number of puncturing columns in MPE table */
-       /* Burst parameters */
-       u32 ErrorTSPackets; /* Number of erroneous transport-stream packets */
-       u32 TotalTSPackets; /* Total number of transport-stream packets */
-       u32 NumOfValidMpeTlbs; /* Number of MPE tables which do not include
-                               * errors after MPE RS decoding */
-       u32 NumOfInvalidMpeTlbs; /* Number of MPE tables which include errors
-                                 * after MPE RS decoding */
-       u32 NumOfCorrectedMpeTlbs; /* Number of MPE tables which were corrected
-                                   * by MPE RS decoding */
-
+       u32 BurstSize;          /* Current burst size in bytes,
+       valid only for DVB-H */
+       u32 BurstDuration;      /* Current burst duration in mSec,
+       valid only for DVB-H */
+       u32 BurstCycleTime;     /* Current burst cycle time in mSec,
+       valid only for DVB-H */
+       u32 CalculatedBurstCycleTime;/* Current burst cycle time in mSec,
+       as calculated by demodulator, valid only for DVB-H */
+       u32 NumOfRows;          /* Number of rows in MPE table,
+       valid only for DVB-H */
+       u32 NumOfPaddCols;      /* Number of padding columns in MPE table,
+       valid only for DVB-H */
+       u32 NumOfPunctCols;     /* Number of puncturing columns in MPE table,
+       valid only for DVB-H */
+       u32 ErrorTSPackets;     /* Number of erroneous
+       transport-stream packets */
+       u32 TotalTSPackets;     /* Total number of transport-stream packets */
+       u32 NumOfValidMpeTlbs;  /* Number of MPE tables which do not include
+       errors after MPE RS decoding */
+       u32 NumOfInvalidMpeTlbs;/* Number of MPE tables which include errors
+       after MPE RS decoding */
+       u32 NumOfCorrectedMpeTlbs;/* Number of MPE tables which were
+       corrected by MPE RS decoding */
        /* Common params */
-       u32 BERErrorCount; /* Number of errornous SYNC bits. */
-       u32 BERBitCount; /* Total number of SYNC bits. */
+       u32 BERErrorCount;      /* Number of errornous SYNC bits. */
+       u32 BERBitCount;        /* Total number of SYNC bits. */
 
        /* Interface information */
-       u32 SmsToHostTxErrors; /* Total number of transmission errors. */
+       u32 SmsToHostTxErrors;  /* Total number of transmission errors. */
 
        /* DAB/T-DMB */
-       u32 PreBER; /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */
+       u32 PreBER;             /* DAB/T-DMB only: Pre Viterbi BER [1E-5] */
 
        /* DVB-H TPS parameters */
-       u32 CellId; /* TPS Cell ID in bits 15..0, bits 31..16 zero;
-                    * if set to 0xFFFFFFFF cell_id not yet recovered */
+       u32 CellId;             /* TPS Cell ID in bits 15..0, bits 31..16 zero;
+        if set to 0xFFFFFFFF cell_id not yet recovered */
+       u32 DvbhSrvIndHP;       /* DVB-H service indication info, bit 1 -
+       Time Slicing indicator, bit 0 - MPE-FEC indicator */
+       u32 DvbhSrvIndLP;       /* DVB-H service indication info, bit 1 -
+       Time Slicing indicator, bit 0 - MPE-FEC indicator */
 
+       u32 NumMPEReceived;     /* DVB-H, Num MPE section received */
+
+       u32 ReservedFields[10]; /* Reserved */
 };
 
-struct SmsMsgStatisticsInfo_ST {
-       u32 RequestResult;
+struct PID_STATISTICS_DATA_S {
+       struct PID_BURST_S {
+               u32 size;
+               u32 padding_cols;
+               u32 punct_cols;
+               u32 duration;
+               u32 cycle;
+               u32 calc_cycle;
+       } burst;
+
+       u32 tot_tbl_cnt;
+       u32 invalid_tbl_cnt;
+       u32 tot_cor_tbl;
+};
 
-       struct SMSHOSTLIB_STATISTICS_ST Stat;
+struct PID_DATA_S {
+       u32 pid;
+       u32 num_rows;
+       struct PID_STATISTICS_DATA_S pid_statistics;
+};
 
-       /* Split the calc of the SNR in DAB */
-       u32 Signal; /* dB */
-       u32 Noise; /* dB */
+#define CORRECT_STAT_RSSI(_stat) ((_stat).RSSI *= -1)
+#define CORRECT_STAT_BANDWIDTH(_stat) (_stat.Bandwidth = 8 - _stat.Bandwidth)
+#define CORRECT_STAT_TRANSMISSON_MODE(_stat) \
+       if (_stat.TransmissionMode == 0) \
+               _stat.TransmissionMode = 2; \
+       else if (_stat.TransmissionMode == 1) \
+               _stat.TransmissionMode = 8; \
+               else \
+                       _stat.TransmissionMode = 4;
+
+struct TRANSMISSION_STATISTICS_S {
+       u32 Frequency;          /* Frequency in Hz */
+       u32 Bandwidth;          /* Bandwidth in MHz */
+       u32 TransmissionMode;   /* FFT mode carriers in Kilos */
+       u32 GuardInterval;      /* Guard Interval from
+       SMSHOSTLIB_GUARD_INTERVALS_ET */
+       u32 CodeRate;           /* Code Rate from SMSHOSTLIB_CODE_RATE_ET */
+       u32 LPCodeRate;         /* Low Priority Code Rate from
+       SMSHOSTLIB_CODE_RATE_ET */
+       u32 Hierarchy;          /* Hierarchy from SMSHOSTLIB_HIERARCHY_ET */
+       u32 Constellation;      /* Constellation from
+       SMSHOSTLIB_CONSTELLATION_ET */
 
+       /* DVB-H TPS parameters */
+       u32 CellId;             /* TPS Cell ID in bits 15..0, bits 31..16 zero;
+        if set to 0xFFFFFFFF cell_id not yet recovered */
+       u32 DvbhSrvIndHP;       /* DVB-H service indication info, bit 1 -
+        Time Slicing indicator, bit 0 - MPE-FEC indicator */
+       u32 DvbhSrvIndLP;       /* DVB-H service indication info, bit 1 -
+        Time Slicing indicator, bit 0 - MPE-FEC indicator */
+       u32 IsDemodLocked;      /* 0 - not locked, 1 - locked */
 };
 
+struct RECEPTION_STATISTICS_S {
+       u32 IsRfLocked;         /* 0 - not locked, 1 - locked */
+       u32 IsDemodLocked;      /* 0 - not locked, 1 - locked */
+       u32 IsExternalLNAOn;    /* 0 - external LNA off, 1 - external LNA on */
+
+       u32 ModemState;         /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */
+       s32 SNR;                /* dB */
+       u32 BER;                /* Post Viterbi BER [1E-5] */
+       u32 BERErrorCount;      /* Number of erronous SYNC bits. */
+       u32 BERBitCount;        /* Total number of SYNC bits. */
+       u32 TS_PER;             /* Transport stream PER,
+       0xFFFFFFFF indicate N/A */
+       u32 MFER;               /* DVB-H frame error rate in percentage,
+       0xFFFFFFFF indicate N/A, valid only for DVB-H */
+       s32 RSSI;               /* dBm */
+       s32 InBandPwr;          /* In band power in dBM */
+       s32 CarrierOffset;      /* Carrier Offset in bin/1024 */
+       u32 ErrorTSPackets;     /* Number of erroneous
+       transport-stream packets */
+       u32 TotalTSPackets;     /* Total number of transport-stream packets */
+
+       s32 MRC_SNR;            /* dB */
+       s32 MRC_RSSI;           /* dBm */
+       s32 MRC_InBandPwr;      /* In band power in dBM */
+};
 
-struct smscore_gpio_config {
+
+/* Statistics information returned as response for
+ * SmsHostApiGetStatisticsEx_Req for DVB applications, SMS1100 and up */
+struct SMSHOSTLIB_STATISTICS_DVB_S {
+       /* Reception */
+       struct RECEPTION_STATISTICS_S ReceptionData;
+
+       /* Transmission parameters */
+       struct TRANSMISSION_STATISTICS_S TransmissionData;
+
+       /* Burst parameters, valid only for DVB-H */
+#define        SRVM_MAX_PID_FILTERS 8
+       struct PID_DATA_S PidData[SRVM_MAX_PID_FILTERS];
+};
+
+struct SRVM_SIGNAL_STATUS_S {
+       u32 result;
+       u32 snr;
+       u32 tsPackets;
+       u32 etsPackets;
+       u32 constellation;
+       u32 hpCode;
+       u32 tpsSrvIndLP;
+       u32 tpsSrvIndHP;
+       u32 cellId;
+       u32 reason;
+
+       s32 inBandPower;
+       u32 requestId;
+};
+
+struct SMSHOSTLIB_I2C_REQ_ST {
+       u32     DeviceAddress; /* I2c device address */
+       u32     WriteCount; /* number of bytes to write */
+       u32     ReadCount; /* number of bytes to read */
+       u8      Data[1];
+};
+
+struct SMSHOSTLIB_I2C_RES_ST {
+       u32     Status; /* non-zero value in case of failure */
+       u32     ReadCount; /* number of bytes read */
+       u8      Data[1];
+};
+
+
+struct smscore_config_gpio {
 #define SMS_GPIO_DIRECTION_INPUT  0
 #define SMS_GPIO_DIRECTION_OUTPUT 1
        u8 direction;
@@ -369,6 +575,47 @@ struct smscore_gpio_config {
        u8 outputdriving;
 };
 
+struct smscore_gpio_config {
+#define SMS_GPIO_DIRECTION_INPUT  0
+#define SMS_GPIO_DIRECTION_OUTPUT 1
+       u8 Direction;
+
+#define SMS_GPIO_PULL_UP_DOWN_NONE     0
+#define SMS_GPIO_PULL_UP_DOWN_PULLDOWN 1
+#define SMS_GPIO_PULL_UP_DOWN_PULLUP   2
+#define SMS_GPIO_PULL_UP_DOWN_KEEPER   3
+       u8 PullUpDown;
+
+#define SMS_GPIO_INPUT_CHARACTERISTICS_NORMAL  0
+#define SMS_GPIO_INPUT_CHARACTERISTICS_SCHMITT 1
+       u8 InputCharacteristics;
+
+#define SMS_GPIO_OUTPUT_SLEW_RATE_SLOW         1 /* 10xx */
+#define SMS_GPIO_OUTPUT_SLEW_RATE_FAST         0 /* 10xx */
+
+
+#define SMS_GPIO_OUTPUT_SLEW_RATE_0_45_V_NS    0 /* 11xx */
+#define SMS_GPIO_OUTPUT_SLEW_RATE_0_9_V_NS     1 /* 11xx */
+#define SMS_GPIO_OUTPUT_SLEW_RATE_1_7_V_NS     2 /* 11xx */
+#define SMS_GPIO_OUTPUT_SLEW_RATE_3_3_V_NS     3 /* 11xx */
+       u8 OutputSlewRate;
+
+#define SMS_GPIO_OUTPUT_DRIVING_S_4mA          0 /* 10xx */
+#define SMS_GPIO_OUTPUT_DRIVING_S_8mA          1 /* 10xx */
+#define SMS_GPIO_OUTPUT_DRIVING_S_12mA         2 /* 10xx */
+#define SMS_GPIO_OUTPUT_DRIVING_S_16mA         3 /* 10xx */
+
+#define SMS_GPIO_OUTPUT_DRIVING_1_5mA          0 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_2_8mA          1 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_4mA            2 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_7mA            3 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_10mA           4 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_11mA           5 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_14mA           6 /* 11xx */
+#define SMS_GPIO_OUTPUT_DRIVING_16mA           7 /* 11xx */
+       u8 OutputDriving;
+};
+
 extern void smscore_registry_setmode(char *devpath, int mode);
 extern int smscore_registry_getmode(char *devpath);
 
@@ -410,10 +657,19 @@ struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev);
 extern void smscore_putbuffer(struct smscore_device_t *coredev,
                              struct smscore_buffer_t *cb);
 
+/* old GPIO managment */
 int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
-                          struct smscore_gpio_config *pinconfig);
+                          struct smscore_config_gpio *pinconfig);
 int smscore_set_gpio(struct smscore_device_t *coredev, u32 pin, int level);
 
+/* new GPIO managment */
+extern int smscore_gpio_configure(struct smscore_device_t *coredev, u8 PinNum,
+               struct smscore_gpio_config *pGpioConfig);
+extern int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
+               u8 NewLevel);
+extern int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 PinNum,
+               u8 *level);
+
 void smscore_set_board_id(struct smscore_device_t *core, int id);
 int smscore_get_board_id(struct smscore_device_t *core);
 
@@ -442,4 +698,4 @@ int smscore_led_state(struct smscore_device_t *core, int led);
        dprintk(KERN_DEBUG, DBG_ADV, fmt, ##arg)
 
 
-#endif /* __smscoreapi_h__ */
+#endif /* __SMS_CORE_API_H__ */
index ba080b95befbf5cda1d3943a4d34eaeab5bf60ee..3ee1c3902c56dcc9d56a26380e5dadb07459cd99 100644 (file)
@@ -1,28 +1,34 @@
-/*
- *  Driver for the Siano SMS1xxx USB dongle
- *
- *  Author: Uri Shkolni
- *
- *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation;
- *
- *  Software distributed under the License is distributed on an "AS IS"
- *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
- *
- *  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.
- */
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2008, Uri Shkolnik
+
+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, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
 
 #include <linux/module.h>
 #include <linux/init.h>
 
+#include "dmxdev.h"
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+
 #include "smscoreapi.h"
+#include "smsendian.h"
 #include "sms-cards.h"
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
@@ -39,12 +45,15 @@ struct smsdvb_client_t {
        struct dvb_frontend     frontend;
 
        fe_status_t             fe_status;
-       int                     fe_ber, fe_snr, fe_unc, fe_signal_strength;
 
-       struct completion       tune_done, stat_done;
+       struct completion       tune_done;
 
        /* todo: save freq/band instead whole struct */
        struct dvb_frontend_parameters fe_params;
+
+       struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb;
+       int event_fe_state;
+       int event_unc_state;
 };
 
 static struct list_head g_smsdvb_clients;
@@ -54,11 +63,69 @@ static int sms_dbg;
 module_param_named(debug, sms_dbg, int, 0644);
 MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
 
+/* Events that may come from DVB v3 adapter */
+static void sms_board_dvb3_event(struct smsdvb_client_t *client,
+               enum SMS_DVB3_EVENTS event) {
+
+       struct smscore_device_t *coredev = client->coredev;
+       switch (event) {
+       case DVB3_EVENT_INIT:
+               sms_debug("DVB3_EVENT_INIT");
+               sms_board_event(coredev, BOARD_EVENT_BIND);
+               break;
+       case DVB3_EVENT_SLEEP:
+               sms_debug("DVB3_EVENT_SLEEP");
+               sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
+               break;
+       case DVB3_EVENT_HOTPLUG:
+               sms_debug("DVB3_EVENT_HOTPLUG");
+               sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
+               break;
+       case DVB3_EVENT_FE_LOCK:
+               if (client->event_fe_state != DVB3_EVENT_FE_LOCK) {
+                       client->event_fe_state = DVB3_EVENT_FE_LOCK;
+                       sms_debug("DVB3_EVENT_FE_LOCK");
+                       sms_board_event(coredev, BOARD_EVENT_FE_LOCK);
+               }
+               break;
+       case DVB3_EVENT_FE_UNLOCK:
+               if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) {
+                       client->event_fe_state = DVB3_EVENT_FE_UNLOCK;
+                       sms_debug("DVB3_EVENT_FE_UNLOCK");
+                       sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK);
+               }
+               break;
+       case DVB3_EVENT_UNC_OK:
+               if (client->event_unc_state != DVB3_EVENT_UNC_OK) {
+                       client->event_unc_state = DVB3_EVENT_UNC_OK;
+                       sms_debug("DVB3_EVENT_UNC_OK");
+                       sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK);
+               }
+               break;
+       case DVB3_EVENT_UNC_ERR:
+               if (client->event_unc_state != DVB3_EVENT_UNC_ERR) {
+                       client->event_unc_state = DVB3_EVENT_UNC_ERR;
+                       sms_debug("DVB3_EVENT_UNC_ERR");
+                       sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS);
+               }
+               break;
+
+       default:
+               sms_err("Unknown dvb3 api event");
+               break;
+       }
+}
+
 static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
 {
        struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
-       struct SmsMsgHdr_ST *phdr =
-               (struct SmsMsgHdr_ST *)(((u8 *) cb->p) + cb->offset);
+       struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p)
+                       + cb->offset);
+       u32 *pMsgData = (u32 *) phdr + 1;
+       /*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/
+       bool is_status_update = false;
+
+       smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr);
 
        switch (phdr->msgType) {
        case MSG_SMS_DVBT_BDA_DATA:
@@ -70,43 +137,110 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
                complete(&client->tune_done);
                break;
 
-       case MSG_SMS_GET_STATISTICS_RES:
-       {
-               struct SmsMsgStatisticsInfo_ST *p =
-                       (struct SmsMsgStatisticsInfo_ST *)(phdr + 1);
-
-               if (p->Stat.IsDemodLocked) {
-                       client->fe_status = FE_HAS_SIGNAL |
-                                           FE_HAS_CARRIER |
-                                           FE_HAS_VITERBI |
-                                           FE_HAS_SYNC |
-                                           FE_HAS_LOCK;
-
-                       client->fe_snr = p->Stat.SNR;
-                       client->fe_ber = p->Stat.BER;
-                       client->fe_unc = p->Stat.BERErrorCount;
-
-                       if (p->Stat.InBandPwr < -95)
-                               client->fe_signal_strength = 0;
-                       else if (p->Stat.InBandPwr > -29)
-                               client->fe_signal_strength = 100;
-                       else
-                               client->fe_signal_strength =
-                                       (p->Stat.InBandPwr + 95) * 3 / 2;
+       case MSG_SMS_SIGNAL_DETECTED_IND:
+               sms_info("MSG_SMS_SIGNAL_DETECTED_IND");
+               client->sms_stat_dvb.TransmissionData.IsDemodLocked = true;
+               is_status_update = true;
+               break;
+
+       case MSG_SMS_NO_SIGNAL_IND:
+               sms_info("MSG_SMS_NO_SIGNAL_IND");
+               client->sms_stat_dvb.TransmissionData.IsDemodLocked = false;
+               is_status_update = true;
+               break;
+
+       case MSG_SMS_TRANSMISSION_IND: {
+               sms_info("MSG_SMS_TRANSMISSION_IND");
+
+               pMsgData++;
+               memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData,
+                               sizeof(struct TRANSMISSION_STATISTICS_S));
+
+               /* Mo need to correct guard interval
+                * (as opposed to old statistics message).
+                */
+               CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData);
+               CORRECT_STAT_TRANSMISSON_MODE(
+                               client->sms_stat_dvb.TransmissionData);
+               is_status_update = true;
+               break;
+       }
+       case MSG_SMS_HO_PER_SLICES_IND: {
+               struct RECEPTION_STATISTICS_S *pReceptionData =
+                               &client->sms_stat_dvb.ReceptionData;
+               struct SRVM_SIGNAL_STATUS_S SignalStatusData;
+
+               /*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/
+               pMsgData++;
+               SignalStatusData.result = pMsgData[0];
+               SignalStatusData.snr = pMsgData[1];
+               SignalStatusData.inBandPower = (s32) pMsgData[2];
+               SignalStatusData.tsPackets = pMsgData[3];
+               SignalStatusData.etsPackets = pMsgData[4];
+               SignalStatusData.constellation = pMsgData[5];
+               SignalStatusData.hpCode = pMsgData[6];
+               SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03;
+               SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03;
+               SignalStatusData.cellId = pMsgData[9] & 0xFFFF;
+               SignalStatusData.reason = pMsgData[10];
+               SignalStatusData.requestId = pMsgData[11];
+               pReceptionData->IsRfLocked = pMsgData[16];
+               pReceptionData->IsDemodLocked = pMsgData[17];
+               pReceptionData->ModemState = pMsgData[12];
+               pReceptionData->SNR = pMsgData[1];
+               pReceptionData->BER = pMsgData[13];
+               pReceptionData->RSSI = pMsgData[14];
+               CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData);
+
+               pReceptionData->InBandPwr = (s32) pMsgData[2];
+               pReceptionData->CarrierOffset = (s32) pMsgData[15];
+               pReceptionData->TotalTSPackets = pMsgData[3];
+               pReceptionData->ErrorTSPackets = pMsgData[4];
+
+               /* TS PER */
+               if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets)
+                               > 0) {
+                       pReceptionData->TS_PER = (SignalStatusData.etsPackets
+                                       * 100) / (SignalStatusData.tsPackets
+                                       + SignalStatusData.etsPackets);
                } else {
-                       client->fe_status = 0;
-                       client->fe_snr =
-                       client->fe_ber =
-                       client->fe_unc =
-                       client->fe_signal_strength = 0;
+                       pReceptionData->TS_PER = 0;
                }
 
-               complete(&client->stat_done);
-               break;
-       } }
+               pReceptionData->BERBitCount = pMsgData[18];
+               pReceptionData->BERErrorCount = pMsgData[19];
 
+               pReceptionData->MRC_SNR = pMsgData[20];
+               pReceptionData->MRC_InBandPwr = pMsgData[21];
+               pReceptionData->MRC_RSSI = pMsgData[22];
+
+               is_status_update = true;
+               break;
+       }
+       }
        smscore_putbuffer(client->coredev, cb);
 
+       if (is_status_update) {
+               if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) {
+                       client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER
+                               | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+                       sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);
+                       if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets
+                                       == 0)
+                               sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
+                       else
+                               sms_board_dvb3_event(client,
+                                               DVB3_EVENT_UNC_ERR);
+
+               } else {
+                       /*client->fe_status =
+                               (phdr->msgType == MSG_SMS_NO_SIGNAL_IND) ?
+                               0 : FE_HAS_SIGNAL;*/
+                       client->fe_status = 0;
+                       sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
+               }
+       }
+
        return 0;
 }
 
@@ -149,6 +283,7 @@ static int smsdvb_start_feed(struct dvb_demux_feed *feed)
        PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
        PidMsg.msgData[0] = feed->pid;
 
+       smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
        return smsclient_sendrequest(client->smsclient,
                                     &PidMsg, sizeof(PidMsg));
 }
@@ -169,6 +304,7 @@ static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
        PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
        PidMsg.msgData[0] = feed->pid;
 
+       smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
        return smsclient_sendrequest(client->smsclient,
                                     &PidMsg, sizeof(PidMsg));
 }
@@ -177,7 +313,10 @@ static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
                                        void *buffer, size_t size,
                                        struct completion *completion)
 {
-       int rc = smsclient_sendrequest(client->smsclient, buffer, size);
+       int rc;
+
+       smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer);
+       rc = smsclient_sendrequest(client->smsclient, buffer, size);
        if (rc < 0)
                return rc;
 
@@ -186,83 +325,61 @@ static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
                                                0 : -ETIME;
 }
 
-static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
-{
-       struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
-                            DVBT_BDA_CONTROL_MSG_ID,
-                            HIF_TASK, sizeof(struct SmsMsgHdr_ST), 0 };
-       int ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
-                                             &client->stat_done);
-       if (ret < 0)
-               return ret;
-
-       if (client->fe_status & FE_HAS_LOCK)
-               sms_board_led_feedback(client->coredev,
-                                      (client->fe_unc == 0) ?
-                                      SMS_LED_HI : SMS_LED_LO);
-       else
-               sms_board_led_feedback(client->coredev, SMS_LED_OFF);
-       return ret;
-}
-
 static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
 {
-       struct smsdvb_client_t *client =
-               container_of(fe, struct smsdvb_client_t, frontend);
-       int rc = smsdvb_send_statistics_request(client);
+       struct smsdvb_client_t *client;
+       client = container_of(fe, struct smsdvb_client_t, frontend);
 
-       if (!rc)
-               *stat = client->fe_status;
+       *stat = client->fe_status;
 
-       return rc;
+       return 0;
 }
 
 static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
-       struct smsdvb_client_t *client =
-               container_of(fe, struct smsdvb_client_t, frontend);
-       int rc = smsdvb_send_statistics_request(client);
+       struct smsdvb_client_t *client;
+       client = container_of(fe, struct smsdvb_client_t, frontend);
 
-       if (!rc)
-               *ber = client->fe_ber;
+       *ber = client->sms_stat_dvb.ReceptionData.BER;
 
-       return rc;
+       return 0;
 }
 
 static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
 {
-       struct smsdvb_client_t *client =
-               container_of(fe, struct smsdvb_client_t, frontend);
-       int rc = smsdvb_send_statistics_request(client);
+       struct smsdvb_client_t *client;
+       client = container_of(fe, struct smsdvb_client_t, frontend);
 
-       if (!rc)
-               *strength = client->fe_signal_strength;
+       if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95)
+               *strength = 0;
+               else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29)
+                       *strength = 100;
+               else
+                       *strength =
+                               (client->sms_stat_dvb.ReceptionData.InBandPwr
+                               + 95) * 3 / 2;
 
-       return rc;
+       return 0;
 }
 
 static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
-       struct smsdvb_client_t *client =
-               container_of(fe, struct smsdvb_client_t, frontend);
-       int rc = smsdvb_send_statistics_request(client);
+       struct smsdvb_client_t *client;
+       client = container_of(fe, struct smsdvb_client_t, frontend);
 
-       if (!rc)
-               *snr = client->fe_snr;
+       *snr = client->sms_stat_dvb.ReceptionData.SNR;
 
-       return rc;
+       return 0;
 }
 
 static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 {
-       struct smsdvb_client_t *client =
-               container_of(fe, struct smsdvb_client_t, frontend);
-       int rc = smsdvb_send_statistics_request(client);
+       struct smsdvb_client_t *client;
+       client = container_of(fe, struct smsdvb_client_t, frontend);
 
-       if (!rc)
-               *ucblocks = client->fe_unc;
+       *ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets;
 
-       return rc;
+       return 0;
 }
 
 static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
@@ -286,12 +403,15 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe,
                struct SmsMsgHdr_ST     Msg;
                u32             Data[3];
        } Msg;
-       int ret;
 
-       Msg.Msg.msgSrcId  = DVBT_BDA_CONTROL_MSG_ID;
-       Msg.Msg.msgDstId  = HIF_TASK;
-       Msg.Msg.msgFlags  = 0;
-       Msg.Msg.msgType   = MSG_SMS_RF_TUNE_REQ;
+       client->fe_status = FE_HAS_SIGNAL;
+       client->event_fe_state = -1;
+       client->event_unc_state = -1;
+
+       Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
+       Msg.Msg.msgDstId = HIF_TASK;
+       Msg.Msg.msgFlags = 0;
+       Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
        Msg.Msg.msgLength = sizeof(Msg);
        Msg.Data[0] = fep->frequency;
        Msg.Data[2] = 12000000;
@@ -307,24 +427,6 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe,
        default: return -EINVAL;
        }
 
-       /* Disable LNA, if any. An error is returned if no LNA is present */
-       ret = sms_board_lna_control(client->coredev, 0);
-       if (ret == 0) {
-               fe_status_t status;
-
-               /* tune with LNA off at first */
-               ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
-                                                 &client->tune_done);
-
-               smsdvb_read_status(fe, &status);
-
-               if (status & FE_HAS_LOCK)
-                       return ret;
-
-               /* previous tune didnt lock - enable LNA and tune again */
-               sms_board_lna_control(client->coredev, 1);
-       }
-
        return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
                                           &client->tune_done);
 }
@@ -349,8 +451,7 @@ static int smsdvb_init(struct dvb_frontend *fe)
        struct smsdvb_client_t *client =
                container_of(fe, struct smsdvb_client_t, frontend);
 
-       sms_board_power(client->coredev, 1);
-
+       sms_board_dvb3_event(client, DVB3_EVENT_INIT);
        return 0;
 }
 
@@ -359,8 +460,7 @@ static int smsdvb_sleep(struct dvb_frontend *fe)
        struct smsdvb_client_t *client =
                container_of(fe, struct smsdvb_client_t, frontend);
 
-       sms_board_led_feedback(client->coredev, SMS_LED_OFF);
-       sms_board_power(client->coredev, 0);
+       sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);
 
        return 0;
 }
@@ -485,7 +585,6 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
        client->coredev = coredev;
 
        init_completion(&client->tune_done);
-       init_completion(&client->stat_done);
 
        kmutex_lock(&g_smsdvb_clientslock);
 
@@ -493,8 +592,11 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev,
 
        kmutex_unlock(&g_smsdvb_clientslock);
 
-       sms_info("success");
+       client->event_fe_state = -1;
+       client->event_unc_state = -1;
+       sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
 
+       sms_info("success");
        sms_board_setup(coredev);
 
        return 0;
@@ -547,5 +649,5 @@ module_init(smsdvb_module_init);
 module_exit(smsdvb_module_exit);
 
 MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
-MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)");
+MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/siano/smsendian.c b/drivers/media/dvb/siano/smsendian.c
new file mode 100644 (file)
index 0000000..457b6d0
--- /dev/null
@@ -0,0 +1,102 @@
+/****************************************************************
+
+ Siano Mobile Silicon, Inc.
+ MDTV receiver kernel modules.
+ Copyright (C) 2006-2009, Uri Shkolnik
+
+ 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, see <http://www.gnu.org/licenses/>.
+
+ ****************************************************************/
+
+#include <asm/byteorder.h>
+
+#include "smsendian.h"
+#include "smscoreapi.h"
+
+void smsendian_handle_tx_message(void *buffer)
+{
+#ifdef __BIG_ENDIAN
+       struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer;
+       int i;
+       int msgWords;
+
+       switch (msg->xMsgHeader.msgType) {
+       case MSG_SMS_DATA_DOWNLOAD_REQ:
+       {
+               msg->msgData[0] = le32_to_cpu(msg->msgData[0]);
+               break;
+       }
+
+       default:
+               msgWords = (msg->xMsgHeader.msgLength -
+                               sizeof(struct SmsMsgHdr_ST))/4;
+
+               for (i = 0; i < msgWords; i++)
+                       msg->msgData[i] = le32_to_cpu(msg->msgData[i]);
+
+               break;
+       }
+#endif /* __BIG_ENDIAN */
+}
+EXPORT_SYMBOL_GPL(smsendian_handle_tx_message);
+
+void smsendian_handle_rx_message(void *buffer)
+{
+#ifdef __BIG_ENDIAN
+       struct SmsMsgData_ST *msg = (struct SmsMsgData_ST *)buffer;
+       int i;
+       int msgWords;
+
+       switch (msg->xMsgHeader.msgType) {
+       case MSG_SMS_GET_VERSION_EX_RES:
+       {
+               struct SmsVersionRes_ST *ver =
+                       (struct SmsVersionRes_ST *) msg;
+               ver->ChipModel = le16_to_cpu(ver->ChipModel);
+               break;
+       }
+
+       case MSG_SMS_DVBT_BDA_DATA:
+       case MSG_SMS_DAB_CHANNEL:
+       case MSG_SMS_DATA_MSG:
+       {
+               break;
+       }
+
+       default:
+       {
+               msgWords = (msg->xMsgHeader.msgLength -
+                               sizeof(struct SmsMsgHdr_ST))/4;
+
+               for (i = 0; i < msgWords; i++)
+                       msg->msgData[i] = le32_to_cpu(msg->msgData[i]);
+
+               break;
+       }
+       }
+#endif /* __BIG_ENDIAN */
+}
+EXPORT_SYMBOL_GPL(smsendian_handle_rx_message);
+
+void smsendian_handle_message_header(void *msg)
+{
+#ifdef __BIG_ENDIAN
+       struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)msg;
+
+       phdr->msgType = le16_to_cpu(phdr->msgType);
+       phdr->msgLength = le16_to_cpu(phdr->msgLength);
+       phdr->msgFlags = le16_to_cpu(phdr->msgFlags);
+#endif /* __BIG_ENDIAN */
+}
+EXPORT_SYMBOL_GPL(smsendian_handle_message_header);
diff --git a/drivers/media/dvb/siano/smsendian.h b/drivers/media/dvb/siano/smsendian.h
new file mode 100644 (file)
index 0000000..1624d6f
--- /dev/null
@@ -0,0 +1,32 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2009, Uri Shkolnik
+
+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, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+
+#ifndef __SMS_ENDIAN_H__
+#define __SMS_ENDIAN_H__
+
+#include <asm/byteorder.h>
+
+extern void smsendian_handle_tx_message(void *buffer);
+extern void smsendian_handle_rx_message(void *buffer);
+extern void smsendian_handle_message_header(void *msg);
+
+#endif /* __SMS_ENDIAN_H__ */
+
diff --git a/drivers/media/dvb/siano/smsir.c b/drivers/media/dvb/siano/smsir.c
new file mode 100644 (file)
index 0000000..e3d776f
--- /dev/null
@@ -0,0 +1,301 @@
+/****************************************************************
+
+ Siano Mobile Silicon, Inc.
+ MDTV receiver kernel modules.
+ Copyright (C) 2006-2009, Uri Shkolnik
+
+ 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, see <http://www.gnu.org/licenses/>.
+
+ ****************************************************************/
+
+
+#include <linux/types.h>
+#include <linux/input.h>
+
+#include "smscoreapi.h"
+#include "smsir.h"
+#include "sms-cards.h"
+
+/* In order to add new IR remote control -
+ * 1) Add it to the <enum ir_kb_type> @ smsir,h,
+ * 2) Add its map to keyboard_layout_maps below
+ * 3) Set your board (sms-cards sub-module) to use it
+ */
+
+static struct keyboard_layout_map_t keyboard_layout_maps[] = {
+               [SMS_IR_KB_DEFAULT_TV] = {
+                       .ir_protocol = IR_RC5,
+                       .rc5_kbd_address = KEYBOARD_ADDRESS_TV1,
+                       .keyboard_layout_map = {
+                                       KEY_0, KEY_1, KEY_2,
+                                       KEY_3, KEY_4, KEY_5,
+                                       KEY_6, KEY_7, KEY_8,
+                                       KEY_9, 0, 0, KEY_POWER,
+                                       KEY_MUTE, 0, 0,
+                                       KEY_VOLUMEUP, KEY_VOLUMEDOWN,
+                                       KEY_BRIGHTNESSUP,
+                                       KEY_BRIGHTNESSDOWN, KEY_CHANNELUP,
+                                       KEY_CHANNELDOWN,
+                                       0, 0, 0, 0, 0, 0, 0, 0,
+                                       0, 0, 0, 0, 0, 0, 0, 0,
+                                       0, 0, 0, 0, 0, 0, 0, 0,
+                                       0, 0, 0, 0, 0, 0, 0, 0,
+                                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+                       }
+               },
+               [SMS_IR_KB_HCW_SILVER] = {
+                       .ir_protocol = IR_RC5,
+                       .rc5_kbd_address = KEYBOARD_ADDRESS_LIGHTING1,
+                       .keyboard_layout_map = {
+                                       KEY_0, KEY_1, KEY_2,
+                                       KEY_3, KEY_4, KEY_5,
+                                       KEY_6, KEY_7, KEY_8,
+                                       KEY_9, KEY_TEXT, KEY_RED,
+                                       KEY_RADIO, KEY_MENU,
+                                       KEY_SUBTITLE,
+                                       KEY_MUTE, KEY_VOLUMEUP,
+                                       KEY_VOLUMEDOWN, KEY_PREVIOUS, 0,
+                                       KEY_UP, KEY_DOWN, KEY_LEFT,
+                                       KEY_RIGHT, KEY_VIDEO, KEY_AUDIO,
+                                       KEY_MHP, KEY_EPG, KEY_TV,
+                                       0, KEY_NEXTSONG, KEY_EXIT,
+                                       KEY_CHANNELUP,  KEY_CHANNELDOWN,
+                                       KEY_CHANNEL, 0,
+                                       KEY_PREVIOUSSONG, KEY_ENTER,
+                                       KEY_SLEEP, 0, 0, KEY_BLUE,
+                                       0, 0, 0, 0, KEY_GREEN, 0,
+                                       KEY_PAUSE, 0, KEY_REWIND,
+                                       0, KEY_FASTFORWARD, KEY_PLAY,
+                                       KEY_STOP, KEY_RECORD,
+                                       KEY_YELLOW, 0, 0, KEY_SELECT,
+                                       KEY_ZOOM, KEY_POWER, 0, 0
+                       }
+               },
+               { } /* Terminating entry */
+};
+
+u32 ir_pos;
+u32    ir_word;
+u32 ir_toggle;
+
+#define RC5_PUSH_BIT(dst, bit, pos)    \
+       { dst <<= 1; dst |= bit; pos++; }
+
+
+static void sms_ir_rc5_event(struct smscore_device_t *coredev,
+                               u32 toggle, u32 addr, u32 cmd)
+{
+       bool toggle_changed;
+       u16 keycode;
+
+       sms_log("IR RC5 word: address %d, command %d, toggle %d",
+                               addr, cmd, toggle);
+
+       toggle_changed = ir_toggle != toggle;
+       /* keep toggle */
+       ir_toggle = toggle;
+
+       if (addr !=
+               keyboard_layout_maps[coredev->ir.ir_kb_type].rc5_kbd_address)
+               return; /* Check for valid address */
+
+       keycode =
+               keyboard_layout_maps
+               [coredev->ir.ir_kb_type].keyboard_layout_map[cmd];
+
+       if (!toggle_changed &&
+                       (keycode != KEY_VOLUMEUP && keycode != KEY_VOLUMEDOWN))
+               return; /* accept only repeated volume, reject other keys */
+
+       sms_log("kernel input keycode (from ir) %d", keycode);
+       input_report_key(coredev->ir.input_dev, keycode, 1);
+       input_sync(coredev->ir.input_dev);
+
+}
+
+/* decode raw bit pattern to RC5 code */
+/* taken from ir-functions.c */
+static u32 ir_rc5_decode(unsigned int code)
+{
+/*     unsigned int org_code = code;*/
+       unsigned int pair;
+       unsigned int rc5 = 0;
+       int i;
+
+       for (i = 0; i < 14; ++i) {
+               pair = code & 0x3;
+               code >>= 2;
+
+               rc5 <<= 1;
+               switch (pair) {
+               case 0:
+               case 2:
+                       break;
+               case 1:
+                       rc5 |= 1;
+                       break;
+               case 3:
+/*     dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);*/
+                       sms_log("bad code");
+                       return 0;
+               }
+       }
+/*
+       dprintk(1, "ir-common: code=%x, rc5=%x, start=%x,
+               toggle=%x, address=%x, "
+               "instr=%x\n", rc5, org_code, RC5_START(rc5),
+               RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
+*/
+       return rc5;
+}
+
+static void sms_rc5_parse_word(struct smscore_device_t *coredev)
+{
+       #define RC5_START(x)    (((x)>>12)&3)
+       #define RC5_TOGGLE(x)   (((x)>>11)&1)
+       #define RC5_ADDR(x)     (((x)>>6)&0x1F)
+       #define RC5_INSTR(x)    ((x)&0x3F)
+
+       int i, j;
+       u32 rc5_word = 0;
+
+       /* Reverse the IR word direction */
+       for (i = 0 ; i < 28 ; i++)
+               RC5_PUSH_BIT(rc5_word, (ir_word>>i)&1, j)
+
+       rc5_word = ir_rc5_decode(rc5_word);
+       /* sms_log("temp = 0x%x, rc5_code = 0x%x", ir_word, rc5_word); */
+
+       sms_ir_rc5_event(coredev,
+                               RC5_TOGGLE(rc5_word),
+                               RC5_ADDR(rc5_word),
+                               RC5_INSTR(rc5_word));
+}
+
+
+static void sms_rc5_accumulate_bits(struct smscore_device_t *coredev,
+               s32 ir_sample)
+{
+       #define RC5_TIME_GRANULARITY    200
+       #define RC5_DEF_BIT_TIME                889
+       #define RC5_MAX_SAME_BIT_CONT   4
+       #define RC5_WORD_LEN                    27 /* 28 bit */
+
+       u32 i, j;
+       s32 delta_time;
+       u32 time = (ir_sample > 0) ? ir_sample : (0-ir_sample);
+       u32 level = (ir_sample < 0) ? 0 : 1;
+
+       for (i = RC5_MAX_SAME_BIT_CONT; i > 0; i--) {
+               delta_time = time - (i*RC5_DEF_BIT_TIME) + RC5_TIME_GRANULARITY;
+               if (delta_time < 0)
+                       continue; /* not so many consecutive bits */
+               if (delta_time > (2 * RC5_TIME_GRANULARITY)) {
+                       /* timeout */
+                       if (ir_pos == (RC5_WORD_LEN-1))
+                               /* complete last bit */
+                               RC5_PUSH_BIT(ir_word, level, ir_pos)
+
+                       if (ir_pos == RC5_WORD_LEN)
+                               sms_rc5_parse_word(coredev);
+                       else if (ir_pos) /* timeout within a word */
+                               sms_log("IR error parsing a word");
+
+                       ir_pos = 0;
+                       ir_word = 0;
+                       /* sms_log("timeout %d", time); */
+                       break;
+               }
+               /* The time is within the range of this number of bits */
+               for (j = 0 ; j < i ; j++)
+                       RC5_PUSH_BIT(ir_word, level, ir_pos)
+
+               break;
+       }
+}
+
+void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
+{
+       #define IR_DATA_RECEIVE_MAX_LEN 520 /* 128*4 + 4 + 4 */
+       u32 i;
+       enum ir_protocol ir_protocol =
+                       keyboard_layout_maps[coredev->ir.ir_kb_type]
+                                            .ir_protocol;
+       s32 *samples;
+       int count = len>>2;
+
+       samples = (s32 *)buf;
+/*     sms_log("IR buffer received, length = %d", count);*/
+
+       for (i = 0; i < count; i++)
+               if (ir_protocol == IR_RC5)
+                       sms_rc5_accumulate_bits(coredev, samples[i]);
+       /*  IR_RCMM not implemented */
+}
+
+int sms_ir_init(struct smscore_device_t *coredev)
+{
+       struct input_dev *input_dev;
+
+       sms_log("Allocating input device");
+       input_dev = input_allocate_device();
+       if (!input_dev) {
+               sms_err("Not enough memory");
+               return -ENOMEM;
+       }
+
+       coredev->ir.input_dev = input_dev;
+       coredev->ir.ir_kb_type =
+               sms_get_board(smscore_get_board_id(coredev))->ir_kb_type;
+       coredev->ir.keyboard_layout_map =
+               keyboard_layout_maps[coredev->ir.ir_kb_type].
+                               keyboard_layout_map;
+       sms_log("IR remote keyboard type is %d", coredev->ir.ir_kb_type);
+
+       coredev->ir.controller = 0;     /* Todo: vega/nova SPI number */
+       coredev->ir.timeout = IR_DEFAULT_TIMEOUT;
+       sms_log("IR port %d, timeout %d ms",
+                       coredev->ir.controller, coredev->ir.timeout);
+
+       snprintf(coredev->ir.name,
+                               IR_DEV_NAME_MAX_LEN,
+                               "SMS IR w/kbd type %d",
+                               coredev->ir.ir_kb_type);
+       input_dev->name = coredev->ir.name;
+       input_dev->phys = coredev->ir.name;
+       input_dev->dev.parent = coredev->device;
+
+       /* Key press events only */
+       input_dev->evbit[0] = BIT_MASK(EV_KEY);
+       input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
+
+       sms_log("Input device (IR) %s is set for key events", input_dev->name);
+
+       if (input_register_device(input_dev)) {
+               sms_err("Failed to register device");
+               input_free_device(input_dev);
+               return -EACCES;
+       }
+
+       return 0;
+}
+
+void sms_ir_exit(struct smscore_device_t *coredev)
+{
+       if (coredev->ir.input_dev)
+               input_unregister_device(coredev->ir.input_dev);
+
+       sms_log("");
+}
+
diff --git a/drivers/media/dvb/siano/smsir.h b/drivers/media/dvb/siano/smsir.h
new file mode 100644 (file)
index 0000000..b7d703e
--- /dev/null
@@ -0,0 +1,93 @@
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2006-2009, Uri Shkolnik
+
+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, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
+
+#ifndef __SMS_IR_H__
+#define __SMS_IR_H__
+
+#include <linux/input.h>
+
+#define IR_DEV_NAME_MAX_LEN            23 /* "SMS IR kbd type nn\0" */
+#define IR_KEYBOARD_LAYOUT_SIZE        64
+#define IR_DEFAULT_TIMEOUT             100
+
+enum ir_kb_type {
+       SMS_IR_KB_DEFAULT_TV,
+       SMS_IR_KB_HCW_SILVER
+};
+
+enum rc5_keyboard_address {
+       KEYBOARD_ADDRESS_TV1 = 0,
+       KEYBOARD_ADDRESS_TV2 = 1,
+       KEYBOARD_ADDRESS_TELETEXT = 2,
+       KEYBOARD_ADDRESS_VIDEO = 3,
+       KEYBOARD_ADDRESS_LV1 = 4,
+       KEYBOARD_ADDRESS_VCR1 = 5,
+       KEYBOARD_ADDRESS_VCR2 = 6,
+       KEYBOARD_ADDRESS_EXPERIMENTAL = 7,
+       KEYBOARD_ADDRESS_SAT1 = 8,
+       KEYBOARD_ADDRESS_CAMERA = 9,
+       KEYBOARD_ADDRESS_SAT2 = 10,
+       KEYBOARD_ADDRESS_CDV = 12,
+       KEYBOARD_ADDRESS_CAMCORDER = 13,
+       KEYBOARD_ADDRESS_PRE_AMP = 16,
+       KEYBOARD_ADDRESS_TUNER = 17,
+       KEYBOARD_ADDRESS_RECORDER1 = 18,
+       KEYBOARD_ADDRESS_PRE_AMP1 = 19,
+       KEYBOARD_ADDRESS_CD_PLAYER = 20,
+       KEYBOARD_ADDRESS_PHONO = 21,
+       KEYBOARD_ADDRESS_SATA = 22,
+       KEYBOARD_ADDRESS_RECORDER2 = 23,
+       KEYBOARD_ADDRESS_CDR = 26,
+       KEYBOARD_ADDRESS_LIGHTING = 29,
+       KEYBOARD_ADDRESS_LIGHTING1 = 30, /* KEYBOARD_ADDRESS_HCW_SILVER */
+       KEYBOARD_ADDRESS_PHONE = 31,
+       KEYBOARD_ADDRESS_NOT_RC5 = 0xFFFF
+};
+
+enum ir_protocol {
+       IR_RC5,
+       IR_RCMM
+};
+
+struct keyboard_layout_map_t {
+       enum ir_protocol ir_protocol;
+       enum rc5_keyboard_address rc5_kbd_address;
+       u16 keyboard_layout_map[IR_KEYBOARD_LAYOUT_SIZE];
+};
+
+struct smscore_device_t;
+
+struct ir_t {
+       struct input_dev *input_dev;
+       enum ir_kb_type ir_kb_type;
+       char name[IR_DEV_NAME_MAX_LEN+1];
+       u16 *keyboard_layout_map;
+       u32 timeout;
+       u32 controller;
+};
+
+int sms_ir_init(struct smscore_device_t *coredev);
+void sms_ir_exit(struct smscore_device_t *coredev);
+void sms_ir_event(struct smscore_device_t *coredev,
+                       const char *buf, int len);
+
+#endif /* __SMS_IR_H__ */
+
diff --git a/drivers/media/dvb/siano/smssdio.c b/drivers/media/dvb/siano/smssdio.c
new file mode 100644 (file)
index 0000000..dfaa49a
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ *  smssdio.c - Siano 1xxx SDIO interface driver
+ *
+ *  Copyright 2008 Pierre Ossman
+ *
+ * Based on code by Siano Mobile Silicon, Inc.,
+ * Copyright (C) 2006-2008, Uri Shkolnik
+ *
+ * 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 hardware is a bit odd in that all transfers should be done
+ * to/from the SMSSDIO_DATA register, yet the "increase address" bit
+ * always needs to be set.
+ *
+ * Also, buffers from the card are always aligned to 128 byte
+ * boundaries.
+ */
+
+/*
+ * General cleanup notes:
+ *
+ * - only typedefs should be name *_t
+ *
+ * - use ERR_PTR and friends for smscore_register_device()
+ *
+ * - smscore_getbuffer should zero fields
+ *
+ * Fix stop command
+ */
+
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+
+#include "smscoreapi.h"
+#include "sms-cards.h"
+
+/* Registers */
+
+#define SMSSDIO_DATA           0x00
+#define SMSSDIO_INT            0x04
+
+static const struct sdio_device_id smssdio_ids[] = {
+       {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_STELLAR),
+        .driver_data = SMS1XXX_BOARD_SIANO_STELLAR},
+       {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_A0),
+        .driver_data = SMS1XXX_BOARD_SIANO_NOVA_A},
+       {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_NOVA_B0),
+        .driver_data = SMS1XXX_BOARD_SIANO_NOVA_B},
+       {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VEGA_A0),
+        .driver_data = SMS1XXX_BOARD_SIANO_VEGA},
+       {SDIO_DEVICE(SDIO_VENDOR_ID_SIANO, SDIO_DEVICE_ID_SIANO_VENICE),
+        .driver_data = SMS1XXX_BOARD_SIANO_VEGA},
+       { /* end: all zeroes */ },
+};
+
+MODULE_DEVICE_TABLE(sdio, smssdio_ids);
+
+struct smssdio_device {
+       struct sdio_func *func;
+
+       struct smscore_device_t *coredev;
+
+       struct smscore_buffer_t *split_cb;
+};
+
+/*******************************************************************/
+/* Siano core callbacks                                            */
+/*******************************************************************/
+
+static int smssdio_sendrequest(void *context, void *buffer, size_t size)
+{
+       int ret;
+       struct smssdio_device *smsdev;
+
+       smsdev = context;
+
+       sdio_claim_host(smsdev->func);
+
+       while (size >= smsdev->func->cur_blksize) {
+               ret = sdio_write_blocks(smsdev->func, SMSSDIO_DATA, buffer, 1);
+               if (ret)
+                       goto out;
+
+               buffer += smsdev->func->cur_blksize;
+               size -= smsdev->func->cur_blksize;
+       }
+
+       if (size) {
+               ret = sdio_write_bytes(smsdev->func, SMSSDIO_DATA,
+                                      buffer, size);
+       }
+
+out:
+       sdio_release_host(smsdev->func);
+
+       return ret;
+}
+
+/*******************************************************************/
+/* SDIO callbacks                                                  */
+/*******************************************************************/
+
+static void smssdio_interrupt(struct sdio_func *func)
+{
+       int ret, isr;
+
+       struct smssdio_device *smsdev;
+       struct smscore_buffer_t *cb;
+       struct SmsMsgHdr_ST *hdr;
+       size_t size;
+
+       smsdev = sdio_get_drvdata(func);
+
+       /*
+        * The interrupt register has no defined meaning. It is just
+        * a way of turning of the level triggered interrupt.
+        */
+       isr = sdio_readb(func, SMSSDIO_INT, &ret);
+       if (ret) {
+               dev_err(&smsdev->func->dev,
+                       "Unable to read interrupt register!\n");
+               return;
+       }
+
+       if (smsdev->split_cb == NULL) {
+               cb = smscore_getbuffer(smsdev->coredev);
+               if (!cb) {
+                       dev_err(&smsdev->func->dev,
+                               "Unable to allocate data buffer!\n");
+                       return;
+               }
+
+               ret = sdio_read_blocks(smsdev->func, cb->p, SMSSDIO_DATA, 1);
+               if (ret) {
+                       dev_err(&smsdev->func->dev,
+                               "Error %d reading initial block!\n", ret);
+                       return;
+               }
+
+               hdr = cb->p;
+
+               if (hdr->msgFlags & MSG_HDR_FLAG_SPLIT_MSG) {
+                       smsdev->split_cb = cb;
+                       return;
+               }
+
+               size = hdr->msgLength - smsdev->func->cur_blksize;
+       } else {
+               cb = smsdev->split_cb;
+               hdr = cb->p;
+
+               size = hdr->msgLength - sizeof(struct SmsMsgHdr_ST);
+
+               smsdev->split_cb = NULL;
+       }
+
+       if (hdr->msgLength > smsdev->func->cur_blksize) {
+               void *buffer;
+
+               size = ALIGN(size, 128);
+               buffer = cb->p + hdr->msgLength;
+
+               BUG_ON(smsdev->func->cur_blksize != 128);
+
+               /*
+                * First attempt to transfer all of it in one go...
+                */
+               ret = sdio_read_blocks(smsdev->func, buffer,
+                                      SMSSDIO_DATA, size / 128);
+               if (ret && ret != -EINVAL) {
+                       smscore_putbuffer(smsdev->coredev, cb);
+                       dev_err(&smsdev->func->dev,
+                               "Error %d reading data from card!\n", ret);
+                       return;
+               }
+
+               /*
+                * ..then fall back to one block at a time if that is
+                * not possible...
+                *
+                * (we have to do this manually because of the
+                * problem with the "increase address" bit)
+                */
+               if (ret == -EINVAL) {
+                       while (size) {
+                               ret = sdio_read_blocks(smsdev->func,
+                                                      buffer, SMSSDIO_DATA, 1);
+                               if (ret) {
+                                       smscore_putbuffer(smsdev->coredev, cb);
+                                       dev_err(&smsdev->func->dev,
+                                               "Error %d reading "
+                                               "data from card!\n", ret);
+                                       return;
+                               }
+
+                               buffer += smsdev->func->cur_blksize;
+                               if (size > smsdev->func->cur_blksize)
+                                       size -= smsdev->func->cur_blksize;
+                               else
+                                       size = 0;
+                       }
+               }
+       }
+
+       cb->size = hdr->msgLength;
+       cb->offset = 0;
+
+       smscore_onresponse(smsdev->coredev, cb);
+}
+
+static int smssdio_probe(struct sdio_func *func,
+                        const struct sdio_device_id *id)
+{
+       int ret;
+
+       int board_id;
+       struct smssdio_device *smsdev;
+       struct smsdevice_params_t params;
+
+       board_id = id->driver_data;
+
+       smsdev = kzalloc(sizeof(struct smssdio_device), GFP_KERNEL);
+       if (!smsdev)
+               return -ENOMEM;
+
+       smsdev->func = func;
+
+       memset(&params, 0, sizeof(struct smsdevice_params_t));
+
+       params.device = &func->dev;
+       params.buffer_size = 0x5000;    /* ?? */
+       params.num_buffers = 22;        /* ?? */
+       params.context = smsdev;
+
+       snprintf(params.devpath, sizeof(params.devpath),
+                "sdio\\%s", sdio_func_id(func));
+
+       params.sendrequest_handler = smssdio_sendrequest;
+
+       params.device_type = sms_get_board(board_id)->type;
+
+       if (params.device_type != SMS_STELLAR)
+               params.flags |= SMS_DEVICE_FAMILY2;
+       else {
+               /*
+                * FIXME: Stellar needs special handling...
+                */
+               ret = -ENODEV;
+               goto free;
+       }
+
+       ret = smscore_register_device(&params, &smsdev->coredev);
+       if (ret < 0)
+               goto free;
+
+       smscore_set_board_id(smsdev->coredev, board_id);
+
+       sdio_claim_host(func);
+
+       ret = sdio_enable_func(func);
+       if (ret)
+               goto release;
+
+       ret = sdio_set_block_size(func, 128);
+       if (ret)
+               goto disable;
+
+       ret = sdio_claim_irq(func, smssdio_interrupt);
+       if (ret)
+               goto disable;
+
+       sdio_set_drvdata(func, smsdev);
+
+       sdio_release_host(func);
+
+       ret = smscore_start_device(smsdev->coredev);
+       if (ret < 0)
+               goto reclaim;
+
+       return 0;
+
+reclaim:
+       sdio_claim_host(func);
+       sdio_release_irq(func);
+disable:
+       sdio_disable_func(func);
+release:
+       sdio_release_host(func);
+       smscore_unregister_device(smsdev->coredev);
+free:
+       kfree(smsdev);
+
+       return ret;
+}
+
+static void smssdio_remove(struct sdio_func *func)
+{
+       struct smssdio_device *smsdev;
+
+       smsdev = sdio_get_drvdata(func);
+
+       /* FIXME: racy! */
+       if (smsdev->split_cb)
+               smscore_putbuffer(smsdev->coredev, smsdev->split_cb);
+
+       smscore_unregister_device(smsdev->coredev);
+
+       sdio_claim_host(func);
+       sdio_release_irq(func);
+       sdio_disable_func(func);
+       sdio_release_host(func);
+
+       kfree(smsdev);
+}
+
+static struct sdio_driver smssdio_driver = {
+       .name = "smssdio",
+       .id_table = smssdio_ids,
+       .probe = smssdio_probe,
+       .remove = smssdio_remove,
+};
+
+/*******************************************************************/
+/* Module functions                                                */
+/*******************************************************************/
+
+int smssdio_module_init(void)
+{
+       int ret = 0;
+
+       printk(KERN_INFO "smssdio: Siano SMS1xxx SDIO driver\n");
+       printk(KERN_INFO "smssdio: Copyright Pierre Ossman\n");
+
+       ret = sdio_register_driver(&smssdio_driver);
+
+       return ret;
+}
+
+void smssdio_module_exit(void)
+{
+       sdio_unregister_driver(&smssdio_driver);
+}
+
+module_init(smssdio_module_init);
+module_exit(smssdio_module_exit);
+
+MODULE_DESCRIPTION("Siano SMS1xxx SDIO driver");
+MODULE_AUTHOR("Pierre Ossman");
+MODULE_LICENSE("GPL");
index 71c65f544c072911cb326f8614097378448e2618..cb8a358b7310d35417413a5300f62ad6a4065cff 100644 (file)
@@ -1,23 +1,23 @@
-/*
- *  Driver for the Siano SMS1xxx USB dongle
- *
- *  author: Anatoly Greenblat
- *
- *  Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation;
- *
- *  Software distributed under the License is distributed on an "AS IS"
- *  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
- *
- *  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.
- */
+/****************************************************************
+
+Siano Mobile Silicon, Inc.
+MDTV receiver kernel modules.
+Copyright (C) 2005-2009, Uri Shkolnik, Anatoly Greenblat
+
+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, see <http://www.gnu.org/licenses/>.
+
+****************************************************************/
 
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -26,6 +26,7 @@
 
 #include "smscoreapi.h"
 #include "sms-cards.h"
+#include "smsendian.h"
 
 static int sms_dbg;
 module_param_named(debug, sms_dbg, int, 0644);
@@ -64,15 +65,16 @@ static void smsusb_onresponse(struct urb *urb)
        struct smsusb_urb_t *surb = (struct smsusb_urb_t *) urb->context;
        struct smsusb_device_t *dev = surb->dev;
 
-       if (urb->status < 0) {
-               sms_err("error, urb status %d, %d bytes",
+       if (urb->status == -ESHUTDOWN) {
+               sms_err("error, urb status %d (-ESHUTDOWN), %d bytes",
                        urb->status, urb->actual_length);
                return;
        }
 
-       if (urb->actual_length > 0) {
-               struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) surb->cb->p;
+       if ((urb->actual_length > 0) && (urb->status == 0)) {
+               struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *)surb->cb->p;
 
+               smsendian_handle_message_header(phdr);
                if (urb->actual_length >= phdr->msgLength) {
                        surb->cb->size = phdr->msgLength;
 
@@ -109,7 +111,10 @@ static void smsusb_onresponse(struct urb *urb)
                                "msglen %d actual %d",
                                phdr->msgLength, urb->actual_length);
                }
-       }
+       } else
+               sms_err("error, urb status %d, %d bytes",
+                       urb->status, urb->actual_length);
+
 
 exit_and_resubmit:
        smsusb_submit_urb(dev, surb);
@@ -176,6 +181,7 @@ static int smsusb_sendrequest(void *context, void *buffer, size_t size)
        struct smsusb_device_t *dev = (struct smsusb_device_t *) context;
        int dummy;
 
+       smsendian_handle_message_header((struct SmsMsgHdr_ST *)buffer);
        return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2),
                            buffer, size, &dummy, 1000);
 }
@@ -333,8 +339,8 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
        case SMS_VEGA:
                dev->buffer_size = USB2_BUFFER_SIZE;
                dev->response_alignment =
-                       dev->udev->ep_in[1]->desc.wMaxPacketSize -
-                       sizeof(struct SmsMsgHdr_ST);
+                   le16_to_cpu(dev->udev->ep_in[1]->desc.wMaxPacketSize) -
+                   sizeof(struct SmsMsgHdr_ST);
 
                params.flags |= SMS_DEVICE_FAMILY2;
                break;
@@ -479,7 +485,6 @@ static int smsusb_resume(struct usb_interface *intf)
 }
 
 struct usb_device_id smsusb_id_table[] = {
-#ifdef CONFIG_DVB_SIANO_SMS1XXX_SMS_IDS
        { USB_DEVICE(0x187f, 0x0010),
                .driver_info = SMS1XXX_BOARD_SIANO_STELLAR },
        { USB_DEVICE(0x187f, 0x0100),
@@ -490,7 +495,6 @@ struct usb_device_id smsusb_id_table[] = {
                .driver_info = SMS1XXX_BOARD_SIANO_NOVA_B },
        { USB_DEVICE(0x187f, 0x0300),
                .driver_info = SMS1XXX_BOARD_SIANO_VEGA },
-#endif
        { USB_DEVICE(0x2040, 0x1700),
                .driver_info = SMS1XXX_BOARD_HAUPPAUGE_CATAMOUNT },
        { USB_DEVICE(0x2040, 0x1800),
@@ -521,8 +525,13 @@ struct usb_device_id smsusb_id_table[] = {
                .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
        { USB_DEVICE(0x2040, 0x5590),
                .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
-       { }             /* Terminating entry */
-};
+       { USB_DEVICE(0x187f, 0x0202),
+               .driver_info = SMS1XXX_BOARD_SIANO_NICE },
+       { USB_DEVICE(0x187f, 0x0301),
+               .driver_info = SMS1XXX_BOARD_SIANO_VENICE },
+       { } /* Terminating entry */
+       };
+
 MODULE_DEVICE_TABLE(usb, smsusb_id_table);
 
 static struct usb_driver smsusb_driver = {
@@ -548,14 +557,14 @@ int smsusb_module_init(void)
 
 void smsusb_module_exit(void)
 {
-       sms_debug("");
        /* Regular USB Cleanup */
        usb_deregister(&smsusb_driver);
+       sms_info("end");
 }
 
 module_init(smsusb_module_init);
 module_exit(smsusb_module_exit);
 
-MODULE_DESCRIPTION("Driver for the Siano SMS1XXX USB dongle");
+MODULE_DESCRIPTION("Driver for the Siano SMS1xxx USB dongle");
 MODULE_AUTHOR("Siano Mobile Silicon, INC. (uris@siano-ms.com)");
 MODULE_LICENSE("GPL");
index e4d0900d5121f0bfa6d343e7ac29de1fb906e542..53884814161c2a064853de36a8557b14b04aad75 100644 (file)
@@ -89,6 +89,7 @@
 
 static void p_to_t(u8 const *buf, long int length, u16 pid,
                   u8 *counter, struct dvb_demux_feed *feed);
+static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len);
 
 
 int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len)
@@ -192,8 +193,6 @@ int av7110_av_start_play(struct av7110 *av7110, int av)
                ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0);
                break;
        }
-       if (!ret)
-               ret = av7110->playing;
        return ret;
 }
 
@@ -437,6 +436,45 @@ static void play_audio_cb(u8 *buf, int count, void *priv)
        aux_ring_buffer_write(&av7110->aout, buf, count);
 }
 
+
+#define FREE_COND_TS (dvb_ringbuffer_free(rb) >= 4096)
+
+static ssize_t ts_play(struct av7110 *av7110, const char __user *buf,
+                      unsigned long count, int nonblock, int type)
+{
+       struct dvb_ringbuffer *rb;
+       u8 *kb;
+       unsigned long todo = count;
+
+       dprintk(2, "%s: type %d cnt %lu\n", __func__, type, count);
+
+       rb = (type) ? &av7110->avout : &av7110->aout;
+       kb = av7110->kbuf[type];
+
+       if (!kb)
+               return -ENOBUFS;
+
+       if (nonblock && !FREE_COND_TS)
+               return -EWOULDBLOCK;
+
+       while (todo >= TS_SIZE) {
+               if (!FREE_COND_TS) {
+                       if (nonblock)
+                               return count - todo;
+                       if (wait_event_interruptible(rb->queue, FREE_COND_TS))
+                               return count - todo;
+               }
+               if (copy_from_user(kb, buf, TS_SIZE))
+                       return -EFAULT;
+               write_ts_to_decoder(av7110, type, kb, TS_SIZE);
+               todo -= TS_SIZE;
+               buf += TS_SIZE;
+       }
+
+       return count - todo;
+}
+
+
 #define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \
                   dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)
 
@@ -780,11 +818,37 @@ static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter,
 }
 
 
+static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len)
+{
+       struct ipack *ipack = &av7110->ipack[type];
+
+       if (buf[1] & TRANS_ERROR) {
+               av7110_ipack_reset(ipack);
+               return -1;
+       }
+
+       if (!(buf[3] & PAYLOAD))
+               return -1;
+
+       if (buf[1] & PAY_START)
+               av7110_ipack_flush(ipack);
+
+       if (buf[3] & ADAPT_FIELD) {
+               len -= buf[4] + 1;
+               buf += buf[4] + 1;
+               if (!len)
+                       return 0;
+       }
+
+       av7110_ipack_instant_repack(buf + 4, len - 4, ipack);
+       return 0;
+}
+
+
 int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len)
 {
        struct dvb_demux *demux = feed->demux;
        struct av7110 *av7110 = (struct av7110 *) demux->priv;
-       struct ipack *ipack = &av7110->ipack[feed->pes_type];
 
        dprintk(2, "av7110:%p, \n", av7110);
 
@@ -804,20 +868,7 @@ int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t l
                return -1;
        }
 
-       if (!(buf[3] & 0x10)) /* no payload? */
-               return -1;
-       if (buf[1] & 0x40)
-               av7110_ipack_flush(ipack);
-
-       if (buf[3] & 0x20) {  /* adaptation field? */
-               len -= buf[4] + 1;
-               buf += buf[4] + 1;
-               if (!len)
-                       return 0;
-       }
-
-       av7110_ipack_instant_repack(buf + 4, len - 4, &av7110->ipack[feed->pes_type]);
-       return 0;
+       return write_ts_to_decoder(av7110, feed->pes_type, buf, len);
 }
 
 
@@ -916,6 +967,7 @@ static ssize_t dvb_video_write(struct file *file, const char __user *buf,
 {
        struct dvb_device *dvbdev = file->private_data;
        struct av7110 *av7110 = dvbdev->priv;
+       unsigned char c;
 
        dprintk(2, "av7110:%p, \n", av7110);
 
@@ -925,7 +977,12 @@ static ssize_t dvb_video_write(struct file *file, const char __user *buf,
        if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY)
                return -EPERM;
 
-       return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1);
+       if (get_user(c, buf))
+               return -EFAULT;
+       if (c == 0x47 && count % TS_SIZE == 0)
+               return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1);
+       else
+               return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1);
 }
 
 static unsigned int dvb_audio_poll(struct file *file, poll_table *wait)
@@ -952,6 +1009,7 @@ static ssize_t dvb_audio_write(struct file *file, const char __user *buf,
 {
        struct dvb_device *dvbdev = file->private_data;
        struct av7110 *av7110 = dvbdev->priv;
+       unsigned char c;
 
        dprintk(2, "av7110:%p, \n", av7110);
 
@@ -959,7 +1017,13 @@ static ssize_t dvb_audio_write(struct file *file, const char __user *buf,
                printk(KERN_ERR "not audio source memory\n");
                return -EPERM;
        }
-       return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0);
+
+       if (get_user(c, buf))
+               return -EFAULT;
+       if (c == 0x47 && count % TS_SIZE == 0)
+               return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 0);
+       else
+               return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0);
 }
 
 static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x00 };
@@ -1062,7 +1126,6 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
                        if (ret)
                                break;
                }
-
                if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) {
                        if (av7110->playing == RP_AV) {
                                ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
@@ -1122,20 +1185,16 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
        case VIDEO_SET_DISPLAY_FORMAT:
        {
                video_displayformat_t format = (video_displayformat_t) arg;
-
                switch (format) {
                case VIDEO_PAN_SCAN:
                        av7110->display_panscan = VID_PAN_SCAN_PREF;
                        break;
-
                case VIDEO_LETTER_BOX:
                        av7110->display_panscan = VID_VC_AND_PS_PREF;
                        break;
-
                case VIDEO_CENTER_CUT_OUT:
                        av7110->display_panscan = VID_CENTRE_CUT_PREF;
                        break;
-
                default:
                        ret = -EINVAL;
                }
@@ -1183,7 +1242,8 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
 
        case VIDEO_SLOWMOTION:
                if (av7110->playing&RP_VIDEO) {
-                       ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0);
+                       if (av7110->trickmode != TRICK_SLOW)
+                               ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0);
                        if (!ret)
                                ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg);
                } else {
@@ -1207,7 +1267,6 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
        case VIDEO_CLEAR_BUFFER:
                dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);
                av7110_ipack_reset(&av7110->ipack[1]);
-
                if (av7110->playing == RP_AV) {
                        ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
                                            __Play, 2, AV_PES, 0);
@@ -1228,13 +1287,13 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
                break;
 
        case VIDEO_SET_STREAMTYPE:
-
                break;
 
        default:
                ret = -ENOIOCTLCMD;
                break;
        }
+
        return ret;
 }
 
@@ -1309,7 +1368,6 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
 
        case AUDIO_CHANNEL_SELECT:
                av7110->audiostate.channel_select = (audio_channel_select_t) arg;
-
                switch(av7110->audiostate.channel_select) {
                case AUDIO_STEREO:
                        ret = audcom(av7110, AUDIO_CMD_STEREO);
@@ -1320,7 +1378,6 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
                                        msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220);
                        }
                        break;
-
                case AUDIO_MONO_LEFT:
                        ret = audcom(av7110, AUDIO_CMD_MONO_L);
                        if (!ret) {
@@ -1330,7 +1387,6 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
                                        msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0200);
                        }
                        break;
-
                case AUDIO_MONO_RIGHT:
                        ret = audcom(av7110, AUDIO_CMD_MONO_R);
                        if (!ret) {
@@ -1340,7 +1396,6 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
                                        msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0210);
                        }
                        break;
-
                default:
                        ret = -EINVAL;
                        break;
@@ -1366,21 +1421,24 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
                        ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
                                            __Play, 2, AV_PES, 0);
                break;
-       case AUDIO_SET_ID:
 
+       case AUDIO_SET_ID:
                break;
+
        case AUDIO_SET_MIXER:
        {
                struct audio_mixer *amix = (struct audio_mixer *)parg;
-
                ret = av7110_set_volume(av7110, amix->volume_left, amix->volume_right);
                break;
        }
+
        case AUDIO_SET_STREAMTYPE:
                break;
+
        default:
                ret = -ENOIOCTLCMD;
        }
+
        return ret;
 }
 
index 5e3f88911a1d2503c1a2dfd3e5ea8b2c8275cead..e162691b515d14d0213c59d624fbb2b95cefff7d 100644 (file)
@@ -1089,7 +1089,7 @@ int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
                else {
                        int i, len = dc->x0-dc->color+1;
                        u8 __user *colors = (u8 __user *)dc->data;
-                       u8 r, g, b, blend;
+                       u8 r, g = 0, b = 0, blend = 0;
                        ret = 0;
                        for (i = 0; i<len; i++) {
                                if (get_user(r, colors + i * 4) ||
index 2210cff738e67a7e47a26d29faddb18633ba0ee1..ce64c6214cc410d473e61eac226ffa3514acea19 100644 (file)
@@ -458,7 +458,7 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
        dprintk(2, "VIDIOC_ENUMINPUT: %d\n", i->index);
 
        if (av7110->analog_tuner_flags) {
-               if (i->index < 0 || i->index >= 4)
+               if (i->index >= 4)
                        return -EINVAL;
        } else {
                if (i->index != 0)
index 855fe74b640bc85d3c5b1ab69936d8f3b3be0a36..8ea9152276744ade58813141ceb91ad121da26dc 100644 (file)
@@ -1413,7 +1413,7 @@ static struct v4l2_input knc1_inputs[KNC1_INPUTS] = {
 static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
 {
        dprintk(1, "VIDIOC_ENUMINPUT %d.\n", i->index);
-       if (i->index < 0 || i->index >= KNC1_INPUTS)
+       if (i->index >= KNC1_INPUTS)
                return -EINVAL;
        memcpy(i, &knc1_inputs[i->index], sizeof(struct v4l2_input));
        return 0;
index 83e9e7750c8cb1e382ddda99e901f7fef1514d48..e48380c48990165955a9dadeb80d90a758aa6e46 100644 (file)
@@ -47,6 +47,9 @@
 #include "bsru6.h"
 #include "bsbe1.h"
 #include "tdhd1.h"
+#include "stv6110x.h"
+#include "stv090x.h"
+#include "isl6423.h"
 
 static int diseqc_method;
 module_param(diseqc_method, int, 0444);
@@ -425,6 +428,44 @@ static u8 read_pwm(struct budget* budget)
        return pwm;
 }
 
+static struct stv090x_config tt1600_stv090x_config = {
+       .device                 = STV0903,
+       .demod_mode             = STV090x_SINGLE,
+       .clk_mode               = STV090x_CLK_EXT,
+
+       .xtal                   = 27000000,
+       .address                = 0x68,
+       .ref_clk                = 27000000,
+
+       .ts1_mode               = STV090x_TSMODE_DVBCI,
+       .ts2_mode               = STV090x_TSMODE_SERIAL_CONTINUOUS,
+
+       .repeater_level         = STV090x_RPTLEVEL_16,
+
+       .tuner_init             = NULL,
+       .tuner_set_mode         = NULL,
+       .tuner_set_frequency    = NULL,
+       .tuner_get_frequency    = NULL,
+       .tuner_set_bandwidth    = NULL,
+       .tuner_get_bandwidth    = NULL,
+       .tuner_set_bbgain       = NULL,
+       .tuner_get_bbgain       = NULL,
+       .tuner_set_refclk       = NULL,
+       .tuner_get_status       = NULL,
+};
+
+static struct stv6110x_config tt1600_stv6110x_config = {
+       .addr                   = 0x60,
+       .refclk                 = 27000000,
+};
+
+static struct isl6423_config tt1600_isl6423_config = {
+       .current_max            = SEC_CURRENT_515m,
+       .curlim                 = SEC_CURRENT_LIM_ON,
+       .mod_extern             = 1,
+       .addr                   = 0x08,
+};
+
 static void frontend_init(struct budget *budget)
 {
        (void)alps_bsbe1_config; /* avoid warning */
@@ -566,6 +607,48 @@ static void frontend_init(struct budget *budget)
                        }
                        break;
                }
+
+       case 0x101c: { /* TT S2-1600 */
+                       struct stv6110x_devctl *ctl;
+                       saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);
+                       msleep(50);
+                       saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);
+                       msleep(250);
+
+                       budget->dvb_frontend = dvb_attach(stv090x_attach,
+                                                         &tt1600_stv090x_config,
+                                                         &budget->i2c_adap,
+                                                         STV090x_DEMODULATOR_0);
+
+                       if (budget->dvb_frontend) {
+
+                               ctl = dvb_attach(stv6110x_attach,
+                                                budget->dvb_frontend,
+                                                &tt1600_stv6110x_config,
+                                                &budget->i2c_adap);
+
+                               tt1600_stv090x_config.tuner_init          = ctl->tuner_init;
+                               tt1600_stv090x_config.tuner_set_mode      = ctl->tuner_set_mode;
+                               tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency;
+                               tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency;
+                               tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth;
+                               tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth;
+                               tt1600_stv090x_config.tuner_set_bbgain    = ctl->tuner_set_bbgain;
+                               tt1600_stv090x_config.tuner_get_bbgain    = ctl->tuner_get_bbgain;
+                               tt1600_stv090x_config.tuner_set_refclk    = ctl->tuner_set_refclk;
+                               tt1600_stv090x_config.tuner_get_status    = ctl->tuner_get_status;
+
+                               dvb_attach(isl6423_attach,
+                                       budget->dvb_frontend,
+                                       &budget->i2c_adap,
+                                       &tt1600_isl6423_config);
+
+                       } else {
+                               dvb_frontend_detach(budget->dvb_frontend);
+                               budget->dvb_frontend = NULL;
+                       }
+               }
+               break;
        }
 
        if (budget->dvb_frontend == NULL) {
@@ -641,6 +724,7 @@ MAKE_BUDGET_INFO(ttbc,      "TT-Budget/WinTV-NOVA-C  PCI",  BUDGET_TT);
 MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T  PCI",  BUDGET_TT);
 MAKE_BUDGET_INFO(satel,        "SATELCO Multimedia PCI",       BUDGET_TT_HW_DISEQC);
 MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(tt1600, "TT-Budget S2-1600 PCI", BUDGET_TT);
 MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY);
 MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY);
 MAKE_BUDGET_INFO(fsact,         "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY);
@@ -653,6 +737,7 @@ static struct pci_device_id pci_tbl[] = {
        MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
        MAKE_EXTENSION_PCI(ttbs,  0x13c2, 0x1016),
        MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018),
+       MAKE_EXTENSION_PCI(tt1600, 0x13c2, 0x101c),
        MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
        MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
        MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60),
index 6135762022940ec4095538bfa446803fb2be6373..ed9cd7ad06042c630ec147e6a3b830a5a2e3904f 100644 (file)
 
  History:
 
+ Version 0.46:
+       Removed usb_dsbr100_open/close calls and radio->users counter. Also,
+       radio->muted changed to radio->status and suspend/resume calls updated.
+
  Version 0.45:
        Converted to v4l2_device.
 
  */
 #include <linux/version.h>     /* for KERNEL_VERSION MACRO     */
 
-#define DRIVER_VERSION "v0.45"
-#define RADIO_VERSION KERNEL_VERSION(0, 4, 5)
+#define DRIVER_VERSION "v0.46"
+#define RADIO_VERSION KERNEL_VERSION(0, 4, 6)
 
 #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
 #define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
@@ -121,13 +125,15 @@ devices, that would be 76 and 91.  */
 #define FREQ_MAX 108.0
 #define FREQ_MUL 16000
 
+/* defines for radio->status */
+#define STARTED        0
+#define STOPPED        1
+
 #define videodev_to_radio(d) container_of(d, struct dsbr100_device, videodev)
 
 static int usb_dsbr100_probe(struct usb_interface *intf,
                             const struct usb_device_id *id);
 static void usb_dsbr100_disconnect(struct usb_interface *intf);
-static int usb_dsbr100_open(struct file *file);
-static int usb_dsbr100_close(struct file *file);
 static int usb_dsbr100_suspend(struct usb_interface *intf,
                                                pm_message_t message);
 static int usb_dsbr100_resume(struct usb_interface *intf);
@@ -145,9 +151,8 @@ struct dsbr100_device {
        struct mutex lock;      /* buffer locking */
        int curfreq;
        int stereo;
-       int users;
        int removed;
-       int muted;
+       int status;
 };
 
 static struct usb_device_id usb_dsbr100_device_table [] = {
@@ -201,7 +206,7 @@ static int dsbr100_start(struct dsbr100_device *radio)
                goto usb_control_msg_failed;
        }
 
-       radio->muted = 0;
+       radio->status = STARTED;
        mutex_unlock(&radio->lock);
        return (radio->transfer_buffer)[0];
 
@@ -244,7 +249,7 @@ static int dsbr100_stop(struct dsbr100_device *radio)
                goto usb_control_msg_failed;
        }
 
-       radio->muted = 1;
+       radio->status = STOPPED;
        mutex_unlock(&radio->lock);
        return (radio->transfer_buffer)[0];
 
@@ -258,12 +263,12 @@ usb_control_msg_failed:
 }
 
 /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
-static int dsbr100_setfreq(struct dsbr100_device *radio, int freq)
+static int dsbr100_setfreq(struct dsbr100_device *radio)
 {
        int retval;
        int request;
+       int freq = (radio->curfreq / 16 * 80) / 1000 + 856;
 
-       freq = (freq / 16 * 80) / 1000 + 856;
        mutex_lock(&radio->lock);
 
        retval = usb_control_msg(radio->usbdev,
@@ -431,7 +436,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
        radio->curfreq = f->frequency;
        mutex_unlock(&radio->lock);
 
-       retval = dsbr100_setfreq(radio, radio->curfreq);
+       retval = dsbr100_setfreq(radio);
        if (retval < 0)
                dev_warn(&radio->usbdev->dev, "Set frequency failed\n");
        return 0;
@@ -473,7 +478,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
-               ctrl->value = radio->muted;
+               ctrl->value = radio->status;
                return 0;
        }
        return -EINVAL;
@@ -543,65 +548,27 @@ static int vidioc_s_audio(struct file *file, void *priv,
        return 0;
 }
 
-static int usb_dsbr100_open(struct file *file)
-{
-       struct dsbr100_device *radio = video_drvdata(file);
-       int retval;
-
-       lock_kernel();
-       radio->users = 1;
-       radio->muted = 1;
-
-       retval = dsbr100_start(radio);
-       if (retval < 0) {
-               dev_warn(&radio->usbdev->dev,
-                        "Radio did not start up properly\n");
-               radio->users = 0;
-               unlock_kernel();
-               return -EIO;
-       }
-
-       retval = dsbr100_setfreq(radio, radio->curfreq);
-       if (retval < 0)
-               dev_warn(&radio->usbdev->dev,
-                       "set frequency failed\n");
-
-       unlock_kernel();
-       return 0;
-}
-
-static int usb_dsbr100_close(struct file *file)
-{
-       struct dsbr100_device *radio = video_drvdata(file);
-       int retval;
-
-       if (!radio)
-               return -ENODEV;
-
-       mutex_lock(&radio->lock);
-       radio->users = 0;
-       mutex_unlock(&radio->lock);
-
-       if (!radio->removed) {
-               retval = dsbr100_stop(radio);
-               if (retval < 0) {
-                       dev_warn(&radio->usbdev->dev,
-                               "dsbr100_stop failed\n");
-               }
-
-       }
-       return 0;
-}
-
 /* Suspend device - stop device. */
 static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message)
 {
        struct dsbr100_device *radio = usb_get_intfdata(intf);
        int retval;
 
-       retval = dsbr100_stop(radio);
-       if (retval < 0)
-               dev_warn(&intf->dev, "dsbr100_stop failed\n");
+       if (radio->status == STARTED) {
+               retval = dsbr100_stop(radio);
+               if (retval < 0)
+                       dev_warn(&intf->dev, "dsbr100_stop failed\n");
+
+               /* After dsbr100_stop() status set to STOPPED.
+                * If we want driver to start radio on resume
+                * we set status equal to STARTED.
+                * On resume we will check status and run radio if needed.
+                */
+
+               mutex_lock(&radio->lock);
+               radio->status = STARTED;
+               mutex_unlock(&radio->lock);
+       }
 
        dev_info(&intf->dev, "going into suspend..\n");
 
@@ -614,9 +581,11 @@ static int usb_dsbr100_resume(struct usb_interface *intf)
        struct dsbr100_device *radio = usb_get_intfdata(intf);
        int retval;
 
-       retval = dsbr100_start(radio);
-       if (retval < 0)
-               dev_warn(&intf->dev, "dsbr100_start failed\n");
+       if (radio->status == STARTED) {
+               retval = dsbr100_start(radio);
+               if (retval < 0)
+                       dev_warn(&intf->dev, "dsbr100_start failed\n");
+       }
 
        dev_info(&intf->dev, "coming out of suspend..\n");
 
@@ -636,8 +605,6 @@ static void usb_dsbr100_video_device_release(struct video_device *videodev)
 /* File system interface */
 static const struct v4l2_file_operations usb_dsbr100_fops = {
        .owner          = THIS_MODULE,
-       .open           = usb_dsbr100_open,
-       .release        = usb_dsbr100_close,
        .ioctl          = video_ioctl2,
 };
 
@@ -695,9 +662,9 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
        mutex_init(&radio->lock);
 
        radio->removed = 0;
-       radio->users = 0;
        radio->usbdev = interface_to_usbdev(intf);
        radio->curfreq = FREQ_MIN * FREQ_MUL;
+       radio->status = STOPPED;
 
        video_set_drvdata(&radio->videodev, radio);
 
index cab19d05e02f91567750c427c4e45dfed73463e7..837467f93805e9c2f32b37c0f71cce6d3852ffef 100644 (file)
@@ -64,6 +64,7 @@
 #include <media/v4l2-ioctl.h>
 #include <linux/usb.h>
 #include <linux/version.h>     /* for KERNEL_VERSION MACRO */
+#include <linux/mutex.h>
 
 /* driver and module definitions */
 #define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>"
index 5cf6c45b91fe4c2559d4764469cd2cf3af160ca9..49c4aab95daba17a6298a007af3ac502bb7a0282 100644 (file)
@@ -49,7 +49,6 @@ struct fmi
        int io;
        int curvol; /* 1 or 0 */
        unsigned long curfreq; /* freq in kHz */
-       __u32 flags;
        struct mutex lock;
 };
 
@@ -57,7 +56,7 @@ static struct fmi fmi_card;
 static struct pnp_dev *dev;
 
 /* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
-/* It is only useful to give freq in intervall of 800 (=0.05Mhz),
+/* It is only useful to give freq in interval of 800 (=0.05Mhz),
  * other bits will be truncated, e.g 92.7400016 -> 92.7, but
  * 92.7400017 -> 92.75
  */
@@ -142,7 +141,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
 static int vidioc_g_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
-       int mult;
        struct fmi *fmi = video_drvdata(file);
 
        if (v->index > 0)
@@ -150,11 +148,10 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 
        strlcpy(v->name, "FM", sizeof(v->name));
        v->type = V4L2_TUNER_RADIO;
-       mult = (fmi->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
-       v->rangelow = RSF16_MINFREQ / mult;
-       v->rangehigh = RSF16_MAXFREQ / mult;
+       v->rangelow = RSF16_MINFREQ;
+       v->rangehigh = RSF16_MAXFREQ;
        v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-       v->capability = fmi->flags & V4L2_TUNER_CAP_LOW;
+       v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW;
        v->audmode = V4L2_TUNER_MODE_STEREO;
        v->signal = fmi_getsigstr(fmi);
        return 0;
@@ -171,8 +168,6 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 {
        struct fmi *fmi = video_drvdata(file);
 
-       if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
-               f->frequency *= 1000;
        if (f->frequency < RSF16_MINFREQ ||
                        f->frequency > RSF16_MAXFREQ)
                return -EINVAL;
@@ -189,8 +184,6 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 
        f->type = V4L2_TUNER_RADIO;
        f->frequency = fmi->curfreq;
-       if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
-               f->frequency /= 1000;
        return 0;
 }
 
@@ -347,7 +340,6 @@ static int __init fmi_init(void)
                return res;
        }
 
-       fmi->flags = V4L2_TUNER_CAP_LOW;
        strlcpy(fmi->vdev.name, v4l2_dev->name, sizeof(fmi->vdev.name));
        fmi->vdev.v4l2_dev = v4l2_dev;
        fmi->vdev.fops = &fmi_fops;
index 935ff9bcdfcc6b4775455857bb0a2604fe3d9758..a11414f648d4f9279431b98d103450d4c8926bfd 100644 (file)
@@ -61,13 +61,12 @@ struct fmr2
        int stereo; /* card is producing stereo audio */
        unsigned long curfreq; /* freq in kHz */
        int card_type;
-       u32 flags;
 };
 
 static struct fmr2 fmr2_card;
 
 /* hw precision is 12.5 kHz
- * It is only useful to give freq in intervall of 200 (=0.0125Mhz),
+ * It is only useful to give freq in interval of 200 (=0.0125Mhz),
  * other bits will be truncated
  */
 #define RSF16_ENCODE(x)        ((x) / 200 + 856)
@@ -221,7 +220,6 @@ static int vidioc_querycap(struct file *file, void  *priv,
 static int vidioc_g_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *v)
 {
-       int mult;
        struct fmr2 *fmr2 = video_drvdata(file);
 
        if (v->index > 0)
@@ -230,13 +228,12 @@ static int vidioc_g_tuner(struct file *file, void *priv,
        strlcpy(v->name, "FM", sizeof(v->name));
        v->type = V4L2_TUNER_RADIO;
 
-       mult = (fmr2->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
-       v->rangelow = RSF16_MINFREQ / mult;
-       v->rangehigh = RSF16_MAXFREQ / mult;
-       v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-       v->capability = fmr2->flags&V4L2_TUNER_CAP_LOW;
-       v->audmode = fmr2->stereo ? V4L2_TUNER_MODE_STEREO:
-                               V4L2_TUNER_MODE_MONO;
+       v->rangelow = RSF16_MINFREQ;
+       v->rangehigh = RSF16_MAXFREQ;
+       v->rxsubchans = fmr2->stereo ? V4L2_TUNER_SUB_STEREO :
+                                       V4L2_TUNER_SUB_MONO;
+       v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW;
+       v->audmode = V4L2_TUNER_MODE_STEREO;
        mutex_lock(&fmr2->lock);
        v->signal = fmr2_getsigstr(fmr2);
        mutex_unlock(&fmr2->lock);
@@ -254,8 +251,6 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 {
        struct fmr2 *fmr2 = video_drvdata(file);
 
-       if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
-               f->frequency *= 1000;
        if (f->frequency < RSF16_MINFREQ ||
                        f->frequency > RSF16_MAXFREQ)
                return -EINVAL;
@@ -279,8 +274,6 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 
        f->type = V4L2_TUNER_RADIO;
        f->frequency = fmr2->curfreq;
-       if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
-               f->frequency /= 1000;
        return 0;
 }
 
@@ -406,7 +399,6 @@ static int __init fmr2_init(void)
        strlcpy(v4l2_dev->name, "sf16fmr2", sizeof(v4l2_dev->name));
        fmr2->io = io;
        fmr2->stereo = 1;
-       fmr2->flags = V4L2_TUNER_CAP_LOW;
        mutex_init(&fmr2->lock);
 
        if (!request_region(fmr2->io, 2, "sf16fmr2")) {
index bd945d04dc90cb095e9550c6572aeb32502c2792..640421ceb24a2a48918b1692367c5394c6fd7968 100644 (file)
@@ -1214,7 +1214,6 @@ static int si470x_fops_release(struct file *file)
                usb_autopm_put_interface(radio->intf);
        }
 
-unlock:
        mutex_unlock(&radio->disconnect_lock);
 
 done:
index 57835f5715fcaab55587224339e594772d477e11..94f440535c648896e9e84264ca94b9594542a243 100644 (file)
@@ -440,6 +440,24 @@ config VIDEO_ADV7175
          To compile this driver as a module, choose M here: the
          module will be called adv7175.
 
+config VIDEO_THS7303
+       tristate "THS7303 Video Amplifier"
+       depends on I2C
+       help
+         Support for TI THS7303 video amplifier
+
+         To compile this driver as a module, choose M here: the
+         module will be called ths7303.
+
+config VIDEO_ADV7343
+       tristate "ADV7343 video encoder"
+       depends on I2C
+       help
+         Support for Analog Devices I2C bus based ADV7343 encoder.
+
+         To compile this driver as a module, choose M here: the
+         module will be called adv7343.
+
 comment "Video improvement chips"
 
 config VIDEO_UPD64031A
@@ -694,7 +712,7 @@ config VIDEO_CAFE_CCIC
 
 config SOC_CAMERA
        tristate "SoC camera support"
-       depends on VIDEO_V4L2 && HAS_DMA
+       depends on VIDEO_V4L2 && HAS_DMA && I2C
        select VIDEOBUF_GEN
        help
          SoC Camera is a common API to several cameras, not connecting
index 3f1a0350a5690a772b9c88dba113223cfca49e47..7fb3add1b387916d9729279b2e78a2a786c7505a 100644 (file)
@@ -12,6 +12,8 @@ omap2cam-objs :=      omap24xxcam.o omap24xxcam-dma.o
 
 videodev-objs  :=      v4l2-dev.o v4l2-ioctl.o v4l2-device.o
 
+# V4L2 core modules
+
 obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o
 ifeq ($(CONFIG_COMPAT),y)
   obj-$(CONFIG_VIDEO_DEV) += v4l2-compat-ioctl32.o
@@ -23,21 +25,15 @@ ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y)
   obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o
 endif
 
-obj-$(CONFIG_VIDEO_TUNER) += tuner.o
+# All i2c modules must come first:
 
-obj-$(CONFIG_VIDEO_BT848) += bt8xx/
-obj-$(CONFIG_VIDEO_IR_I2C)  += ir-kbd-i2c.o
+obj-$(CONFIG_VIDEO_TUNER) += tuner.o
 obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
 obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
 obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
-
 obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
 obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
 obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o
-obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
-obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o
-obj-$(CONFIG_VIDEO_W9966) += w9966.o
-
 obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o
 obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o
 obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o
@@ -49,16 +45,47 @@ obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o
 obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o
 obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o
 obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o
+obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o
 obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o
 obj-$(CONFIG_VIDEO_BT819) += bt819.o
 obj-$(CONFIG_VIDEO_BT856) += bt856.o
 obj-$(CONFIG_VIDEO_BT866) += bt866.o
 obj-$(CONFIG_VIDEO_KS0127) += ks0127.o
+obj-$(CONFIG_VIDEO_THS7303) += ths7303.o
+obj-$(CONFIG_VIDEO_VINO) += indycam.o
+obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
+obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
+obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
+obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
+obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
+obj-$(CONFIG_VIDEO_M52790) += m52790.o
+obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
+obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
+obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
+obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o
+obj-$(CONFIG_VIDEO_CX25840) += cx25840/
+obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
+obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
+obj-$(CONFIG_VIDEO_OV7670)     += ov7670.o
+obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
+obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
 
-obj-$(CONFIG_VIDEO_ZORAN) += zoran/
+obj-$(CONFIG_SOC_CAMERA_MT9M001)       += mt9m001.o
+obj-$(CONFIG_SOC_CAMERA_MT9M111)       += mt9m111.o
+obj-$(CONFIG_SOC_CAMERA_MT9T031)       += mt9t031.o
+obj-$(CONFIG_SOC_CAMERA_MT9V022)       += mt9v022.o
+obj-$(CONFIG_SOC_CAMERA_OV772X)                += ov772x.o
+obj-$(CONFIG_SOC_CAMERA_TW9910)                += tw9910.o
 
+# And now the v4l2 drivers:
+
+obj-$(CONFIG_VIDEO_BT848) += bt8xx/
+obj-$(CONFIG_VIDEO_ZORAN) += zoran/
+obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
+obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o
+obj-$(CONFIG_VIDEO_W9966) += w9966.o
 obj-$(CONFIG_VIDEO_PMS) += pms.o
-obj-$(CONFIG_VIDEO_VINO) += vino.o indycam.o
+obj-$(CONFIG_VIDEO_VINO) += vino.o
 obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
 obj-$(CONFIG_VIDEO_CPIA) += cpia.o
 obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
@@ -69,17 +96,7 @@ obj-$(CONFIG_VIDEO_CX88) += cx88/
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
 obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
 obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
-obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
-obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o
 obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
-obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
-obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
-obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
-obj-$(CONFIG_VIDEO_M52790) += m52790.o
-obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
-obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
-obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
-obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o
 obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
 obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
 obj-$(CONFIG_VIDEO_MXB) += mxb.o
@@ -92,19 +109,12 @@ obj-$(CONFIG_VIDEOBUF_DMA_CONTIG) += videobuf-dma-contig.o
 obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o
 obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o
 obj-$(CONFIG_VIDEO_BTCX)  += btcx-risc.o
-obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
 
 obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
 
-obj-$(CONFIG_VIDEO_CX25840) += cx25840/
-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_VIDEO_TCM825X) += tcm825x.o
 
 obj-$(CONFIG_USB_DABUSB)        += dabusb.o
 obj-$(CONFIG_USB_OV511)         += ov511.o
@@ -134,24 +144,21 @@ obj-$(CONFIG_VIDEO_CX18) += cx18/
 obj-$(CONFIG_VIDEO_VIVI) += vivi.o
 obj-$(CONFIG_VIDEO_CX23885) += cx23885/
 
+obj-$(CONFIG_VIDEO_OMAP2)              += omap2cam.o
+obj-$(CONFIG_SOC_CAMERA)               += soc_camera.o
+obj-$(CONFIG_SOC_CAMERA_PLATFORM)      += soc_camera_platform.o
+# soc-camera host drivers have to be linked after camera drivers
 obj-$(CONFIG_VIDEO_MX1)                        += mx1_camera.o
 obj-$(CONFIG_VIDEO_MX3)                        += mx3_camera.o
 obj-$(CONFIG_VIDEO_PXA27x)             += pxa_camera.o
 obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)      += sh_mobile_ceu_camera.o
-obj-$(CONFIG_VIDEO_OMAP2)              += omap2cam.o
-obj-$(CONFIG_SOC_CAMERA)               += soc_camera.o
-obj-$(CONFIG_SOC_CAMERA_MT9M001)       += mt9m001.o
-obj-$(CONFIG_SOC_CAMERA_MT9M111)       += mt9m111.o
-obj-$(CONFIG_SOC_CAMERA_MT9T031)       += mt9t031.o
-obj-$(CONFIG_SOC_CAMERA_MT9V022)       += mt9v022.o
-obj-$(CONFIG_SOC_CAMERA_OV772X)                += ov772x.o
-obj-$(CONFIG_SOC_CAMERA_PLATFORM)      += soc_camera_platform.o
-obj-$(CONFIG_SOC_CAMERA_TW9910)                += tw9910.o
 
 obj-$(CONFIG_VIDEO_AU0828) += au0828/
 
 obj-$(CONFIG_USB_VIDEO_CLASS)  += uvc/
 
+obj-$(CONFIG_VIDEO_IR_I2C)  += ir-kbd-i2c.o
+
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
 EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
 EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/video/adv7343.c b/drivers/media/video/adv7343.c
new file mode 100644 (file)
index 0000000..30f5caf
--- /dev/null
@@ -0,0 +1,534 @@
+/*
+ * adv7343 - ADV7343 Video Encoder Driver
+ *
+ * The encoder hardware does not support SECAM.
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ctype.h>
+#include <linux/i2c.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/videodev2.h>
+#include <linux/uaccess.h>
+#include <linux/version.h>
+
+#include <media/adv7343.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+
+#include "adv7343_regs.h"
+
+MODULE_DESCRIPTION("ADV7343 video encoder driver");
+MODULE_LICENSE("GPL");
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level 0-1");
+
+struct adv7343_state {
+       struct v4l2_subdev sd;
+       u8 reg00;
+       u8 reg01;
+       u8 reg02;
+       u8 reg35;
+       u8 reg80;
+       u8 reg82;
+       int bright;
+       int hue;
+       int gain;
+       u32 output;
+       v4l2_std_id std;
+};
+
+static inline struct adv7343_state *to_state(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct adv7343_state, sd);
+}
+
+static inline int adv7343_write(struct v4l2_subdev *sd, u8 reg, u8 value)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static const u8 adv7343_init_reg_val[] = {
+       ADV7343_SOFT_RESET, ADV7343_SOFT_RESET_DEFAULT,
+       ADV7343_POWER_MODE_REG, ADV7343_POWER_MODE_REG_DEFAULT,
+
+       ADV7343_HD_MODE_REG1, ADV7343_HD_MODE_REG1_DEFAULT,
+       ADV7343_HD_MODE_REG2, ADV7343_HD_MODE_REG2_DEFAULT,
+       ADV7343_HD_MODE_REG3, ADV7343_HD_MODE_REG3_DEFAULT,
+       ADV7343_HD_MODE_REG4, ADV7343_HD_MODE_REG4_DEFAULT,
+       ADV7343_HD_MODE_REG5, ADV7343_HD_MODE_REG5_DEFAULT,
+       ADV7343_HD_MODE_REG6, ADV7343_HD_MODE_REG6_DEFAULT,
+       ADV7343_HD_MODE_REG7, ADV7343_HD_MODE_REG7_DEFAULT,
+
+       ADV7343_SD_MODE_REG1, ADV7343_SD_MODE_REG1_DEFAULT,
+       ADV7343_SD_MODE_REG2, ADV7343_SD_MODE_REG2_DEFAULT,
+       ADV7343_SD_MODE_REG3, ADV7343_SD_MODE_REG3_DEFAULT,
+       ADV7343_SD_MODE_REG4, ADV7343_SD_MODE_REG4_DEFAULT,
+       ADV7343_SD_MODE_REG5, ADV7343_SD_MODE_REG5_DEFAULT,
+       ADV7343_SD_MODE_REG6, ADV7343_SD_MODE_REG6_DEFAULT,
+       ADV7343_SD_MODE_REG7, ADV7343_SD_MODE_REG7_DEFAULT,
+       ADV7343_SD_MODE_REG8, ADV7343_SD_MODE_REG8_DEFAULT,
+
+       ADV7343_SD_HUE_REG, ADV7343_SD_HUE_REG_DEFAULT,
+       ADV7343_SD_CGMS_WSS0, ADV7343_SD_CGMS_WSS0_DEFAULT,
+       ADV7343_SD_BRIGHTNESS_WSS, ADV7343_SD_BRIGHTNESS_WSS_DEFAULT,
+};
+
+/*
+ *                         2^32
+ * FSC(reg) =  FSC (HZ) * --------
+ *                       27000000
+ */
+static const struct adv7343_std_info stdinfo[] = {
+       {
+               /* FSC(Hz) = 3,579,545.45 Hz */
+               SD_STD_NTSC, 569408542, V4L2_STD_NTSC,
+       }, {
+               /* FSC(Hz) = 3,575,611.00 Hz */
+               SD_STD_PAL_M, 568782678, V4L2_STD_PAL_M,
+       }, {
+               /* FSC(Hz) = 3,582,056.00 */
+               SD_STD_PAL_N, 569807903, V4L2_STD_PAL_Nc,
+       }, {
+               /* FSC(Hz) = 4,433,618.75 Hz */
+               SD_STD_PAL_N, 705268427, V4L2_STD_PAL_N,
+       }, {
+               /* FSC(Hz) = 4,433,618.75 Hz */
+               SD_STD_PAL_BDGHI, 705268427, V4L2_STD_PAL,
+       }, {
+               /* FSC(Hz) = 4,433,618.75 Hz */
+               SD_STD_NTSC, 705268427, V4L2_STD_NTSC_443,
+       }, {
+               /* FSC(Hz) = 4,433,618.75 Hz */
+               SD_STD_PAL_M, 705268427, V4L2_STD_PAL_60,
+       },
+};
+
+static int adv7343_setstd(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct adv7343_state *state = to_state(sd);
+       struct adv7343_std_info *std_info;
+       int output_idx, num_std;
+       char *fsc_ptr;
+       u8 reg, val;
+       int err = 0;
+       int i = 0;
+
+       output_idx = state->output;
+
+       std_info = (struct adv7343_std_info *)stdinfo;
+       num_std = ARRAY_SIZE(stdinfo);
+
+       for (i = 0; i < num_std; i++) {
+               if (std_info[i].stdid & std)
+                       break;
+       }
+
+       if (i == num_std) {
+               v4l2_dbg(1, debug, sd,
+                               "Invalid std or std is not supported: %llx\n",
+                                               (unsigned long long)std);
+               return -EINVAL;
+       }
+
+       /* Set the standard */
+       val = state->reg80 & (~(SD_STD_MASK));
+       val |= std_info[i].standard_val3;
+       err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val);
+       if (err < 0)
+               goto setstd_exit;
+
+       state->reg80 = val;
+
+       /* Configure the input mode register */
+       val = state->reg01 & (~((u8) INPUT_MODE_MASK));
+       val |= SD_INPUT_MODE;
+       err = adv7343_write(sd, ADV7343_MODE_SELECT_REG, val);
+       if (err < 0)
+               goto setstd_exit;
+
+       state->reg01 = val;
+
+       /* Program the sub carrier frequency registers */
+       fsc_ptr = (unsigned char *)&std_info[i].fsc_val;
+       reg = ADV7343_FSC_REG0;
+       for (i = 0; i < 4; i++, reg++, fsc_ptr++) {
+               err = adv7343_write(sd, reg, *fsc_ptr);
+               if (err < 0)
+                       goto setstd_exit;
+       }
+
+       val = state->reg80;
+
+       /* Filter settings */
+       if (std & (V4L2_STD_NTSC | V4L2_STD_NTSC_443))
+               val &= 0x03;
+       else if (std & ~V4L2_STD_SECAM)
+               val |= 0x04;
+
+       err = adv7343_write(sd, ADV7343_SD_MODE_REG1, val);
+       if (err < 0)
+               goto setstd_exit;
+
+       state->reg80 = val;
+
+setstd_exit:
+       if (err != 0)
+               v4l2_err(sd, "Error setting std, write failed\n");
+
+       return err;
+}
+
+static int adv7343_setoutput(struct v4l2_subdev *sd, u32 output_type)
+{
+       struct adv7343_state *state = to_state(sd);
+       unsigned char val;
+       int err = 0;
+
+       if (output_type > ADV7343_SVIDEO_ID) {
+               v4l2_dbg(1, debug, sd,
+                       "Invalid output type or output type not supported:%d\n",
+                                                               output_type);
+               return -EINVAL;
+       }
+
+       /* Enable Appropriate DAC */
+       val = state->reg00 & 0x03;
+
+       if (output_type == ADV7343_COMPOSITE_ID)
+               val |= ADV7343_COMPOSITE_POWER_VALUE;
+       else if (output_type == ADV7343_COMPONENT_ID)
+               val |= ADV7343_COMPONENT_POWER_VALUE;
+       else
+               val |= ADV7343_SVIDEO_POWER_VALUE;
+
+       err = adv7343_write(sd, ADV7343_POWER_MODE_REG, val);
+       if (err < 0)
+               goto setoutput_exit;
+
+       state->reg00 = val;
+
+       /* Enable YUV output */
+       val = state->reg02 | YUV_OUTPUT_SELECT;
+       err = adv7343_write(sd, ADV7343_MODE_REG0, val);
+       if (err < 0)
+               goto setoutput_exit;
+
+       state->reg02 = val;
+
+       /* configure SD DAC Output 2 and SD DAC Output 1 bit to zero */
+       val = state->reg82 & (SD_DAC_1_DI & SD_DAC_2_DI);
+       err = adv7343_write(sd, ADV7343_SD_MODE_REG2, val);
+       if (err < 0)
+               goto setoutput_exit;
+
+       state->reg82 = val;
+
+       /* configure ED/HD Color DAC Swap and ED/HD RGB Input Enable bit to
+        * zero */
+       val = state->reg35 & (HD_RGB_INPUT_DI & HD_DAC_SWAP_DI);
+       err = adv7343_write(sd, ADV7343_HD_MODE_REG6, val);
+       if (err < 0)
+               goto setoutput_exit;
+
+       state->reg35 = val;
+
+setoutput_exit:
+       if (err != 0)
+               v4l2_err(sd, "Error setting output, write failed\n");
+
+       return err;
+}
+
+static int adv7343_log_status(struct v4l2_subdev *sd)
+{
+       struct adv7343_state *state = to_state(sd);
+
+       v4l2_info(sd, "Standard: %llx\n", (unsigned long long)state->std);
+       v4l2_info(sd, "Output: %s\n", (state->output == 0) ? "Composite" :
+                       ((state->output == 1) ? "Component" : "S-Video"));
+       return 0;
+}
+
+static int adv7343_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+       switch (qc->id) {
+       case V4L2_CID_BRIGHTNESS:
+               return v4l2_ctrl_query_fill(qc, ADV7343_BRIGHTNESS_MIN,
+                                               ADV7343_BRIGHTNESS_MAX, 1,
+                                               ADV7343_BRIGHTNESS_DEF);
+       case V4L2_CID_HUE:
+               return v4l2_ctrl_query_fill(qc, ADV7343_HUE_MIN,
+                                               ADV7343_HUE_MAX, 1 ,
+                                               ADV7343_HUE_DEF);
+       case V4L2_CID_GAIN:
+               return v4l2_ctrl_query_fill(qc, ADV7343_GAIN_MIN,
+                                               ADV7343_GAIN_MAX, 1,
+                                               ADV7343_GAIN_DEF);
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int adv7343_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct adv7343_state *state = to_state(sd);
+       int err = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               if (ctrl->value < ADV7343_BRIGHTNESS_MIN ||
+                                       ctrl->value > ADV7343_BRIGHTNESS_MAX) {
+                       v4l2_dbg(1, debug, sd,
+                                       "invalid brightness settings %d\n",
+                                                               ctrl->value);
+                       return -ERANGE;
+               }
+
+               state->bright = ctrl->value;
+               err = adv7343_write(sd, ADV7343_SD_BRIGHTNESS_WSS,
+                                       state->bright);
+               break;
+
+       case V4L2_CID_HUE:
+               if (ctrl->value < ADV7343_HUE_MIN ||
+                                       ctrl->value > ADV7343_HUE_MAX) {
+                       v4l2_dbg(1, debug, sd, "invalid hue settings %d\n",
+                                                               ctrl->value);
+                       return -ERANGE;
+               }
+
+               state->hue = ctrl->value;
+               err = adv7343_write(sd, ADV7343_SD_HUE_REG, state->hue);
+               break;
+
+       case V4L2_CID_GAIN:
+               if (ctrl->value < ADV7343_GAIN_MIN ||
+                                       ctrl->value > ADV7343_GAIN_MAX) {
+                       v4l2_dbg(1, debug, sd, "invalid gain settings %d\n",
+                                                               ctrl->value);
+                       return -ERANGE;
+               }
+
+               if ((ctrl->value > POSITIVE_GAIN_MAX) &&
+                       (ctrl->value < NEGATIVE_GAIN_MIN)) {
+                       v4l2_dbg(1, debug, sd,
+                               "gain settings not within the specified range\n");
+                       return -ERANGE;
+               }
+
+               state->gain = ctrl->value;
+               err = adv7343_write(sd, ADV7343_DAC2_OUTPUT_LEVEL, state->gain);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       if (err < 0)
+               v4l2_err(sd, "Failed to set the encoder controls\n");
+
+       return err;
+}
+
+static int adv7343_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct adv7343_state *state = to_state(sd);
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               ctrl->value = state->bright;
+               break;
+
+       case V4L2_CID_HUE:
+               ctrl->value = state->hue;
+               break;
+
+       case V4L2_CID_GAIN:
+               ctrl->value = state->gain;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int adv7343_g_chip_ident(struct v4l2_subdev *sd,
+                               struct v4l2_dbg_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7343, 0);
+}
+
+static const struct v4l2_subdev_core_ops adv7343_core_ops = {
+       .log_status     = adv7343_log_status,
+       .g_chip_ident   = adv7343_g_chip_ident,
+       .g_ctrl         = adv7343_g_ctrl,
+       .s_ctrl         = adv7343_s_ctrl,
+       .queryctrl      = adv7343_queryctrl,
+};
+
+static int adv7343_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       struct adv7343_state *state = to_state(sd);
+       int err = 0;
+
+       if (state->std == std)
+               return 0;
+
+       err = adv7343_setstd(sd, std);
+       if (!err)
+               state->std = std;
+
+       return err;
+}
+
+static int adv7343_s_routing(struct v4l2_subdev *sd,
+               u32 input, u32 output, u32 config)
+{
+       struct adv7343_state *state = to_state(sd);
+       int err = 0;
+
+       if (state->output == output)
+               return 0;
+
+       err = adv7343_setoutput(sd, output);
+       if (!err)
+               state->output = output;
+
+       return err;
+}
+
+static const struct v4l2_subdev_video_ops adv7343_video_ops = {
+       .s_std_output   = adv7343_s_std_output,
+       .s_routing      = adv7343_s_routing,
+};
+
+static const struct v4l2_subdev_ops adv7343_ops = {
+       .core   = &adv7343_core_ops,
+       .video  = &adv7343_video_ops,
+};
+
+static int adv7343_initialize(struct v4l2_subdev *sd)
+{
+       struct adv7343_state *state = to_state(sd);
+       int err = 0;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(adv7343_init_reg_val); i += 2) {
+
+               err = adv7343_write(sd, adv7343_init_reg_val[i],
+                                       adv7343_init_reg_val[i+1]);
+               if (err) {
+                       v4l2_err(sd, "Error initializing\n");
+                       return err;
+               }
+       }
+
+       /* Configure for default video standard */
+       err = adv7343_setoutput(sd, state->output);
+       if (err < 0) {
+               v4l2_err(sd, "Error setting output during init\n");
+               return -EINVAL;
+       }
+
+       err = adv7343_setstd(sd, state->std);
+       if (err < 0) {
+               v4l2_err(sd, "Error setting std during init\n");
+               return -EINVAL;
+       }
+
+       return err;
+}
+
+static int adv7343_probe(struct i2c_client *client,
+                               const struct i2c_device_id *id)
+{
+       struct adv7343_state *state;
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
+
+       state = kzalloc(sizeof(struct adv7343_state), GFP_KERNEL);
+       if (state == NULL)
+               return -ENOMEM;
+
+       state->reg00    = 0x80;
+       state->reg01    = 0x00;
+       state->reg02    = 0x20;
+       state->reg35    = 0x00;
+       state->reg80    = ADV7343_SD_MODE_REG1_DEFAULT;
+       state->reg82    = ADV7343_SD_MODE_REG2_DEFAULT;
+
+       state->output = ADV7343_COMPOSITE_ID;
+       state->std = V4L2_STD_NTSC;
+
+       v4l2_i2c_subdev_init(&state->sd, client, &adv7343_ops);
+       return adv7343_initialize(&state->sd);
+}
+
+static int adv7343_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(to_state(sd));
+
+       return 0;
+}
+
+static const struct i2c_device_id adv7343_id[] = {
+       {"adv7343", 0},
+       {},
+};
+
+MODULE_DEVICE_TABLE(i2c, adv7343_id);
+
+static struct i2c_driver adv7343_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "adv7343",
+       },
+       .probe          = adv7343_probe,
+       .remove         = adv7343_remove,
+       .id_table       = adv7343_id,
+};
+
+static __init int init_adv7343(void)
+{
+       return i2c_add_driver(&adv7343_driver);
+}
+
+static __exit void exit_adv7343(void)
+{
+       i2c_del_driver(&adv7343_driver);
+}
+
+module_init(init_adv7343);
+module_exit(exit_adv7343);
diff --git a/drivers/media/video/adv7343_regs.h b/drivers/media/video/adv7343_regs.h
new file mode 100644 (file)
index 0000000..3431045
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * ADV7343 encoder related structure and register definitions
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef ADV7343_REG_H
+#define ADV7343_REGS_H
+
+struct adv7343_std_info {
+       u32 standard_val3;
+       u32 fsc_val;
+       v4l2_std_id stdid;
+};
+
+/* Register offset macros */
+#define ADV7343_POWER_MODE_REG         (0x00)
+#define ADV7343_MODE_SELECT_REG                (0x01)
+#define ADV7343_MODE_REG0              (0x02)
+
+#define ADV7343_DAC2_OUTPUT_LEVEL      (0x0b)
+
+#define ADV7343_SOFT_RESET             (0x17)
+
+#define ADV7343_HD_MODE_REG1           (0x30)
+#define ADV7343_HD_MODE_REG2           (0x31)
+#define ADV7343_HD_MODE_REG3           (0x32)
+#define ADV7343_HD_MODE_REG4           (0x33)
+#define ADV7343_HD_MODE_REG5           (0x34)
+#define ADV7343_HD_MODE_REG6           (0x35)
+
+#define ADV7343_HD_MODE_REG7           (0x39)
+
+#define ADV7343_SD_MODE_REG1           (0x80)
+#define ADV7343_SD_MODE_REG2           (0x82)
+#define ADV7343_SD_MODE_REG3           (0x83)
+#define ADV7343_SD_MODE_REG4           (0x84)
+#define ADV7343_SD_MODE_REG5           (0x86)
+#define ADV7343_SD_MODE_REG6           (0x87)
+#define ADV7343_SD_MODE_REG7           (0x88)
+#define ADV7343_SD_MODE_REG8           (0x89)
+
+#define ADV7343_FSC_REG0               (0x8C)
+#define ADV7343_FSC_REG1               (0x8D)
+#define ADV7343_FSC_REG2               (0x8E)
+#define ADV7343_FSC_REG3               (0x8F)
+
+#define ADV7343_SD_CGMS_WSS0           (0x99)
+
+#define ADV7343_SD_HUE_REG             (0xA0)
+#define ADV7343_SD_BRIGHTNESS_WSS      (0xA1)
+
+/* Default values for the registers */
+#define ADV7343_POWER_MODE_REG_DEFAULT         (0x10)
+#define ADV7343_HD_MODE_REG1_DEFAULT           (0x3C)  /* Changed Default
+                                                          720p EAVSAV code*/
+#define ADV7343_HD_MODE_REG2_DEFAULT           (0x01)  /* Changed Pixel data
+                                                          valid */
+#define ADV7343_HD_MODE_REG3_DEFAULT           (0x00)  /* Color delay 0 clks */
+#define ADV7343_HD_MODE_REG4_DEFAULT           (0xE8)  /* Changed */
+#define ADV7343_HD_MODE_REG5_DEFAULT           (0x08)
+#define ADV7343_HD_MODE_REG6_DEFAULT           (0x00)
+#define ADV7343_HD_MODE_REG7_DEFAULT           (0x00)
+#define ADV7343_SD_MODE_REG8_DEFAULT           (0x00)
+#define ADV7343_SOFT_RESET_DEFAULT             (0x02)
+#define ADV7343_COMPOSITE_POWER_VALUE          (0x80)
+#define ADV7343_COMPONENT_POWER_VALUE          (0x1C)
+#define ADV7343_SVIDEO_POWER_VALUE             (0x60)
+#define ADV7343_SD_HUE_REG_DEFAULT             (127)
+#define ADV7343_SD_BRIGHTNESS_WSS_DEFAULT      (0x03)
+
+#define ADV7343_SD_CGMS_WSS0_DEFAULT           (0x10)
+
+#define ADV7343_SD_MODE_REG1_DEFAULT           (0x00)
+#define ADV7343_SD_MODE_REG2_DEFAULT           (0xC9)
+#define ADV7343_SD_MODE_REG3_DEFAULT           (0x10)
+#define ADV7343_SD_MODE_REG4_DEFAULT           (0x01)
+#define ADV7343_SD_MODE_REG5_DEFAULT           (0x02)
+#define ADV7343_SD_MODE_REG6_DEFAULT           (0x0C)
+#define ADV7343_SD_MODE_REG7_DEFAULT           (0x04)
+#define ADV7343_SD_MODE_REG8_DEFAULT           (0x00)
+
+/* Bit masks for Mode Select Register */
+#define INPUT_MODE_MASK                        (0x70)
+#define SD_INPUT_MODE                  (0x00)
+#define HD_720P_INPUT_MODE             (0x10)
+#define HD_1080I_INPUT_MODE            (0x10)
+
+/* Bit masks for Mode Register 0 */
+#define TEST_PATTERN_BLACK_BAR_EN      (0x04)
+#define YUV_OUTPUT_SELECT              (0x20)
+#define RGB_OUTPUT_SELECT              (0xDF)
+
+/* Bit masks for DAC output levels */
+#define DAC_OUTPUT_LEVEL_MASK          (0xFF)
+#define POSITIVE_GAIN_MAX              (0x40)
+#define POSITIVE_GAIN_MIN              (0x00)
+#define NEGATIVE_GAIN_MAX              (0xFF)
+#define NEGATIVE_GAIN_MIN              (0xC0)
+
+/* Bit masks for soft reset register */
+#define SOFT_RESET                     (0x02)
+
+/* Bit masks for HD Mode Register 1 */
+#define OUTPUT_STD_MASK                (0x03)
+#define OUTPUT_STD_SHIFT       (0)
+#define OUTPUT_STD_EIA0_2      (0x00)
+#define OUTPUT_STD_EIA0_1      (0x01)
+#define OUTPUT_STD_FULL                (0x02)
+#define EMBEDDED_SYNC          (0x04)
+#define EXTERNAL_SYNC          (0xFB)
+#define STD_MODE_SHIFT         (3)
+#define STD_MODE_MASK          (0x1F)
+#define STD_MODE_720P          (0x05)
+#define STD_MODE_720P_25       (0x08)
+#define STD_MODE_720P_30       (0x07)
+#define STD_MODE_720P_50       (0x06)
+#define STD_MODE_1080I         (0x0D)
+#define STD_MODE_1080I_25fps   (0x0E)
+#define STD_MODE_1080P_24      (0x12)
+#define STD_MODE_1080P_25      (0x10)
+#define STD_MODE_1080P_30      (0x0F)
+#define STD_MODE_525P          (0x00)
+#define STD_MODE_625P          (0x03)
+
+/* Bit masks for SD Mode Register 1 */
+#define SD_STD_MASK            (0x03)
+#define SD_STD_NTSC            (0x00)
+#define SD_STD_PAL_BDGHI       (0x01)
+#define SD_STD_PAL_M           (0x02)
+#define SD_STD_PAL_N           (0x03)
+#define SD_LUMA_FLTR_MASK      (0x7)
+#define SD_LUMA_FLTR_SHIFT     (0x2)
+#define SD_CHROMA_FLTR_MASK    (0x7)
+#define SD_CHROMA_FLTR_SHIFT   (0x5)
+
+/* Bit masks for SD Mode Register 2 */
+#define SD_PBPR_SSAF_EN                (0x01)
+#define SD_PBPR_SSAF_DI                (0xFE)
+#define SD_DAC_1_DI            (0xFD)
+#define SD_DAC_2_DI            (0xFB)
+#define SD_PEDESTAL_EN         (0x08)
+#define SD_PEDESTAL_DI         (0xF7)
+#define SD_SQUARE_PIXEL_EN     (0x10)
+#define SD_SQUARE_PIXEL_DI     (0xEF)
+#define SD_PIXEL_DATA_VALID    (0x40)
+#define SD_ACTIVE_EDGE_EN      (0x80)
+#define SD_ACTIVE_EDGE_DI      (0x7F)
+
+/* Bit masks for HD Mode Register 6 */
+#define HD_RGB_INPUT_EN                (0x02)
+#define HD_RGB_INPUT_DI                (0xFD)
+#define HD_PBPR_SYNC_EN                (0x04)
+#define HD_PBPR_SYNC_DI                (0xFB)
+#define HD_DAC_SWAP_EN         (0x08)
+#define HD_DAC_SWAP_DI         (0xF7)
+#define HD_GAMMA_CURVE_A       (0xEF)
+#define HD_GAMMA_CURVE_B       (0x10)
+#define HD_GAMMA_EN            (0x20)
+#define HD_GAMMA_DI            (0xDF)
+#define HD_ADPT_FLTR_MODEB     (0x40)
+#define HD_ADPT_FLTR_MODEA     (0xBF)
+#define HD_ADPT_FLTR_EN                (0x80)
+#define HD_ADPT_FLTR_DI                (0x7F)
+
+#define ADV7343_BRIGHTNESS_MAX (127)
+#define ADV7343_BRIGHTNESS_MIN (0)
+#define ADV7343_BRIGHTNESS_DEF (3)
+#define ADV7343_HUE_MAX                (255)
+#define ADV7343_HUE_MIN                (0)
+#define ADV7343_HUE_DEF                (127)
+#define ADV7343_GAIN_MAX       (255)
+#define ADV7343_GAIN_MIN       (0)
+#define ADV7343_GAIN_DEF       (0)
+
+#endif
index 053bbe8c8e3aaf89bd8850c5196400fdeb34e129..830c4a933f635ffc8256bd3deff50409380aa1bb 100644 (file)
@@ -136,9 +136,9 @@ int au0828_tuner_callback(void *priv, int component, int command, int arg)
                        /* Tuner Reset Command from xc5000 */
                        /* Drive the tuner into reset and out */
                        au0828_clear(dev, REG_001, 2);
-                       mdelay(200);
+                       mdelay(10);
                        au0828_set(dev, REG_001, 2);
-                       mdelay(50);
+                       mdelay(10);
                        return 0;
                } else {
                        printk(KERN_ERR
index a1e4c0d769a6d014329165764647fc2c4c02568b..3544a2f12f13a1497f54ca30609a26e8e9ba8a49 100644 (file)
@@ -36,6 +36,11 @@ int au0828_debug;
 module_param_named(debug, au0828_debug, int, 0644);
 MODULE_PARM_DESC(debug, "enable debug messages");
 
+static unsigned int disable_usb_speed_check;
+module_param(disable_usb_speed_check, int, 0444);
+MODULE_PARM_DESC(disable_usb_speed_check,
+                "override min bandwidth requirement of 480M bps");
+
 #define _AU0828_BULKPIPE 0x03
 #define _BULKPIPESIZE 0xffff
 
@@ -181,6 +186,18 @@ static int au0828_usb_probe(struct usb_interface *interface,
                le16_to_cpu(usbdev->descriptor.idProduct),
                ifnum);
 
+       /*
+        * Make sure we have 480 Mbps of bandwidth, otherwise things like
+        * video stream wouldn't likely work, since 12 Mbps is generally
+        * not enough even for most Digital TV streams.
+        */
+       if (usbdev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
+               printk(KERN_ERR "au0828: Device initialization failed.\n");
+               printk(KERN_ERR "au0828: Device must be connected to a "
+                      "high-speed USB 2.0 port.\n");
+               return -ENODEV;
+       }
+
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (dev == NULL) {
                printk(KERN_ERR "%s() Unable to allocate memory\n", __func__);
index 27bedc6c779114da92758f7efb494fa3ca6582f0..51527d7b55a757124e546fa4842efbac67c48688 100644 (file)
@@ -829,6 +829,9 @@ static int au0828_v4l2_close(struct file *filp)
 
                au0828_uninit_isoc(dev);
 
+               /* Save some power by putting tuner to sleep */
+               v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_standby);
+
                /* When close the device, set the usb intf0 into alt0 to free
                   USB bandwidth */
                ret = usb_set_interface(dev->usbdev, 0, 0);
@@ -910,11 +913,6 @@ static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
 
        rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
 
-       dprintk(2, "vma start=0x%08lx, size=%ld, ret=%d\n",
-               (unsigned long)vma->vm_start,
-               (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
-               rc);
-
        return rc;
 }
 
index 23b7499b31852d5aa7f0b3f52c5f5c2f37b481f6..5eb1464af6703f3825599e05bc4683a2e09dc250 100644 (file)
@@ -3152,6 +3152,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
        struct bttv_fh *fh = file->private_data;
        struct bttv_buffer *buf;
        enum v4l2_field field;
+       unsigned int rc = POLLERR;
 
        if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
                if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
@@ -3160,9 +3161,10 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
        }
 
        if (check_btres(fh,RESOURCE_VIDEO_STREAM)) {
+               mutex_lock(&fh->cap.vb_lock);
                /* streaming capture */
                if (list_empty(&fh->cap.stream))
-                       return POLLERR;
+                       goto err;
                buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
        } else {
                /* read() capture */
@@ -3191,11 +3193,12 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
        poll_wait(file, &buf->vb.done, wait);
        if (buf->vb.state == VIDEOBUF_DONE ||
            buf->vb.state == VIDEOBUF_ERROR)
-               return POLLIN|POLLRDNORM;
-       return 0;
+               rc =  POLLIN|POLLRDNORM;
+       else
+               rc = 0;
 err:
        mutex_unlock(&fh->cap.vb_lock);
-       return POLLERR;
+       return rc;
 }
 
 static int bttv_open(struct file *file)
@@ -4166,7 +4169,6 @@ static struct video_device *vdev_init(struct bttv *btv,
        if (NULL == vfd)
                return NULL;
        *vfd = *template;
-       vfd->minor   = -1;
        vfd->v4l2_dev = &btv->c.v4l2_dev;
        vfd->release = video_device_release;
        vfd->debug   = bttv_debug;
@@ -4629,7 +4631,7 @@ static int __init bttv_init_module(void)
 #endif
        if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
                gbuffers = 2;
-       if (gbufsize < 0 || gbufsize > BTTV_MAX_FBUF)
+       if (gbufsize > BTTV_MAX_FBUF)
                gbufsize = BTTV_MAX_FBUF;
        gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
        if (bttv_verbose)
index a99d92fac3dc4e7731cfa9b2349886ac926b6d6c..ebd1ee9dc871d222f6f918b8670aa407037e9777 100644 (file)
@@ -389,6 +389,27 @@ int __devinit init_bttv_i2c(struct bttv *btv)
        }
        if (0 == btv->i2c_rc && i2c_scan)
                do_i2c_scan(btv->c.v4l2_dev.name, &btv->i2c_client);
+
+       /* Instantiate the IR receiver device, if present */
+       if (0 == btv->i2c_rc) {
+               struct i2c_board_info info;
+               /* The external IR receiver is at i2c address 0x34 (0x35 for
+                  reads).  Future Hauppauge cards will have an internal
+                  receiver at 0x30 (0x31 for reads).  In theory, both can be
+                  fitted, and Hauppauge suggest an external overrides an
+                  internal.
+
+                  That's why we probe 0x1a (~0x34) first. CB
+               */
+               const unsigned short addr_list[] = {
+                       0x1a, 0x18, 0x4b, 0x64, 0x30,
+                       I2C_CLIENT_END
+               };
+
+               memset(&info, 0, sizeof(struct i2c_board_info));
+               strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+               i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list);
+       }
        return btv->i2c_rc;
 }
 
index d4099f5312ac4ab8ac2ad00b1eb9ae405e847c2d..0b4a8f309cfab14c65727e378cc6d352b3bea881 100644 (file)
@@ -1064,7 +1064,7 @@ static int ioctl_querymenu(void *arg,struct camera_data *cam)
 
        switch(m->id) {
        case CPIA2_CID_FLICKER_MODE:
-               if(m->index < 0 || m->index >= NUM_FLICKER_CONTROLS)
+               if (m->index >= NUM_FLICKER_CONTROLS)
                        return -EINVAL;
 
                strcpy(m->name, flicker_controls[m->index].name);
@@ -1082,14 +1082,14 @@ static int ioctl_querymenu(void *arg,struct camera_data *cam)
                                        maximum = i;
                        }
                }
-               if(m->index < 0 || m->index > maximum)
+               if (m->index > maximum)
                        return -EINVAL;
 
                strcpy(m->name, framerate_controls[m->index].name);
                break;
            }
        case CPIA2_CID_LIGHTS:
-               if(m->index < 0 || m->index >= NUM_LIGHTS_CONTROLS)
+               if (m->index >= NUM_LIGHTS_CONTROLS)
                        return -EINVAL;
 
                strcpy(m->name, lights_controls[m->index].name);
index 7a8ad5963de8c774b7ac5368c8f2729d44e6e00f..35268923911c94b88bf527bc0734941cd3617b95 100644 (file)
 #include "cx18-cards.h"
 #include "cx18-audio.h"
 
-#define CX18_AUDIO_ENABLE 0xc72014
+#define CX18_AUDIO_ENABLE    0xc72014
+#define CX18_AI1_MUX_MASK    0x30
+#define CX18_AI1_MUX_I2S1    0x00
+#define CX18_AI1_MUX_I2S2    0x10
+#define CX18_AI1_MUX_843_I2S 0x20
 
 /* Selects the audio input and output according to the current
    settings. */
 int cx18_audio_set_io(struct cx18 *cx)
 {
        const struct cx18_card_audio_input *in;
-       u32 val;
+       u32 u, v;
        int err;
 
        /* Determine which input to use */
@@ -52,9 +56,37 @@ int cx18_audio_set_io(struct cx18 *cx)
                return err;
 
        /* FIXME - this internal mux should be abstracted to a subdev */
-       val = cx18_read_reg(cx, CX18_AUDIO_ENABLE) & ~0x30;
-       val |= (in->audio_input > CX18_AV_AUDIO_SERIAL2) ? 0x20 :
-                                       (in->audio_input << 4);
-       cx18_write_reg_expect(cx, val | 0xb00, CX18_AUDIO_ENABLE, val, 0x30);
+       u = cx18_read_reg(cx, CX18_AUDIO_ENABLE);
+       v = u & ~CX18_AI1_MUX_MASK;
+       switch (in->audio_input) {
+       case CX18_AV_AUDIO_SERIAL1:
+               v |= CX18_AI1_MUX_I2S1;
+               break;
+       case CX18_AV_AUDIO_SERIAL2:
+               v |= CX18_AI1_MUX_I2S2;
+               break;
+       default:
+               v |= CX18_AI1_MUX_843_I2S;
+               break;
+       }
+       if (v == u) {
+               /* force a toggle of some AI1 MUX control bits */
+               u &= ~CX18_AI1_MUX_MASK;
+               switch (in->audio_input) {
+               case CX18_AV_AUDIO_SERIAL1:
+                       u |= CX18_AI1_MUX_843_I2S;
+                       break;
+               case CX18_AV_AUDIO_SERIAL2:
+                       u |= CX18_AI1_MUX_843_I2S;
+                       break;
+               default:
+                       u |= CX18_AI1_MUX_I2S1;
+                       break;
+               }
+               cx18_write_reg_expect(cx, u | 0xb00, CX18_AUDIO_ENABLE,
+                                     u, CX18_AI1_MUX_MASK);
+       }
+       cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
+                             v, CX18_AI1_MUX_MASK);
        return 0;
 }
index cf2bd888a429a8e00d45304bd48644fa7efdbdc2..536dedb23ba36cb3080a53c0e958c6049d20300c 100644 (file)
@@ -99,9 +99,39 @@ int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask,
                             or_value);
 }
 
-static void cx18_av_initialize(struct cx18 *cx)
+static int cx18_av_init(struct v4l2_subdev *sd, u32 val)
 {
-       struct cx18_av_state *state = &cx->av_state;
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
+
+       /*
+        * The crystal freq used in calculations in this driver will be
+        * 28.636360 MHz.
+        * Aim to run the PLLs' VCOs near 400 MHz to minimze errors.
+        */
+
+       /*
+        * VDCLK  Integer = 0x0f, Post Divider = 0x04
+        * AIMCLK Integer = 0x0e, Post Divider = 0x16
+        */
+       cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f);
+
+       /* VDCLK Fraction = 0x2be2fe */
+       /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */
+       cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe);
+
+       /* AIMCLK Fraction = 0x05227ad */
+       /* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz pre post-div*/
+       cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad);
+
+       /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
+       cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56);
+       return 0;
+}
+
+static void cx18_av_initialize(struct v4l2_subdev *sd)
+{
+       struct cx18_av_state *state = to_cx18_av_state(sd);
+       struct cx18 *cx = v4l2_get_subdevdata(sd);
        u32 v;
 
        cx18_av_loadfw(cx);
@@ -150,6 +180,26 @@ static void cx18_av_initialize(struct cx18 *cx)
        cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0x8000);
        cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0);
 
+       /*
+        * Disable Video Auto-config of the Analog Front End and Video PLL.
+        *
+        * Since we only use BT.656 pixel mode, which works for both 525 and 625
+        * line systems, it's just easier for us to set registers
+        * 0x102 (CXADEC_CHIP_CTRL), 0x104-0x106 (CXADEC_AFE_CTRL),
+        * 0x108-0x109 (CXADEC_PLL_CTRL1), and 0x10c-0x10f (CXADEC_VID_PLL_FRAC)
+        * ourselves, than to run around cleaning up after the auto-config.
+        *
+        * (Note: my CX23418 chip doesn't seem to let the ACFG_DIS bit
+        * get set to 1, but OTOH, it doesn't seem to do AFE and VID PLL
+        * autoconfig either.)
+        *
+        * As a default, also turn off Dual mode for ADC2 and set ADC2 to CH3.
+        */
+       cx18_av_and_or4(cx, CXADEC_CHIP_CTRL, 0xFFFBFFFF, 0x00120000);
+
+       /* Setup the Video and and Aux/Audio PLLs */
+       cx18_av_init(sd, 0);
+
        /* set video to auto-detect */
        /* Clear bits 11-12 to enable slow locking mode.  Set autodetect mode */
        /* set the comb notch = 1 */
@@ -176,12 +226,23 @@ static void cx18_av_initialize(struct cx18 *cx)
        /* EncSetSignalStd(dwDevNum, pEnc->dwSigStd); */
        /* EncSetVideoInput(dwDevNum, pEnc->VidIndSelection); */
 
-       v = cx18_av_read4(cx, CXADEC_AFE_CTRL);
-       v &= 0xFFFBFFFF;            /* turn OFF bit 18 for droop_comp_ch1 */
-       v &= 0xFFFF7FFF;            /* turn OFF bit 9 for clamp_sel_ch1 */
-       v &= 0xFFFFFFFE;            /* turn OFF bit 0 for 12db_ch1 */
-       /* v |= 0x00000001;*/            /* turn ON bit 0 for 12db_ch1 */
-       cx18_av_write4(cx, CXADEC_AFE_CTRL, v);
+       /*
+        * Analog Front End (AFE)
+        * Default to luma on ch1/ADC1, chroma on ch2/ADC2, SIF on ch3/ADC2
+        *  bypass_ch[1-3]     use filter
+        *  droop_comp_ch[1-3] disable
+        *  clamp_en_ch[1-3]   disable
+        *  aud_in_sel         ADC2
+        *  luma_in_sel        ADC1
+        *  chroma_in_sel      ADC2
+        *  clamp_sel_ch[2-3]  midcode
+        *  clamp_sel_ch1      video decoder
+        *  vga_sel_ch3        audio decoder
+        *  vga_sel_ch[1-2]    video decoder
+        *  half_bw_ch[1-3]    disable
+        *  +12db_ch[1-3]      disable
+        */
+       cx18_av_and_or4(cx, CXADEC_AFE_CTRL, 0xFF000000, 0x00005D00);
 
 /*     if(dwEnable && dw3DCombAvailable) { */
 /*             CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x7728021F); */
@@ -195,50 +256,18 @@ static void cx18_av_initialize(struct cx18 *cx)
 
 static int cx18_av_reset(struct v4l2_subdev *sd, u32 val)
 {
-       struct cx18 *cx = v4l2_get_subdevdata(sd);
-
-       cx18_av_initialize(cx);
-       return 0;
-}
-
-static int cx18_av_init(struct v4l2_subdev *sd, u32 val)
-{
-       struct cx18 *cx = v4l2_get_subdevdata(sd);
-
-       /*
-        * The crystal freq used in calculations in this driver will be
-        * 28.636360 MHz.
-        * Aim to run the PLLs' VCOs near 400 MHz to minimze errors.
-        */
-
-       /*
-        * VDCLK  Integer = 0x0f, Post Divider = 0x04
-        * AIMCLK Integer = 0x0e, Post Divider = 0x16
-        */
-       cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f);
-
-       /* VDCLK Fraction = 0x2be2fe */
-       /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */
-       cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe);
-
-       /* AIMCLK Fraction = 0x05227ad */
-       /* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz pre post-div*/
-       cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad);
-
-       /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */
-       cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56);
+       cx18_av_initialize(sd);
        return 0;
 }
 
 static int cx18_av_load_fw(struct v4l2_subdev *sd)
 {
        struct cx18_av_state *state = to_cx18_av_state(sd);
-       struct cx18 *cx = v4l2_get_subdevdata(sd);
 
        if (!state->is_initialized) {
                /* initialize on first use */
                state->is_initialized = 1;
-               cx18_av_initialize(cx);
+               cx18_av_initialize(sd);
        }
        return 0;
 }
@@ -248,8 +277,15 @@ void cx18_av_std_setup(struct cx18 *cx)
        struct cx18_av_state *state = &cx->av_state;
        struct v4l2_subdev *sd = &state->sd;
        v4l2_std_id std = state->std;
+
+       /*
+        * Video ADC crystal clock to pixel clock SRC decimation ratio
+        * 28.636360 MHz/13.5 Mpps * 256 = 0x21f.07b
+        */
+       const int src_decimation = 0x21f;
+
        int hblank, hactive, burst, vblank, vactive, sc;
-       int vblank656, src_decimation;
+       int vblank656;
        int luma_lpf, uv_lpf, comb;
        u32 pll_int, pll_frac, pll_post;
 
@@ -259,40 +295,96 @@ void cx18_av_std_setup(struct cx18 *cx)
        else
                cx18_av_write(cx, 0x49f, 0x14);
 
+       /*
+        * Note: At the end of a field, there are 3 sets of half line duration
+        * (double horizontal rate) pulses:
+        *
+        * 5 (625) or 6 (525) half-lines to blank for the vertical retrace
+        * 5 (625) or 6 (525) vertical sync pulses of half line duration
+        * 5 (625) or 6 (525) half-lines of equalization pulses
+        */
        if (std & V4L2_STD_625_50) {
-               /* FIXME - revisit these for Sliced VBI */
+               /*
+                * The following relationships of half line counts should hold:
+                * 625 = vblank656 + vactive
+                * 10 = vblank656 - vblank = vsync pulses + equalization pulses
+                *
+                * vblank656: half lines after line 625/mid-313 of blanked video
+                * vblank:    half lines, after line 5/317, of blanked video
+                * vactive:   half lines of active video +
+                *              5 half lines after the end of active video
+                *
+                * As far as I can tell:
+                * vblank656 starts counting from the falling edge of the first
+                *      vsync pulse (start of line 1 or mid-313)
+                * vblank starts counting from the after the 5 vsync pulses and
+                *      5 or 4 equalization pulses (start of line 6 or 318)
+                *
+                * For 625 line systems the driver will extract VBI information
+                * from lines 6-23 and lines 318-335 (but the slicer can only
+                * handle 17 lines, not the 18 in the vblank region).
+                * In addition, we need vblank656 and vblank to be one whole
+                * line longer, to cover line 24 and 336, so the SAV/EAV RP
+                * codes get generated such that the encoder can actually
+                * extract line 23 & 335 (WSS).  We'll lose 1 line in each field
+                * at the top of the screen.
+                *
+                * It appears the 5 half lines that happen after active
+                * video must be included in vactive (579 instead of 574),
+                * otherwise the colors get badly displayed in various regions
+                * of the screen.  I guess the chroma comb filter gets confused
+                * without them (at least when a PVR-350 is the PAL source).
+                */
+               vblank656 = 48; /* lines  1 -  24  &  313 - 336 */
+               vblank = 38;    /* lines  6 -  24  &  318 - 336 */
+               vactive = 579;  /* lines 24 - 313  &  337 - 626 */
+
+               /*
+                * For a 13.5 Mpps clock and 15,625 Hz line rate, a line is
+                * is 864 pixels = 720 active + 144 blanking.  ITU-R BT.601
+                * specifies 12 luma clock periods or ~ 0.9 * 13.5 Mpps after
+                * the end of active video to start a horizontal line, so that
+                * leaves 132 pixels of hblank to ignore.
+                */
                hblank = 132;
                hactive = 720;
-               burst = 93;
-               vblank = 36;
-               vactive = 580;
-               vblank656 = 40;
-               src_decimation = 0x21f;
 
+               /*
+                * Burst gate delay (for 625 line systems)
+                * Hsync leading edge to color burst rise = 5.6 us
+                * Color burst width = 2.25 us
+                * Gate width = 4 pixel clocks
+                * (5.6 us + 2.25/2 us) * 13.5 Mpps + 4/2 clocks = 92.79 clocks
+                */
+               burst = 93;
                luma_lpf = 2;
                if (std & V4L2_STD_PAL) {
                        uv_lpf = 1;
                        comb = 0x20;
-                       sc = 688739;
+                       /* sc = 4433618.75 * src_decimation/28636360 * 2^13 */
+                       sc = 688700;
                } else if (std == V4L2_STD_PAL_Nc) {
                        uv_lpf = 1;
                        comb = 0x20;
-                       sc = 556453;
+                       /* sc = 3582056.25 * src_decimation/28636360 * 2^13 */
+                       sc = 556422;
                } else { /* SECAM */
                        uv_lpf = 0;
                        comb = 0;
-                       sc = 672351;
+                       /* (fr + fb)/2 = (4406260 + 4250000)/2 = 4328130 */
+                       /* sc = 4328130 * src_decimation/28636360 * 2^13 */
+                       sc = 672314;
                }
        } else {
                /*
                 * The following relationships of half line counts should hold:
-                * 525 = vsync + vactive + vblank656
-                * 12 = vblank656 - vblank
+                * 525 = prevsync + vblank656 + vactive
+                * 12 = vblank656 - vblank = vsync pulses + equalization pulses
                 *
-                * vsync:     always 6 half-lines of vsync pulses
-                * vactive:   half lines of active video
+                * prevsync:  6 half-lines before the vsync pulses
                 * vblank656: half lines, after line 3/mid-266, of blanked video
                 * vblank:    half lines, after line 9/272, of blanked video
+                * vactive:   half lines of active video
                 *
                 * As far as I can tell:
                 * vblank656 starts counting from the falling edge of the first
@@ -319,20 +411,30 @@ void cx18_av_std_setup(struct cx18 *cx)
                luma_lpf = 1;
                uv_lpf = 1;
 
-               src_decimation = 0x21f;
+               /*
+                * Burst gate delay (for 525 line systems)
+                * Hsync leading edge to color burst rise = 5.3 us
+                * Color burst width = 2.5 us
+                * Gate width = 4 pixel clocks
+                * (5.3 us + 2.5/2 us) * 13.5 Mpps + 4/2 clocks = 90.425 clocks
+                */
                if (std == V4L2_STD_PAL_60) {
-                       burst = 0x5b;
+                       burst = 90;
                        luma_lpf = 2;
                        comb = 0x20;
-                       sc = 688739;
+                       /* sc = 4433618.75 * src_decimation/28636360 * 2^13 */
+                       sc = 688700;
                } else if (std == V4L2_STD_PAL_M) {
-                       burst = 0x61;
+                       /* The 97 needs to be verified against PAL-M timings */
+                       burst = 97;
                        comb = 0x20;
-                       sc = 555452;
+                       /* sc = 3575611.49 * src_decimation/28636360 * 2^13 */
+                       sc = 555421;
                } else {
-                       burst = 0x5b;
+                       burst = 90;
                        comb = 0x66;
-                       sc = 556063;
+                       /* sc = 3579545.45.. * src_decimation/28636360 * 2^13 */
+                       sc = 556032;
                }
        }
 
@@ -344,23 +446,26 @@ void cx18_av_std_setup(struct cx18 *cx)
                            pll_int, pll_frac, pll_post);
 
        if (pll_post) {
-               int fin, fsc, pll;
+               int fsc, pll;
+               u64 tmp;
 
                pll = (28636360L * ((((u64)pll_int) << 25) + pll_frac)) >> 25;
                pll /= pll_post;
-               CX18_DEBUG_INFO_DEV(sd, "PLL = %d.%06d MHz\n",
+               CX18_DEBUG_INFO_DEV(sd, "Video PLL = %d.%06d MHz\n",
                                    pll / 1000000, pll % 1000000);
-               CX18_DEBUG_INFO_DEV(sd, "PLL/8 = %d.%06d MHz\n",
+               CX18_DEBUG_INFO_DEV(sd, "Pixel rate = %d.%06d Mpixel/sec\n",
                                    pll / 8000000, (pll / 8) % 1000000);
 
-               fin = ((u64)src_decimation * pll) >> 12;
-               CX18_DEBUG_INFO_DEV(sd, "ADC Sampling freq = %d.%06d MHz\n",
-                                   fin / 1000000, fin % 1000000);
+               CX18_DEBUG_INFO_DEV(sd, "ADC XTAL/pixel clock decimation ratio "
+                                   "= %d.%03d\n", src_decimation / 256,
+                                   ((src_decimation % 256) * 1000) / 256);
 
-               fsc = (((u64)sc) * pll) >> 24L;
+               tmp = 28636360 * (u64) sc;
+               do_div(tmp, src_decimation);
+               fsc = tmp >> 13;
                CX18_DEBUG_INFO_DEV(sd,
-                                   "Chroma sub-carrier freq = %d.%06d MHz\n",
-                                   fsc / 1000000, fsc % 1000000);
+                                   "Chroma sub-carrier initial freq = %d.%06d "
+                                   "MHz\n", fsc / 1000000, fsc % 1000000);
 
                CX18_DEBUG_INFO_DEV(sd, "hblank %i, hactive %i, vblank %i, "
                                    "vactive %i, vblank656 %i, src_dec %i, "
@@ -470,16 +575,23 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
 {
        struct cx18_av_state *state = &cx->av_state;
        struct v4l2_subdev *sd = &state->sd;
-       u8 is_composite = (vid_input >= CX18_AV_COMPOSITE1 &&
-                          vid_input <= CX18_AV_COMPOSITE8);
-       u8 reg;
-       u8 v;
+
+       enum analog_signal_type {
+               NONE, CVBS, Y, C, SIF, Pb, Pr
+       } ch[3] = {NONE, NONE, NONE};
+
+       u8 afe_mux_cfg;
+       u8 adc2_cfg;
+       u32 afe_cfg;
+       int i;
 
        CX18_DEBUG_INFO_DEV(sd, "decoder set video input %d, audio input %d\n",
                            vid_input, aud_input);
 
-       if (is_composite) {
-               reg = 0xf0 + (vid_input - CX18_AV_COMPOSITE1);
+       if (vid_input >= CX18_AV_COMPOSITE1 &&
+           vid_input <= CX18_AV_COMPOSITE8) {
+               afe_mux_cfg = 0xf0 + (vid_input - CX18_AV_COMPOSITE1);
+               ch[0] = CVBS;
        } else {
                int luma = vid_input & 0xf0;
                int chroma = vid_input & 0xf00;
@@ -493,26 +605,45 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
                                     vid_input);
                        return -EINVAL;
                }
-               reg = 0xf0 + ((luma - CX18_AV_SVIDEO_LUMA1) >> 4);
+               afe_mux_cfg = 0xf0 + ((luma - CX18_AV_SVIDEO_LUMA1) >> 4);
+               ch[0] = Y;
                if (chroma >= CX18_AV_SVIDEO_CHROMA7) {
-                       reg &= 0x3f;
-                       reg |= (chroma - CX18_AV_SVIDEO_CHROMA7) >> 2;
+                       afe_mux_cfg &= 0x3f;
+                       afe_mux_cfg |= (chroma - CX18_AV_SVIDEO_CHROMA7) >> 2;
+                       ch[2] = C;
                } else {
-                       reg &= 0xcf;
-                       reg |= (chroma - CX18_AV_SVIDEO_CHROMA4) >> 4;
+                       afe_mux_cfg &= 0xcf;
+                       afe_mux_cfg |= (chroma - CX18_AV_SVIDEO_CHROMA4) >> 4;
+                       ch[1] = C;
                }
        }
+       /* TODO: LeadTek WinFast DVR3100 H & WinFast PVR2100 can do Y/Pb/Pr */
 
        switch (aud_input) {
        case CX18_AV_AUDIO_SERIAL1:
        case CX18_AV_AUDIO_SERIAL2:
                /* do nothing, use serial audio input */
                break;
-       case CX18_AV_AUDIO4: reg &= ~0x30; break;
-       case CX18_AV_AUDIO5: reg &= ~0x30; reg |= 0x10; break;
-       case CX18_AV_AUDIO6: reg &= ~0x30; reg |= 0x20; break;
-       case CX18_AV_AUDIO7: reg &= ~0xc0; break;
-       case CX18_AV_AUDIO8: reg &= ~0xc0; reg |= 0x40; break;
+       case CX18_AV_AUDIO4:
+               afe_mux_cfg &= ~0x30;
+               ch[1] = SIF;
+               break;
+       case CX18_AV_AUDIO5:
+               afe_mux_cfg = (afe_mux_cfg & ~0x30) | 0x10;
+               ch[1] = SIF;
+               break;
+       case CX18_AV_AUDIO6:
+               afe_mux_cfg = (afe_mux_cfg & ~0x30) | 0x20;
+               ch[1] = SIF;
+               break;
+       case CX18_AV_AUDIO7:
+               afe_mux_cfg &= ~0xc0;
+               ch[2] = SIF;
+               break;
+       case CX18_AV_AUDIO8:
+               afe_mux_cfg = (afe_mux_cfg & ~0xc0) | 0x40;
+               ch[2] = SIF;
+               break;
 
        default:
                CX18_ERR_DEV(sd, "0x%04x is not a valid audio input!\n",
@@ -520,24 +651,65 @@ static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
                return -EINVAL;
        }
 
-       cx18_av_write_expect(cx, 0x103, reg, reg, 0xf7);
+       /* Set up analog front end multiplexers */
+       cx18_av_write_expect(cx, 0x103, afe_mux_cfg, afe_mux_cfg, 0xf7);
        /* Set INPUT_MODE to Composite (0) or S-Video (1) */
-       cx18_av_and_or(cx, 0x401, ~0x6, is_composite ? 0 : 0x02);
+       cx18_av_and_or(cx, 0x401, ~0x6, ch[0] == CVBS ? 0 : 0x02);
 
        /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
-       v = cx18_av_read(cx, 0x102);
-       if (reg & 0x80)
-               v &= ~0x2;
+       adc2_cfg = cx18_av_read(cx, 0x102);
+       if (ch[2] == NONE)
+               adc2_cfg &= ~0x2; /* No sig on CH3, set ADC2 to CH2 for input */
        else
-               v |= 0x2;
+               adc2_cfg |= 0x2;  /* Signal on CH3, set ADC2 to CH3 for input */
+
        /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
-       if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
-               v |= 0x4;
+       if (ch[1] != NONE && ch[2] != NONE)
+               adc2_cfg |= 0x4; /* Set dual mode */
        else
-               v &= ~0x4;
-       cx18_av_write_expect(cx, 0x102, v, v, 0x17);
+               adc2_cfg &= ~0x4; /* Clear dual mode */
+       cx18_av_write_expect(cx, 0x102, adc2_cfg, adc2_cfg, 0x17);
+
+       /* Configure the analog front end */
+       afe_cfg = cx18_av_read4(cx, CXADEC_AFE_CTRL);
+       afe_cfg &= 0xff000000;
+       afe_cfg |= 0x00005000; /* CHROMA_IN, AUD_IN: ADC2; LUMA_IN: ADC1 */
+       if (ch[1] != NONE && ch[2] != NONE)
+               afe_cfg |= 0x00000030; /* half_bw_ch[2-3] since in dual mode */
+
+       for (i = 0; i < 3; i++) {
+               switch (ch[i]) {
+               default:
+               case NONE:
+                       /* CLAMP_SEL = Fixed to midcode clamp level */
+                       afe_cfg |= (0x00000200 << i);
+                       break;
+               case CVBS:
+               case Y:
+                       if (i > 0)
+                               afe_cfg |= 0x00002000; /* LUMA_IN_SEL: ADC2 */
+                       break;
+               case C:
+               case Pb:
+               case Pr:
+                       /* CLAMP_SEL = Fixed to midcode clamp level */
+                       afe_cfg |= (0x00000200 << i);
+                       if (i == 0 && ch[i] == C)
+                               afe_cfg &= ~0x00001000; /* CHROMA_IN_SEL ADC1 */
+                       break;
+               case SIF:
+                       /*
+                        * VGA_GAIN_SEL = Audio Decoder
+                        * CLAMP_SEL = Fixed to midcode clamp level
+                        */
+                       afe_cfg |= (0x00000240 << i);
+                       if (i == 0)
+                               afe_cfg &= ~0x00004000; /* AUD_IN_SEL ADC1 */
+                       break;
+               }
+       }
 
-       /*cx18_av_and_or4(cx, 0x104, ~0x001b4180, 0x00004180);*/
+       cx18_av_write4(cx, CXADEC_AFE_CTRL, afe_cfg);
 
        state->vid_input = vid_input;
        state->aud_input = aud_input;
@@ -858,9 +1030,9 @@ static int cx18_av_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
                 * cx18_av_std_setup(), above standard values:
                 *
                 * 480 + 1 for 60 Hz systems
-                * 576 + 4 for 50 Hz systems
+                * 576 + 3 for 50 Hz systems
                 */
-               Vlines = pix->height + (is_50Hz ? 4 : 1);
+               Vlines = pix->height + (is_50Hz ? 3 : 1);
 
                /*
                 * Invalid height and width scaling requests are:
index 49a55cc8d839af13bbbe3dca43c06dd70a443220..b9e8cc5d264a4ec12a45ab9bd0fd29bb6b386380 100644 (file)
 #include "cx18-io.h"
 #include <linux/firmware.h>
 
-#define CX18_AUDIO_ENABLE 0xc72014
+#define CX18_AUDIO_ENABLE    0xc72014
+#define CX18_AI1_MUX_MASK    0x30
+#define CX18_AI1_MUX_I2S1    0x00
+#define CX18_AI1_MUX_I2S2    0x10
+#define CX18_AI1_MUX_843_I2S 0x20
+#define CX18_AI1_MUX_INVALID 0x30
+
 #define FWFILE "v4l-cx23418-dig.fw"
 
+static int cx18_av_verifyfw(struct cx18 *cx, const struct firmware *fw)
+{
+       struct v4l2_subdev *sd = &cx->av_state.sd;
+       int ret = 0;
+       const u8 *data;
+       u32 size;
+       int addr;
+       u32 expected, dl_control;
+
+       /* Ensure we put the 8051 in reset and enable firmware upload mode */
+       dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
+       do {
+               dl_control &= 0x00ffffff;
+               dl_control |= 0x0f000000;
+               cx18_av_write4_noretry(cx, CXADEC_DL_CTL, dl_control);
+               dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
+       } while ((dl_control & 0xff000000) != 0x0f000000);
+
+       /* Read and auto increment until at address 0x0000 */
+       while (dl_control & 0x3fff)
+               dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
+
+       data = fw->data;
+       size = fw->size;
+       for (addr = 0; addr < size; addr++) {
+               dl_control &= 0xffff3fff; /* ignore top 2 bits of address */
+               expected = 0x0f000000 | ((u32)data[addr] << 16) | addr;
+               if (expected != dl_control) {
+                       CX18_ERR_DEV(sd, "verification of %s firmware load "
+                                    "failed: expected %#010x got %#010x\n",
+                                    FWFILE, expected, dl_control);
+                       ret = -EIO;
+                       break;
+               }
+               dl_control = cx18_av_read4(cx, CXADEC_DL_CTL);
+       }
+       if (ret == 0)
+               CX18_INFO_DEV(sd, "verified load of %s firmware (%d bytes)\n",
+                             FWFILE, size);
+       return ret;
+}
+
 int cx18_av_loadfw(struct cx18 *cx)
 {
        struct v4l2_subdev *sd = &cx->av_state.sd;
        const struct firmware *fw = NULL;
        u32 size;
-       u32 v;
+       u32 u, v;
        const u8 *ptr;
        int i;
        int retries1 = 0;
@@ -95,6 +143,12 @@ int cx18_av_loadfw(struct cx18 *cx)
        }
 
        cx18_av_write4_expect(cx, CXADEC_DL_CTL,
+                               0x03000000 | fw->size, 0x03000000, 0x13000000);
+
+       CX18_INFO_DEV(sd, "loaded %s firmware (%d bytes)\n", FWFILE, size);
+
+       if (cx18_av_verifyfw(cx, fw) == 0)
+               cx18_av_write4_expect(cx, CXADEC_DL_CTL,
                                0x13000000 | fw->size, 0x13000000, 0x13000000);
 
        /* Output to the 416 */
@@ -135,6 +189,28 @@ int cx18_av_loadfw(struct cx18 *cx)
                cx18_write_reg_expect(cx, v & 0xFFFFFBFF, CX18_AUDIO_ENABLE,
                                      0, 0x400);
 
+       /* Toggle the AI1 MUX */
+       v = cx18_read_reg(cx, CX18_AUDIO_ENABLE);
+       u = v & CX18_AI1_MUX_MASK;
+       v &= ~CX18_AI1_MUX_MASK;
+       if (u == CX18_AI1_MUX_843_I2S || u == CX18_AI1_MUX_INVALID) {
+               /* Switch to I2S1 */
+               v |= CX18_AI1_MUX_I2S1;
+               cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
+                                     v, CX18_AI1_MUX_MASK);
+               /* Switch back to the A/V decoder core I2S output */
+               v = (v & ~CX18_AI1_MUX_MASK) | CX18_AI1_MUX_843_I2S;
+       } else {
+               /* Switch to the A/V decoder core I2S output */
+               v |= CX18_AI1_MUX_843_I2S;
+               cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
+                                     v, CX18_AI1_MUX_MASK);
+               /* Switch back to I2S1 or I2S2 */
+               v = (v & ~CX18_AI1_MUX_MASK) | u;
+       }
+       cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE,
+                             v, CX18_AI1_MUX_MASK);
+
        /* Enable WW auto audio standard detection */
        v = cx18_av_read4(cx, CXADEC_STD_DET_CTL);
        v |= 0xFF;   /* Auto by default */
@@ -143,7 +219,5 @@ int cx18_av_loadfw(struct cx18 *cx)
        cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, v, v, 0x3F00FFFF);
 
        release_firmware(fw);
-
-       CX18_INFO_DEV(sd, "loaded %s firmware (%d bytes)\n", FWFILE, size);
        return 0;
 }
index 23b31670bf1dbc9143028ac2b68b78a1fb6844a1..a51732bcca4b61343c09f4397c17f75f64243c97 100644 (file)
@@ -255,8 +255,8 @@ int cx18_av_vbi_s_fmt(struct cx18 *cx, struct v4l2_format *fmt)
        }
 
        cx18_av_write(cx, 0x43c, 0x16);
-       /* FIXME - should match vblank set in cx18_av_std_setup() */
-       cx18_av_write(cx, 0x474, is_pal ? 0x2a : 26);
+       /* Should match vblank set in cx18_av_std_setup() */
+       cx18_av_write(cx, 0x474, is_pal ? 38 : 26);
        return 0;
 }
 
index 9bc221837847675b1643c8b38459acedb1303483..c92a25036f0e291768a131ceff4b349b59dd34cd 100644 (file)
@@ -340,13 +340,12 @@ static const struct cx18_card cx18_card_toshiba_qosmio_dvbt = {
 
 static const struct cx18_card_pci_info cx18_pci_leadtek_pvr2100[] = {
        { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6f27 }, /* PVR2100   */
-       { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6690 }, /* DVR3100 H */
        { 0, 0, 0 }
 };
 
 static const struct cx18_card cx18_card_leadtek_pvr2100 = {
        .type = CX18_CARD_LEADTEK_PVR2100,
-       .name = "Leadtek WinFast PVR2100/DVR3100 H",
+       .name = "Leadtek WinFast PVR2100",
        .comment = "Experimenters and photos needed for device to work well.\n"
                  "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n",
        .v4l2_capabilities = CX18_CAP_ENCODER,
@@ -365,15 +364,12 @@ static const struct cx18_card cx18_card_leadtek_pvr2100 = {
                { CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL1, 1 },
        },
        .tuners = {
-               /* XC3028 tuner */
+               /* XC2028 tuner */
                { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
        },
        .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 },
        .ddr = {
-               /*
-                * Pointer to proper DDR config values provided by
-                * Terry Wu <terrywu at leadtek.com.tw>
-                */
+               /* Pointer to proper DDR config values provided by Terry Wu */
                .chip_config = 0x303,
                .refresh = 0x3bb,
                .timing1 = 0x24220e83,
@@ -392,6 +388,58 @@ static const struct cx18_card cx18_card_leadtek_pvr2100 = {
 
 /* ------------------------------------------------------------------------- */
 
+/* Leadtek WinFast DVR3100 H */
+
+static const struct cx18_card_pci_info cx18_pci_leadtek_dvr3100h[] = {
+       { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6690 }, /* DVR3100 H */
+       { 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_leadtek_dvr3100h = {
+       .type = CX18_CARD_LEADTEK_DVR3100H,
+       .name = "Leadtek WinFast DVR3100 H",
+       .comment = "Simultaneous DVB-T and Analog capture supported,\n"
+                 "\texcept when capturing Analog from the antenna input.\n",
+       .v4l2_capabilities = CX18_CAP_ENCODER,
+       .hw_audio_ctrl = CX18_HW_418_AV,
+       .hw_muxer = CX18_HW_GPIO_MUX,
+       .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_MUX |
+                 CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
+       .video_inputs = {
+               { CX18_CARD_INPUT_VID_TUNER,  0, CX18_AV_COMPOSITE2 },
+               { CX18_CARD_INPUT_SVIDEO1,    1,
+                       CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+               { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE7 },
+       },
+       .audio_inputs = {
+               { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5,        0 },
+               { CX18_CARD_INPUT_LINE_IN1,  CX18_AV_AUDIO_SERIAL1, 1 },
+       },
+       .tuners = {
+               /* XC3028 tuner */
+               { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+       },
+       .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 },
+       .ddr = {
+               /* Pointer to proper DDR config values provided by Terry Wu */
+               .chip_config = 0x303,
+               .refresh = 0x3bb,
+               .timing1 = 0x24220e83,
+               .timing2 = 0x1f,
+               .tune_lane = 0,
+               .initial_emrs = 0x2,
+       },
+       .gpio_init.initial_value = 0x6,
+       .gpio_init.direction = 0x7,
+       .gpio_audio_input = { .mask   = 0x7,
+                             .tuner  = 0x6, .linein = 0x2, .radio  = 0x2 },
+       .xceive_pin = 1,
+       .pci_list = cx18_pci_leadtek_dvr3100h,
+       .i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
 static const struct cx18_card *cx18_card_list[] = {
        &cx18_card_hvr1600_esmt,
        &cx18_card_hvr1600_samsung,
@@ -400,6 +448,7 @@ static const struct cx18_card *cx18_card_list[] = {
        &cx18_card_cnxt_raptor_pal,
        &cx18_card_toshiba_qosmio_dvbt,
        &cx18_card_leadtek_pvr2100,
+       &cx18_card_leadtek_dvr3100h,
 };
 
 const struct cx18_card *cx18_get_card(u16 index)
index 82fc2f9d40219d3ff0075239597553a8909d930b..8e35c3aed544a3f9a1e0479b6334fac4363488ba 100644 (file)
@@ -176,8 +176,10 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx,
                return -EBUSY;
 
        if (fmt != V4L2_MPEG_STREAM_VBI_FMT_IVTV ||
-           type != V4L2_MPEG_STREAM_TYPE_MPEG2_PS) {
-               /* We don't do VBI insertion aside from IVTV format in a PS */
+           !(type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS ||
+             type == V4L2_MPEG_STREAM_TYPE_MPEG2_DVD ||
+             type == V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD)) {
+               /* Only IVTV fmt VBI insertion & only MPEG-2 PS type streams */
                cx->vbi.insert_mpeg = V4L2_MPEG_STREAM_VBI_FMT_NONE;
                CX18_DEBUG_INFO("disabled insertion of sliced VBI data into "
                                "the MPEG stream\n");
index 49b1c3d7b1a81ab264a5fe3503f06b1158f76980..92026e82e10ef0349b8ac2bdbdf88d4c9aad30f8 100644 (file)
@@ -30,6 +30,7 @@
 #include "cx18-irq.h"
 #include "cx18-gpio.h"
 #include "cx18-firmware.h"
+#include "cx18-queue.h"
 #include "cx18-streams.h"
 #include "cx18-av-core.h"
 #include "cx18-scb.h"
@@ -151,7 +152,8 @@ MODULE_PARM_DESC(cardtype,
                 "\t\t\t 4 = Yuan MPC718\n"
                 "\t\t\t 5 = Conexant Raptor PAL/SECAM\n"
                 "\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n"
-                "\t\t\t 7 = Leadtek WinFast PVR2100/DVR3100 H\n"
+                "\t\t\t 7 = Leadtek WinFast PVR2100\n"
+                "\t\t\t 8 = Leadtek WinFast DVR3100 H\n"
                 "\t\t\t 0 = Autodetect (default)\n"
                 "\t\t\t-1 = Ignore this card\n\t\t");
 MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
@@ -312,7 +314,7 @@ static void cx18_process_eeprom(struct cx18 *cx)
        CX18_INFO("Autodetected %s\n", cx->card_name);
 
        if (tv.tuner_type == TUNER_ABSENT)
-               CX18_ERR("tveeprom cannot autodetect tuner!");
+               CX18_ERR("tveeprom cannot autodetect tuner!\n");
 
        if (cx->options.tuner == -1)
                cx->options.tuner = tv.tuner_type;
@@ -546,6 +548,40 @@ done:
        cx->card_i2c = cx->card->i2c;
 }
 
+static int __devinit cx18_create_in_workq(struct cx18 *cx)
+{
+       snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in",
+                cx->v4l2_dev.name);
+       cx->in_work_queue = create_singlethread_workqueue(cx->in_workq_name);
+       if (cx->in_work_queue == NULL) {
+               CX18_ERR("Unable to create incoming mailbox handler thread\n");
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static int __devinit cx18_create_out_workq(struct cx18 *cx)
+{
+       snprintf(cx->out_workq_name, sizeof(cx->out_workq_name), "%s-out",
+                cx->v4l2_dev.name);
+       cx->out_work_queue = create_workqueue(cx->out_workq_name);
+       if (cx->out_work_queue == NULL) {
+               CX18_ERR("Unable to create outgoing mailbox handler threads\n");
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static void __devinit cx18_init_in_work_orders(struct cx18 *cx)
+{
+       int i;
+       for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) {
+               cx->in_work_order[i].cx = cx;
+               cx->in_work_order[i].str = cx->epu_debug_str;
+               INIT_WORK(&cx->in_work_order[i].work, cx18_in_work_handler);
+       }
+}
+
 /* Precondition: the cx18 structure has been memset to 0. Only
    the dev and instance fields have been filled in.
    No assumptions on the card type may be made here (see cx18_init_struct2
@@ -553,7 +589,7 @@ done:
  */
 static int __devinit cx18_init_struct1(struct cx18 *cx)
 {
-       int i;
+       int ret;
 
        cx->base_addr = pci_resource_start(cx->pci_dev, 0);
 
@@ -562,18 +598,18 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
        mutex_init(&cx->epu2apu_mb_lock);
        mutex_init(&cx->epu2cpu_mb_lock);
 
-       cx->work_queue = create_singlethread_workqueue(cx->v4l2_dev.name);
-       if (cx->work_queue == NULL) {
-               CX18_ERR("Unable to create work hander thread\n");
-               return -ENOMEM;
-       }
+       ret = cx18_create_out_workq(cx);
+       if (ret)
+               return ret;
 
-       for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++) {
-               cx->epu_work_order[i].cx = cx;
-               cx->epu_work_order[i].str = cx->epu_debug_str;
-               INIT_WORK(&cx->epu_work_order[i].work, cx18_epu_work_handler);
+       ret = cx18_create_in_workq(cx);
+       if (ret) {
+               destroy_workqueue(cx->out_work_queue);
+               return ret;
        }
 
+       cx18_init_in_work_orders(cx);
+
        /* start counting open_id at 1 */
        cx->open_id = 1;
 
@@ -759,17 +795,17 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
                retval = -ENODEV;
                goto err;
        }
-       if (cx18_init_struct1(cx)) {
-               retval = -ENOMEM;
+
+       retval = cx18_init_struct1(cx);
+       if (retval)
                goto err;
-       }
 
        CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr);
 
        /* PCI Device Setup */
        retval = cx18_setup_pci(cx, pci_dev, pci_id);
        if (retval != 0)
-               goto free_workqueue;
+               goto free_workqueues;
 
        /* map io memory */
        CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n",
@@ -943,8 +979,9 @@ free_map:
        cx18_iounmap(cx);
 free_mem:
        release_mem_region(cx->base_addr, CX18_MEM_SIZE);
-free_workqueue:
-       destroy_workqueue(cx->work_queue);
+free_workqueues:
+       destroy_workqueue(cx->in_work_queue);
+       destroy_workqueue(cx->out_work_queue);
 err:
        if (retval == 0)
                retval = -ENODEV;
@@ -1053,11 +1090,19 @@ int cx18_init_on_first_open(struct cx18 *cx)
        return 0;
 }
 
-static void cx18_cancel_epu_work_orders(struct cx18 *cx)
+static void cx18_cancel_in_work_orders(struct cx18 *cx)
 {
        int i;
-       for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++)
-               cancel_work_sync(&cx->epu_work_order[i].work);
+       for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++)
+               cancel_work_sync(&cx->in_work_order[i].work);
+}
+
+static void cx18_cancel_out_work_orders(struct cx18 *cx)
+{
+       int i;
+       for (i = 0; i < CX18_MAX_STREAMS; i++)
+               if (&cx->streams[i].video_dev != NULL)
+                       cancel_work_sync(&cx->streams[i].out_work_order);
 }
 
 static void cx18_remove(struct pci_dev *pci_dev)
@@ -1073,15 +1118,20 @@ static void cx18_remove(struct pci_dev *pci_dev)
        if (atomic_read(&cx->tot_capturing) > 0)
                cx18_stop_all_captures(cx);
 
-       /* Interrupts */
+       /* Stop interrupts that cause incoming work to be queued */
        cx18_sw1_irq_disable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
+
+       /* Incoming work can cause outgoing work, so clean up incoming first */
+       cx18_cancel_in_work_orders(cx);
+       cx18_cancel_out_work_orders(cx);
+
+       /* Stop ack interrupts that may have been needed for work to finish */
        cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
 
        cx18_halt_firmware(cx);
 
-       cx18_cancel_epu_work_orders(cx);
-
-       destroy_workqueue(cx->work_queue);
+       destroy_workqueue(cx->in_work_queue);
+       destroy_workqueue(cx->out_work_queue);
 
        cx18_streams_cleanup(cx, 1);
 
index ece4f281ef4254df1ec84b5bcc8676c316f84061..c6a1e907f63afd928ace5530d7a45857ccbd97a3 100644 (file)
@@ -80,8 +80,9 @@
 #define CX18_CARD_YUAN_MPC718        3 /* Yuan MPC718 */
 #define CX18_CARD_CNXT_RAPTOR_PAL     4        /* Conexant Raptor PAL */
 #define CX18_CARD_TOSHIBA_QOSMIO_DVBT 5 /* Toshiba Qosmio Interal DVB-T/Analog*/
-#define CX18_CARD_LEADTEK_PVR2100     6 /* Leadtek WinFast PVR2100/DVR3100 H */
-#define CX18_CARD_LAST                       6
+#define CX18_CARD_LEADTEK_PVR2100     6 /* Leadtek WinFast PVR2100 */
+#define CX18_CARD_LEADTEK_DVR3100H    7 /* Leadtek WinFast DVR3100 H */
+#define CX18_CARD_LAST                       7
 
 #define CX18_ENC_STREAM_TYPE_MPG  0
 #define CX18_ENC_STREAM_TYPE_TS   1
@@ -254,6 +255,7 @@ struct cx18_options {
 #define CX18_F_S_INTERNAL_USE  5       /* this stream is used internally (sliced VBI processing) */
 #define CX18_F_S_STREAMOFF     7       /* signal end of stream EOS */
 #define CX18_F_S_APPL_IO        8      /* this stream is used read/written by an application */
+#define CX18_F_S_STOPPING      9       /* telling the fw to stop capturing */
 
 /* per-cx18, i_flags */
 #define CX18_F_I_LOADED_FW             0       /* Loaded firmware 1st time */
@@ -285,6 +287,7 @@ struct cx18_queue {
        struct list_head list;
        atomic_t buffers;
        u32 bytesused;
+       spinlock_t lock;
 };
 
 struct cx18_dvb {
@@ -305,7 +308,7 @@ struct cx18_scb; /* forward reference */
 
 
 #define CX18_MAX_MDL_ACKS 2
-#define CX18_MAX_EPU_WORK_ORDERS (CX18_MAX_FW_MDLS_PER_STREAM + 7)
+#define CX18_MAX_IN_WORK_ORDERS (CX18_MAX_FW_MDLS_PER_STREAM + 7)
 /* CPU_DE_RELEASE_MDL can burst CX18_MAX_FW_MDLS_PER_STREAM orders in a group */
 
 #define CX18_F_EWO_MB_STALE_UPON_RECEIPT 0x1
@@ -313,7 +316,7 @@ struct cx18_scb; /* forward reference */
 #define CX18_F_EWO_MB_STALE \
             (CX18_F_EWO_MB_STALE_UPON_RECEIPT | CX18_F_EWO_MB_STALE_WHILE_PROC)
 
-struct cx18_epu_work_order {
+struct cx18_in_work_order {
        struct work_struct work;
        atomic_t pending;
        struct cx18 *cx;
@@ -337,7 +340,6 @@ struct cx18_stream {
        unsigned mdl_offset;
 
        u32 id;
-       struct mutex qlock;     /* locks access to the queues */
        unsigned long s_flags;  /* status flags, see above */
        int dma;                /* can be PCI_DMA_TODEVICE,
                                   PCI_DMA_FROMDEVICE or
@@ -353,6 +355,8 @@ struct cx18_stream {
        struct cx18_queue q_busy;       /* busy buffers - in use by firmware */
        struct cx18_queue q_full;       /* full buffers - data for user apps */
 
+       struct work_struct out_work_order;
+
        /* DVB / Digital Transport */
        struct cx18_dvb dvb;
 };
@@ -568,10 +572,14 @@ struct cx18 {
        u32 sw2_irq_mask;
        u32 hw2_irq_mask;
 
-       struct workqueue_struct *work_queue;
-       struct cx18_epu_work_order epu_work_order[CX18_MAX_EPU_WORK_ORDERS];
+       struct workqueue_struct *in_work_queue;
+       char in_workq_name[11]; /* "cx18-NN-in" */
+       struct cx18_in_work_order in_work_order[CX18_MAX_IN_WORK_ORDERS];
        char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */
 
+       struct workqueue_struct *out_work_queue;
+       char out_workq_name[12]; /* "cx18-NN-out" */
+
        /* i2c */
        struct i2c_adapter i2c_adap[2];
        struct i2c_algo_bit_data i2c_algo[2];
index 3b86f57cd15af5148aa4ec0d1284c21218fdf6b9..6ea3fe623ef49470d9a900197f41a3768f440596 100644 (file)
 #include "cx18-version.h"
 #include "cx18-dvb.h"
 #include "cx18-io.h"
+#include "cx18-queue.h"
 #include "cx18-streams.h"
 #include "cx18-cards.h"
+#include "cx18-gpio.h"
 #include "s5h1409.h"
 #include "mxl5005s.h"
+#include "zl10353.h"
+#include "tuner-xc2028.h"
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 #define CX18_REG_DMUX_NUM_PORT_0_CONTROL 0xd5a000
+#define CX18_CLOCK_ENABLE2              0xc71024
+#define CX18_DMUX_CLK_MASK              0x0080
 
 static struct mxl5005s_config hauppauge_hvr1600_tuner = {
        .i2c_address     = 0xC6 >> 1,
@@ -57,7 +63,15 @@ static struct s5h1409_config hauppauge_hvr1600_config = {
        .inversion     = S5H1409_INVERSION_OFF,
        .status_mode   = S5H1409_DEMODLOCKING,
        .mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
+};
 
+/* Information/confirmation of proper config values provided by Terry Wu */
+static struct zl10353_config leadtek_dvr3100h_demod = {
+       .demod_address         = 0x1e >> 1, /* Datasheet suggested straps */
+       .if2                   = 45600,     /* 4.560 MHz IF from the XC3028 */
+       .parallel_ts           = 1,         /* Not a serial TS */
+       .no_tuner              = 1,         /* XC3028 is not behind the gate */
+       .disable_i2c_gate_ctrl = 1,         /* Disable the I2C gate */
 };
 
 static int dvb_register(struct cx18_stream *stream);
@@ -98,6 +112,7 @@ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
                cx18_write_reg(cx, v, CX18_REG_DMUX_NUM_PORT_0_CONTROL);
                break;
 
+       case CX18_CARD_LEADTEK_DVR3100H:
        default:
                /* Assumption - Parallel transport - Signalling
                 * undefined or default.
@@ -267,8 +282,7 @@ void cx18_dvb_unregister(struct cx18_stream *stream)
 }
 
 /* All the DVB attach calls go here, this function get's modified
- * for each new card. No other function in this file needs
- * to change.
+ * for each new card. cx18_dvb_start_feed() will also need changes.
  */
 static int dvb_register(struct cx18_stream *stream)
 {
@@ -289,6 +303,29 @@ static int dvb_register(struct cx18_stream *stream)
                        ret = 0;
                }
                break;
+       case CX18_CARD_LEADTEK_DVR3100H:
+               dvb->fe = dvb_attach(zl10353_attach,
+                                    &leadtek_dvr3100h_demod,
+                                    &cx->i2c_adap[1]);
+               if (dvb->fe != NULL) {
+                       struct dvb_frontend *fe;
+                       struct xc2028_config cfg = {
+                               .i2c_adap = &cx->i2c_adap[1],
+                               .i2c_addr = 0xc2 >> 1,
+                               .ctrl = NULL,
+                       };
+                       static struct xc2028_ctrl ctrl = {
+                               .fname   = XC2028_DEFAULT_FIRMWARE,
+                               .max_len = 64,
+                               .demod   = XC3028_FE_ZARLINK456,
+                               .type    = XC2028_AUTO,
+                       };
+
+                       fe = dvb_attach(xc2028_attach, dvb->fe, &cfg);
+                       if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+                               fe->ops.tuner_ops.set_config(fe, &ctrl);
+               }
+               break;
        default:
                /* No Digital Tv Support */
                break;
@@ -299,6 +336,8 @@ static int dvb_register(struct cx18_stream *stream)
                return -1;
        }
 
+       dvb->fe->callback = cx18_reset_tuner_gpio;
+
        ret = dvb_register_frontend(&dvb->dvb_adapter, dvb->fe);
        if (ret < 0) {
                if (dvb->fe->ops.release)
@@ -306,5 +345,16 @@ static int dvb_register(struct cx18_stream *stream)
                return ret;
        }
 
+       /*
+        * The firmware seems to enable the TS DMUX clock
+        * under various circumstances.  However, since we know we
+        * might use it, let's just turn it on ourselves here.
+        */
+       cx18_write_reg_expect(cx,
+                             (CX18_DMUX_CLK_MASK << 16) | CX18_DMUX_CLK_MASK,
+                             CX18_CLOCK_ENABLE2,
+                             CX18_DMUX_CLK_MASK,
+                             (CX18_DMUX_CLK_MASK << 16) | CX18_DMUX_CLK_MASK);
+
        return ret;
 }
index b3889c0b26974dd6c4f1806cb99d2a624464562d..29969c18949c707eb336b18badea0437ff04d54b 100644 (file)
@@ -265,8 +265,13 @@ static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
                 * an MPEG-2 Program Pack start code, and provide only
                 * up to that point to the user, so it's easy to insert VBI data
                 * the next time around.
+                *
+                * This will not work for an MPEG-2 TS and has only been
+                * verified by analysis to work for an MPEG-2 PS.  Helen Buus
+                * pointed out this works for the CX23416 MPEG-2 DVD compatible
+                * stream, and research indicates both the MPEG 2 SVCD and DVD
+                * stream types use an MPEG-2 PS container.
                 */
-               /* FIXME - This only works for an MPEG-2 PS, not a TS */
                /*
                 * An MPEG-2 Program Stream (PS) is a series of
                 * MPEG-2 Program Packs terminated by an
index 2226e5791e99412a4437ca73cd4bd7f59cd80796..afe46c3d4057acbf08bcb30af07552d619ae9aaf 100644 (file)
@@ -131,7 +131,7 @@ static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name)
  * Functions that run in a work_queue work handling context
  */
 
-static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order)
+static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order)
 {
        u32 handle, mdl_ack_count, id;
        struct cx18_mailbox *mb;
@@ -191,29 +191,30 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order)
                if (buf == NULL) {
                        CX18_WARN("Could not find buf %d for stream %s\n",
                                  id, s->name);
-                       /* Put as many buffers as possible back into fw use */
-                       cx18_stream_load_fw_queue(s);
                        continue;
                }
 
-               if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) {
-                       CX18_DEBUG_HI_DMA("TS recv bytesused = %d\n",
-                                         buf->bytesused);
-                       dvb_dmx_swfilter(&s->dvb.demux, buf->buf,
-                                        buf->bytesused);
+               CX18_DEBUG_HI_DMA("%s recv bytesused = %d\n",
+                                 s->name, buf->bytesused);
+
+               if (s->type != CX18_ENC_STREAM_TYPE_TS)
+                       cx18_enqueue(s, buf, &s->q_full);
+               else {
+                       if (s->dvb.enabled)
+                               dvb_dmx_swfilter(&s->dvb.demux, buf->buf,
+                                                buf->bytesused);
+                       cx18_enqueue(s, buf, &s->q_free);
                }
-               /* Put as many buffers as possible back into fw use */
-               cx18_stream_load_fw_queue(s);
-               /* Put back TS buffer, since it was removed from all queues */
-               if (s->type == CX18_ENC_STREAM_TYPE_TS)
-                       cx18_stream_put_buf_fw(s, buf);
        }
+       /* Put as many buffers as possible back into fw use */
+       cx18_stream_load_fw_queue(s);
+
        wake_up(&cx->dma_waitq);
        if (s->id != -1)
                wake_up(&s->waitq);
 }
 
-static void epu_debug(struct cx18 *cx, struct cx18_epu_work_order *order)
+static void epu_debug(struct cx18 *cx, struct cx18_in_work_order *order)
 {
        char *p;
        char *str = order->str;
@@ -224,7 +225,7 @@ static void epu_debug(struct cx18 *cx, struct cx18_epu_work_order *order)
                CX18_INFO("FW version: %s\n", p - 1);
 }
 
-static void epu_cmd(struct cx18 *cx, struct cx18_epu_work_order *order)
+static void epu_cmd(struct cx18 *cx, struct cx18_in_work_order *order)
 {
        switch (order->rpu) {
        case CPU:
@@ -253,18 +254,18 @@ static void epu_cmd(struct cx18 *cx, struct cx18_epu_work_order *order)
 }
 
 static
-void free_epu_work_order(struct cx18 *cx, struct cx18_epu_work_order *order)
+void free_in_work_order(struct cx18 *cx, struct cx18_in_work_order *order)
 {
        atomic_set(&order->pending, 0);
 }
 
-void cx18_epu_work_handler(struct work_struct *work)
+void cx18_in_work_handler(struct work_struct *work)
 {
-       struct cx18_epu_work_order *order =
-                       container_of(work, struct cx18_epu_work_order, work);
+       struct cx18_in_work_order *order =
+                       container_of(work, struct cx18_in_work_order, work);
        struct cx18 *cx = order->cx;
        epu_cmd(cx, order);
-       free_epu_work_order(cx, order);
+       free_in_work_order(cx, order);
 }
 
 
@@ -272,7 +273,7 @@ void cx18_epu_work_handler(struct work_struct *work)
  * Functions that run in an interrupt handling context
  */
 
-static void mb_ack_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
+static void mb_ack_irq(struct cx18 *cx, struct cx18_in_work_order *order)
 {
        struct cx18_mailbox __iomem *ack_mb;
        u32 ack_irq, req;
@@ -308,7 +309,7 @@ static void mb_ack_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
        return;
 }
 
-static int epu_dma_done_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
+static int epu_dma_done_irq(struct cx18 *cx, struct cx18_in_work_order *order)
 {
        u32 handle, mdl_ack_offset, mdl_ack_count;
        struct cx18_mailbox *mb;
@@ -334,7 +335,7 @@ static int epu_dma_done_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
 }
 
 static
-int epu_debug_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
+int epu_debug_irq(struct cx18 *cx, struct cx18_in_work_order *order)
 {
        u32 str_offset;
        char *str = order->str;
@@ -355,7 +356,7 @@ int epu_debug_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
 }
 
 static inline
-int epu_cmd_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
+int epu_cmd_irq(struct cx18 *cx, struct cx18_in_work_order *order)
 {
        int ret = -1;
 
@@ -387,12 +388,12 @@ int epu_cmd_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
 }
 
 static inline
-struct cx18_epu_work_order *alloc_epu_work_order_irq(struct cx18 *cx)
+struct cx18_in_work_order *alloc_in_work_order_irq(struct cx18 *cx)
 {
        int i;
-       struct cx18_epu_work_order *order = NULL;
+       struct cx18_in_work_order *order = NULL;
 
-       for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++) {
+       for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) {
                /*
                 * We only need "pending" atomic to inspect its contents,
                 * and need not do a check and set because:
@@ -401,8 +402,8 @@ struct cx18_epu_work_order *alloc_epu_work_order_irq(struct cx18 *cx)
                 * 2. "pending" is only set here, and we're serialized because
                 * we're called in an IRQ handler context.
                 */
-               if (atomic_read(&cx->epu_work_order[i].pending) == 0) {
-                       order = &cx->epu_work_order[i];
+               if (atomic_read(&cx->in_work_order[i].pending) == 0) {
+                       order = &cx->in_work_order[i];
                        atomic_set(&order->pending, 1);
                        break;
                }
@@ -414,7 +415,7 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu)
 {
        struct cx18_mailbox __iomem *mb;
        struct cx18_mailbox *order_mb;
-       struct cx18_epu_work_order *order;
+       struct cx18_in_work_order *order;
        int submit;
 
        switch (rpu) {
@@ -428,7 +429,7 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu)
                return;
        }
 
-       order = alloc_epu_work_order_irq(cx);
+       order = alloc_in_work_order_irq(cx);
        if (order == NULL) {
                CX18_WARN("Unable to find blank work order form to schedule "
                          "incoming mailbox command processing\n");
@@ -461,7 +462,7 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu)
         */
        submit = epu_cmd_irq(cx, order);
        if (submit > 0) {
-               queue_work(cx->work_queue, &order->work);
+               queue_work(cx->in_work_queue, &order->work);
        }
 }
 
@@ -478,9 +479,10 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
        u32 __iomem *xpu_state;
        wait_queue_head_t *waitq;
        struct mutex *mb_lock;
-       long int timeout, ret;
+       unsigned long int t0, timeout, ret;
        int i;
        char argstr[MAX_MB_ARGUMENTS*11+1];
+       DEFINE_WAIT(w);
 
        if (info == NULL) {
                CX18_WARN("unknown cmd %x\n", cmd);
@@ -562,25 +564,49 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
 
        CX18_DEBUG_HI_IRQ("sending interrupt SW1: %x to send %s\n",
                          irq, info->name);
+
+       /* So we don't miss the wakeup, prepare to wait before notifying fw */
+       prepare_to_wait(waitq, &w, TASK_UNINTERRUPTIBLE);
        cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq);
 
-       ret = wait_event_timeout(
-                      *waitq,
-                      cx18_readl(cx, &mb->ack) == cx18_readl(cx, &mb->request),
-                      timeout);
+       t0 = jiffies;
+       ack = cx18_readl(cx, &mb->ack);
+       if (ack != req) {
+               schedule_timeout(timeout);
+               ret = jiffies - t0;
+               ack = cx18_readl(cx, &mb->ack);
+       } else {
+               ret = jiffies - t0;
+       }
 
-       if (ret == 0) {
-               /* Timed out */
+       finish_wait(waitq, &w);
+
+       if (req != ack) {
                mutex_unlock(mb_lock);
-               CX18_DEBUG_WARN("sending %s timed out waiting %d msecs for RPU "
-                               "acknowledgement\n",
-                               info->name, jiffies_to_msecs(timeout));
+               if (ret >= timeout) {
+                       /* Timed out */
+                       CX18_DEBUG_WARN("sending %s timed out waiting %d msecs "
+                                       "for RPU acknowledgement\n",
+                                       info->name, jiffies_to_msecs(ret));
+               } else {
+                       CX18_DEBUG_WARN("woken up before mailbox ack was ready "
+                                       "after submitting %s to RPU.  only "
+                                       "waited %d msecs on req %u but awakened"
+                                       " with unmatched ack %u\n",
+                                       info->name,
+                                       jiffies_to_msecs(ret),
+                                       req, ack);
+               }
                return -EINVAL;
        }
 
-       if (ret != timeout)
+       if (ret >= timeout)
+               CX18_DEBUG_WARN("failed to be awakened upon RPU acknowledgment "
+                               "sending %s; timed out waiting %d msecs\n",
+                               info->name, jiffies_to_msecs(ret));
+       else
                CX18_DEBUG_HI_API("waited %u msecs for %s to be acked\n",
-                                 jiffies_to_msecs(timeout-ret), info->name);
+                                 jiffies_to_msecs(ret), info->name);
 
        /* Collect data returned by the XPU */
        for (i = 0; i < MAX_MB_ARGUMENTS; i++)
index ce2b6686aa005268363be2335ea61ba0910a001f..e23aaac5b280a58effb251af3df7a1acd6f1ec4d 100644 (file)
@@ -95,6 +95,6 @@ int cx18_api_func(void *priv, u32 cmd, int in, int out,
 
 void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu);
 
-void cx18_epu_work_handler(struct work_struct *work);
+void cx18_in_work_handler(struct work_struct *work);
 
 #endif
index 3046b8e74345081d30608af439ff09e17b3a331f..fa1ed7897d97abc8dc7c1c8bd5451220baa6a6ff 100644 (file)
@@ -23,8 +23,8 @@
  */
 
 #include "cx18-driver.h"
-#include "cx18-streams.h"
 #include "cx18-queue.h"
+#include "cx18-streams.h"
 #include "cx18-scb.h"
 
 void cx18_buf_swap(struct cx18_buffer *buf)
@@ -53,13 +53,13 @@ struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
                buf->skipped = 0;
        }
 
-       mutex_lock(&s->qlock);
-
        /* q_busy is restricted to a max buffer count imposed by firmware */
        if (q == &s->q_busy &&
            atomic_read(&q->buffers) >= CX18_MAX_FW_MDLS_PER_STREAM)
                q = &s->q_free;
 
+       spin_lock(&q->lock);
+
        if (to_front)
                list_add(&buf->list, &q->list); /* LIFO */
        else
@@ -67,7 +67,7 @@ struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
        q->bytesused += buf->bytesused - buf->readpos;
        atomic_inc(&q->buffers);
 
-       mutex_unlock(&s->qlock);
+       spin_unlock(&q->lock);
        return q;
 }
 
@@ -75,7 +75,7 @@ struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q)
 {
        struct cx18_buffer *buf = NULL;
 
-       mutex_lock(&s->qlock);
+       spin_lock(&q->lock);
        if (!list_empty(&q->list)) {
                buf = list_first_entry(&q->list, struct cx18_buffer, list);
                list_del_init(&buf->list);
@@ -83,7 +83,7 @@ struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q)
                buf->skipped = 0;
                atomic_dec(&q->buffers);
        }
-       mutex_unlock(&s->qlock);
+       spin_unlock(&q->lock);
        return buf;
 }
 
@@ -94,9 +94,23 @@ struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id,
        struct cx18_buffer *buf;
        struct cx18_buffer *tmp;
        struct cx18_buffer *ret = NULL;
-
-       mutex_lock(&s->qlock);
+       LIST_HEAD(sweep_up);
+
+       /*
+        * We don't have to acquire multiple q locks here, because we are
+        * serialized by the single threaded work handler.
+        * Buffers from the firmware will thus remain in order as
+        * they are moved from q_busy to q_full or to the dvb ring buffer.
+        */
+       spin_lock(&s->q_busy.lock);
        list_for_each_entry_safe(buf, tmp, &s->q_busy.list, list) {
+               /*
+                * We should find what the firmware told us is done,
+                * right at the front of the queue.  If we don't, we likely have
+                * missed a buffer done message from the firmware.
+                * Once we skip a buffer repeatedly, relative to the size of
+                * q_busy, we have high confidence we've missed it.
+                */
                if (buf->id != id) {
                        buf->skipped++;
                        if (buf->skipped >= atomic_read(&s->q_busy.buffers)-1) {
@@ -105,38 +119,41 @@ struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id,
                                          "times - it must have dropped out of "
                                          "rotation\n", s->name, buf->id,
                                          buf->skipped);
-                               /* move it to q_free */
-                               list_move_tail(&buf->list, &s->q_free.list);
-                               buf->bytesused = buf->readpos = buf->b_flags =
-                                       buf->skipped = 0;
+                               /* Sweep it up to put it back into rotation */
+                               list_move_tail(&buf->list, &sweep_up);
                                atomic_dec(&s->q_busy.buffers);
-                               atomic_inc(&s->q_free.buffers);
                        }
                        continue;
                }
-
-               buf->bytesused = bytesused;
-               /* Sync the buffer before we release the qlock */
-               cx18_buf_sync_for_cpu(s, buf);
-               if (s->type == CX18_ENC_STREAM_TYPE_TS) {
-                       /*
-                        * TS doesn't use q_full.  As we pull the buffer off of
-                        * the queue here, the caller will have to put it back.
-                        */
-                       list_del_init(&buf->list);
-               } else {
-                       /* Move buffer from q_busy to q_full */
-                       list_move_tail(&buf->list, &s->q_full.list);
-                       set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags);
-                       s->q_full.bytesused += buf->bytesused;
-                       atomic_inc(&s->q_full.buffers);
-               }
+               /*
+                * We pull the desired buffer off of the queue here.  Something
+                * will have to put it back on a queue later.
+                */
+               list_del_init(&buf->list);
                atomic_dec(&s->q_busy.buffers);
-
                ret = buf;
                break;
        }
-       mutex_unlock(&s->qlock);
+       spin_unlock(&s->q_busy.lock);
+
+       /*
+        * We found the buffer for which we were looking.  Get it ready for
+        * the caller to put on q_full or in the dvb ring buffer.
+        */
+       if (ret != NULL) {
+               ret->bytesused = bytesused;
+               ret->skipped = 0;
+               /* readpos and b_flags were 0'ed when the buf went on q_busy */
+               cx18_buf_sync_for_cpu(s, ret);
+               if (s->type != CX18_ENC_STREAM_TYPE_TS)
+                       set_bit(CX18_F_B_NEED_BUF_SWAP, &ret->b_flags);
+       }
+
+       /* Put any buffers the firmware is ignoring back into normal rotation */
+       list_for_each_entry_safe(buf, tmp, &sweep_up, list) {
+               list_del_init(&buf->list);
+               cx18_enqueue(s, buf, &s->q_free);
+       }
        return ret;
 }
 
@@ -148,7 +165,7 @@ static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q)
        if (q == &s->q_free)
                return;
 
-       mutex_lock(&s->qlock);
+       spin_lock(&q->lock);
        while (!list_empty(&q->list)) {
                buf = list_first_entry(&q->list, struct cx18_buffer, list);
                list_move_tail(&buf->list, &s->q_free.list);
@@ -156,7 +173,7 @@ static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q)
                atomic_inc(&s->q_free.buffers);
        }
        cx18_queue_init(q);
-       mutex_unlock(&s->qlock);
+       spin_unlock(&q->lock);
 }
 
 void cx18_flush_queues(struct cx18_stream *s)
index 0932b76b2373a76022274e5163c1976c5107191c..54d248e16d85e882d0f1d757c8111389df10b73d 100644 (file)
@@ -116,12 +116,16 @@ static void cx18_stream_init(struct cx18 *cx, int type)
        s->buffers = cx->stream_buffers[type];
        s->buf_size = cx->stream_buf_size[type];
 
-       mutex_init(&s->qlock);
        init_waitqueue_head(&s->waitq);
        s->id = -1;
+       spin_lock_init(&s->q_free.lock);
        cx18_queue_init(&s->q_free);
+       spin_lock_init(&s->q_busy.lock);
        cx18_queue_init(&s->q_busy);
+       spin_lock_init(&s->q_full.lock);
        cx18_queue_init(&s->q_full);
+
+       INIT_WORK(&s->out_work_order, cx18_out_work_handler);
 }
 
 static int cx18_prep_dev(struct cx18 *cx, int type)
@@ -367,9 +371,14 @@ static void cx18_vbi_setup(struct cx18_stream *s)
                 * Tell the encoder to capture 21-4+1=18 lines per field,
                 * since we want lines 10 through 21.
                 *
-                * FIXME - revisit for 625/50 systems
+                * For 625/50 systems, according to the VIP 2 & BT.656 std:
+                * The EAV RP code's Field bit toggles on line 1, a few lines
+                * after the Vertcal Blank bit has already toggled.
+                * (We've actually set the digitizer so that the Field bit
+                * toggles on line 2.) Tell the encoder to capture 23-2+1=22
+                * lines per field, since we want lines 6 through 23.
                 */
-               lines = cx->is_60hz ? (21 - 4 + 1) * 2 : 38;
+               lines = cx->is_60hz ? (21 - 4 + 1) * 2 : (23 - 2 + 1) * 2;
        }
 
        data[0] = s->handle;
@@ -431,14 +440,16 @@ static void cx18_vbi_setup(struct cx18_stream *s)
        cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data);
 }
 
-struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s,
-                                         struct cx18_buffer *buf)
+static
+struct cx18_queue *_cx18_stream_put_buf_fw(struct cx18_stream *s,
+                                          struct cx18_buffer *buf)
 {
        struct cx18 *cx = s->cx;
        struct cx18_queue *q;
 
        /* Don't give it to the firmware, if we're not running a capture */
        if (s->handle == CX18_INVALID_TASK_HANDLE ||
+           test_bit(CX18_F_S_STOPPING, &s->s_flags) ||
            !test_bit(CX18_F_S_STREAMING, &s->s_flags))
                return cx18_enqueue(s, buf, &s->q_free);
 
@@ -453,7 +464,8 @@ struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s,
        return q;
 }
 
-void cx18_stream_load_fw_queue(struct cx18_stream *s)
+static
+void _cx18_stream_load_fw_queue(struct cx18_stream *s)
 {
        struct cx18_queue *q;
        struct cx18_buffer *buf;
@@ -467,11 +479,19 @@ void cx18_stream_load_fw_queue(struct cx18_stream *s)
                buf = cx18_dequeue(s, &s->q_free);
                if (buf == NULL)
                        break;
-               q = cx18_stream_put_buf_fw(s, buf);
+               q = _cx18_stream_put_buf_fw(s, buf);
        } while (atomic_read(&s->q_busy.buffers) < CX18_MAX_FW_MDLS_PER_STREAM
                 && q == &s->q_busy);
 }
 
+void cx18_out_work_handler(struct work_struct *work)
+{
+       struct cx18_stream *s =
+                        container_of(work, struct cx18_stream, out_work_order);
+
+       _cx18_stream_load_fw_queue(s);
+}
+
 int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
 {
        u32 data[MAX_MB_ARGUMENTS];
@@ -600,19 +620,20 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
 
        /* Init all the cpu_mdls for this stream */
        cx18_flush_queues(s);
-       mutex_lock(&s->qlock);
+       spin_lock(&s->q_free.lock);
        list_for_each_entry(buf, &s->q_free.list, list) {
                cx18_writel(cx, buf->dma_handle,
                                        &cx->scb->cpu_mdl[buf->id].paddr);
                cx18_writel(cx, s->buf_size, &cx->scb->cpu_mdl[buf->id].length);
        }
-       mutex_unlock(&s->qlock);
-       cx18_stream_load_fw_queue(s);
+       spin_unlock(&s->q_free.lock);
+       _cx18_stream_load_fw_queue(s);
 
        /* begin_capture */
        if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) {
                CX18_DEBUG_WARN("Error starting capture!\n");
                /* Ensure we're really not capturing before releasing MDLs */
+               set_bit(CX18_F_S_STOPPING, &s->s_flags);
                if (s->type == CX18_ENC_STREAM_TYPE_MPG)
                        cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1);
                else
@@ -622,6 +643,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
                cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle);
                cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
                s->handle = CX18_INVALID_TASK_HANDLE;
+               clear_bit(CX18_F_S_STOPPING, &s->s_flags);
                if (atomic_read(&cx->tot_capturing) == 0) {
                        set_bit(CX18_F_I_EOS, &cx->i_flags);
                        cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK);
@@ -666,6 +688,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
        if (atomic_read(&cx->tot_capturing) == 0)
                return 0;
 
+       set_bit(CX18_F_S_STOPPING, &s->s_flags);
        if (s->type == CX18_ENC_STREAM_TYPE_MPG)
                cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, !gop_end);
        else
@@ -689,6 +712,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
 
        cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
        s->handle = CX18_INVALID_TASK_HANDLE;
+       clear_bit(CX18_F_S_STOPPING, &s->s_flags);
 
        if (atomic_read(&cx->tot_capturing) > 0)
                return 0;
index 420e0a172945e7c6d63f5e6bf9e62f50be2e63be..1afc3fd9d822539317801a747c58ff39e84dbb9a 100644 (file)
@@ -28,10 +28,24 @@ int cx18_streams_setup(struct cx18 *cx);
 int cx18_streams_register(struct cx18 *cx);
 void cx18_streams_cleanup(struct cx18 *cx, int unregister);
 
+/* Related to submission of buffers to firmware */
+static inline void cx18_stream_load_fw_queue(struct cx18_stream *s)
+{
+       struct cx18 *cx = s->cx;
+       queue_work(cx->out_work_queue, &s->out_work_order);
+}
+
+static inline void cx18_stream_put_buf_fw(struct cx18_stream *s,
+                                         struct cx18_buffer *buf)
+{
+       /* Put buf on q_free; the out work handler will move buf(s) to q_busy */
+       cx18_enqueue(s, buf, &s->q_free);
+       cx18_stream_load_fw_queue(s);
+}
+
+void cx18_out_work_handler(struct work_struct *work);
+
 /* Capture related */
-void cx18_stream_load_fw_queue(struct cx18_stream *s);
-struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s,
-                                         struct cx18_buffer *buf);
 int cx18_start_v4l2_encode_stream(struct cx18_stream *s);
 int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end);
 
index bd9bd44da791a3df585609523574199294520384..45494b094e7fc568196eb51f2e0a90c92def7165 100644 (file)
@@ -24,7 +24,7 @@
 
 #define CX18_DRIVER_NAME "cx18"
 #define CX18_DRIVER_VERSION_MAJOR 1
-#define CX18_DRIVER_VERSION_MINOR 1
+#define CX18_DRIVER_VERSION_MINOR 2
 #define CX18_DRIVER_VERSION_PATCHLEVEL 0
 
 #define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL)
index 1be3881be991f05ffe546add717b859d86acdf6e..6a9464079b4cf7bb2161f0b1998d421bfbbbbc99 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/bitmap.h>
 #include <linux/usb.h>
 #include <linux/i2c.h>
-#include <linux/version.h>
 #include <linux/mm.h>
 #include <linux/mutex.h>
 
index c8a32b1b53812654f3442939d2e14b7571087a28..63d2239fd324e14e3104b16615a7c5b2e9bed9d7 100644 (file)
@@ -281,12 +281,12 @@ static void cx231xx_config_tuner(struct cx231xx *dev)
 }
 
 /* ----------------------------------------------------------------------- */
-void cx231xx_set_ir(struct cx231xx *dev, struct IR_i2c *ir)
+void cx231xx_register_i2c_ir(struct cx231xx *dev)
 {
-       if (disable_ir) {
-               ir->get_key = NULL;
+       if (disable_ir)
                return;
-       }
+
+       /* REVISIT: instantiate IR device */
 
        /* detect & configure */
        switch (dev->model) {
index b4a03d813e00d7b9c3001bc52233bb48e0556c87..33219dc4d64987e640f109f853ec6a8b30159cc7 100644 (file)
@@ -424,34 +424,6 @@ static u32 functionality(struct i2c_adapter *adap)
        return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
 }
 
-/*
- * attach_inform()
- * gets called when a device attaches to the i2c bus
- * does some basic configuration
- */
-static int attach_inform(struct i2c_client *client)
-{
-       struct cx231xx_i2c *bus = i2c_get_adapdata(client->adapter);
-       struct cx231xx *dev = bus->dev;
-
-       switch (client->addr << 1) {
-       case 0x8e:
-               {
-                       struct IR_i2c *ir = i2c_get_clientdata(client);
-                       dprintk1(1, "attach_inform: IR detected (%s).\n",
-                                ir->phys);
-                       cx231xx_set_ir(dev, ir);
-                       break;
-               }
-               break;
-
-       default:
-               break;
-       }
-
-       return 0;
-}
-
 static struct i2c_algorithm cx231xx_algo = {
        .master_xfer = cx231xx_i2c_xfer,
        .functionality = functionality,
@@ -462,7 +434,6 @@ static struct i2c_adapter cx231xx_adap_template = {
        .name = "cx231xx",
        .id = I2C_HW_B_CX231XX,
        .algo = &cx231xx_algo,
-       .client_register = attach_inform,
 };
 
 static struct i2c_client cx231xx_client_template = {
@@ -537,6 +508,9 @@ int cx231xx_i2c_register(struct cx231xx_i2c *bus)
        if (0 == bus->i2c_rc) {
                if (i2c_scan)
                        cx231xx_do_i2c_scan(dev, &bus->i2c_client);
+
+               /* Instantiate the IR receiver device, if present */
+               cx231xx_register_i2c_ir(dev);
        } else
                cx231xx_warn("%s: i2c bus %d register FAILED\n",
                             dev->name, bus->nr);
index 97e304c3c799ba81106d5836e6c5c1c234348244..48f22fa38e6cc7a527256227442ab331b4466319 100644 (file)
@@ -36,7 +36,7 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
 
 #define i2cdprintk(fmt, arg...) \
        if (ir_debug) { \
-               printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg); \
+               printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
        }
 
 #define dprintk(fmt, arg...) \
index 94180526909c3d8a2c3f05a288dee7875e921b2a..e97b8023a6557a8fe15c39c921b0c36038733730 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/bitmap.h>
 #include <linux/usb.h>
 #include <linux/i2c.h>
-#include <linux/version.h>
 #include <linux/mm.h>
 #include <linux/mutex.h>
 
index aa4a23ef491a3341e2851cc6429a25345f9fbbc6..e38eb2d425f78fdfcb03976973e1c445850705d3 100644 (file)
@@ -738,7 +738,7 @@ extern void cx231xx_card_setup(struct cx231xx *dev);
 extern struct cx231xx_board cx231xx_boards[];
 extern struct usb_device_id cx231xx_id_table[];
 extern const unsigned int cx231xx_bcount;
-void cx231xx_set_ir(struct cx231xx *dev, struct IR_i2c *ir);
+void cx231xx_register_i2c_ir(struct cx231xx *dev);
 int cx231xx_tuner_callback(void *ptr, int component, int command, int arg);
 
 /* Provided by cx231xx-input.c */
index 9a6536998d904348fb3a0ee5377c18363766de99..08582e58bdbf368529099eb249fb77eaab9038cb 100644 (file)
@@ -312,7 +312,7 @@ static void netup_read_ci_status(struct work_struct *work)
                "TS config = %02x\n", __func__, state->ci_i2c_addr, 0, buf[0],
                buf[32]);
 
-       if (buf[0] && 1)
+       if (buf[0] & 1)
                state->status = DVB_CA_EN50221_POLL_CAM_PRESENT |
                        DVB_CA_EN50221_POLL_CAM_READY;
        else
index 6f5df90af93ef2a89f2c4bc48bf0c64640b89dea..2943bfd32a94a4b74acb19d6a9076abd7e1d3388 100644 (file)
@@ -1742,7 +1742,6 @@ static struct video_device *cx23885_video_dev_alloc(
        if (NULL == vfd)
                return NULL;
        *vfd = *template;
-       vfd->minor   = -1;
        snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
                type, cx23885_boards[tsport->dev->board].name);
        vfd->parent  = &pci->dev;
index 6d6293f7d428e6fe501f2c2b4d3d02727dc1132a..ce29b5e34a11329f58e5fca573205d8316876ff7 100644 (file)
@@ -181,6 +181,26 @@ struct cx23885_board cx23885_boards[] = {
                .portb          = CX23885_MPEG_DVB,
                .portc          = CX23885_MPEG_DVB,
        },
+       [CX23885_BOARD_HAUPPAUGE_HVR1270] = {
+               .name           = "Hauppauge WinTV-HVR1270",
+               .portc          = CX23885_MPEG_DVB,
+       },
+       [CX23885_BOARD_HAUPPAUGE_HVR1275] = {
+               .name           = "Hauppauge WinTV-HVR1275",
+               .portc          = CX23885_MPEG_DVB,
+       },
+       [CX23885_BOARD_HAUPPAUGE_HVR1255] = {
+               .name           = "Hauppauge WinTV-HVR1255",
+               .portc          = CX23885_MPEG_DVB,
+       },
+       [CX23885_BOARD_HAUPPAUGE_HVR1210] = {
+               .name           = "Hauppauge WinTV-HVR1210",
+               .portc          = CX23885_MPEG_DVB,
+       },
+       [CX23885_BOARD_MYGICA_X8506] = {
+               .name           = "Mygica X8506 DMB-TH",
+               .portb          = CX23885_MPEG_DVB,
+       },
 };
 const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
 
@@ -280,6 +300,30 @@ struct cx23885_subid cx23885_subids[] = {
                .subvendor = 0x1b55,
                .subdevice = 0x2a2c,
                .card      = CX23885_BOARD_NETUP_DUAL_DVBS2_CI,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x2211,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1270,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x2215,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1275,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x2251,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1255,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x2291,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1210,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x2295,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR1210,
+       }, {
+               .subvendor = 0x14f1,
+               .subdevice = 0x8651,
+               .card      = CX23885_BOARD_MYGICA_X8506,
        },
 };
 const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -321,6 +365,42 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
 
        /* Make sure we support the board model */
        switch (tv.model) {
+       case 22001:
+               /* WinTV-HVR1270 (PCIe, Retail, half height)
+                * ATSC/QAM and basic analog, IR Blast */
+       case 22009:
+               /* WinTV-HVR1210 (PCIe, Retail, half height)
+                * DVB-T and basic analog, IR Blast */
+       case 22011:
+               /* WinTV-HVR1270 (PCIe, Retail, half height)
+                * ATSC/QAM and basic analog, IR Recv */
+       case 22019:
+               /* WinTV-HVR1210 (PCIe, Retail, half height)
+                * DVB-T and basic analog, IR Recv */
+       case 22021:
+               /* WinTV-HVR1275 (PCIe, Retail, half height)
+                * ATSC/QAM and basic analog, IR Recv */
+       case 22029:
+               /* WinTV-HVR1210 (PCIe, Retail, half height)
+                * DVB-T and basic analog, IR Recv */
+       case 22101:
+               /* WinTV-HVR1270 (PCIe, Retail, full height)
+                * ATSC/QAM and basic analog, IR Blast */
+       case 22109:
+               /* WinTV-HVR1210 (PCIe, Retail, full height)
+                * DVB-T and basic analog, IR Blast */
+       case 22111:
+               /* WinTV-HVR1270 (PCIe, Retail, full height)
+                * ATSC/QAM and basic analog, IR Recv */
+       case 22119:
+               /* WinTV-HVR1210 (PCIe, Retail, full height)
+                * DVB-T and basic analog, IR Recv */
+       case 22121:
+               /* WinTV-HVR1275 (PCIe, Retail, full height)
+                * ATSC/QAM and basic analog, IR Recv */
+       case 22129:
+               /* WinTV-HVR1210 (PCIe, Retail, full height)
+                * DVB-T and basic analog, IR Recv */
        case 71009:
                /* WinTV-HVR1200 (PCIe, Retail, full height)
                 * DVB-T and basic analog */
@@ -619,6 +699,30 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
                /* enable irq */
                cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/
                break;
+       case CX23885_BOARD_HAUPPAUGE_HVR1270:
+       case CX23885_BOARD_HAUPPAUGE_HVR1275:
+       case CX23885_BOARD_HAUPPAUGE_HVR1255:
+       case CX23885_BOARD_HAUPPAUGE_HVR1210:
+               /* GPIO-5 RF Control: 0 = RF1 Terrestrial, 1 = RF2 Cable */
+               /* GPIO-6 I2C Gate which can isolate the demod from the bus */
+               /* GPIO-9 Demod reset */
+
+               /* Put the parts into reset and back */
+               cx23885_gpio_enable(dev, GPIO_9 | GPIO_6 | GPIO_5, 1);
+               cx23885_gpio_set(dev, GPIO_9 | GPIO_6 | GPIO_5);
+               cx23885_gpio_clear(dev, GPIO_9);
+               mdelay(20);
+               cx23885_gpio_set(dev, GPIO_9);
+               break;
+       case CX23885_BOARD_MYGICA_X8506:
+               /* GPIO-1 reset XC5000 */
+               /* GPIO-2 reset LGS8GL5 */
+               cx_set(GP0_IO, 0x00060000);
+               cx_clear(GP0_IO, 0x00000006);
+               mdelay(100);
+               cx_set(GP0_IO, 0x00060006);
+               mdelay(100);
+               break;
        }
 }
 
@@ -631,6 +735,10 @@ int cx23885_ir_init(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1800:
        case CX23885_BOARD_HAUPPAUGE_HVR1200:
        case CX23885_BOARD_HAUPPAUGE_HVR1400:
+       case CX23885_BOARD_HAUPPAUGE_HVR1270:
+       case CX23885_BOARD_HAUPPAUGE_HVR1275:
+       case CX23885_BOARD_HAUPPAUGE_HVR1255:
+       case CX23885_BOARD_HAUPPAUGE_HVR1210:
                /* FIXME: Implement me */
                break;
        case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
@@ -666,6 +774,10 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
        case CX23885_BOARD_HAUPPAUGE_HVR1200:
        case CX23885_BOARD_HAUPPAUGE_HVR1700:
+       case CX23885_BOARD_HAUPPAUGE_HVR1270:
+       case CX23885_BOARD_HAUPPAUGE_HVR1275:
+       case CX23885_BOARD_HAUPPAUGE_HVR1255:
+       case CX23885_BOARD_HAUPPAUGE_HVR1210:
                if (dev->i2c_bus[0].i2c_rc == 0)
                        hauppauge_eeprom(dev, eeprom+0xc0);
                break;
@@ -714,6 +826,11 @@ void cx23885_card_setup(struct cx23885_dev *dev)
                ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
                ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
                break;
+       case CX23885_BOARD_MYGICA_X8506:
+               ts1->gen_ctrl_val  = 0x5; /* Parallel */
+               ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+               ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+               break;
        case CX23885_BOARD_HAUPPAUGE_HVR1250:
        case CX23885_BOARD_HAUPPAUGE_HVR1500:
        case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
@@ -723,6 +840,10 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1400:
        case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
        case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
+       case CX23885_BOARD_HAUPPAUGE_HVR1270:
+       case CX23885_BOARD_HAUPPAUGE_HVR1275:
+       case CX23885_BOARD_HAUPPAUGE_HVR1255:
+       case CX23885_BOARD_HAUPPAUGE_HVR1210:
        default:
                ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
                ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
index beda42925ce761c961e7b08673a195cd6e6017fe..bf7bb1c412fb6e3735daf7dee875fa1b1a705ac0 100644 (file)
@@ -1700,9 +1700,13 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
        }
 
        if (cx23885_boards[dev->board].cimax > 0 &&
-               ((pci_status & PCI_MSK_GPIO0) || (pci_status & PCI_MSK_GPIO1)))
-               /* handled += cx23885_irq_gpio(dev, pci_status); */
-               handled += netup_ci_slot_status(dev, pci_status);
+               ((pci_status & PCI_MSK_GPIO0) ||
+                       (pci_status & PCI_MSK_GPIO1))) {
+
+               if (cx23885_boards[dev->board].cimax > 0)
+                       handled += netup_ci_slot_status(dev, pci_status);
+
+       }
 
        if (ts1_status) {
                if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
@@ -1729,6 +1733,88 @@ out:
        return IRQ_RETVAL(handled);
 }
 
+static inline int encoder_on_portb(struct cx23885_dev *dev)
+{
+       return cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER;
+}
+
+static inline int encoder_on_portc(struct cx23885_dev *dev)
+{
+       return cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER;
+}
+
+/* Mask represents 32 different GPIOs, GPIO's are split into multiple
+ * registers depending on the board configuration (and whether the
+ * 417 encoder (wi it's own GPIO's) are present. Each GPIO bit will
+ * be pushed into the correct hardware register, regardless of the
+ * physical location. Certain registers are shared so we sanity check
+ * and report errors if we think we're tampering with a GPIo that might
+ * be assigned to the encoder (and used for the host bus).
+ *
+ * GPIO  2 thru  0 - On the cx23885 bridge
+ * GPIO 18 thru  3 - On the cx23417 host bus interface
+ * GPIO 23 thru 19 - On the cx25840 a/v core
+ */
+void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask)
+{
+       if (mask & 0x7)
+               cx_set(GP0_IO, mask & 0x7);
+
+       if (mask & 0x0007fff8) {
+               if (encoder_on_portb(dev) || encoder_on_portc(dev))
+                       printk(KERN_ERR
+                               "%s: Setting GPIO on encoder ports\n",
+                               dev->name);
+               cx_set(MC417_RWD, (mask & 0x0007fff8) >> 3);
+       }
+
+       /* TODO: 23-19 */
+       if (mask & 0x00f80000)
+               printk(KERN_INFO "%s: Unsupported\n", dev->name);
+}
+
+void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask)
+{
+       if (mask & 0x00000007)
+               cx_clear(GP0_IO, mask & 0x7);
+
+       if (mask & 0x0007fff8) {
+               if (encoder_on_portb(dev) || encoder_on_portc(dev))
+                       printk(KERN_ERR
+                               "%s: Clearing GPIO moving on encoder ports\n",
+                               dev->name);
+               cx_clear(MC417_RWD, (mask & 0x7fff8) >> 3);
+       }
+
+       /* TODO: 23-19 */
+       if (mask & 0x00f80000)
+               printk(KERN_INFO "%s: Unsupported\n", dev->name);
+}
+
+void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput)
+{
+       if ((mask & 0x00000007) && asoutput)
+               cx_set(GP0_IO, (mask & 0x7) << 16);
+       else if ((mask & 0x00000007) && !asoutput)
+               cx_clear(GP0_IO, (mask & 0x7) << 16);
+
+       if (mask & 0x0007fff8) {
+               if (encoder_on_portb(dev) || encoder_on_portc(dev))
+                       printk(KERN_ERR
+                               "%s: Enabling GPIO on encoder ports\n",
+                               dev->name);
+       }
+
+       /* MC417_OEN is active low for output, write 1 for an input */
+       if ((mask & 0x0007fff8) && asoutput)
+               cx_clear(MC417_OEN, (mask & 0x7fff8) >> 3);
+
+       else if ((mask & 0x0007fff8) && !asoutput)
+               cx_set(MC417_OEN, (mask & 0x7fff8) >> 3);
+
+       /* TODO: 23-19 */
+}
+
 static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
                                     const struct pci_device_id *pci_id)
 {
index 1dc070da8652b8bcc5fdca72cfae39760944fe65..e236df23370ea52f350fcb7e52e50aead5a56191 100644 (file)
 #include "lnbh24.h"
 #include "cx24116.h"
 #include "cimax2.h"
+#include "lgs8gxx.h"
 #include "netup-eeprom.h"
 #include "netup-init.h"
+#include "lgdt3305.h"
 
 static unsigned int debug;
 
@@ -122,7 +124,22 @@ static struct tda10048_config hauppauge_hvr1200_config = {
        .demod_address    = 0x10 >> 1,
        .output_mode      = TDA10048_SERIAL_OUTPUT,
        .fwbulkwritelen   = TDA10048_BULKWRITE_200,
-       .inversion        = TDA10048_INVERSION_ON
+       .inversion        = TDA10048_INVERSION_ON,
+       .dtv6_if_freq_khz = TDA10048_IF_3300,
+       .dtv7_if_freq_khz = TDA10048_IF_3800,
+       .dtv8_if_freq_khz = TDA10048_IF_4300,
+       .clk_freq_khz     = TDA10048_CLK_16000,
+};
+
+static struct tda10048_config hauppauge_hvr1210_config = {
+       .demod_address    = 0x10 >> 1,
+       .output_mode      = TDA10048_SERIAL_OUTPUT,
+       .fwbulkwritelen   = TDA10048_BULKWRITE_200,
+       .inversion        = TDA10048_INVERSION_ON,
+       .dtv6_if_freq_khz = TDA10048_IF_3300,
+       .dtv7_if_freq_khz = TDA10048_IF_3500,
+       .dtv8_if_freq_khz = TDA10048_IF_4000,
+       .clk_freq_khz     = TDA10048_CLK_16000,
 };
 
 static struct s5h1409_config hauppauge_ezqam_config = {
@@ -194,6 +211,16 @@ static struct s5h1411_config dvico_s5h1411_config = {
        .mpeg_timing   = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
 };
 
+static struct s5h1411_config hcw_s5h1411_config = {
+       .output_mode   = S5H1411_SERIAL_OUTPUT,
+       .gpio          = S5H1411_GPIO_OFF,
+       .vsb_if        = S5H1411_IF_44000,
+       .qam_if        = S5H1411_IF_4000,
+       .inversion     = S5H1411_INVERSION_ON,
+       .status_mode   = S5H1411_DEMODLOCKING,
+       .mpeg_timing   = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
 static struct xc5000_config hauppauge_hvr1500q_tunerconfig = {
        .i2c_address      = 0x61,
        .if_khz           = 5380,
@@ -224,6 +251,32 @@ static struct tda18271_config hauppauge_hvr1200_tuner_config = {
        .gate    = TDA18271_GATE_ANALOG,
 };
 
+static struct tda18271_config hauppauge_hvr1210_tuner_config = {
+       .gate    = TDA18271_GATE_DIGITAL,
+};
+
+static struct tda18271_std_map hauppauge_hvr127x_std_map = {
+       .atsc_6   = { .if_freq = 3250, .agc_mode = 3, .std = 4,
+                     .if_lvl = 1, .rfagc_top = 0x58 },
+       .qam_6    = { .if_freq = 4000, .agc_mode = 3, .std = 5,
+                     .if_lvl = 1, .rfagc_top = 0x58 },
+};
+
+static struct tda18271_config hauppauge_hvr127x_config = {
+       .std_map = &hauppauge_hvr127x_std_map,
+};
+
+static struct lgdt3305_config hauppauge_lgdt3305_config = {
+       .i2c_addr           = 0x0e,
+       .mpeg_mode          = LGDT3305_MPEG_SERIAL,
+       .tpclk_edge         = LGDT3305_TPCLK_FALLING_EDGE,
+       .tpvalid_polarity   = LGDT3305_TP_VALID_HIGH,
+       .deny_i2c_rptr      = 1,
+       .spectral_inversion = 1,
+       .qam_if_khz         = 4000,
+       .vsb_if_khz         = 3250,
+};
+
 static struct dibx000_agc_config xc3028_agc_config = {
        BAND_VHF | BAND_UHF,    /* band_caps */
 
@@ -368,10 +421,29 @@ static struct cx24116_config dvbworld_cx24116_config = {
        .demod_address = 0x05,
 };
 
+static struct lgs8gxx_config mygica_x8506_lgs8gl5_config = {
+       .prod = LGS8GXX_PROD_LGS8GL5,
+       .demod_address = 0x19,
+       .serial_ts = 0,
+       .ts_clk_pol = 1,
+       .ts_clk_gated = 1,
+       .if_clk_freq = 30400, /* 30.4 MHz */
+       .if_freq = 5380, /* 5.38 MHz */
+       .if_neg_center = 1,
+       .ext_adc = 0,
+       .adc_signed = 0,
+       .if_neg_edge = 0,
+};
+
+static struct xc5000_config mygica_x8506_xc5000_config = {
+       .i2c_address = 0x61,
+       .if_khz = 5380,
+};
+
 static int dvb_register(struct cx23885_tsport *port)
 {
        struct cx23885_dev *dev = port->dev;
-       struct cx23885_i2c *i2c_bus = NULL;
+       struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL;
        struct videobuf_dvb_frontend *fe0;
        int ret;
 
@@ -396,6 +468,29 @@ static int dvb_register(struct cx23885_tsport *port)
                                   &hauppauge_generic_tunerconfig, 0);
                }
                break;
+       case CX23885_BOARD_HAUPPAUGE_HVR1270:
+       case CX23885_BOARD_HAUPPAUGE_HVR1275:
+               i2c_bus = &dev->i2c_bus[0];
+               fe0->dvb.frontend = dvb_attach(lgdt3305_attach,
+                                              &hauppauge_lgdt3305_config,
+                                              &i2c_bus->i2c_adap);
+               if (fe0->dvb.frontend != NULL) {
+                       dvb_attach(tda18271_attach, fe0->dvb.frontend,
+                                  0x60, &dev->i2c_bus[1].i2c_adap,
+                                  &hauppauge_hvr127x_config);
+               }
+               break;
+       case CX23885_BOARD_HAUPPAUGE_HVR1255:
+               i2c_bus = &dev->i2c_bus[0];
+               fe0->dvb.frontend = dvb_attach(s5h1411_attach,
+                                              &hcw_s5h1411_config,
+                                              &i2c_bus->i2c_adap);
+               if (fe0->dvb.frontend != NULL) {
+                       dvb_attach(tda18271_attach, fe0->dvb.frontend,
+                                  0x60, &dev->i2c_bus[1].i2c_adap,
+                                  &hauppauge_tda18271_config);
+               }
+               break;
        case CX23885_BOARD_HAUPPAUGE_HVR1800:
                i2c_bus = &dev->i2c_bus[0];
                switch (alt_tuner) {
@@ -496,6 +591,17 @@ static int dvb_register(struct cx23885_tsport *port)
                                &hauppauge_hvr1200_tuner_config);
                }
                break;
+       case CX23885_BOARD_HAUPPAUGE_HVR1210:
+               i2c_bus = &dev->i2c_bus[0];
+               fe0->dvb.frontend = dvb_attach(tda10048_attach,
+                       &hauppauge_hvr1210_config,
+                       &i2c_bus->i2c_adap);
+               if (fe0->dvb.frontend != NULL) {
+                       dvb_attach(tda18271_attach, fe0->dvb.frontend,
+                               0x60, &dev->i2c_bus[1].i2c_adap,
+                               &hauppauge_hvr1210_tuner_config);
+               }
+               break;
        case CX23885_BOARD_HAUPPAUGE_HVR1400:
                i2c_bus = &dev->i2c_bus[0];
                fe0->dvb.frontend = dvb_attach(dib7000p_attach,
@@ -659,6 +765,19 @@ static int dvb_register(struct cx23885_tsport *port)
                        break;
                }
                break;
+       case CX23885_BOARD_MYGICA_X8506:
+               i2c_bus = &dev->i2c_bus[0];
+               i2c_bus2 = &dev->i2c_bus[1];
+               fe0->dvb.frontend = dvb_attach(lgs8gxx_attach,
+                       &mygica_x8506_lgs8gl5_config,
+                       &i2c_bus->i2c_adap);
+               if (fe0->dvb.frontend != NULL) {
+                       dvb_attach(xc5000_attach,
+                               fe0->dvb.frontend,
+                               &i2c_bus2->i2c_adap,
+                               &mygica_x8506_xc5000_config);
+               }
+               break;
        default:
                printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
                        " isn't supported yet\n",
index 3421bd12056a95ee58a4604ca380354f4ccb444c..384dec34134fe56ef6298909fa6a633a0c9bec4b 100644 (file)
@@ -357,6 +357,18 @@ int cx23885_i2c_register(struct cx23885_i2c *bus)
                printk(KERN_WARNING "%s: i2c bus %d register FAILED\n",
                        dev->name, bus->nr);
 
+       /* Instantiate the IR receiver device, if present */
+       if (0 == bus->i2c_rc) {
+               struct i2c_board_info info;
+               const unsigned short addr_list[] = {
+                       0x6b, I2C_CLIENT_END
+               };
+
+               memset(&info, 0, sizeof(struct i2c_board_info));
+               strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+               i2c_new_probed_device(&bus->i2c_adap, &info, addr_list);
+       }
+
        return bus->i2c_rc;
 }
 
index 68068c6d098729c53b43d11c30f83c241e6d5cc4..66bbd2e711057fba20904513ca102640dc425331 100644 (file)
@@ -796,6 +796,7 @@ static unsigned int video_poll(struct file *file,
 {
        struct cx23885_fh *fh = file->private_data;
        struct cx23885_buffer *buf;
+       unsigned int rc = POLLERR;
 
        if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
                if (!res_get(fh->dev, fh, RESOURCE_VBI))
@@ -803,23 +804,28 @@ static unsigned int video_poll(struct file *file,
                return videobuf_poll_stream(file, &fh->vbiq, wait);
        }
 
+       mutex_lock(&fh->vidq.vb_lock);
        if (res_check(fh, RESOURCE_VIDEO)) {
                /* streaming capture */
                if (list_empty(&fh->vidq.stream))
-                       return POLLERR;
+                       goto done;
                buf = list_entry(fh->vidq.stream.next,
                        struct cx23885_buffer, vb.stream);
        } else {
                /* read() capture */
                buf = (struct cx23885_buffer *)fh->vidq.read_buf;
                if (NULL == buf)
-                       return POLLERR;
+                       goto done;
        }
        poll_wait(file, &buf->vb.done, wait);
        if (buf->vb.state == VIDEOBUF_DONE ||
            buf->vb.state == VIDEOBUF_ERROR)
-               return POLLIN|POLLRDNORM;
-       return 0;
+               rc =  POLLIN|POLLRDNORM;
+       else
+               rc = 0;
+done:
+       mutex_unlock(&fh->vidq.vb_lock);
+       return rc;
 }
 
 static int video_release(struct file *file)
index 85642831ea8e935ffc96b1457aeaade824c7b598..1a2ac518a3f1ae21362ae8694a4289d1d4c78cba 100644 (file)
 #define CX23885_BOARD_TEVII_S470               15
 #define CX23885_BOARD_DVBWORLD_2005            16
 #define CX23885_BOARD_NETUP_DUAL_DVBS2_CI      17
+#define CX23885_BOARD_HAUPPAUGE_HVR1270        18
+#define CX23885_BOARD_HAUPPAUGE_HVR1275        19
+#define CX23885_BOARD_HAUPPAUGE_HVR1255        20
+#define CX23885_BOARD_HAUPPAUGE_HVR1210        21
+#define CX23885_BOARD_MYGICA_X8506             22
+
+#define GPIO_0 0x00000001
+#define GPIO_1 0x00000002
+#define GPIO_2 0x00000004
+#define GPIO_3 0x00000008
+#define GPIO_4 0x00000010
+#define GPIO_5 0x00000020
+#define GPIO_6 0x00000040
+#define GPIO_7 0x00000080
+#define GPIO_8 0x00000100
+#define GPIO_9 0x00000200
 
 /* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
 #define CX23885_NORMS (\
@@ -422,6 +438,11 @@ extern int cx23885_restart_queue(struct cx23885_tsport *port,
 extern void cx23885_wakeup(struct cx23885_tsport *port,
                           struct cx23885_dmaqueue *q, u32 count);
 
+extern void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask);
+extern void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask);
+extern void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask,
+       int asoutput);
+
 
 /* ----------------------------------------------------------- */
 /* cx23885-cards.c                                             */
index b06b1275a9eca270d157f6f8bdaa3839535c61cd..5b7e26761f0a78006ebfd064dbc667db4edcc8b7 100644 (file)
@@ -1,5 +1,5 @@
 cx88xx-objs    := cx88-cards.o cx88-core.o cx88-i2c.o cx88-tvaudio.o \
-                  cx88-input.o
+                  cx88-dsp.o cx88-input.o
 cx8800-objs    := cx88-video.o cx88-vbi.o
 cx8802-objs    := cx88-mpeg.o
 
index 0ccdf36626e30a0f30d47e7bb7fb44c2bfe04833..5a67445dd6ed900f465f3fb2334a2c5346e5f419 100644 (file)
@@ -871,7 +871,7 @@ static struct pci_driver cx88_audio_pci_driver = {
        .name     = "cx88_audio",
        .id_table = cx88_audio_pci_tbl,
        .probe    = cx88_audio_initdev,
-       .remove   = cx88_audio_finidev,
+       .remove   = __devexit_p(cx88_audio_finidev),
 };
 
 /****************************************************************************
@@ -881,7 +881,7 @@ static struct pci_driver cx88_audio_pci_driver = {
 /*
  * module init
  */
-static int cx88_audio_init(void)
+static int __init cx88_audio_init(void)
 {
        printk(KERN_INFO "cx2388x alsa driver version %d.%d.%d loaded\n",
               (CX88_VERSION_CODE >> 16) & 0xff,
@@ -897,9 +897,8 @@ static int cx88_audio_init(void)
 /*
  * module remove
  */
-static void cx88_audio_fini(void)
+static void __exit cx88_audio_fini(void)
 {
-
        pci_unregister_driver(&cx88_audio_pci_driver);
 }
 
index 6bbbfc66bb4bf2ac84be1fc56ecf5c7c0f8cc145..94b7a52629d057c0bd5295ec7783388026484eae 100644 (file)
@@ -1969,6 +1969,54 @@ static const struct cx88_board cx88_boards[] = {
                },
                .mpeg           = CX88_MPEG_DVB,
        },
+       [CX88_BOARD_HAUPPAUGE_IRONLY] = {
+               .name           = "Hauppauge WinTV-IR Only",
+               .tuner_type     = UNSET,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+       },
+       [CX88_BOARD_WINFAST_DTV1800H] = {
+               .name           = "Leadtek WinFast DTV1800 Hybrid",
+               .tuner_type     = TUNER_XC2028,
+               .radio_type     = TUNER_XC2028,
+               .tuner_addr     = 0x61,
+               .radio_addr     = 0x61,
+               /*
+                * GPIO setting
+                *
+                *  2: mute (0=off,1=on)
+                * 12: tuner reset pin
+                * 13: audio source (0=tuner audio,1=line in)
+                * 14: FM (0=on,1=off ???)
+                */
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+                       .gpio0  = 0x0400,       /* pin 2 = 0 */
+                       .gpio1  = 0x6040,       /* pin 13 = 0, pin 14 = 1 */
+                       .gpio2  = 0x0000,
+               }, {
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+                       .gpio0  = 0x0400,       /* pin 2 = 0 */
+                       .gpio1  = 0x6060,       /* pin 13 = 1, pin 14 = 1 */
+                       .gpio2  = 0x0000,
+               }, {
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+                       .gpio0  = 0x0400,       /* pin 2 = 0 */
+                       .gpio1  = 0x6060,       /* pin 13 = 1, pin 14 = 1 */
+                       .gpio2  = 0x0000,
+               } },
+               .radio = {
+                       .type   = CX88_RADIO,
+                       .gpio0  = 0x0400,       /* pin 2 = 0 */
+                       .gpio1  = 0x6000,       /* pin 13 = 0, pin 14 = 0 */
+                       .gpio2  = 0x0000,
+               },
+               .mpeg           = CX88_MPEG_DVB,
+       },
 };
 
 /* ------------------------------------------------------------------ */
@@ -2382,6 +2430,14 @@ static const struct cx88_subid cx88_subids[] = {
                .subvendor = 0x153b,
                .subdevice = 0x1177,
                .card      = CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII,
+       }, {
+               .subvendor = 0x0070,
+               .subdevice = 0x9290,
+               .card      = CX88_BOARD_HAUPPAUGE_IRONLY,
+       }, {
+               .subvendor = 0x107d,
+               .subdevice = 0x6654,
+               .card      = CX88_BOARD_WINFAST_DTV1800H,
        },
 };
 
@@ -2448,6 +2504,7 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
        case 90500: /* Nova-T-PCI (oem) */
        case 90501: /* Nova-T-PCI (oem/IR) */
        case 92000: /* Nova-SE2 (OEM, No Video or IR) */
+       case 92900: /* WinTV-IROnly (No analog or digital Video inputs) */
        case 94009: /* WinTV-HVR1100 (Video and IR Retail) */
        case 94501: /* WinTV-HVR1100 (Video and IR OEM) */
        case 96009: /* WinTV-HVR1300 (PAL Video, MPEG Video and IR RX) */
@@ -2579,6 +2636,23 @@ static int cx88_xc3028_geniatech_tuner_callback(struct cx88_core *core,
        return -EINVAL;
 }
 
+static int cx88_xc3028_winfast1800h_callback(struct cx88_core *core,
+                                            int command, int arg)
+{
+       switch (command) {
+       case XC2028_TUNER_RESET:
+               /* GPIO 12 (xc3028 tuner reset) */
+               cx_set(MO_GP1_IO, 0x1010);
+               mdelay(50);
+               cx_clear(MO_GP1_IO, 0x10);
+               mdelay(50);
+               cx_set(MO_GP1_IO, 0x10);
+               mdelay(50);
+               return 0;
+       }
+       return -EINVAL;
+}
+
 /* ------------------------------------------------------------------- */
 /* some Divco specific stuff                                           */
 static int cx88_pv_8000gt_callback(struct cx88_core *core,
@@ -2651,6 +2725,8 @@ static int cx88_xc2028_tuner_callback(struct cx88_core *core,
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
        case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
                return cx88_dvico_xc2028_callback(core, command, arg);
+       case CX88_BOARD_WINFAST_DTV1800H:
+               return cx88_xc3028_winfast1800h_callback(core, command, arg);
        }
 
        switch (command) {
@@ -2690,10 +2766,22 @@ static int cx88_xc5000_tuner_callback(struct cx88_core *core,
        switch (core->boardnr) {
        case CX88_BOARD_PINNACLE_PCTV_HD_800i:
                if (command == 0) { /* This is the reset command from xc5000 */
-                       /* Reset XC5000 tuner via SYS_RSTO_pin */
-                       cx_write(MO_SRST_IO, 0);
-                       msleep(10);
-                       cx_write(MO_SRST_IO, 1);
+
+                       /* djh - According to the engineer at PCTV Systems,
+                          the xc5000 reset pin is supposed to be on GPIO12.
+                          However, despite three nights of effort, pulling
+                          that GPIO low didn't reset the xc5000.  While
+                          pulling MO_SRST_IO low does reset the xc5000, this
+                          also resets in the s5h1409 being reset as well.
+                          This causes tuning to always fail since the internal
+                          state of the s5h1409 does not match the driver's
+                          state.  Given that the only two conditions in which
+                          the driver performs a reset is during firmware load
+                          and powering down the chip, I am taking out the
+                          reset.  We know that the chip is being reset
+                          when the cx88 comes online, and not being able to
+                          do power management for this board is worse than
+                          not having any tuning at all. */
                        return 0;
                } else {
                        err_printk(core, "xc5000: unknown tuner "
@@ -2825,6 +2913,16 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core)
                cx_set(MO_GP0_IO, 0x00000080); /* 702 out of reset */
                udelay(1000);
                break;
+
+       case CX88_BOARD_WINFAST_DTV1800H:
+               /* GPIO 12 (xc3028 tuner reset) */
+               cx_set(MO_GP1_IO, 0x1010);
+               mdelay(50);
+               cx_clear(MO_GP1_IO, 0x10);
+               mdelay(50);
+               cx_set(MO_GP1_IO, 0x10);
+               mdelay(50);
+               break;
        }
 }
 
@@ -2845,6 +2943,7 @@ void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl)
                        core->i2c_algo.udelay = 16;
                break;
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
+       case CX88_BOARD_WINFAST_DTV1800H:
                ctl->demod = XC3028_FE_ZARLINK456;
                break;
        case CX88_BOARD_KWORLD_ATSC_120:
@@ -2907,6 +3006,7 @@ static void cx88_card_setup(struct cx88_core *core)
        case CX88_BOARD_HAUPPAUGE_HVR1300:
        case CX88_BOARD_HAUPPAUGE_HVR4000:
        case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
+       case CX88_BOARD_HAUPPAUGE_IRONLY:
                if (0 == core->i2c_rc)
                        hauppauge_eeprom(core, eeprom);
                break;
index 0e149b22bd194b14943fa30799ec143e36270343..cf634606ba9a3bc082d0d55e77d0918452a3f16e 100644 (file)
@@ -231,7 +231,7 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
  * can use the whole SDRAM for the DMA fifos.  To simplify things, we
  * use a static memory layout.  That surely will waste memory in case
  * we don't use all DMA channels at the same time (which will be the
- * case most of the time).  But that still gives us enougth FIFO space
+ * case most of the time).  But that still gives us enough FIFO space
  * to be able to deal with insane long pci latencies ...
  *
  * FIFO space allocations:
@@ -241,6 +241,7 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
  *    channel  24    (vbi)      -  4.0k
  *    channels 25+26 (audio)    -  4.0k
  *    channel  28    (mpeg)     -  4.0k
+ *    channel  27    (audio rds)-  3.0k
  *    TOTAL                     = 29.0k
  *
  * Every channel has 160 bytes control data (64 bytes instruction
@@ -337,6 +338,18 @@ struct sram_channel cx88_sram_channels[] = {
                .cnt1_reg   = MO_DMA28_CNT1,
                .cnt2_reg   = MO_DMA28_CNT2,
        },
+       [SRAM_CH27] = {
+               .name       = "audio rds",
+               .cmds_start = 0x1801C0,
+               .ctrl_start = 0x180860,
+               .cdt        = 0x180860 + 64,
+               .fifo_start = 0x187400,
+               .fifo_size  = 0x000C00,
+               .ptr1_reg   = MO_DMA27_PTR1,
+               .ptr2_reg   = MO_DMA27_PTR2,
+               .cnt1_reg   = MO_DMA27_CNT1,
+               .cnt2_reg   = MO_DMA27_CNT2,
+       },
 };
 
 int cx88_sram_channel_setup(struct cx88_core *core,
@@ -598,6 +611,7 @@ int cx88_reset(struct cx88_core *core)
        cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], 128, 0);
        cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], 128, 0);
        cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28], 188*4, 0);
+       cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH27], 128, 0);
 
        /* misc init ... */
        cx_write(MO_INPUT_FORMAT, ((1 << 13) |   // agc enable
@@ -796,6 +810,8 @@ int cx88_start_audio_dma(struct cx88_core *core)
        /* constant 128 made buzz in analog Nicam-stereo for bigger fifo_size */
        int bpl = cx88_sram_channels[SRAM_CH25].fifo_size/4;
 
+       int rds_bpl = cx88_sram_channels[SRAM_CH27].fifo_size/AUD_RDS_LINES;
+
        /* If downstream RISC is enabled, bail out; ALSA is managing DMA */
        if (cx_read(MO_AUD_DMACNTRL) & 0x10)
                return 0;
@@ -803,12 +819,14 @@ int cx88_start_audio_dma(struct cx88_core *core)
        /* setup fifo + format */
        cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], bpl, 0);
        cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], bpl, 0);
+       cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH27],
+                               rds_bpl, 0);
 
        cx_write(MO_AUDD_LNGTH, bpl); /* fifo bpl size */
-       cx_write(MO_AUDR_LNGTH, bpl); /* fifo bpl size */
+       cx_write(MO_AUDR_LNGTH, rds_bpl); /* fifo bpl size */
 
-       /* start dma */
-       cx_write(MO_AUD_DMACNTRL, 0x0003); /* Up and Down fifo enable */
+       /* enable Up, Down and Audio RDS fifo */
+       cx_write(MO_AUD_DMACNTRL, 0x0007);
 
        return 0;
 }
@@ -1010,7 +1028,6 @@ struct video_device *cx88_vdev_init(struct cx88_core *core,
        if (NULL == vfd)
                return NULL;
        *vfd = *template;
-       vfd->minor   = -1;
        vfd->v4l2_dev = &core->v4l2_dev;
        vfd->parent = &pci->dev;
        vfd->release = video_device_release;
diff --git a/drivers/media/video/cx88/cx88-dsp.c b/drivers/media/video/cx88/cx88-dsp.c
new file mode 100644 (file)
index 0000000..3e5eaf3
--- /dev/null
@@ -0,0 +1,312 @@
+/*
+ *
+ *  Stereo and SAP detection for cx88
+ *
+ *  Copyright (c) 2009 Marton Balint <cus@fazekas.hu>
+ *
+ *  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/jiffies.h>
+#include <asm/div64.h>
+
+#include "cx88.h"
+#include "cx88-reg.h"
+
+#define INT_PI                 ((s32)(3.141592653589 * 32768.0))
+
+#define compat_remainder(a, b) \
+        ((float)(((s32)((a)*100))%((s32)((b)*100)))/100.0)
+
+#define baseband_freq(carrier, srate, tone) ((s32)( \
+        (compat_remainder(carrier + tone, srate)) / srate * 2 * INT_PI))
+
+/* We calculate the baseband frequencies of the carrier and the pilot tones
+ * based on the the sampling rate of the audio rds fifo. */
+
+#define FREQ_A2_CARRIER         baseband_freq(54687.5, 2689.36, 0.0)
+#define FREQ_A2_DUAL            baseband_freq(54687.5, 2689.36, 274.1)
+#define FREQ_A2_STEREO          baseband_freq(54687.5, 2689.36, 117.5)
+
+/* The frequencies below are from the reference driver. They probably need
+ * further adjustments, because they are not tested at all. You may even need
+ * to play a bit with the registers of the chip to select the proper signal
+ * for the input of the audio rds fifo, and measure it's sampling rate to
+ * calculate the proper baseband frequencies... */
+
+#define FREQ_A2M_CARRIER       ((s32)(2.114516 * 32768.0))
+#define FREQ_A2M_DUAL          ((s32)(2.754916 * 32768.0))
+#define FREQ_A2M_STEREO                ((s32)(2.462326 * 32768.0))
+
+#define FREQ_EIAJ_CARRIER      ((s32)(1.963495 * 32768.0)) /* 5pi/8  */
+#define FREQ_EIAJ_DUAL         ((s32)(2.562118 * 32768.0))
+#define FREQ_EIAJ_STEREO       ((s32)(2.601053 * 32768.0))
+
+#define FREQ_BTSC_DUAL         ((s32)(1.963495 * 32768.0)) /* 5pi/8  */
+#define FREQ_BTSC_DUAL_REF     ((s32)(1.374446 * 32768.0)) /* 7pi/16 */
+
+#define FREQ_BTSC_SAP          ((s32)(2.471532 * 32768.0))
+#define FREQ_BTSC_SAP_REF      ((s32)(1.730072 * 32768.0))
+
+/* The spectrum of the signal should be empty between these frequencies. */
+#define FREQ_NOISE_START       ((s32)(0.100000 * 32768.0))
+#define FREQ_NOISE_END         ((s32)(1.200000 * 32768.0))
+
+static unsigned int dsp_debug;
+module_param(dsp_debug, int, 0644);
+MODULE_PARM_DESC(dsp_debug, "enable audio dsp debug messages");
+
+#define dprintk(level, fmt, arg...)    if (dsp_debug >= level) \
+       printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg)
+
+static s32 int_cos(u32 x)
+{
+       u32 t2, t4, t6, t8;
+       s32 ret;
+       u16 period = x / INT_PI;
+       if (period % 2)
+               return -int_cos(x - INT_PI);
+       x = x % INT_PI;
+       if (x > INT_PI/2)
+               return -int_cos(INT_PI/2 - (x % (INT_PI/2)));
+       /* Now x is between 0 and INT_PI/2.
+        * To calculate cos(x) we use it's Taylor polinom. */
+       t2 = x*x/32768/2;
+       t4 = t2*x/32768*x/32768/3/4;
+       t6 = t4*x/32768*x/32768/5/6;
+       t8 = t6*x/32768*x/32768/7/8;
+       ret = 32768-t2+t4-t6+t8;
+       return ret;
+}
+
+static u32 int_goertzel(s16 x[], u32 N, u32 freq)
+{
+       /* We use the Goertzel algorithm to determine the power of the
+        * given frequency in the signal */
+       s32 s_prev = 0;
+       s32 s_prev2 = 0;
+       s32 coeff = 2*int_cos(freq);
+       u32 i;
+
+       u64 tmp;
+       u32 divisor;
+
+       for (i = 0; i < N; i++) {
+               s32 s = x[i] + ((s64)coeff*s_prev/32768) - s_prev2;
+               s_prev2 = s_prev;
+               s_prev = s;
+       }
+
+       tmp = (s64)s_prev2 * s_prev2 + (s64)s_prev * s_prev -
+                     (s64)coeff * s_prev2 * s_prev / 32768;
+
+       /* XXX: N must be low enough so that N*N fits in s32.
+        * Else we need two divisions. */
+       divisor = N * N;
+       do_div(tmp, divisor);
+
+       return (u32) tmp;
+}
+
+static u32 freq_magnitude(s16 x[], u32 N, u32 freq)
+{
+       u32 sum = int_goertzel(x, N, freq);
+       return (u32)int_sqrt(sum);
+}
+
+static u32 noise_magnitude(s16 x[], u32 N, u32 freq_start, u32 freq_end)
+{
+       int i;
+       u32 sum = 0;
+       u32 freq_step;
+       int samples = 5;
+
+       if (N > 192) {
+               /* The last 192 samples are enough for noise detection */
+               x += (N-192);
+               N = 192;
+       }
+
+       freq_step = (freq_end - freq_start) / (samples - 1);
+
+       for (i = 0; i < samples; i++) {
+               sum += int_goertzel(x, N, freq_start);
+               freq_start += freq_step;
+       }
+
+       return (u32)int_sqrt(sum / samples);
+}
+
+static s32 detect_a2_a2m_eiaj(struct cx88_core *core, s16 x[], u32 N)
+{
+       s32 carrier, stereo, dual, noise;
+       s32 carrier_freq, stereo_freq, dual_freq;
+       s32 ret;
+
+       switch (core->tvaudio) {
+       case WW_BG:
+       case WW_DK:
+               carrier_freq = FREQ_A2_CARRIER;
+               stereo_freq = FREQ_A2_STEREO;
+               dual_freq = FREQ_A2_DUAL;
+               break;
+       case WW_M:
+               carrier_freq = FREQ_A2M_CARRIER;
+               stereo_freq = FREQ_A2M_STEREO;
+               dual_freq = FREQ_A2M_DUAL;
+               break;
+       case WW_EIAJ:
+               carrier_freq = FREQ_EIAJ_CARRIER;
+               stereo_freq = FREQ_EIAJ_STEREO;
+               dual_freq = FREQ_EIAJ_DUAL;
+               break;
+       default:
+               printk(KERN_WARNING "%s/0: unsupported audio mode %d for %s\n",
+                      core->name, core->tvaudio, __func__);
+               return UNSET;
+       }
+
+       carrier = freq_magnitude(x, N, carrier_freq);
+       stereo  = freq_magnitude(x, N, stereo_freq);
+       dual    = freq_magnitude(x, N, dual_freq);
+       noise   = noise_magnitude(x, N, FREQ_NOISE_START, FREQ_NOISE_END);
+
+       dprintk(1, "detect a2/a2m/eiaj: carrier=%d, stereo=%d, dual=%d, "
+                  "noise=%d\n", carrier, stereo, dual, noise);
+
+       if (stereo > dual)
+               ret = V4L2_TUNER_SUB_STEREO;
+       else
+               ret = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+
+       if (core->tvaudio == WW_EIAJ) {
+               /* EIAJ checks may need adjustments */
+               if ((carrier > max(stereo, dual)*2) &&
+                   (carrier < max(stereo, dual)*6) &&
+                   (carrier > 20 && carrier < 200) &&
+                   (max(stereo, dual) > min(stereo, dual))) {
+                       /* For EIAJ the carrier is always present,
+                          so we probably don't need noise detection */
+                       return ret;
+               }
+       } else {
+               if ((carrier > max(stereo, dual)*2) &&
+                   (carrier < max(stereo, dual)*8) &&
+                   (carrier > 20 && carrier < 200) &&
+                   (noise < 10) &&
+                   (max(stereo, dual) > min(stereo, dual)*2)) {
+                       return ret;
+               }
+       }
+       return V4L2_TUNER_SUB_MONO;
+}
+
+static s32 detect_btsc(struct cx88_core *core, s16 x[], u32 N)
+{
+       s32 sap_ref = freq_magnitude(x, N, FREQ_BTSC_SAP_REF);
+       s32 sap = freq_magnitude(x, N, FREQ_BTSC_SAP);
+       s32 dual_ref = freq_magnitude(x, N, FREQ_BTSC_DUAL_REF);
+       s32 dual = freq_magnitude(x, N, FREQ_BTSC_DUAL);
+       dprintk(1, "detect btsc: dual_ref=%d, dual=%d, sap_ref=%d, sap=%d"
+                  "\n", dual_ref, dual, sap_ref, sap);
+       /* FIXME: Currently not supported */
+       return UNSET;
+}
+
+static s16 *read_rds_samples(struct cx88_core *core, u32 *N)
+{
+       struct sram_channel *srch = &cx88_sram_channels[SRAM_CH27];
+       s16 *samples;
+
+       unsigned int i;
+       unsigned int bpl = srch->fifo_size/AUD_RDS_LINES;
+       unsigned int spl = bpl/4;
+       unsigned int sample_count = spl*(AUD_RDS_LINES-1);
+
+       u32 current_address = cx_read(srch->ptr1_reg);
+       u32 offset = (current_address - srch->fifo_start + bpl);
+
+       dprintk(1, "read RDS samples: current_address=%08x (offset=%08x), "
+               "sample_count=%d, aud_intstat=%08x\n", current_address,
+               current_address - srch->fifo_start, sample_count,
+               cx_read(MO_AUD_INTSTAT));
+
+       samples = kmalloc(sizeof(s16)*sample_count, GFP_KERNEL);
+       if (!samples)
+               return NULL;
+
+       *N = sample_count;
+
+       for (i = 0; i < sample_count; i++)  {
+               offset = offset % (AUD_RDS_LINES*bpl);
+               samples[i] = cx_read(srch->fifo_start + offset);
+               offset += 4;
+       }
+
+       if (dsp_debug >= 2) {
+               dprintk(2, "RDS samples dump: ");
+               for (i = 0; i < sample_count; i++)
+                       printk("%hd ", samples[i]);
+               printk(".\n");
+       }
+
+       return samples;
+}
+
+s32 cx88_dsp_detect_stereo_sap(struct cx88_core *core)
+{
+       s16 *samples;
+       u32 N = 0;
+       s32 ret = UNSET;
+
+       /* If audio RDS fifo is disabled, we can't read the samples */
+       if (!(cx_read(MO_AUD_DMACNTRL) & 0x04))
+               return ret;
+       if (!(cx_read(AUD_CTL) & EN_FMRADIO_EN_RDS))
+               return ret;
+
+       /* Wait at least 500 ms after an audio standard change */
+       if (time_before(jiffies, core->last_change + msecs_to_jiffies(500)))
+               return ret;
+
+       samples = read_rds_samples(core, &N);
+
+       if (!samples)
+               return ret;
+
+       switch (core->tvaudio) {
+       case WW_BG:
+       case WW_DK:
+               ret = detect_a2_a2m_eiaj(core, samples, N);
+               break;
+       case WW_BTSC:
+               ret = detect_btsc(core, samples, N);
+               break;
+       }
+
+       kfree(samples);
+
+       if (UNSET != ret)
+               dprintk(1, "stereo/sap detection result:%s%s%s\n",
+                          (ret & V4L2_TUNER_SUB_MONO) ? " mono" : "",
+                          (ret & V4L2_TUNER_SUB_STEREO) ? " stereo" : "",
+                          (ret & V4L2_TUNER_SUB_LANG2) ? " dual" : "");
+
+       return ret;
+}
+EXPORT_SYMBOL(cx88_dsp_detect_stereo_sap);
+
index 9389cf290c1bfc815b5752697eaf120babecbcd3..c44e8760021932bf907ce3be5e135db9f661c5a8 100644 (file)
@@ -1014,6 +1014,7 @@ static int dvb_register(struct cx8802_dev *dev)
                }
                break;
         case CX88_BOARD_PINNACLE_HYBRID_PCTV:
+       case CX88_BOARD_WINFAST_DTV1800H:
                fe0->dvb.frontend = dvb_attach(zl10353_attach,
                                               &cx88_pinnacle_hybrid_pctv,
                                               &core->i2c_adap);
index 996b4ed5a4fc8ae414cd18abc1a6d1cdb44ef092..ee1ca39db06ad684758dc4da0bfa8b35aa8e1f56 100644 (file)
@@ -180,6 +180,19 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
                        do_i2c_scan(core->name,&core->i2c_client);
        } else
                printk("%s: i2c register FAILED\n", core->name);
+
+       /* Instantiate the IR receiver device, if present */
+       if (0 == core->i2c_rc) {
+               struct i2c_board_info info;
+               const unsigned short addr_list[] = {
+                       0x18, 0x6b, 0x71,
+                       I2C_CLIENT_END
+               };
+
+               memset(&info, 0, sizeof(struct i2c_board_info));
+               strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+               i2c_new_probed_device(&core->i2c_adap, &info, addr_list);
+       }
        return core->i2c_rc;
 }
 
index ec05312a9b6222f2ba627fde070777d17ef82188..d91f5c51206d0cdcacdae124b96ad5eca50de199 100644 (file)
@@ -91,6 +91,8 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
                gpio=(gpio & 0x7fd) + (auxgpio & 0xef);
                break;
        case CX88_BOARD_WINFAST_DTV1000:
+       case CX88_BOARD_WINFAST_DTV1800H:
+       case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
                gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900);
                auxgpio = gpio;
                break;
@@ -217,11 +219,13 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
        case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
        case CX88_BOARD_PCHDTV_HD3000:
        case CX88_BOARD_PCHDTV_HD5500:
+       case CX88_BOARD_HAUPPAUGE_IRONLY:
                ir_codes = ir_codes_hauppauge_new;
                ir_type = IR_TYPE_RC5;
                ir->sampling = 1;
                break;
        case CX88_BOARD_WINFAST_DTV2000H:
+       case CX88_BOARD_WINFAST_DTV1800H:
                ir_codes = ir_codes_winfast;
                ir->gpio_addr = MO_GP0_IO;
                ir->mask_keycode = 0x8f8;
@@ -230,6 +234,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
                break;
        case CX88_BOARD_WINFAST2000XP_EXPERT:
        case CX88_BOARD_WINFAST_DTV1000:
+       case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
                ir_codes = ir_codes_winfast;
                ir->gpio_addr = MO_GP0_IO;
                ir->mask_keycode = 0x8f8;
@@ -459,6 +464,7 @@ void cx88_ir_irq(struct cx88_core *core)
        case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
        case CX88_BOARD_PCHDTV_HD3000:
        case CX88_BOARD_PCHDTV_HD5500:
+       case CX88_BOARD_HAUPPAUGE_IRONLY:
                ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
                ir_dprintk("biphase decoded: %x\n", ircode);
                /*
index 7dd506b987fe76d06be6788104f67ce88cd72bc2..e8316cf7f32f70b8e76b78eac4569b205cddf15d 100644 (file)
@@ -163,6 +163,8 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl)
        /* unmute */
        volume = cx_sread(SHADOW_AUD_VOL_CTL);
        cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, volume);
+
+       core->last_change = jiffies;
 }
 
 /* ----------------------------------------------------------- */
@@ -745,6 +747,7 @@ void cx88_set_tvaudio(struct cx88_core *core)
                break;
        case WW_BG:
        case WW_DK:
+       case WW_M:
        case WW_I:
        case WW_L:
                /* prepare all dsp registers */
@@ -756,6 +759,7 @@ void cx88_set_tvaudio(struct cx88_core *core)
                if (0 == cx88_detect_nicam(core)) {
                        /* fall back to fm / am mono */
                        set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
+                       core->audiomode_current = V4L2_TUNER_MODE_MONO;
                        core->use_nicam = 0;
                } else {
                        core->use_nicam = 1;
@@ -787,6 +791,7 @@ void cx88_set_tvaudio(struct cx88_core *core)
 void cx88_newstation(struct cx88_core *core)
 {
        core->audiomode_manual = UNSET;
+       core->last_change = jiffies;
 }
 
 void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
@@ -805,12 +810,50 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
                        aud_ctl_names[cx_read(AUD_CTL) & 63]);
        core->astat = reg;
 
-/* TODO
-       Reading from AUD_STATUS is not enough
-       for auto-detecting sap/dual-fm/nicam.
-       Add some code here later.
-*/
+       t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP |
+           V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+       t->rxsubchans = UNSET;
+       t->audmode = V4L2_TUNER_MODE_MONO;
+
+       switch (mode) {
+       case 0:
+               t->audmode = V4L2_TUNER_MODE_STEREO;
+               break;
+       case 1:
+               t->audmode = V4L2_TUNER_MODE_LANG2;
+               break;
+       case 2:
+               t->audmode = V4L2_TUNER_MODE_MONO;
+               break;
+       case 3:
+               t->audmode = V4L2_TUNER_MODE_SAP;
+               break;
+       }
 
+       switch (core->tvaudio) {
+       case WW_BTSC:
+       case WW_BG:
+       case WW_DK:
+       case WW_M:
+       case WW_EIAJ:
+               if (!core->use_nicam) {
+                       t->rxsubchans = cx88_dsp_detect_stereo_sap(core);
+                       break;
+               }
+               break;
+       default:
+               /* nothing */
+               break;
+       }
+
+       /* If software stereo detection is not supported... */
+       if (UNSET == t->rxsubchans) {
+               t->rxsubchans = V4L2_TUNER_SUB_MONO;
+               /* If the hardware itself detected stereo, also return
+                  stereo as an available subchannel */
+               if (V4L2_TUNER_MODE_STEREO == t->audmode)
+                       t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
+       }
        return;
 }
 
@@ -847,6 +890,7 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
                break;
        case WW_BG:
        case WW_DK:
+       case WW_M:
        case WW_I:
        case WW_L:
                if (1 == core->use_nicam) {
@@ -872,20 +916,18 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
                                set_audio_standard_A2(core, EN_A2_FORCE_MONO1);
                        } else {
                                /* TODO: Add A2 autodection */
+                               mask = 0x3f;
                                switch (mode) {
                                case V4L2_TUNER_MODE_MONO:
                                case V4L2_TUNER_MODE_LANG1:
-                                       set_audio_standard_A2(core,
-                                                             EN_A2_FORCE_MONO1);
+                                       ctl = EN_A2_FORCE_MONO1;
                                        break;
                                case V4L2_TUNER_MODE_LANG2:
-                                       set_audio_standard_A2(core,
-                                                             EN_A2_FORCE_MONO2);
+                                       ctl = EN_A2_FORCE_MONO2;
                                        break;
                                case V4L2_TUNER_MODE_STEREO:
                                case V4L2_TUNER_MODE_LANG1_LANG2:
-                                       set_audio_standard_A2(core,
-                                                             EN_A2_FORCE_STEREO);
+                                       ctl = EN_A2_FORCE_STEREO;
                                        break;
                                }
                        }
@@ -932,24 +974,39 @@ int cx88_audio_thread(void *data)
                        break;
                try_to_freeze();
 
-               /* just monitor the audio status for now ... */
-               memset(&t, 0, sizeof(t));
-               cx88_get_stereo(core, &t);
-
-               if (UNSET != core->audiomode_manual)
-                       /* manually set, don't do anything. */
-                       continue;
-
-               /* monitor signal */
-               if (t.rxsubchans & V4L2_TUNER_SUB_STEREO)
-                       mode = V4L2_TUNER_MODE_STEREO;
-               else
-                       mode = V4L2_TUNER_MODE_MONO;
-               if (mode == core->audiomode_current)
-                       continue;
-
-               /* automatically switch to best available mode */
-               cx88_set_stereo(core, mode, 0);
+               switch (core->tvaudio) {
+               case WW_BG:
+               case WW_DK:
+               case WW_M:
+               case WW_I:
+               case WW_L:
+                       if (core->use_nicam)
+                               goto hw_autodetect;
+
+                       /* just monitor the audio status for now ... */
+                       memset(&t, 0, sizeof(t));
+                       cx88_get_stereo(core, &t);
+
+                       if (UNSET != core->audiomode_manual)
+                               /* manually set, don't do anything. */
+                               continue;
+
+                       /* monitor signal and set stereo if available */
+                       if (t.rxsubchans & V4L2_TUNER_SUB_STEREO)
+                               mode = V4L2_TUNER_MODE_STEREO;
+                       else
+                               mode = V4L2_TUNER_MODE_MONO;
+                       if (mode == core->audiomode_current)
+                               continue;
+                       /* automatically switch to best available mode */
+                       cx88_set_stereo(core, mode, 0);
+                       break;
+               default:
+hw_autodetect:
+                       /* stereo autodetection is supported by hardware so
+                          we don't need to do it manually. Do nothing. */
+                       break;
+               }
        }
 
        dprintk("cx88: tvaudio thread exiting\n");
index b993d42fe73c138f5bfc9c289d16d1aa0a13ce13..0ccac702bea4998e66dc30dfcac3aca9282390eb 100644 (file)
@@ -869,6 +869,7 @@ video_poll(struct file *file, struct poll_table_struct *wait)
 {
        struct cx8800_fh *fh = file->private_data;
        struct cx88_buffer *buf;
+       unsigned int rc = POLLERR;
 
        if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
                if (!res_get(fh->dev,fh,RESOURCE_VBI))
@@ -876,22 +877,27 @@ video_poll(struct file *file, struct poll_table_struct *wait)
                return videobuf_poll_stream(file, &fh->vbiq, wait);
        }
 
+       mutex_lock(&fh->vidq.vb_lock);
        if (res_check(fh,RESOURCE_VIDEO)) {
                /* streaming capture */
                if (list_empty(&fh->vidq.stream))
-                       return POLLERR;
+                       goto done;
                buf = list_entry(fh->vidq.stream.next,struct cx88_buffer,vb.stream);
        } else {
                /* read() capture */
                buf = (struct cx88_buffer*)fh->vidq.read_buf;
                if (NULL == buf)
-                       return POLLERR;
+                       goto done;
        }
        poll_wait(file, &buf->vb.done, wait);
        if (buf->vb.state == VIDEOBUF_DONE ||
            buf->vb.state == VIDEOBUF_ERROR)
-               return POLLIN|POLLRDNORM;
-       return 0;
+               rc = POLLIN|POLLRDNORM;
+       else
+               rc = 0;
+done:
+       mutex_unlock(&fh->vidq.vb_lock);
+       return rc;
 }
 
 static int video_release(struct file *file)
@@ -926,8 +932,10 @@ static int video_release(struct file *file)
        file->private_data = NULL;
        kfree(fh);
 
+       mutex_lock(&dev->core->lock);
        if(atomic_dec_and_test(&dev->core->users))
                call_all(dev->core, tuner, s_standby);
+       mutex_unlock(&dev->core->lock);
 
        return 0;
 }
index 7724d168fc040434d6429e01c11ca82ddaeb87ea..9d83762163f5fe8f2c0b307dc1e0bd99fcadcc14 100644 (file)
@@ -65,6 +65,8 @@
 #define VBI_LINE_COUNT              17
 #define VBI_LINE_LENGTH           2048
 
+#define AUD_RDS_LINES               4
+
 /* need "shadow" registers for some write-only ones ... */
 #define SHADOW_AUD_VOL_CTL           1
 #define SHADOW_AUD_BAL_CTL           2
@@ -132,6 +134,7 @@ struct cx88_ctrl {
 #define SRAM_CH25 4   /* audio */
 #define SRAM_CH26 5
 #define SRAM_CH28 6   /* mpeg */
+#define SRAM_CH27 7   /* audio rds */
 /* more */
 
 struct sram_channel {
@@ -232,6 +235,8 @@ extern struct sram_channel cx88_sram_channels[];
 #define CX88_BOARD_TBS_8910                77
 #define CX88_BOARD_PROF_6200               78
 #define CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII 79
+#define CX88_BOARD_HAUPPAUGE_IRONLY        80
+#define CX88_BOARD_WINFAST_DTV1800H        81
 
 enum cx88_itype {
        CX88_VMUX_COMPOSITE1 = 1,
@@ -350,6 +355,7 @@ struct cx88_core {
        u32                        input;
        u32                        astat;
        u32                        use_nicam;
+       unsigned long              last_change;
 
        /* IR remote control state */
        struct cx88_IR             *ir;
@@ -652,6 +658,7 @@ extern void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl);
 #define WW_I2SPT        8
 #define WW_FM           9
 #define WW_I2SADC       10
+#define WW_M            11
 
 void cx88_set_tvaudio(struct cx88_core *core);
 void cx88_newstation(struct cx88_core *core);
@@ -664,6 +671,11 @@ int cx8802_unregister_driver(struct cx8802_driver *drv);
 struct cx8802_dev *cx8802_get_device(int minor);
 struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype);
 
+/* ----------------------------------------------------------- */
+/* cx88-dsp.c                                                  */
+
+s32 cx88_dsp_detect_stereo_sap(struct cx88_core *core);
+
 /* ----------------------------------------------------------- */
 /* cx88-input.c                                                */
 
index ba3709bec3f0a42d84d34d2ba88e8bd62feb104a..ec2f45dde1643d72a849aa15004bbde91a1ff2c3 100644 (file)
@@ -747,8 +747,14 @@ static const struct file_operations dabusb_fops =
        .release =      dabusb_release,
 };
 
+static char *dabusb_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev));
+}
+
 static struct usb_class_driver dabusb_class = {
        .name =         "dabusb%d",
+       .nodename =     dabusb_nodename,
        .fops =         &dabusb_fops,
        .minor_base =   DABUSB_MINOR,
 };
index 0131322475bfa4792619ac0b0cdb881a36035843..7bd8a70f0a0b2b5b28bdd03bd06f28a6331ac93f 100644 (file)
@@ -339,6 +339,11 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
        mutex_lock(&dev->lock);
        dev->adev.users--;
        em28xx_audio_analog_set(dev);
+       if (substream->runtime->dma_area) {
+               dprintk("freeing\n");
+               vfree(substream->runtime->dma_area);
+               substream->runtime->dma_area = NULL;
+       }
        mutex_unlock(&dev->lock);
 
        return 0;
index 7c70738479dd0ea79a1d277567ac89368655cddd..00cc791a9e440a7524aefa017d872e5a1d08894b 100644 (file)
@@ -49,6 +49,11 @@ static unsigned int disable_ir;
 module_param(disable_ir, int, 0444);
 MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
 
+static unsigned int disable_usb_speed_check;
+module_param(disable_usb_speed_check, int, 0444);
+MODULE_PARM_DESC(disable_usb_speed_check,
+                "override min bandwidth requirement of 480M bps");
+
 static unsigned int card[]     = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
 module_param_array(card,  int, NULL, 0444);
 MODULE_PARM_DESC(card,     "card type");
@@ -104,6 +109,24 @@ static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = {
 /* Board  - EM2870 Kworld 355u
    Analog - No input analog */
 
+/* Board - EM2882 Kworld 315U digital */
+static struct em28xx_reg_seq em2882_kworld_315u_digital[] = {
+       {EM28XX_R08_GPIO,       0xff,   0xff,           10},
+       {EM28XX_R08_GPIO,       0xfe,   0xff,           10},
+       {EM2880_R04_GPO,        0x04,   0xff,           10},
+       {EM2880_R04_GPO,        0x0c,   0xff,           10},
+       {EM28XX_R08_GPIO,       0x7e,   0xff,           10},
+       {  -1,                  -1,     -1,             -1},
+};
+
+static struct em28xx_reg_seq em2882_kworld_315u_tuner_gpio[] = {
+       {EM2880_R04_GPO,        0x08,   0xff,           10},
+       {EM2880_R04_GPO,        0x0c,   0xff,           10},
+       {EM2880_R04_GPO,        0x08,   0xff,           10},
+       {EM2880_R04_GPO,        0x0c,   0xff,           10},
+       {  -1,                  -1,     -1,             -1},
+};
+
 static struct em28xx_reg_seq kworld_330u_analog[] = {
        {EM28XX_R08_GPIO,       0x6d,   ~EM_GPIO_4,     10},
        {EM2880_R04_GPO,        0x00,   0xff,           10},
@@ -140,6 +163,16 @@ static struct em28xx_reg_seq compro_mute_gpio[] = {
        {  -1,                  -1,             -1,             -1},
 };
 
+/* Terratec AV350 */
+static struct em28xx_reg_seq terratec_av350_mute_gpio[] = {
+       {EM28XX_R08_GPIO,       0xff,   0x7f,           10},
+       {       -1,             -1,     -1,             -1},
+};
+
+static struct em28xx_reg_seq terratec_av350_unmute_gpio[] = {
+       {EM28XX_R08_GPIO,       0xff,   0xff,           10},
+       {       -1,             -1,     -1,             -1},
+};
 /*
  *  Board definitions
  */
@@ -992,16 +1025,17 @@ struct em28xx_board em28xx_boards[] = {
                        .amux     = EM28XX_AMUX_LINE_IN,
                } },
        },
-       [EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA] = {
-               .name                = "PointNix Intra-Oral Camera",
+       [EM2860_BOARD_SAA711X_REFERENCE_DESIGN] = {
+               .name                = "EM2860/SAA711X Reference Design",
                .has_snapshot_button = 1,
-               .tda9887_conf        = TDA9887_PRESENT,
                .tuner_type          = TUNER_ABSENT,
                .decoder             = EM28XX_SAA711X,
                .input               = { {
                        .type     = EM28XX_VMUX_SVIDEO,
                        .vmux     = SAA7115_SVIDEO3,
-                       .amux     = EM28XX_AMUX_VIDEO,
+               }, {
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = SAA7115_COMPOSITE0,
                } },
        },
        [EM2880_BOARD_MSI_DIGIVOX_AD] = {
@@ -1095,6 +1129,63 @@ struct em28xx_board em28xx_boards[] = {
                        .gpio     = default_analog,
                } },
        },
+       [EM2882_BOARD_KWORLD_ATSC_315U] = {
+               .name           = "KWorld ATSC 315U HDTV TV Box",
+               .valid          = EM28XX_BOARD_NOT_VALIDATED,
+               .tuner_type     = TUNER_THOMSON_DTT761X,
+               .tuner_gpio     = em2882_kworld_315u_tuner_gpio,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .decoder        = EM28XX_SAA711X,
+               .has_dvb        = 1,
+               .dvb_gpio       = em2882_kworld_315u_digital,
+               .xclk           = EM28XX_XCLK_FREQUENCY_12MHZ,
+               .i2c_speed      = EM28XX_I2C_CLK_WAIT_ENABLE,
+               /* Analog mode - still not ready */
+               /*.input        = { {
+                       .type = EM28XX_VMUX_TELEVISION,
+                       .vmux = SAA7115_COMPOSITE2,
+                       .amux = EM28XX_AMUX_VIDEO,
+                       .gpio = em2882_kworld_315u_analog,
+                       .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO,
+               }, {
+                       .type = EM28XX_VMUX_COMPOSITE1,
+                       .vmux = SAA7115_COMPOSITE0,
+                       .amux = EM28XX_AMUX_LINE_IN,
+                       .gpio = em2882_kworld_315u_analog1,
+                       .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO,
+               }, {
+                       .type = EM28XX_VMUX_SVIDEO,
+                       .vmux = SAA7115_SVIDEO3,
+                       .amux = EM28XX_AMUX_LINE_IN,
+                       .gpio = em2882_kworld_315u_analog1,
+                       .aout = EM28XX_AOUT_PCM_IN | EM28XX_AOUT_PCM_STEREO,
+               } }, */
+       },
+       [EM2880_BOARD_EMPIRE_DUAL_TV] = {
+               .name = "Empire dual TV",
+               .tuner_type = TUNER_XC2028,
+               .tuner_gpio = default_tuner_gpio,
+               .has_dvb = 1,
+               .dvb_gpio = default_digital,
+               .mts_firmware = 1,
+               .decoder = EM28XX_TVP5150,
+               .input = { {
+                       .type = EM28XX_VMUX_TELEVISION,
+                       .vmux = TVP5150_COMPOSITE0,
+                       .amux = EM28XX_AMUX_VIDEO,
+                       .gpio = default_analog,
+               }, {
+                       .type = EM28XX_VMUX_COMPOSITE1,
+                       .vmux = TVP5150_COMPOSITE1,
+                       .amux = EM28XX_AMUX_LINE_IN,
+                       .gpio = default_analog,
+               }, {
+                       .type = EM28XX_VMUX_SVIDEO,
+                       .vmux = TVP5150_SVIDEO,
+                       .amux = EM28XX_AMUX_LINE_IN,
+                       .gpio = default_analog,
+               } },
+       },
        [EM2881_BOARD_DNT_DA2_HYBRID] = {
                .name         = "DNT DA2 Hybrid",
                .valid        = EM28XX_BOARD_NOT_VALIDATED,
@@ -1322,6 +1413,42 @@ struct em28xx_board em28xx_boards[] = {
                        .amux     = EM28XX_AMUX_VIDEO,
                } },
        },
+       [EM2860_BOARD_TERRATEC_GRABBY] = {
+               .name            = "Terratec Grabby",
+               .vchannels       = 2,
+               .tuner_type      = TUNER_ABSENT,
+               .decoder         = EM28XX_SAA711X,
+               .xclk            = EM28XX_XCLK_FREQUENCY_12MHZ,
+               .input           = { {
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = SAA7115_COMPOSITE0,
+                       .amux     = EM28XX_AMUX_VIDEO2,
+               }, {
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = SAA7115_SVIDEO3,
+                       .amux     = EM28XX_AMUX_VIDEO2,
+               } },
+       },
+       [EM2860_BOARD_TERRATEC_AV350] = {
+               .name            = "Terratec AV350",
+               .vchannels       = 2,
+               .tuner_type      = TUNER_ABSENT,
+               .decoder         = EM28XX_TVP5150,
+               .xclk            = EM28XX_XCLK_FREQUENCY_12MHZ,
+               .mute_gpio       = terratec_av350_mute_gpio,
+               .input           = { {
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .vmux     = TVP5150_COMPOSITE1,
+                       .amux     = EM28XX_AUDIO_SRC_LINE,
+                       .gpio     = terratec_av350_unmute_gpio,
+
+               }, {
+                       .type     = EM28XX_VMUX_SVIDEO,
+                       .vmux     = TVP5150_SVIDEO,
+                       .amux     = EM28XX_AUDIO_SRC_LINE,
+                       .gpio     = terratec_av350_unmute_gpio,
+               } },
+       },
 };
 const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
 
@@ -1355,6 +1482,8 @@ struct usb_device_id em28xx_id_table[] = {
                        .driver_info = EM2880_BOARD_KWORLD_DVB_305U },
        { USB_DEVICE(0xeb1a, 0xe310),
                        .driver_info = EM2880_BOARD_MSI_DIGIVOX_AD },
+       { USB_DEVICE(0xeb1a, 0xa313),
+               .driver_info = EM2882_BOARD_KWORLD_ATSC_315U },
        { USB_DEVICE(0xeb1a, 0xa316),
                        .driver_info = EM2883_BOARD_KWORLD_HYBRID_330U },
        { USB_DEVICE(0xeb1a, 0xe320),
@@ -1385,6 +1514,10 @@ struct usb_device_id em28xx_id_table[] = {
                        .driver_info = EM2870_BOARD_TERRATEC_XS },
        { USB_DEVICE(0x0ccd, 0x0047),
                        .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS },
+       { USB_DEVICE(0x0ccd, 0x0084),
+                       .driver_info = EM2860_BOARD_TERRATEC_AV350 },
+       { USB_DEVICE(0x0ccd, 0x0096),
+                       .driver_info = EM2860_BOARD_TERRATEC_GRABBY },
        { USB_DEVICE(0x185b, 0x2870),
                        .driver_info = EM2870_BOARD_COMPRO_VIDEOMATE },
        { USB_DEVICE(0x185b, 0x2041),
@@ -1437,13 +1570,14 @@ static struct em28xx_hash_table em28xx_eeprom_hash[] = {
        {0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF},
        {0x72cc5a8b, EM2820_BOARD_PROLINK_PLAYTV_BOX4_USB2, TUNER_YMEC_TVF_5533MF},
        {0x966a0441, EM2880_BOARD_KWORLD_DVB_310U, TUNER_XC2028},
+       {0x9567eb1a, EM2880_BOARD_EMPIRE_DUAL_TV, TUNER_XC2028},
 };
 
 /* I2C devicelist hash table for devices with generic USB IDs */
 static struct em28xx_hash_table em28xx_i2c_hash[] = {
        {0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC},
        {0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC},
-       {0x1ba50080, EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA, TUNER_ABSENT},
+       {0x1ba50080, EM2860_BOARD_SAA711X_REFERENCE_DESIGN, TUNER_ABSENT},
        {0xc51200e3, EM2820_BOARD_GADMEI_TVR200, TUNER_LG_PAL_NEW_TAPC},
 };
 
@@ -1619,6 +1753,17 @@ void em28xx_pre_card_setup(struct em28xx *dev)
                em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
                break;
 
+       case EM2882_BOARD_KWORLD_ATSC_315U:
+               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xff);
+               msleep(10);
+               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfe);
+               msleep(10);
+               em28xx_write_reg(dev, EM2880_R04_GPO, 0x00);
+               msleep(10);
+               em28xx_write_reg(dev, EM2880_R04_GPO, 0x08);
+               msleep(10);
+               break;
+
        case EM2860_BOARD_KAIOMY_TVNPC_U2:
                em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x07", 1);
                em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
@@ -1664,6 +1809,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
        ctl->mts = em28xx_boards[dev->model].mts_firmware;
 
        switch (dev->model) {
+       case EM2880_BOARD_EMPIRE_DUAL_TV:
        case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
                ctl->demod = XC3028_FE_ZARLINK456;
                break;
@@ -1835,12 +1981,20 @@ static int em28xx_hint_board(struct em28xx *dev)
 }
 
 /* ----------------------------------------------------------------------- */
-void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir)
+void em28xx_register_i2c_ir(struct em28xx *dev)
 {
-       if (disable_ir) {
-               ir->get_key = NULL;
-               return ;
-       }
+       struct i2c_board_info info;
+       struct IR_i2c_init_data init_data;
+       const unsigned short addr_list[] = {
+                0x30, 0x47, I2C_CLIENT_END
+       };
+
+       if (disable_ir)
+               return;
+
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       memset(&init_data, 0, sizeof(struct IR_i2c_init_data));
+       strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
 
        /* detect & configure */
        switch (dev->model) {
@@ -1850,22 +2004,19 @@ void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir)
                break;
        case (EM2800_BOARD_TERRATEC_CINERGY_200):
        case (EM2820_BOARD_TERRATEC_CINERGY_250):
-               ir->ir_codes = ir_codes_em_terratec;
-               ir->get_key = em28xx_get_key_terratec;
-               snprintf(ir->c.name, sizeof(ir->c.name),
-                        "i2c IR (EM28XX Terratec)");
+               init_data.ir_codes = ir_codes_em_terratec;
+               init_data.get_key = em28xx_get_key_terratec;
+               init_data.name = "i2c IR (EM28XX Terratec)";
                break;
        case (EM2820_BOARD_PINNACLE_USB_2):
-               ir->ir_codes = ir_codes_pinnacle_grey;
-               ir->get_key = em28xx_get_key_pinnacle_usb_grey;
-               snprintf(ir->c.name, sizeof(ir->c.name),
-                        "i2c IR (EM28XX Pinnacle PCTV)");
+               init_data.ir_codes = ir_codes_pinnacle_grey;
+               init_data.get_key = em28xx_get_key_pinnacle_usb_grey;
+               init_data.name = "i2c IR (EM28XX Pinnacle PCTV)";
                break;
        case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
-               ir->ir_codes = ir_codes_hauppauge_new;
-               ir->get_key = em28xx_get_key_em_haup;
-               snprintf(ir->c.name, sizeof(ir->c.name),
-                        "i2c IR (EM2840 Hauppauge)");
+               init_data.ir_codes = ir_codes_hauppauge_new;
+               init_data.get_key = em28xx_get_key_em_haup;
+               init_data.name = "i2c IR (EM2840 Hauppauge)";
                break;
        case (EM2820_BOARD_MSI_VOX_USB_2):
                break;
@@ -1876,6 +2027,10 @@ void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir)
        case (EM2800_BOARD_GRABBEEX_USB2800):
                break;
        }
+
+       if (init_data.name)
+               info.platform_data = &init_data;
+       i2c_new_probed_device(&dev->i2c_adap, &info, addr_list);
 }
 
 void em28xx_card_setup(struct em28xx *dev)
@@ -1886,6 +2041,9 @@ void em28xx_card_setup(struct em28xx *dev)
        if (em28xx_boards[dev->model].tuner_addr)
                dev->tuner_addr = em28xx_boards[dev->model].tuner_addr;
 
+       if (em28xx_boards[dev->model].tda9887_conf)
+               dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf;
+
        /* request some modules */
        switch (dev->model) {
        case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
@@ -1915,6 +2073,12 @@ void em28xx_card_setup(struct em28xx *dev)
 #endif
                break;
        }
+       case EM2882_BOARD_KWORLD_ATSC_315U:
+               em28xx_write_reg(dev, 0x0d, 0x42);
+               msleep(10);
+               em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xfd);
+               msleep(10);
+               break;
        case EM2820_BOARD_KWORLD_PVRTV2800RF:
                /* GPIO enables sound on KWORLD PVR TV 2800RF */
                em28xx_write_reg(dev, EM28XX_R08_GPIO, 0xf9);
@@ -2279,6 +2443,20 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                ifnum,
                interface->altsetting->desc.bInterfaceNumber);
 
+       /*
+        * Make sure we have 480 Mbps of bandwidth, otherwise things like
+        * video stream wouldn't likely work, since 12 Mbps is generally
+        * not enough even for most Digital TV streams.
+        */
+       if (udev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) {
+               printk(DRIVER_NAME ": Device initialization failed.\n");
+               printk(DRIVER_NAME ": Device must be connected to a high-speed"
+                      " USB 2.0 port.\n");
+               em28xx_devused &= ~(1<<nr);
+               retval = -ENODEV;
+               goto err;
+       }
+
        if (nr >= EM28XX_MAXBOARDS) {
                printk(DRIVER_NAME ": Supports only %i em28xx boards.\n",
                                EM28XX_MAXBOARDS);
index 192b76cdd5d733fb300b73e2dee2ee9134104ff4..c8d7ce8fbd368a403c47e6260e036801182144e9 100644 (file)
@@ -500,18 +500,21 @@ int em28xx_audio_setup(struct em28xx *dev)
 
        /* See how this device is configured */
        cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG);
-       if (cfg < 0)
+       em28xx_info("Config register raw data: 0x%02x\n", cfg);
+       if (cfg < 0) {
+               /* Register read error?  */
                cfg = EM28XX_CHIPCFG_AC97; /* Be conservative */
-       else
-               em28xx_info("Config register raw data: 0x%02x\n", cfg);
-
-       if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
-                   EM28XX_CHIPCFG_I2S_3_SAMPRATES) {
+       } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) == 0x00) {
+               /* The device doesn't have vendor audio at all */
+               dev->has_alsa_audio = 0;
+               dev->audio_mode.has_audio = 0;
+               return 0;
+       } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
+                  EM28XX_CHIPCFG_I2S_3_SAMPRATES) {
                em28xx_info("I2S Audio (3 sample rates)\n");
                dev->audio_mode.i2s_3rates = 1;
-       }
-       if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
-                   EM28XX_CHIPCFG_I2S_5_SAMPRATES) {
+       } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
+                  EM28XX_CHIPCFG_I2S_5_SAMPRATES) {
                em28xx_info("I2S Audio (5 sample rates)\n");
                dev->audio_mode.i2s_5rates = 1;
        }
@@ -938,7 +941,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
        dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
                                              GFP_KERNEL);
        if (!dev->isoc_ctl.transfer_buffer) {
-               em28xx_errdev("cannot allocate memory for usbtransfer\n");
+               em28xx_errdev("cannot allocate memory for usb transfer\n");
                kfree(dev->isoc_ctl.urb);
                return -ENOMEM;
        }
@@ -1012,6 +1015,41 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
 }
 EXPORT_SYMBOL_GPL(em28xx_init_isoc);
 
+/* Determine the packet size for the DVB stream for the given device
+   (underlying value programmed into the eeprom) */
+int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev)
+{
+       unsigned int chip_cfg2;
+       unsigned int packet_size = 564;
+
+       if (dev->chip_id == CHIP_ID_EM2874) {
+               /* FIXME - for now assume 564 like it was before, but the
+                  em2874 code should be added to return the proper value... */
+               packet_size = 564;
+       } else {
+               /* TS max packet size stored in bits 1-0 of R01 */
+               chip_cfg2 = em28xx_read_reg(dev, EM28XX_R01_CHIPCFG2);
+               switch (chip_cfg2 & EM28XX_CHIPCFG2_TS_PACKETSIZE_MASK) {
+               case EM28XX_CHIPCFG2_TS_PACKETSIZE_188:
+                       packet_size = 188;
+                       break;
+               case EM28XX_CHIPCFG2_TS_PACKETSIZE_376:
+                       packet_size = 376;
+                       break;
+               case EM28XX_CHIPCFG2_TS_PACKETSIZE_564:
+                       packet_size = 564;
+                       break;
+               case EM28XX_CHIPCFG2_TS_PACKETSIZE_752:
+                       packet_size = 752;
+                       break;
+               }
+       }
+
+       em28xx_coredbg("dvb max packet size=%d\n", packet_size);
+       return packet_size;
+}
+EXPORT_SYMBOL_GPL(em28xx_isoc_dvb_max_packetsize);
+
 /*
  * em28xx_wake_i2c()
  * configure i2c attached devices
index fcd25511209bc985f7273f057340a1bf07c6f5d2..563dd2b1c8e90e8d9efc0f8f4b967eb8b0fb7bdb 100644 (file)
@@ -25,6 +25,8 @@
 #include "em28xx.h"
 #include <media/v4l2-common.h>
 #include <media/videobuf-vmalloc.h>
+#include <media/tuner.h>
+#include "tuner-simple.h"
 
 #include "lgdt330x.h"
 #include "zl10353.h"
@@ -46,7 +48,6 @@ if (debug >= level)                                           \
 } while (0)
 
 #define EM28XX_DVB_NUM_BUFS 5
-#define EM28XX_DVB_MAX_PACKETSIZE 564
 #define EM28XX_DVB_MAX_PACKETS 64
 
 struct em28xx_dvb {
@@ -142,14 +143,17 @@ static int start_streaming(struct em28xx_dvb *dvb)
 {
        int rc;
        struct em28xx *dev = dvb->adapter.priv;
+       int max_dvb_packet_size;
 
        usb_set_interface(dev->udev, 0, 1);
        rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
        if (rc < 0)
                return rc;
 
+       max_dvb_packet_size = em28xx_isoc_dvb_max_packetsize(dev);
+
        return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS,
-                               EM28XX_DVB_NUM_BUFS, EM28XX_DVB_MAX_PACKETSIZE,
+                               EM28XX_DVB_NUM_BUFS, max_dvb_packet_size,
                                dvb_isoc_copy);
 }
 
@@ -431,6 +435,7 @@ static int dvb_init(struct em28xx *dev)
        case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
        case EM2880_BOARD_TERRATEC_HYBRID_XS:
        case EM2880_BOARD_KWORLD_DVB_310U:
+       case EM2880_BOARD_EMPIRE_DUAL_TV:
                dvb->frontend = dvb_attach(zl10353_attach,
                                           &em28xx_zl10353_with_xc3028,
                                           &dev->i2c_adap);
@@ -448,6 +453,18 @@ static int dvb_init(struct em28xx *dev)
                        goto out_free;
                }
                break;
+       case EM2882_BOARD_KWORLD_ATSC_315U:
+               dvb->frontend = dvb_attach(lgdt330x_attach,
+                                          &em2880_lgdt3303_dev,
+                                          &dev->i2c_adap);
+               if (dvb->frontend != NULL) {
+                       if (!dvb_attach(simple_tuner_attach, dvb->frontend,
+                               &dev->i2c_adap, 0x61, TUNER_THOMSON_DTT761X)) {
+                               result = -EINVAL;
+                               goto out_free;
+                       }
+               }
+               break;
        case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
 #ifdef EM28XX_DRX397XD_SUPPORT
                /* We don't have the config structure properly populated, so
index f0bf1d960c759a081652ade96e3573d6326a6113..2c86fcf089f59b45de048179e4be46fe76c989d4 100644 (file)
@@ -451,27 +451,6 @@ static u32 functionality(struct i2c_adapter *adap)
        return I2C_FUNC_SMBUS_EMUL;
 }
 
-/*
- * attach_inform()
- * gets called when a device attaches to the i2c bus
- * does some basic configuration
- */
-static int attach_inform(struct i2c_client *client)
-{
-       struct em28xx *dev = client->adapter->algo_data;
-       struct IR_i2c *ir = i2c_get_clientdata(client);
-
-       switch (client->addr << 1) {
-       case 0x60:
-       case 0x8e:
-               dprintk1(1, "attach_inform: IR detected (%s).\n", ir->phys);
-               em28xx_set_ir(dev, ir);
-               break;
-       }
-
-       return 0;
-}
-
 static struct i2c_algorithm em28xx_algo = {
        .master_xfer   = em28xx_i2c_xfer,
        .functionality = functionality,
@@ -482,7 +461,6 @@ static struct i2c_adapter em28xx_adap_template = {
        .name = "em28xx",
        .id = I2C_HW_B_EM28XX,
        .algo = &em28xx_algo,
-       .client_register = attach_inform,
 };
 
 static struct i2c_client em28xx_client_template = {
@@ -575,6 +553,9 @@ int em28xx_i2c_register(struct em28xx *dev)
        if (i2c_scan)
                em28xx_do_i2c_scan(dev);
 
+       /* Instantiate the IR receiver device, if present */
+       em28xx_register_i2c_ir(dev);
+
        return 0;
 }
 
index a5abfd7a19f577d4e00bd4bbaf42f647641b9385..7a0fe3816e3db6613d051c528ac8a25347ea8d97 100644 (file)
@@ -40,7 +40,7 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
 
 #define i2cdprintk(fmt, arg...) \
        if (ir_debug) { \
-               printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg); \
+               printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
        }
 
 #define dprintk(fmt, arg...) \
@@ -85,7 +85,7 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        unsigned char b;
 
        /* poll IR chip */
-       if (1 != i2c_master_recv(&ir->c, &b, 1)) {
+       if (1 != i2c_master_recv(ir->c, &b, 1)) {
                i2cdprintk("read error\n");
                return -EIO;
        }
@@ -114,7 +114,7 @@ int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        unsigned char code;
 
        /* poll IR chip */
-       if (2 != i2c_master_recv(&ir->c, buf, 2))
+       if (2 != i2c_master_recv(ir->c, buf, 2))
                return -EIO;
 
        /* Does eliminate repeated parity code */
@@ -147,7 +147,7 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
 
        /* poll IR chip */
 
-       if (3 != i2c_master_recv(&ir->c, buf, 3)) {
+       if (3 != i2c_master_recv(ir->c, buf, 3)) {
                i2cdprintk("read error\n");
                return -EIO;
        }
index 24e39c56811e98713f8497cca6f46fbd48409209..a2676d63cfd0a673cfd26b6e0ddd593ecab10e5a 100644 (file)
 #define EM28XX_CHIPCFG_AC97                    0x10
 #define EM28XX_CHIPCFG_AUDIOMASK               0x30
 
+#define EM28XX_R01_CHIPCFG2    0x01
+
+/* em28xx Chip Configuration 2 0x01 */
+#define EM28XX_CHIPCFG2_TS_PRESENT             0x10
+#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_MASK   0x0c /* bits 3-2 */
+#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_1MF    0x00
+#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_2MF    0x04
+#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_4MF    0x08
+#define EM28XX_CHIPCFG2_TS_REQ_INTERVAL_8MF    0x0c
+#define EM28XX_CHIPCFG2_TS_PACKETSIZE_MASK     0x03 /* bits 0-1 */
+#define EM28XX_CHIPCFG2_TS_PACKETSIZE_188      0x00
+#define EM28XX_CHIPCFG2_TS_PACKETSIZE_376      0x01
+#define EM28XX_CHIPCFG2_TS_PACKETSIZE_564      0x02
+#define EM28XX_CHIPCFG2_TS_PACKETSIZE_752      0x03
+
+
        /* GPIO/GPO registers */
 #define EM2880_R04_GPO 0x04    /* em2880-em2883 only */
 #define EM28XX_R08_GPIO        0x08    /* em2820 or upper */
index 4c4e58004f5473fb8c2c1d0dfb188f4d1b4a8b51..8bf81be1da615eee54c89d5961e19283dd8ef64c 100644 (file)
@@ -58,7 +58,7 @@
 #define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950   16
 #define EM2880_BOARD_PINNACLE_PCTV_HD_PRO      17
 #define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2        18
-#define EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA  19
+#define EM2860_BOARD_SAA711X_REFERENCE_DESIGN  19
 #define EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600   20
 #define EM2800_BOARD_GRABBEEX_USB2800           21
 #define EM2750_BOARD_UNKNOWN                     22
 #define EM2860_BOARD_KAIOMY_TVNPC_U2              63
 #define EM2860_BOARD_EASYCAP                      64
 #define EM2820_BOARD_IODATA_GVMVP_SZ             65
+#define EM2880_BOARD_EMPIRE_DUAL_TV              66
+#define EM2860_BOARD_TERRATEC_GRABBY             67
+#define EM2860_BOARD_TERRATEC_AV350              68
+#define EM2882_BOARD_KWORLD_ATSC_315U            69
 
 /* Limits minimum and default number of buffers */
 #define EM28XX_MIN_BUF 4
@@ -615,6 +619,7 @@ int em28xx_init_isoc(struct em28xx *dev, int max_packets,
                     int num_bufs, int max_pkt_size,
                     int (*isoc_copy) (struct em28xx *dev, struct urb *urb));
 void em28xx_uninit_isoc(struct em28xx *dev);
+int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev);
 int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
 int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio);
 void em28xx_wake_i2c(struct em28xx *dev);
@@ -639,7 +644,7 @@ extern void em28xx_card_setup(struct em28xx *dev);
 extern struct em28xx_board em28xx_boards[];
 extern struct usb_device_id em28xx_id_table[];
 extern const unsigned int em28xx_bcount;
-void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir);
+void em28xx_register_i2c_ir(struct em28xx *dev);
 int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
 void em28xx_release_resources(struct em28xx *dev);
 
index 00e6863ed66692d20581b88559041084fed917ad..480ec5c87d0ed3ecc8696ad1cd2a56ad007a10f3 100644 (file)
@@ -168,6 +168,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
        cam->cam_mode = fpix_mode;
        cam->nmodes = 1;
+       cam->bulk = 1;
        cam->bulk_size = FPIX_MAX_TRANSFER;
 
        INIT_WORK(&dev->work_struct, dostream);
index a2741d7dccfeca4696c0167fce5b317f5eba7e56..f7e0355ad644f5181bcdbbd36bb3fa1b9483f82e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Main USB camera driver
  *
- * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2008-2009 Jean-Francois Moine (http://moinejf.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
@@ -47,7 +47,7 @@ MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
 MODULE_DESCRIPTION("GSPCA USB Camera Driver");
 MODULE_LICENSE("GPL");
 
-#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 5, 0)
+#define DRIVER_VERSION_NUMBER  KERNEL_VERSION(2, 6, 0)
 
 #ifdef GSPCA_DEBUG
 int gspca_debug = D_ERR | D_PROBE;
@@ -441,7 +441,7 @@ static void destroy_urbs(struct gspca_dev *gspca_dev)
  * look for an input transfer endpoint in an alternate setting
  */
 static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt,
-                                         __u8 xfer)
+                                         int xfer)
 {
        struct usb_host_endpoint *ep;
        int i, attr;
@@ -449,7 +449,8 @@ static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt,
        for (i = 0; i < alt->desc.bNumEndpoints; i++) {
                ep = &alt->endpoint[i];
                attr = ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
-               if (attr == xfer)
+               if (attr == xfer
+                   && ep->desc.wMaxPacketSize != 0)
                        return ep;
        }
        return NULL;
@@ -467,37 +468,28 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev)
 {
        struct usb_interface *intf;
        struct usb_host_endpoint *ep;
-       int i, ret;
+       int xfer, i, ret;
 
        intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
        ep = NULL;
+       xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK
+                                  : USB_ENDPOINT_XFER_ISOC;
        i = gspca_dev->alt;                     /* previous alt setting */
-
-       /* try isoc */
        while (--i >= 0) {
-               ep = alt_xfer(&intf->altsetting[i],
-                               USB_ENDPOINT_XFER_ISOC);
+               ep = alt_xfer(&intf->altsetting[i], xfer);
                if (ep)
                        break;
        }
-
-       /* if no isoc, try bulk (alt 0 only) */
        if (ep == NULL) {
-               ep = alt_xfer(&intf->altsetting[0],
-                               USB_ENDPOINT_XFER_BULK);
-               if (ep == NULL) {
-                       err("no transfer endpoint found");
-                       return NULL;
-               }
-               i = 0;
-               gspca_dev->bulk = 1;
+               err("no transfer endpoint found");
+               return NULL;
        }
        PDEBUG(D_STREAM, "use alt %d ep 0x%02x",
                        i, ep->desc.bEndpointAddress);
-       if (i > 0) {
+       if (gspca_dev->nbalt > 1) {
                ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i);
                if (ret < 0) {
-                       err("set interface err %d", ret);
+                       err("set alt %d err %d", i, ret);
                        return NULL;
                }
        }
@@ -517,13 +509,13 @@ static int create_urbs(struct gspca_dev *gspca_dev,
        /* calculate the packet size and the number of packets */
        psize = le16_to_cpu(ep->desc.wMaxPacketSize);
 
-       if (!gspca_dev->bulk) {                 /* isoc */
+       if (!gspca_dev->cam.bulk) {             /* isoc */
 
                /* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */
                psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
-               npkt = ISO_MAX_SIZE / psize;
-               if (npkt > ISO_MAX_PKT)
-                       npkt = ISO_MAX_PKT;
+               npkt = gspca_dev->cam.npkt;
+               if (npkt == 0)
+                       npkt = 32;              /* default value */
                bsize = psize * npkt;
                PDEBUG(D_STREAM,
                        "isoc %d pkts size %d = bsize:%d",
@@ -617,7 +609,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
                        goto out;
 
                /* clear the bulk endpoint */
-               if (gspca_dev->bulk)
+               if (gspca_dev->cam.bulk)
                        usb_clear_halt(gspca_dev->dev,
                                        gspca_dev->urb[0]->pipe);
 
@@ -630,7 +622,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
                gspca_dev->streaming = 1;
 
                /* some bulk transfers are started by the subdriver */
-               if (gspca_dev->bulk && gspca_dev->cam.bulk_nurbs == 0)
+               if (gspca_dev->cam.bulk && gspca_dev->cam.bulk_nurbs == 0)
                        break;
 
                /* submit the URBs */
@@ -661,6 +653,8 @@ static int gspca_set_alt0(struct gspca_dev *gspca_dev)
 {
        int ret;
 
+       if (gspca_dev->alt == 0)
+               return 0;
        ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0);
        if (ret < 0)
                PDEBUG(D_ERR|D_STREAM, "set alt 0 err %d", ret);
@@ -869,6 +863,32 @@ out:
        return ret;
 }
 
+static int vidioc_enum_framesizes(struct file *file, void *priv,
+                                 struct v4l2_frmsizeenum *fsize)
+{
+       struct gspca_dev *gspca_dev = priv;
+       int i;
+       __u32 index = 0;
+
+       for (i = 0; i < gspca_dev->cam.nmodes; i++) {
+               if (fsize->pixel_format !=
+                               gspca_dev->cam.cam_mode[i].pixelformat)
+                       continue;
+
+               if (fsize->index == index) {
+                       fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+                       fsize->discrete.width =
+                               gspca_dev->cam.cam_mode[i].width;
+                       fsize->discrete.height =
+                               gspca_dev->cam.cam_mode[i].height;
+                       return 0;
+               }
+               index++;
+       }
+
+       return -EINVAL;
+}
+
 static void gspca_release(struct video_device *vfd)
 {
        struct gspca_dev *gspca_dev = container_of(vfd, struct gspca_dev, vdev);
@@ -989,43 +1009,54 @@ out:
        return ret;
 }
 
+static const struct ctrl *get_ctrl(struct gspca_dev *gspca_dev,
+                                  int id)
+{
+       const struct ctrl *ctrls;
+       int i;
+
+       for (i = 0, ctrls = gspca_dev->sd_desc->ctrls;
+            i < gspca_dev->sd_desc->nctrls;
+            i++, ctrls++) {
+               if (gspca_dev->ctrl_dis & (1 << i))
+                       continue;
+               if (id == ctrls->qctrl.id)
+                       return ctrls;
+       }
+       return NULL;
+}
+
 static int vidioc_queryctrl(struct file *file, void *priv,
                           struct v4l2_queryctrl *q_ctrl)
 {
        struct gspca_dev *gspca_dev = priv;
-       int i, ix;
+       const struct ctrl *ctrls;
+       int i;
        u32 id;
 
-       ix = -1;
+       ctrls = NULL;
        id = q_ctrl->id;
        if (id & V4L2_CTRL_FLAG_NEXT_CTRL) {
                id &= V4L2_CTRL_ID_MASK;
                id++;
                for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
-                       if (gspca_dev->sd_desc->ctrls[i].qctrl.id < id)
+                       if (gspca_dev->ctrl_dis & (1 << i))
                                continue;
-                       if (ix < 0) {
-                               ix = i;
+                       if (ctrls->qctrl.id < id)
                                continue;
+                       if (ctrls != NULL) {
+                               if (gspca_dev->sd_desc->ctrls[i].qctrl.id
+                                           > ctrls->qctrl.id)
+                                       continue;
                        }
-                       if (gspca_dev->sd_desc->ctrls[i].qctrl.id
-                                   > gspca_dev->sd_desc->ctrls[ix].qctrl.id)
-                               continue;
-                       ix = i;
-               }
-       }
-       for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
-               if (id == gspca_dev->sd_desc->ctrls[i].qctrl.id) {
-                       ix = i;
-                       break;
+                       ctrls = &gspca_dev->sd_desc->ctrls[i];
                }
+       } else {
+               ctrls = get_ctrl(gspca_dev, id);
        }
-       if (ix < 0)
+       if (ctrls == NULL)
                return -EINVAL;
-       memcpy(q_ctrl, &gspca_dev->sd_desc->ctrls[ix].qctrl,
-               sizeof *q_ctrl);
-       if (gspca_dev->ctrl_dis & (1 << ix))
-               q_ctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+       memcpy(q_ctrl, ctrls, sizeof *q_ctrl);
        return 0;
 }
 
@@ -1034,56 +1065,45 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
 {
        struct gspca_dev *gspca_dev = priv;
        const struct ctrl *ctrls;
-       int i, ret;
+       int ret;
 
-       for (i = 0, ctrls = gspca_dev->sd_desc->ctrls;
-            i < gspca_dev->sd_desc->nctrls;
-            i++, ctrls++) {
-               if (ctrl->id != ctrls->qctrl.id)
-                       continue;
-               if (gspca_dev->ctrl_dis & (1 << i))
-                       return -EINVAL;
-               if (ctrl->value < ctrls->qctrl.minimum
-                   || ctrl->value > ctrls->qctrl.maximum)
-                       return -ERANGE;
-               PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value);
-               if (mutex_lock_interruptible(&gspca_dev->usb_lock))
-                       return -ERESTARTSYS;
-               if (gspca_dev->present)
-                       ret = ctrls->set(gspca_dev, ctrl->value);
-               else
-                       ret = -ENODEV;
-               mutex_unlock(&gspca_dev->usb_lock);
-               return ret;
-       }
-       return -EINVAL;
+       ctrls = get_ctrl(gspca_dev, ctrl->id);
+       if (ctrls == NULL)
+               return -EINVAL;
+
+       if (ctrl->value < ctrls->qctrl.minimum
+           || ctrl->value > ctrls->qctrl.maximum)
+               return -ERANGE;
+       PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value);
+       if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+               return -ERESTARTSYS;
+       if (gspca_dev->present)
+               ret = ctrls->set(gspca_dev, ctrl->value);
+       else
+               ret = -ENODEV;
+       mutex_unlock(&gspca_dev->usb_lock);
+       return ret;
 }
 
 static int vidioc_g_ctrl(struct file *file, void *priv,
                         struct v4l2_control *ctrl)
 {
        struct gspca_dev *gspca_dev = priv;
-
        const struct ctrl *ctrls;
-       int i, ret;
+       int ret;
 
-       for (i = 0, ctrls = gspca_dev->sd_desc->ctrls;
-            i < gspca_dev->sd_desc->nctrls;
-            i++, ctrls++) {
-               if (ctrl->id != ctrls->qctrl.id)
-                       continue;
-               if (gspca_dev->ctrl_dis & (1 << i))
-                       return -EINVAL;
-               if (mutex_lock_interruptible(&gspca_dev->usb_lock))
-                       return -ERESTARTSYS;
-               if (gspca_dev->present)
-                       ret = ctrls->get(gspca_dev, &ctrl->value);
-               else
-                       ret = -ENODEV;
-               mutex_unlock(&gspca_dev->usb_lock);
-               return ret;
-       }
-       return -EINVAL;
+       ctrls = get_ctrl(gspca_dev, ctrl->id);
+       if (ctrls == NULL)
+               return -EINVAL;
+
+       if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+               return -ERESTARTSYS;
+       if (gspca_dev->present)
+               ret = ctrls->get(gspca_dev, &ctrl->value);
+       else
+               ret = -ENODEV;
+       mutex_unlock(&gspca_dev->usb_lock);
+       return ret;
 }
 
 /*fixme: have an audio flag in gspca_dev?*/
@@ -1864,6 +1884,7 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = {
        .vidioc_g_parm          = vidioc_g_parm,
        .vidioc_s_parm          = vidioc_s_parm,
        .vidioc_s_std           = vidioc_s_std,
+       .vidioc_enum_framesizes = vidioc_enum_framesizes,
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
        .vidiocgmbuf          = vidiocgmbuf,
 #endif
@@ -1943,7 +1964,7 @@ int gspca_dev_probe(struct usb_interface *intf,
 
        /* init video stuff */
        memcpy(&gspca_dev->vdev, &gspca_template, sizeof gspca_template);
-       gspca_dev->vdev.parent = &dev->dev;
+       gspca_dev->vdev.parent = &intf->dev;
        gspca_dev->module = module;
        gspca_dev->present = 1;
        ret = video_register_device(&gspca_dev->vdev,
index 58e8ff02136a46bbca14802753c3c09e45115314..bd1faff8864454a9aa163603570fb62c935eab64 100644 (file)
@@ -44,8 +44,6 @@ extern int gspca_debug;
 #define GSPCA_MAX_FRAMES 16    /* maximum number of video frame buffers */
 /* image transfers */
 #define MAX_NURBS 4            /* max number of URBs */
-#define ISO_MAX_PKT 32         /* max number of packets in an ISOC transfer */
-#define ISO_MAX_SIZE 0x8000    /* max size of one URB buffer (32 Kb) */
 
 /* device information - set at probe time */
 struct cam {
@@ -56,6 +54,9 @@ struct cam {
                                 * - cannot be > MAX_NURBS
                                 * - when 0 and bulk_size != 0 means
                                 *   1 URB and submit done by subdriver */
+       u8 bulk;                /* image transfer by 0:isoc / 1:bulk */
+       u8 npkt;                /* number of packets in an ISOC message
+                                * 0 is the default value: 32 packets */
        u32 input_flags;        /* value for ENUM_INPUT status flags */
 };
 
@@ -168,7 +169,6 @@ struct gspca_dev {
        __u8 iface;                     /* USB interface number */
        __u8 alt;                       /* USB alternate setting */
        __u8 nbalt;                     /* number of USB alternate settings */
-       u8 bulk;                        /* image transfer by 0:isoc / 1:bulk */
 };
 
 int gspca_dev_probe(struct usb_interface *intf,
index 9fa3644f4869971d73aa76337c625da57e8f5eb3..bf7a19a1e6d1470c3b5dbc611187a499ea53add8 100644 (file)
@@ -2,9 +2,10 @@ obj-$(CONFIG_USB_M5602) += gspca_m5602.o
 
 gspca_m5602-objs := m5602_core.o \
                    m5602_ov9650.o \
+                   m5602_ov7660.o \
                    m5602_mt9m111.o \
                    m5602_po1030.o \
                    m5602_s5k83a.o \
                    m5602_s5k4aa.o
 
-EXTRA_CFLAGS += -Idrivers/media/video/gspca
\ No newline at end of file
+EXTRA_CFLAGS += -Idrivers/media/video/gspca
index 8f1cea6fd3bface9c601eda1dc6de8befc507a0b..1127a405c9b2ce2f9687aff3292ecf6fc7d31b6c 100644 (file)
 #define M5602_XB_SEN_CLK_DIV           0x15
 #define M5602_XB_AUD_CLK_CTRL          0x16
 #define M5602_XB_AUD_CLK_DIV           0x17
+#define M5602_OB_AC_LINK_STATE         0x22
+#define M5602_OB_PCM_SLOT_INDEX                0x24
+#define M5602_OB_GPIO_SLOT_INDEX       0x25
+#define M5602_OB_ACRX_STATUS_ADDRESS_H 0x28
+#define M5602_OB_ACRX_STATUS_DATA_L    0x29
+#define M5602_OB_ACRX_STATUS_DATA_H    0x2a
+#define M5602_OB_ACTX_COMMAND_ADDRESS  0x31
+#define M5602_OB_ACRX_COMMAND_DATA_L   0x32
+#define M5602_OB_ACTX_COMMAND_DATA_H   0X33
 #define M5602_XB_DEVCTR1               0x41
 #define M5602_XB_EPSETR0               0x42
 #define M5602_XB_EPAFCTR               0x47
 #define M5602_XB_GPIO_EN_L             0x75
 #define M5602_XB_GPIO_DAT              0x76
 #define M5602_XB_GPIO_DIR              0x77
-#define M5602_XB_MISC_CTL              0x70
+#define M5602_XB_SEN_CLK_CONTROL       0x80
+#define M5602_XB_SEN_CLK_DIVISION      0x81
+#define M5602_XB_CPR_CLK_CONTROL       0x82
+#define M5602_XB_CPR_CLK_DIVISION      0x83
+#define M5602_XB_MCU_CLK_CONTROL       0x84
+#define M5602_XB_MCU_CLK_DIVISION      0x85
+#define M5602_XB_DCT_CLK_CONTROL       0x86
+#define M5602_XB_DCT_CLK_DIVISION      0x87
+#define M5602_XB_EC_CLK_CONTROL                0x88
+#define M5602_XB_EC_CLK_DIVISION       0x89
+#define M5602_XB_LBUF_CLK_CONTROL      0x8a
+#define M5602_XB_LBUF_CLK_DIVISION     0x8b
 
 #define I2C_BUSY 0x80
 
@@ -128,10 +148,10 @@ struct sd {
 };
 
 int m5602_read_bridge(
-       struct sd *sd, u8 address, u8 *i2c_data);
+       struct sd *sd, const u8 address, u8 *i2c_data);
 
 int m5602_write_bridge(
-       struct sd *sd, u8 address, u8 i2c_data);
+       struct sd *sd, const u8 address, const u8 i2c_data);
 
 int m5602_write_sensor(struct sd *sd, const u8 address,
                       u8 *i2c_data, const u8 len);
index 1aac2985fee6db002240466fbabd0981ee350f43..8a5bba16ff32379c2b0472f25a33cc9e5863a257 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #include "m5602_ov9650.h"
+#include "m5602_ov7660.h"
 #include "m5602_mt9m111.h"
 #include "m5602_po1030.h"
 #include "m5602_s5k83a.h"
@@ -35,7 +36,7 @@ static const __devinitdata struct usb_device_id m5602_table[] = {
 MODULE_DEVICE_TABLE(usb, m5602_table);
 
 /* Reads a byte from the m5602 */
-int m5602_read_bridge(struct sd *sd, u8 address, u8 *i2c_data)
+int m5602_read_bridge(struct sd *sd, const u8 address, u8 *i2c_data)
 {
        int err;
        struct usb_device *udev = sd->gspca_dev.dev;
@@ -56,7 +57,7 @@ int m5602_read_bridge(struct sd *sd, u8 address, u8 *i2c_data)
 }
 
 /* Writes a byte to to the m5602 */
-int m5602_write_bridge(struct sd *sd, u8 address, u8 i2c_data)
+int m5602_write_bridge(struct sd *sd, const u8 address, const u8 i2c_data)
 {
        int err;
        struct usb_device *udev = sd->gspca_dev.dev;
@@ -80,6 +81,17 @@ int m5602_write_bridge(struct sd *sd, u8 address, u8 i2c_data)
        return (err < 0) ? err : 0;
 }
 
+int m5602_wait_for_i2c(struct sd *sd)
+{
+       int err;
+       u8 data;
+
+       do {
+               err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, &data);
+       } while ((data & I2C_BUSY) && !err);
+       return err;
+}
+
 int m5602_read_sensor(struct sd *sd, const u8 address,
                       u8 *i2c_data, const u8 len)
 {
@@ -88,9 +100,7 @@ int m5602_read_sensor(struct sd *sd, const u8 address,
        if (!len || len > sd->sensor->i2c_regW)
                return -EINVAL;
 
-       do {
-               err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
-       } while ((*i2c_data & I2C_BUSY) && !err);
+       err = m5602_wait_for_i2c(sd);
        if (err < 0)
                return err;
 
@@ -103,21 +113,25 @@ int m5602_read_sensor(struct sd *sd, const u8 address,
        if (err < 0)
                return err;
 
+       /* Sensors with registers that are of only
+          one byte width are differently read */
+
+       /* FIXME: This works with the ov9650, but has issues with the po1030 */
        if (sd->sensor->i2c_regW == 1) {
-               err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, len);
+               err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 1);
                if (err < 0)
                        return err;
 
                err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x08);
-               if (err < 0)
-                       return err;
        } else {
                err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x18 + len);
-               if (err < 0)
-                       return err;
        }
 
        for (i = 0; (i < len) && !err; i++) {
+               err = m5602_wait_for_i2c(sd);
+               if (err < 0)
+                       return err;
+
                err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
 
                PDEBUG(D_CONF, "Reading sensor register "
@@ -206,6 +220,11 @@ static int m5602_probe_sensor(struct sd *sd)
        if (!sd->sensor->probe(sd))
                return 0;
 
+       /* Try the ov7660 */
+       sd->sensor = &ov7660;
+       if (!sd->sensor->probe(sd))
+               return 0;
+
        /* Try the s5k83a */
        sd->sensor = &s5k83a;
        if (!sd->sensor->probe(sd))
@@ -409,8 +428,9 @@ MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 module_param(force_sensor, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(force_sensor,
-               "force detection of sensor, "
-               "1 = OV9650, 2 = S5K83A, 3 = S5K4AA, 4 = MT9M111, 5 = PO1030");
+               "forces detection of a sensor, "
+               "1 = OV9650, 2 = S5K83A, 3 = S5K4AA, "
+               "4 = MT9M111, 5 = PO1030, 6 = OV7660");
 
 module_param(dump_bridge, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(dump_bridge, "Dumps all usb bridge registers at startup");
index 7d3f9e348ef4d5b6a576da145611da5d367e1c24..8d071dff6944bf01d178180764f70cf166e17b5b 100644 (file)
 
 #include "m5602_mt9m111.h"
 
+static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
+                                        __s32 val);
+static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev,
+                                         __s32 *val);
+static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
+
 static struct v4l2_pix_format mt9m111_modes[] = {
        {
                640,
@@ -32,6 +49,7 @@ static struct v4l2_pix_format mt9m111_modes[] = {
 };
 
 const static struct ctrl mt9m111_ctrls[] = {
+#define VFLIP_IDX 0
        {
                {
                        .id             = V4L2_CID_VFLIP,
@@ -44,7 +62,9 @@ const static struct ctrl mt9m111_ctrls[] = {
                },
                .set = mt9m111_set_vflip,
                .get = mt9m111_get_vflip
-       }, {
+       },
+#define HFLIP_IDX 1
+       {
                {
                        .id             = V4L2_CID_HFLIP,
                        .type           = V4L2_CTRL_TYPE_BOOLEAN,
@@ -56,7 +76,9 @@ const static struct ctrl mt9m111_ctrls[] = {
                },
                .set = mt9m111_set_hflip,
                .get = mt9m111_get_hflip
-       }, {
+       },
+#define GAIN_IDX 2
+       {
                {
                        .id             = V4L2_CID_GAIN,
                        .type           = V4L2_CTRL_TYPE_INTEGER,
@@ -64,21 +86,80 @@ const static struct ctrl mt9m111_ctrls[] = {
                        .minimum        = 0,
                        .maximum        = (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2,
                        .step           = 1,
-                       .default_value  = DEFAULT_GAIN,
+                       .default_value  = MT9M111_DEFAULT_GAIN,
                        .flags          = V4L2_CTRL_FLAG_SLIDER
                },
                .set = mt9m111_set_gain,
                .get = mt9m111_get_gain
-       }
+       },
+#define AUTO_WHITE_BALANCE_IDX 3
+       {
+               {
+                       .id             = V4L2_CID_AUTO_WHITE_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "auto white balance",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0,
+               },
+               .set = mt9m111_set_auto_white_balance,
+               .get = mt9m111_get_auto_white_balance
+       },
+#define GREEN_BALANCE_IDX 4
+       {
+               {
+                       .id             = M5602_V4L2_CID_GREEN_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "green balance",
+                       .minimum        = 0x00,
+                       .maximum        = 0x7ff,
+                       .step           = 0x1,
+                       .default_value  = MT9M111_GREEN_GAIN_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = mt9m111_set_green_balance,
+               .get = mt9m111_get_green_balance
+       },
+#define BLUE_BALANCE_IDX 5
+       {
+               {
+                       .id             = V4L2_CID_BLUE_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "blue balance",
+                       .minimum        = 0x00,
+                       .maximum        = 0x7ff,
+                       .step           = 0x1,
+                       .default_value  = MT9M111_BLUE_GAIN_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = mt9m111_set_blue_balance,
+               .get = mt9m111_get_blue_balance
+       },
+#define RED_BALANCE_IDX 5
+       {
+               {
+                       .id             = V4L2_CID_RED_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "red balance",
+                       .minimum        = 0x00,
+                       .maximum        = 0x7ff,
+                       .step           = 0x1,
+                       .default_value  = MT9M111_RED_GAIN_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = mt9m111_set_red_balance,
+               .get = mt9m111_get_red_balance
+       },
 };
 
-
 static void mt9m111_dump_registers(struct sd *sd);
 
 int mt9m111_probe(struct sd *sd)
 {
        u8 data[2] = {0x00, 0x00};
        int i;
+       s32 *sensor_settings;
 
        if (force_sensor) {
                if (force_sensor == MT9M111_SENSOR) {
@@ -117,16 +198,27 @@ int mt9m111_probe(struct sd *sd)
        return -ENODEV;
 
 sensor_found:
+       sensor_settings = kmalloc(ARRAY_SIZE(mt9m111_ctrls) * sizeof(s32),
+                                 GFP_KERNEL);
+       if (!sensor_settings)
+               return -ENOMEM;
+
        sd->gspca_dev.cam.cam_mode = mt9m111_modes;
        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(mt9m111_modes);
        sd->desc->ctrls = mt9m111_ctrls;
        sd->desc->nctrls = ARRAY_SIZE(mt9m111_ctrls);
+
+       for (i = 0; i < ARRAY_SIZE(mt9m111_ctrls); i++)
+               sensor_settings[i] = mt9m111_ctrls[i].qctrl.default_value;
+       sd->sensor_priv = sensor_settings;
+
        return 0;
 }
 
 int mt9m111_init(struct sd *sd)
 {
        int i, err = 0;
+       s32 *sensor_settings = sd->sensor_priv;
 
        /* Init the sensor */
        for (i = 0; i < ARRAY_SIZE(init_mt9m111) && !err; i++) {
@@ -147,36 +239,154 @@ int mt9m111_init(struct sd *sd)
        if (dump_sensor)
                mt9m111_dump_registers(sd);
 
-       return (err < 0) ? err : 0;
+       err = mt9m111_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
+       if (err < 0)
+               return err;
+
+       err = mt9m111_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
+       if (err < 0)
+               return err;
+
+       err = mt9m111_set_green_balance(&sd->gspca_dev,
+                                        sensor_settings[GREEN_BALANCE_IDX]);
+       if (err < 0)
+               return err;
+
+       err = mt9m111_set_blue_balance(&sd->gspca_dev,
+                                        sensor_settings[BLUE_BALANCE_IDX]);
+       if (err < 0)
+               return err;
+
+       err = mt9m111_set_red_balance(&sd->gspca_dev,
+                                       sensor_settings[RED_BALANCE_IDX]);
+       if (err < 0)
+               return err;
+
+       return mt9m111_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
 }
 
-int mt9m111_power_down(struct sd *sd)
+int mt9m111_start(struct sd *sd)
 {
-       return 0;
+       int i, err = 0;
+       u8 data[2];
+       struct cam *cam = &sd->gspca_dev.cam;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       int width = cam->cam_mode[sd->gspca_dev.curr_mode].width - 1;
+       int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
+
+       for (i = 0; i < ARRAY_SIZE(start_mt9m111) && !err; i++) {
+               if (start_mt9m111[i][0] == BRIDGE) {
+                       err = m5602_write_bridge(sd,
+                               start_mt9m111[i][1],
+                               start_mt9m111[i][2]);
+               } else {
+                       data[0] = start_mt9m111[i][2];
+                       data[1] = start_mt9m111[i][3];
+                       err = m5602_write_sensor(sd,
+                               start_mt9m111[i][1], data, 2);
+               }
+       }
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff);
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff));
+       if (err < 0)
+               return err;
+
+       for (i = 0; i < 2 && !err; i++)
+               err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 2);
+       if (err < 0)
+               return err;
+
+       for (i = 0; i < 2 && !err; i++)
+               err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 0);
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
+                                (width >> 8) & 0xff);
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, width & 0xff);
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
+       if (err < 0)
+               return err;
+
+       switch (width) {
+       case 640:
+               PDEBUG(D_V4L2, "Configuring camera for VGA mode");
+               data[0] = MT9M111_RMB_OVER_SIZED;
+               data[1] = MT9M111_RMB_ROW_SKIP_2X |
+                         MT9M111_RMB_COLUMN_SKIP_2X |
+                         (sensor_settings[VFLIP_IDX] << 0) |
+                         (sensor_settings[HFLIP_IDX] << 1);
+
+               err = m5602_write_sensor(sd,
+                                        MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
+               break;
+
+       case 320:
+               PDEBUG(D_V4L2, "Configuring camera for QVGA mode");
+               data[0] = MT9M111_RMB_OVER_SIZED;
+               data[1] = MT9M111_RMB_ROW_SKIP_4X |
+                               MT9M111_RMB_COLUMN_SKIP_4X |
+                               (sensor_settings[VFLIP_IDX] << 0) |
+                               (sensor_settings[HFLIP_IDX] << 1);
+               err = m5602_write_sensor(sd,
+                                        MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
+               break;
+       }
+       return err;
 }
 
-int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+void mt9m111_disconnect(struct sd *sd)
+{
+       sd->sensor = NULL;
+       kfree(sd->sensor_priv);
+}
+
+static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
 {
-       int err;
-       u8 data[2] = {0x00, 0x00};
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
 
-       err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
-                                 data, 2);
-       *val = data[0] & MT9M111_RMB_MIRROR_ROWS;
+       *val = sensor_settings[VFLIP_IDX];
        PDEBUG(D_V4L2, "Read vertical flip %d", *val);
 
-       return err;
+       return 0;
 }
 
-int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 data[2] = {0x00, 0x00};
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
 
        PDEBUG(D_V4L2, "Set vertical flip to %d", val);
 
+       sensor_settings[VFLIP_IDX] = val;
+
+       /* The mt9m111 is flipped by default */
+       val = !val;
+
        /* Set the correct page map */
        err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
        if (err < 0)
@@ -186,34 +396,37 @@ int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
        if (err < 0)
                return err;
 
-       data[0] = (data[0] & 0xfe) | val;
+       data[1] = (data[1] & 0xfe) | val;
        err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
                                   data, 2);
        return err;
 }
 
-int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
 {
-       int err;
-       u8 data[2] = {0x00, 0x00};
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
 
-       err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
-                                 data, 2);
-       *val = data[0] & MT9M111_RMB_MIRROR_COLS;
+       *val = sensor_settings[HFLIP_IDX];
        PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
 
-       return err;
+       return 0;
 }
 
-int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 data[2] = {0x00, 0x00};
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
 
        PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
 
+       sensor_settings[HFLIP_IDX] = val;
+
+       /* The mt9m111 is flipped by default */
+       val = !val;
+
        /* Set the correct page map */
        err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
        if (err < 0)
@@ -223,36 +436,62 @@ int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
        if (err < 0)
                return err;
 
-       data[0] = (data[0] & 0xfd) | ((val << 1) & 0x02);
+       data[1] = (data[1] & 0xfd) | ((val << 1) & 0x02);
        err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
                                        data, 2);
        return err;
 }
 
-int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
 {
-       int err, tmp;
-       u8 data[2] = {0x00, 0x00};
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
 
-       err = m5602_read_sensor(sd, MT9M111_SC_GLOBAL_GAIN, data, 2);
-       tmp = ((data[1] << 8) | data[0]);
+       *val = sensor_settings[GAIN_IDX];
+       PDEBUG(D_V4L2, "Read gain %d", *val);
 
-       *val = ((tmp & (1 << 10)) * 2) |
-             ((tmp & (1 <<  9)) * 2) |
-             ((tmp & (1 <<  8)) * 2) |
-              (tmp & 0x7f);
+       return 0;
+}
 
-       PDEBUG(D_V4L2, "Read gain %d", *val);
+static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
+                                         __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+       int err;
+       u8 data[2];
+
+       err = m5602_read_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2);
+       if (err < 0)
+               return err;
+
+       sensor_settings[AUTO_WHITE_BALANCE_IDX] = val & 0x01;
+       data[1] = ((data[1] & 0xfd) | ((val & 0x01) << 1));
 
+       err = m5602_write_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2);
+
+       PDEBUG(D_V4L2, "Set auto white balance %d", val);
        return err;
 }
 
-int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev,
+                                         __s32 *val) {
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
+       PDEBUG(D_V4L2, "Read auto white balance %d", *val);
+       return 0;
+}
+
+static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err, tmp;
        u8 data[2] = {0x00, 0x00};
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       sensor_settings[GAIN_IDX] = val;
 
        /* Set the correct page map */
        err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
@@ -275,8 +514,8 @@ int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
        else
                tmp = val;
 
-       data[1] = (tmp & 0xff00) >> 8;
-       data[0] = (tmp & 0xff);
+       data[1] = (tmp & 0xff);
+       data[0] = (tmp & 0xff00) >> 8;
        PDEBUG(D_V4L2, "tmp=%d, data[1]=%d, data[0]=%d", tmp,
               data[1], data[0]);
 
@@ -286,6 +525,89 @@ int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
+static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       u8 data[2];
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       sensor_settings[GREEN_BALANCE_IDX] = val;
+       data[1] = (val & 0xff);
+       data[0] = (val & 0xff00) >> 8;
+
+       PDEBUG(D_V4L2, "Set green balance %d", val);
+       err = m5602_write_sensor(sd, MT9M111_SC_GREEN_1_GAIN,
+                                data, 2);
+       if (err < 0)
+               return err;
+
+       return m5602_write_sensor(sd, MT9M111_SC_GREEN_2_GAIN,
+                                 data, 2);
+}
+
+static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[GREEN_BALANCE_IDX];
+       PDEBUG(D_V4L2, "Read green balance %d", *val);
+       return 0;
+}
+
+static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+       u8 data[2];
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       sensor_settings[BLUE_BALANCE_IDX] = val;
+       data[1] = (val & 0xff);
+       data[0] = (val & 0xff00) >> 8;
+
+       PDEBUG(D_V4L2, "Set blue balance %d", val);
+
+       return m5602_write_sensor(sd, MT9M111_SC_BLUE_GAIN,
+                                 data, 2);
+}
+
+static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[BLUE_BALANCE_IDX];
+       PDEBUG(D_V4L2, "Read blue balance %d", *val);
+       return 0;
+}
+
+static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+       u8 data[2];
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       sensor_settings[RED_BALANCE_IDX] = val;
+       data[1] = (val & 0xff);
+       data[0] = (val & 0xff00) >> 8;
+
+       PDEBUG(D_V4L2, "Set red balance %d", val);
+
+       return m5602_write_sensor(sd, MT9M111_SC_RED_GAIN,
+                                 data, 2);
+}
+
+static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[RED_BALANCE_IDX];
+       PDEBUG(D_V4L2, "Read red balance %d", *val);
+       return 0;
+}
+
 static void mt9m111_dump_registers(struct sd *sd)
 {
        u8 address, value[2] = {0x00, 0x00};
index 00c6db02bdb7724987e4d38f41cdc13ab94d93f3..b3de77823091bf56ab37913e4122dd8fbc5e9ddf 100644 (file)
@@ -37,7 +37,6 @@
 #define MT9M111_SC_VBLANK_CONTEXT_A            0x08
 #define MT9M111_SC_SHUTTER_WIDTH               0x09
 #define MT9M111_SC_ROW_SPEED                   0x0a
-
 #define MT9M111_SC_EXTRA_DELAY                 0x0b
 #define MT9M111_SC_SHUTTER_DELAY               0x0c
 #define MT9M111_SC_RESET                       0x0d
@@ -50,9 +49,6 @@
 #define MT9M111_SC_GREEN_2_GAIN                        0x2e
 #define MT9M111_SC_GLOBAL_GAIN                 0x2f
 
-#define MT9M111_RMB_MIRROR_ROWS                        (1 << 0)
-#define MT9M111_RMB_MIRROR_COLS                        (1 << 1)
-
 #define MT9M111_CONTEXT_CONTROL                        0xc8
 #define MT9M111_PAGE_MAP                       0xf0
 #define MT9M111_BYTEWISE_ADDRESS               0xf1
 #define MT9M111_COLORPIPE                      0x01
 #define MT9M111_CAMERA_CONTROL                 0x02
 
+#define MT9M111_RESET                          (1 << 0)
+#define MT9M111_RESTART                                (1 << 1)
+#define MT9M111_ANALOG_STANDBY                 (1 << 2)
+#define MT9M111_CHIP_ENABLE                    (1 << 3)
+#define MT9M111_CHIP_DISABLE                   (0 << 3)
+#define MT9M111_OUTPUT_DISABLE                 (1 << 4)
+#define MT9M111_SHOW_BAD_FRAMES                        (1 << 0)
+#define MT9M111_RESTART_BAD_FRAMES             (1 << 1)
+#define MT9M111_SYNCHRONIZE_CHANGES            (1 << 7)
+
+#define MT9M111_RMB_OVER_SIZED                 (1 << 0)
+#define MT9M111_RMB_MIRROR_ROWS                        (1 << 0)
+#define MT9M111_RMB_MIRROR_COLS                        (1 << 1)
+#define MT9M111_RMB_ROW_SKIP_2X                        (1 << 2)
+#define MT9M111_RMB_COLUMN_SKIP_2X             (1 << 3)
+#define MT9M111_RMB_ROW_SKIP_4X                        (1 << 4)
+#define MT9M111_RMB_COLUMN_SKIP_4X             (1 << 5)
+
+#define MT9M111_COLOR_MATRIX_BYPASS            (1 << 4)
+#define MT9M111_SEL_CONTEXT_B                  (1 << 3)
+
+#define MT9M111_TRISTATE_PIN_IN_STANDBY                (1 << 1)
+#define MT9M111_SOC_SOFT_STANDBY               (1 << 0)
+
+#define MT9M111_2D_DEFECT_CORRECTION_ENABLE    (1 << 0)
+
 #define INITIAL_MAX_GAIN                       64
-#define DEFAULT_GAIN                           283
+#define MT9M111_DEFAULT_GAIN                   283
+#define MT9M111_GREEN_GAIN_DEFAULT             0x20
+#define MT9M111_BLUE_GAIN_DEFAULT              0x20
+#define MT9M111_RED_GAIN_DEFAULT               0x20
 
 /*****************************************************************************/
 
@@ -85,16 +110,10 @@ extern int dump_sensor;
 
 int mt9m111_probe(struct sd *sd);
 int mt9m111_init(struct sd *sd);
-int mt9m111_power_down(struct sd *sd);
+int mt9m111_start(struct sd *sd);
+void mt9m111_disconnect(struct sd *sd);
 
-int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-
-const static struct m5602_sensor mt9m111 = {
+static const struct m5602_sensor mt9m111 = {
        .name = "MT9M111",
 
        .i2c_slave_id = 0xba,
@@ -102,7 +121,8 @@ const static struct m5602_sensor mt9m111 = {
 
        .probe = mt9m111_probe,
        .init = mt9m111_init,
-       .power_down = mt9m111_power_down
+       .disconnect = mt9m111_disconnect,
+       .start = mt9m111_start,
 };
 
 static const unsigned char preinit_mt9m111[][4] =
@@ -117,7 +137,14 @@ static const unsigned char preinit_mt9m111[][4] =
        {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
 
        {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0xff, 0xf7},
+       {SENSOR, MT9M111_SC_RESET,
+               MT9M111_RESET |
+               MT9M111_RESTART |
+               MT9M111_ANALOG_STANDBY |
+               MT9M111_CHIP_DISABLE,
+               MT9M111_SHOW_BAD_FRAMES |
+               MT9M111_RESTART_BAD_FRAMES |
+               MT9M111_SYNCHRONIZE_CHANGES},
 
        {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
        {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
@@ -145,731 +172,42 @@ static const unsigned char init_mt9m111[][4] =
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
        {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
        {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0xff, 0xff},
-       {SENSOR, MT9M111_SC_RESET, 0xff, 0xff},
-       {SENSOR, MT9M111_SC_RESET, 0xff, 0xde},
-       {SENSOR, MT9M111_SC_RESET, 0xff, 0xff},
-       {SENSOR, MT9M111_SC_RESET, 0xff, 0xf7},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
 
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00},
-
-       {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0xff, 0xff},
-
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
        {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
        {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
-
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x05},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10},
-       {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
-       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
-       {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
-       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
-       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00},
-
-       {SENSOR, 0xcd, 0x00, 0x0e},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00},
-       {SENSOR, 0xd0, 0x00, 0x40},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
-       {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
-       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
-       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
-       {SENSOR, 0x33, 0x03, 0x49},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
-
-       {SENSOR, 0x33, 0x03, 0x49},
-       {SENSOR, 0x34, 0xc0, 0x19},
-       {SENSOR, 0x3f, 0x20, 0x20},
-       {SENSOR, 0x40, 0x20, 0x20},
-       {SENSOR, 0x5a, 0xc0, 0x0a},
-       {SENSOR, 0x70, 0x7b, 0x0a},
-       {SENSOR, 0x71, 0xff, 0x00},
-       {SENSOR, 0x72, 0x19, 0x0e},
-       {SENSOR, 0x73, 0x18, 0x0f},
-       {SENSOR, 0x74, 0x57, 0x32},
-       {SENSOR, 0x75, 0x56, 0x34},
-       {SENSOR, 0x76, 0x73, 0x35},
-       {SENSOR, 0x77, 0x30, 0x12},
-       {SENSOR, 0x78, 0x79, 0x02},
-       {SENSOR, 0x79, 0x75, 0x06},
-       {SENSOR, 0x7a, 0x77, 0x0a},
-       {SENSOR, 0x7b, 0x78, 0x09},
-       {SENSOR, 0x7c, 0x7d, 0x06},
-       {SENSOR, 0x7d, 0x31, 0x10},
-       {SENSOR, 0x7e, 0x00, 0x7e},
-       {SENSOR, 0x80, 0x59, 0x04},
-       {SENSOR, 0x81, 0x59, 0x04},
-       {SENSOR, 0x82, 0x57, 0x0a},
-       {SENSOR, 0x83, 0x58, 0x0b},
-       {SENSOR, 0x84, 0x47, 0x0c},
-       {SENSOR, 0x85, 0x48, 0x0e},
-       {SENSOR, 0x86, 0x5b, 0x02},
-       {SENSOR, 0x87, 0x00, 0x5c},
-       {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08},
-       {SENSOR, 0x60, 0x00, 0x80},
-       {SENSOR, 0x61, 0x00, 0x00},
-       {SENSOR, 0x62, 0x00, 0x00},
-       {SENSOR, 0x63, 0x00, 0x00},
-       {SENSOR, 0x64, 0x00, 0x00},
-
-       {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d},
-       {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x18},
-       {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x04},
-       {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x08},
-       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x38},
-       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11},
-       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x38},
-       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11},
-       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x03},
-       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x03},
-       {SENSOR, 0x30, 0x04, 0x00},
-
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
-       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0xf4},
-       {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xea},
-
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
-       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x09},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x0c},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x04},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00},
-       {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03},
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
        {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
        {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
        {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
-
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x05},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10},
-       {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
-       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
-       {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
-       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
-       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
-
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00},
-       {SENSOR, 0xcd, 0x00, 0x0e},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00},
-       {SENSOR, 0xd0, 0x00, 0x40},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
-       {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
-       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
-       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
-       {SENSOR, 0x33, 0x03, 0x49},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
-
-       {SENSOR, 0x33, 0x03, 0x49},
-       {SENSOR, 0x34, 0xc0, 0x19},
-       {SENSOR, 0x3f, 0x20, 0x20},
-       {SENSOR, 0x40, 0x20, 0x20},
-       {SENSOR, 0x5a, 0xc0, 0x0a},
-       {SENSOR, 0x70, 0x7b, 0x0a},
-       {SENSOR, 0x71, 0xff, 0x00},
-       {SENSOR, 0x72, 0x19, 0x0e},
-       {SENSOR, 0x73, 0x18, 0x0f},
-       {SENSOR, 0x74, 0x57, 0x32},
-       {SENSOR, 0x75, 0x56, 0x34},
-       {SENSOR, 0x76, 0x73, 0x35},
-       {SENSOR, 0x77, 0x30, 0x12},
-       {SENSOR, 0x78, 0x79, 0x02},
-       {SENSOR, 0x79, 0x75, 0x06},
-       {SENSOR, 0x7a, 0x77, 0x0a},
-       {SENSOR, 0x7b, 0x78, 0x09},
-       {SENSOR, 0x7c, 0x7d, 0x06},
-       {SENSOR, 0x7d, 0x31, 0x10},
-       {SENSOR, 0x7e, 0x00, 0x7e},
-       {SENSOR, 0x80, 0x59, 0x04},
-       {SENSOR, 0x81, 0x59, 0x04},
-       {SENSOR, 0x82, 0x57, 0x0a},
-       {SENSOR, 0x83, 0x58, 0x0b},
-       {SENSOR, 0x84, 0x47, 0x0c},
-       {SENSOR, 0x85, 0x48, 0x0e},
-       {SENSOR, 0x86, 0x5b, 0x02},
-       {SENSOR, 0x87, 0x00, 0x5c},
-       {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08},
-       {SENSOR, 0x60, 0x00, 0x80},
-       {SENSOR, 0x61, 0x00, 0x00},
-       {SENSOR, 0x62, 0x00, 0x00},
-       {SENSOR, 0x63, 0x00, 0x00},
-       {SENSOR, 0x64, 0x00, 0x00},
-
-       {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d},
-       {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x18},
-       {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x04},
-       {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x08},
-       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x38},
-       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11},
-       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x38},
-       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11},
-       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x03},
-       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x03},
-       {SENSOR, 0x30, 0x04, 0x00},
-
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
-       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0xf4},
-       {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xea},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x09},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x0c},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x04},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
-
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00},
-       {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03},
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
        {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
        {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
        {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
        {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
        {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
 
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x05},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
        {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
        {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
        {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
        {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10},
+       {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00,
+                       MT9M111_CP_OPERATING_MODE_CTL},
        {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
-       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01},
+       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00,
+                               MT9M111_2D_DEFECT_CORRECTION_ENABLE},
+       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00,
+                               MT9M111_2D_DEFECT_CORRECTION_ENABLE},
        {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
        {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
        {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
        {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
-
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00},
        {SENSOR, 0xcd, 0x00, 0x0e},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00},
        {SENSOR, 0xd0, 0x00, 0x40},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
-       {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
-       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
-       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
-       {SENSOR, 0x33, 0x03, 0x49},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
-
-       {SENSOR, 0x33, 0x03, 0x49},
-       {SENSOR, 0x34, 0xc0, 0x19},
-       {SENSOR, 0x3f, 0x20, 0x20},
-       {SENSOR, 0x40, 0x20, 0x20},
-       {SENSOR, 0x5a, 0xc0, 0x0a},
-       {SENSOR, 0x70, 0x7b, 0x0a},
-       {SENSOR, 0x71, 0xff, 0x00},
-       {SENSOR, 0x72, 0x19, 0x0e},
-       {SENSOR, 0x73, 0x18, 0x0f},
-       {SENSOR, 0x74, 0x57, 0x32},
-       {SENSOR, 0x75, 0x56, 0x34},
-       {SENSOR, 0x76, 0x73, 0x35},
-       {SENSOR, 0x77, 0x30, 0x12},
-       {SENSOR, 0x78, 0x79, 0x02},
-       {SENSOR, 0x79, 0x75, 0x06},
-       {SENSOR, 0x7a, 0x77, 0x0a},
-       {SENSOR, 0x7b, 0x78, 0x09},
-       {SENSOR, 0x7c, 0x7d, 0x06},
-       {SENSOR, 0x7d, 0x31, 0x10},
-       {SENSOR, 0x7e, 0x00, 0x7e},
-       {SENSOR, 0x80, 0x59, 0x04},
-       {SENSOR, 0x81, 0x59, 0x04},
-       {SENSOR, 0x82, 0x57, 0x0a},
-       {SENSOR, 0x83, 0x58, 0x0b},
-       {SENSOR, 0x84, 0x47, 0x0c},
-       {SENSOR, 0x85, 0x48, 0x0e},
-       {SENSOR, 0x86, 0x5b, 0x02},
-       {SENSOR, 0x87, 0x00, 0x5c},
-       {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08},
-       {SENSOR, 0x60, 0x00, 0x80},
-       {SENSOR, 0x61, 0x00, 0x00},
-       {SENSOR, 0x62, 0x00, 0x00},
-       {SENSOR, 0x63, 0x00, 0x00},
-       {SENSOR, 0x64, 0x00, 0x00},
 
-       {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d},
-       {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x18},
-       {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x04},
-       {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x08},
-       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x38},
-       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11},
-       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x38},
-       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11},
-       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x03},
-       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x03},
-       {SENSOR, 0x30, 0x04, 0x00},
-
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
-       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0xf4},
-       {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xea},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x09},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x0c},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x04},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03},
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x05},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10},
-       {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
-       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
-       {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
-       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
-       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
-
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, 0xcd, 0x00, 0x0e},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, 0xd0, 0x00, 0x40},
        {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
        {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
        {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, 0x33, 0x03, 0x49},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-
-       {SENSOR, 0x33, 0x03, 0x49},
-       {SENSOR, 0x34, 0xc0, 0x19},
-       {SENSOR, 0x3f, 0x20, 0x20},
-       {SENSOR, 0x40, 0x20, 0x20},
-       {SENSOR, 0x5a, 0xc0, 0x0a},
-       {SENSOR, 0x70, 0x7b, 0x0a},
-       {SENSOR, 0x71, 0xff, 0x00},
-       {SENSOR, 0x72, 0x19, 0x0e},
-       {SENSOR, 0x73, 0x18, 0x0f},
-       {SENSOR, 0x74, 0x57, 0x32},
-       {SENSOR, 0x75, 0x56, 0x34},
-       {SENSOR, 0x76, 0x73, 0x35},
-       {SENSOR, 0x77, 0x30, 0x12},
-       {SENSOR, 0x78, 0x79, 0x02},
-       {SENSOR, 0x79, 0x75, 0x06},
-       {SENSOR, 0x7a, 0x77, 0x0a},
-       {SENSOR, 0x7b, 0x78, 0x09},
-       {SENSOR, 0x7c, 0x7d, 0x06},
-       {SENSOR, 0x7d, 0x31, 0x10},
-       {SENSOR, 0x7e, 0x00, 0x7e},
-       {SENSOR, 0x80, 0x59, 0x04},
-       {SENSOR, 0x81, 0x59, 0x04},
-       {SENSOR, 0x82, 0x57, 0x0a},
-       {SENSOR, 0x83, 0x58, 0x0b},
-       {SENSOR, 0x84, 0x47, 0x0c},
-       {SENSOR, 0x85, 0x48, 0x0e},
-       {SENSOR, 0x86, 0x5b, 0x02},
-       {SENSOR, 0x87, 0x00, 0x5c},
-       {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08},
-       {SENSOR, 0x60, 0x00, 0x80},
-       {SENSOR, 0x61, 0x00, 0x00},
-       {SENSOR, 0x62, 0x00, 0x00},
-       {SENSOR, 0x63, 0x00, 0x00},
-       {SENSOR, 0x64, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d},
-       {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x12},
-       {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x00},
-       {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x10},
-       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x60},
-       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11},
-       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x60},
-       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11},
-       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x0f},
-       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x0f},
-       {SENSOR, 0x30, 0x04, 0x00},
-
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
-       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe3, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x87, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0x90},
-       {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xe6},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x09},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x0c},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x04},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03},
 
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x05},
        {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10},
-       {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
-       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01},
-       {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
-       {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
-       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
-       {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
-
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, 0xcd, 0x00, 0x0e},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, 0xd0, 0x00, 0x40},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
-       {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-       {SENSOR, 0x33, 0x03, 0x49},
-       {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
-       {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
-       {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-
        {SENSOR, 0x33, 0x03, 0x49},
        {SENSOR, 0x34, 0xc0, 0x19},
        {SENSOR, 0x3f, 0x20, 0x20},
@@ -898,25 +236,29 @@ static const unsigned char init_mt9m111[][4] =
        {SENSOR, 0x85, 0x48, 0x0e},
        {SENSOR, 0x86, 0x5b, 0x02},
        {SENSOR, 0x87, 0x00, 0x5c},
-       {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08},
+       {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, MT9M111_SEL_CONTEXT_B},
        {SENSOR, 0x60, 0x00, 0x80},
        {SENSOR, 0x61, 0x00, 0x00},
        {SENSOR, 0x62, 0x00, 0x00},
        {SENSOR, 0x63, 0x00, 0x00},
        {SENSOR, 0x64, 0x00, 0x00},
 
-       {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d},
-       {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x12},
-       {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x00},
-       {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x10},
-       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x60},
-       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11},
-       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x60},
-       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11},
-       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x0f},
-       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x0f},
+       {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d}, /* 13 */
+       {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x12}, /* 18 */
+       {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x00}, /* 1024 */
+       {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x10}, /* 1296 */
+       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x60}, /* 352 */
+       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11}, /* 17 */
+       {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x60}, /* 352 */
+       {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11}, /* 17 */
+       {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x0f}, /* 271 */
        {SENSOR, 0x30, 0x04, 0x00},
+       /* Set number of blank rows chosen to 400 */
+       {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0x90},
+};
 
+static const unsigned char start_mt9m111[][4] =
+{
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
        {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
@@ -928,25 +270,6 @@ static const unsigned char init_mt9m111[][4] =
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, /* 639*/
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
-       {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-       /* Set number of blank rows chosen to 400 */
-       {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0x90},
-       /* Set the global gain to 283 (of 512) */
-       {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x03, 0x63}
 };
 
 #endif
diff --git a/drivers/media/video/gspca/m5602/m5602_ov7660.c b/drivers/media/video/gspca/m5602/m5602_ov7660.c
new file mode 100644 (file)
index 0000000..7aafeb7
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Driver for the ov7660 sensor
+ *
+ * Copyright (C) 2009 Erik Andrén
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * 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 "m5602_ov7660.h"
+
+static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+
+const static struct ctrl ov7660_ctrls[] = {
+#define GAIN_IDX 1
+       {
+               {
+                       .id             = V4L2_CID_GAIN,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "gain",
+                       .minimum        = 0x00,
+                       .maximum        = 0xff,
+                       .step           = 0x1,
+                       .default_value  = OV7660_DEFAULT_GAIN,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = ov7660_set_gain,
+               .get = ov7660_get_gain
+       },
+};
+
+static struct v4l2_pix_format ov7660_modes[] = {
+       {
+               640,
+               480,
+               V4L2_PIX_FMT_SBGGR8,
+               V4L2_FIELD_NONE,
+               .sizeimage =
+                       640 * 480,
+               .bytesperline = 640,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0
+       }
+};
+
+static void ov7660_dump_registers(struct sd *sd);
+
+int ov7660_probe(struct sd *sd)
+{
+       int err = 0, i;
+       u8 prod_id = 0, ver_id = 0;
+
+       s32 *sensor_settings;
+
+       if (force_sensor) {
+               if (force_sensor == OV7660_SENSOR) {
+                       info("Forcing an %s sensor", ov7660.name);
+                       goto sensor_found;
+               }
+               /* If we want to force another sensor,
+               don't try to probe this one */
+               return -ENODEV;
+       }
+
+       /* Do the preinit */
+       for (i = 0; i < ARRAY_SIZE(preinit_ov7660) && !err; i++) {
+               u8 data[2];
+
+               if (preinit_ov7660[i][0] == BRIDGE) {
+                       err = m5602_write_bridge(sd,
+                               preinit_ov7660[i][1],
+                               preinit_ov7660[i][2]);
+               } else {
+                       data[0] = preinit_ov7660[i][2];
+                       err = m5602_write_sensor(sd,
+                               preinit_ov7660[i][1], data, 1);
+               }
+       }
+       if (err < 0)
+               return err;
+
+       if (m5602_read_sensor(sd, OV7660_PID, &prod_id, 1))
+               return -ENODEV;
+
+       if (m5602_read_sensor(sd, OV7660_VER, &ver_id, 1))
+               return -ENODEV;
+
+       info("Sensor reported 0x%x%x", prod_id, ver_id);
+
+       if ((prod_id == 0x76) && (ver_id == 0x60)) {
+               info("Detected a ov7660 sensor");
+               goto sensor_found;
+       }
+       return -ENODEV;
+
+sensor_found:
+       sensor_settings = kmalloc(
+               ARRAY_SIZE(ov7660_ctrls) * sizeof(s32), GFP_KERNEL);
+       if (!sensor_settings)
+               return -ENOMEM;
+
+       sd->gspca_dev.cam.cam_mode = ov7660_modes;
+       sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov7660_modes);
+       sd->desc->ctrls = ov7660_ctrls;
+       sd->desc->nctrls = ARRAY_SIZE(ov7660_ctrls);
+
+       for (i = 0; i < ARRAY_SIZE(ov7660_ctrls); i++)
+               sensor_settings[i] = ov7660_ctrls[i].qctrl.default_value;
+       sd->sensor_priv = sensor_settings;
+
+       return 0;
+}
+
+int ov7660_init(struct sd *sd)
+{
+       int i, err = 0;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       /* Init the sensor */
+       for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) {
+               u8 data[2];
+
+               if (init_ov7660[i][0] == BRIDGE) {
+                       err = m5602_write_bridge(sd,
+                               init_ov7660[i][1],
+                               init_ov7660[i][2]);
+               } else {
+                       data[0] = init_ov7660[i][2];
+                       err = m5602_write_sensor(sd,
+                                       init_ov7660[i][1], data, 1);
+               }
+       }
+
+       if (dump_sensor)
+               ov7660_dump_registers(sd);
+
+       err = ov7660_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
+       if (err < 0)
+               return err;
+
+       return err;
+}
+
+int ov7660_start(struct sd *sd)
+{
+       return 0;
+}
+
+int ov7660_stop(struct sd *sd)
+{
+       return 0;
+}
+
+void ov7660_disconnect(struct sd *sd)
+{
+       ov7660_stop(sd);
+
+       sd->sensor = NULL;
+       kfree(sd->sensor_priv);
+}
+
+static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[GAIN_IDX];
+       PDEBUG(D_V4L2, "Read gain %d", *val);
+       return 0;
+}
+
+static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       u8 i2c_data;
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       PDEBUG(D_V4L2, "Setting gain to %d", val);
+
+       sensor_settings[GAIN_IDX] = val;
+
+       err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1);
+       return err;
+}
+
+static void ov7660_dump_registers(struct sd *sd)
+{
+       int address;
+       info("Dumping the ov7660 register state");
+       for (address = 0; address < 0xa9; address++) {
+               u8 value;
+               m5602_read_sensor(sd, address, &value, 1);
+               info("register 0x%x contains 0x%x",
+                    address, value);
+       }
+
+       info("ov7660 register state dump complete");
+
+       info("Probing for which registers that are read/write");
+       for (address = 0; address < 0xff; address++) {
+               u8 old_value, ctrl_value;
+               u8 test_value[2] = {0xff, 0xff};
+
+               m5602_read_sensor(sd, address, &old_value, 1);
+               m5602_write_sensor(sd, address, test_value, 1);
+               m5602_read_sensor(sd, address, &ctrl_value, 1);
+
+               if (ctrl_value == test_value[0])
+                       info("register 0x%x is writeable", address);
+               else
+                       info("register 0x%x is read only", address);
+
+               /* Restore original value */
+               m5602_write_sensor(sd, address, &old_value, 1);
+       }
+}
diff --git a/drivers/media/video/gspca/m5602/m5602_ov7660.h b/drivers/media/video/gspca/m5602/m5602_ov7660.h
new file mode 100644 (file)
index 0000000..3f2c169
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * Driver for the ov7660 sensor
+ *
+ * Copyright (C) 2009 Erik Andrén
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * 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.
+ *
+ */
+
+#ifndef M5602_OV7660_H_
+#define M5602_OV7660_H_
+
+#include "m5602_sensor.h"
+
+#define OV7660_GAIN            0x00
+#define OV7660_BLUE_GAIN       0x01
+#define OV7660_RED_GAIN                0x02
+#define OV7660_VREF            0x03
+#define OV7660_COM1            0x04
+#define OV7660_BAVE            0x05
+#define OV7660_GEAVE           0x06
+#define OV7660_AECHH           0x07
+#define OV7660_RAVE            0x08
+#define OV7660_COM2            0x09
+#define OV7660_PID             0x0a
+#define OV7660_VER             0x0b
+#define OV7660_COM3            0x0c
+#define OV7660_COM4            0x0d
+#define OV7660_COM5            0x0e
+#define OV7660_COM6            0x0f
+#define OV7660_AECH            0x10
+#define OV7660_CLKRC           0x11
+#define OV7660_COM7            0x12
+#define OV7660_COM8            0x13
+#define OV7660_COM9            0x14
+#define OV7660_COM10           0x15
+#define OV7660_RSVD16          0x16
+#define OV7660_HSTART          0x17
+#define OV7660_HSTOP           0x18
+#define OV7660_VSTART          0x19
+#define OV7660_VSTOP           0x1a
+#define OV7660_PSHFT           0x1b
+#define OV7660_MIDH            0x1c
+#define OV7660_MIDL            0x1d
+#define OV7660_MVFP            0x1e
+#define OV7660_LAEC            0x1f
+#define OV7660_BOS             0x20
+#define OV7660_GBOS            0x21
+#define OV7660_GROS            0x22
+#define OV7660_ROS             0x23
+#define OV7660_AEW             0x24
+#define OV7660_AEB             0x25
+#define OV7660_VPT             0x26
+#define OV7660_BBIAS           0x27
+#define OV7660_GbBIAS          0x28
+#define OV7660_RSVD29          0x29
+#define OV7660_RBIAS           0x2c
+#define OV7660_HREF            0x32
+#define OV7660_ADC             0x37
+#define OV7660_OFON            0x39
+#define OV7660_TSLB            0x3a
+#define OV7660_COM12           0x3c
+#define OV7660_COM13           0x3d
+#define OV7660_LCC1            0x62
+#define OV7660_LCC2            0x63
+#define OV7660_LCC3            0x64
+#define OV7660_LCC4            0x65
+#define OV7660_LCC5            0x66
+#define OV7660_HV              0x69
+#define OV7660_RSVDA1          0xa1
+
+#define OV7660_DEFAULT_GAIN            0x0e
+#define OV7660_DEFAULT_RED_GAIN        0x80
+#define OV7660_DEFAULT_BLUE_GAIN       0x80
+#define OV7660_DEFAULT_SATURATION      0x00
+#define OV7660_DEFAULT_EXPOSURE        0x20
+
+/* Kernel module parameters */
+extern int force_sensor;
+extern int dump_sensor;
+
+int ov7660_probe(struct sd *sd);
+int ov7660_init(struct sd *sd);
+int ov7660_start(struct sd *sd);
+int ov7660_stop(struct sd *sd);
+void ov7660_disconnect(struct sd *sd);
+
+const static struct m5602_sensor ov7660 = {
+       .name = "ov7660",
+       .i2c_slave_id = 0x42,
+       .i2c_regW = 1,
+       .probe = ov7660_probe,
+       .init = ov7660_init,
+       .start = ov7660_start,
+       .stop = ov7660_stop,
+       .disconnect = ov7660_disconnect,
+};
+
+static const unsigned char preinit_ov7660[][4] =
+{
+       {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
+       {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d},
+       {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x03},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x03},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+
+       {SENSOR, OV7660_OFON, 0x0c},
+       {SENSOR, OV7660_COM2, 0x11},
+       {SENSOR, OV7660_COM7, 0x05},
+
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x01},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}
+};
+
+static const unsigned char init_ov7660[][4] =
+{
+       {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
+       {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d},
+       {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x03},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x03},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+
+       {SENSOR, OV7660_OFON, 0x0c},
+       {SENSOR, OV7660_COM2, 0x11},
+       {SENSOR, OV7660_COM7, 0x05},
+
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x01},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
+
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x02},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+
+       {SENSOR, OV7660_AECH, OV7660_DEFAULT_EXPOSURE},
+       {SENSOR, OV7660_COM1, 0x00},
+
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x01},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
+
+       {SENSOR, OV7660_COM7, 0x80},
+       {SENSOR, OV7660_CLKRC, 0x80},
+       {SENSOR, OV7660_BLUE_GAIN, 0x80},
+       {SENSOR, OV7660_RED_GAIN, 0x80},
+       {SENSOR, OV7660_COM9, 0x4c},
+       {SENSOR, OV7660_OFON, 0x43},
+       {SENSOR, OV7660_COM12, 0x28},
+       {SENSOR, OV7660_COM8, 0x00},
+       {SENSOR, OV7660_COM10, 0x40},
+       {SENSOR, OV7660_HSTART, 0x0c},
+       {SENSOR, OV7660_HSTOP, 0x61},
+       {SENSOR, OV7660_HREF, 0xa4},
+       {SENSOR, OV7660_PSHFT, 0x0b},
+       {SENSOR, OV7660_VSTART, 0x01},
+       {SENSOR, OV7660_VSTOP, 0x7a},
+       {SENSOR, OV7660_VREF, 0x00},
+       {SENSOR, OV7660_COM7, 0x05},
+       {SENSOR, OV7660_COM6, 0x4b},
+       {SENSOR, OV7660_BBIAS, 0x98},
+       {SENSOR, OV7660_GbBIAS, 0x98},
+       {SENSOR, OV7660_RSVD29, 0x98},
+       {SENSOR, OV7660_RBIAS, 0x98},
+       {SENSOR, OV7660_COM1, 0x00},
+       {SENSOR, OV7660_AECH, 0x00},
+       {SENSOR, OV7660_AECHH, 0x00},
+       {SENSOR, OV7660_ADC, 0x04},
+       {SENSOR, OV7660_COM13, 0x00},
+       {SENSOR, OV7660_RSVDA1, 0x23},
+       {SENSOR, OV7660_TSLB, 0x0d},
+       {SENSOR, OV7660_HV, 0x80},
+       {SENSOR, OV7660_LCC1, 0x00},
+       {SENSOR, OV7660_LCC2, 0x00},
+       {SENSOR, OV7660_LCC3, 0x10},
+       {SENSOR, OV7660_LCC4, 0x40},
+       {SENSOR, OV7660_LCC5, 0x01},
+
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81},
+       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
+       {BRIDGE, M5602_XB_SIG_INI, 0x01},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x08},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0}, /* 480 */
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x00},
+       {BRIDGE, M5602_XB_SIG_INI, 0x02},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x27}, /* 39 */
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x02},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0xa7}, /* 679 */
+       {BRIDGE, M5602_XB_SIG_INI, 0x00},
+
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+
+       {SENSOR, OV7660_AECH, 0x20},
+       {SENSOR, OV7660_COM1, 0x00},
+       {SENSOR, OV7660_OFON, 0x0c},
+       {SENSOR, OV7660_COM2, 0x11},
+       {SENSOR, OV7660_COM7, 0x05},
+       {SENSOR, OV7660_BLUE_GAIN, 0x80},
+       {SENSOR, OV7660_RED_GAIN, 0x80},
+
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x01},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
+       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08},
+       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}
+};
+
+#endif
index fc4548fd441dc1674d807628b0a68ad3bca8aca6..c2739d6605a14612cd3db4a20124bd6d8be6b411 100644 (file)
 
 #include "m5602_ov9650.h"
 
+static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
+static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev,
+                                        __s32 *val);
+static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
+                                        __s32 val);
+static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val);
+
 /* Vertically and horizontally flips the image if matched, needed for machines
    where the sensor is mounted upside down */
 static
     const
        struct dmi_system_id ov9650_flip_dmi_table[] = {
        {
-               .ident = "ASUS A6VC",
+               .ident = "ASUS A6Ja",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "A6VC")
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A6J")
                }
        },
        {
-               .ident = "ASUS A6VM",
+               .ident = "ASUS A6JC",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "A6VM")
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A6JC")
                }
        },
        {
-               .ident = "ASUS A6JC",
+               .ident = "ASUS A6K",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "A6JC")
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A6K")
                }
        },
        {
-               .ident = "ASUS A6Ja",
+               .ident = "ASUS A6Kt",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "A6J")
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt")
                }
        },
        {
-               .ident = "ASUS A6Kt",
+               .ident = "ASUS A6VA",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt")
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A6VA")
+               }
+       },
+       {
+
+               .ident = "ASUS A6VC",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A6VC")
+               }
+       },
+       {
+               .ident = "ASUS A6VM",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A6VM")
+               }
+       },
+       {
+               .ident = "ASUS A7V",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "A7V")
                }
        },
        {
@@ -68,7 +111,7 @@ static
        {}
 };
 
-const static struct ctrl ov9650_ctrls[] = {
+static const struct ctrl ov9650_ctrls[] = {
 #define EXPOSURE_IDX 0
        {
                {
@@ -102,6 +145,7 @@ const static struct ctrl ov9650_ctrls[] = {
 #define RED_BALANCE_IDX 2
        {
                {
+                       .id             = V4L2_CID_RED_BALANCE,
                        .type           = V4L2_CTRL_TYPE_INTEGER,
                        .name           = "red balance",
                        .minimum        = 0x00,
@@ -116,6 +160,7 @@ const static struct ctrl ov9650_ctrls[] = {
 #define BLUE_BALANCE_IDX 3
        {
                {
+                       .id             = V4L2_CID_BLUE_BALANCE,
                        .type           = V4L2_CTRL_TYPE_INTEGER,
                        .name           = "blue balance",
                        .minimum        = 0x00,
@@ -182,7 +227,22 @@ const static struct ctrl ov9650_ctrls[] = {
                },
                .set = ov9650_set_auto_gain,
                .get = ov9650_get_auto_gain
+       },
+#define AUTO_EXPOSURE_IDX 8
+       {
+               {
+                       .id             = V4L2_CID_EXPOSURE_AUTO,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "auto exposure",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 1
+               },
+               .set = ov9650_set_auto_exposure,
+               .get = ov9650_get_auto_exposure
        }
+
 };
 
 static struct v4l2_pix_format ov9650_modes[] = {
@@ -289,12 +349,6 @@ sensor_found:
        for (i = 0; i < ARRAY_SIZE(ov9650_ctrls); i++)
                sensor_settings[i] = ov9650_ctrls[i].qctrl.default_value;
        sd->sensor_priv = sensor_settings;
-
-       if (dmi_check_system(ov9650_flip_dmi_table) && !err) {
-               info("vflip quirk active");
-               sensor_settings[VFLIP_IDX] = 1;
-       }
-
        return 0;
 }
 
@@ -316,7 +370,8 @@ int ov9650_init(struct sd *sd)
                        err = m5602_write_bridge(sd, init_ov9650[i][1], data);
        }
 
-       err = ov9650_set_exposure(&sd->gspca_dev, sensor_settings[EXPOSURE_IDX]);
+       err = ov9650_set_exposure(&sd->gspca_dev,
+                                  sensor_settings[EXPOSURE_IDX]);
        if (err < 0)
                return err;
 
@@ -324,11 +379,13 @@ int ov9650_init(struct sd *sd)
        if (err < 0)
                return err;
 
-       err = ov9650_set_red_balance(&sd->gspca_dev, sensor_settings[RED_BALANCE_IDX]);
+       err = ov9650_set_red_balance(&sd->gspca_dev,
+                                     sensor_settings[RED_BALANCE_IDX]);
        if (err < 0)
                return err;
 
-       err = ov9650_set_blue_balance(&sd->gspca_dev, sensor_settings[BLUE_BALANCE_IDX]);
+       err = ov9650_set_blue_balance(&sd->gspca_dev,
+                                      sensor_settings[BLUE_BALANCE_IDX]);
        if (err < 0)
                return err;
 
@@ -340,11 +397,18 @@ int ov9650_init(struct sd *sd)
        if (err < 0)
                return err;
 
-       err = ov9650_set_auto_white_balance(&sd->gspca_dev, sensor_settings[AUTO_WHITE_BALANCE_IDX]);
+       err = ov9650_set_auto_exposure(&sd->gspca_dev,
+                               sensor_settings[AUTO_EXPOSURE_IDX]);
+       if (err < 0)
+               return err;
+
+       err = ov9650_set_auto_white_balance(&sd->gspca_dev,
+                               sensor_settings[AUTO_WHITE_BALANCE_IDX]);
        if (err < 0)
                return err;
 
-       err = ov9650_set_auto_gain(&sd->gspca_dev, sensor_settings[AUTO_GAIN_CTRL_IDX]);
+       err = ov9650_set_auto_gain(&sd->gspca_dev,
+                               sensor_settings[AUTO_GAIN_CTRL_IDX]);
        return err;
 }
 
@@ -360,7 +424,10 @@ int ov9650_start(struct sd *sd)
        int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
        int hor_offs = OV9650_LEFT_OFFSET;
 
-       if (sensor_settings[VFLIP_IDX])
+       if ((!dmi_check_system(ov9650_flip_dmi_table) &&
+               sensor_settings[VFLIP_IDX]) ||
+               (dmi_check_system(ov9650_flip_dmi_table) &&
+               !sensor_settings[VFLIP_IDX]))
                ver_offs--;
 
        if (width <= 320)
@@ -406,6 +473,14 @@ int ov9650_start(struct sd *sd)
        if (err < 0)
                return err;
 
+       err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 2);
+       if (err < 0)
+               return err;
+
        err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
                                 (hor_offs >> 8) & 0xff);
        if (err < 0)
@@ -425,6 +500,10 @@ int ov9650_start(struct sd *sd)
        if (err < 0)
                return err;
 
+       err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
+       if (err < 0)
+               return err;
+
        switch (width) {
        case 640:
                PDEBUG(D_V4L2, "Configuring camera for VGA mode");
@@ -467,32 +546,15 @@ int ov9650_stop(struct sd *sd)
        return m5602_write_sensor(sd, OV9650_COM2, &data, 1);
 }
 
-int ov9650_power_down(struct sd *sd)
-{
-       int i, err = 0;
-       for (i = 0; i < ARRAY_SIZE(power_down_ov9650) && !err; i++) {
-               u8 data = power_down_ov9650[i][2];
-               if (power_down_ov9650[i][0] == SENSOR)
-                       err = m5602_write_sensor(sd,
-                                           power_down_ov9650[i][1], &data, 1);
-               else
-                       err = m5602_write_bridge(sd, power_down_ov9650[i][1],
-                                                data);
-       }
-
-       return err;
-}
-
 void ov9650_disconnect(struct sd *sd)
 {
        ov9650_stop(sd);
-       ov9650_power_down(sd);
 
        sd->sensor = NULL;
        kfree(sd->sensor_priv);
 }
 
-int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        s32 *sensor_settings = sd->sensor_priv;
@@ -502,7 +564,7 @@ int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
-int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        s32 *sensor_settings = sd->sensor_priv;
@@ -532,7 +594,7 @@ int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
-int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        s32 *sensor_settings = sd->sensor_priv;
@@ -542,7 +604,7 @@ int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
-int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 i2c_data;
@@ -573,7 +635,7 @@ int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
-int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        s32 *sensor_settings = sd->sensor_priv;
@@ -583,7 +645,7 @@ int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
-int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 i2c_data;
@@ -599,7 +661,7 @@ int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
-int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        s32 *sensor_settings = sd->sensor_priv;
@@ -610,7 +672,7 @@ int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
-int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 i2c_data;
@@ -626,7 +688,7 @@ int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
-int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        s32 *sensor_settings = sd->sensor_priv;
@@ -636,7 +698,7 @@ int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
-int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 i2c_data;
@@ -646,13 +708,20 @@ int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
        PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
 
        sensor_settings[HFLIP_IDX] = val;
-       i2c_data = ((val & 0x01) << 5) | (sensor_settings[VFLIP_IDX] << 4);
+
+       if (!dmi_check_system(ov9650_flip_dmi_table))
+               i2c_data = ((val & 0x01) << 5) |
+                               (sensor_settings[VFLIP_IDX] << 4);
+       else
+               i2c_data = ((val & 0x01) << 5) |
+                               (!sensor_settings[VFLIP_IDX] << 4);
+
        err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
 
        return err;
 }
 
-int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        s32 *sensor_settings = sd->sensor_priv;
@@ -663,7 +732,7 @@ int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
-int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 i2c_data;
@@ -673,6 +742,9 @@ int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
        PDEBUG(D_V4L2, "Set vertical flip to %d", val);
        sensor_settings[VFLIP_IDX] = val;
 
+       if (dmi_check_system(ov9650_flip_dmi_table))
+               val = !val;
+
        i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5);
        err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
        if (err < 0)
@@ -685,48 +757,38 @@ int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
-int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        s32 *sensor_settings = sd->sensor_priv;
 
-       *val = sensor_settings[GAIN_IDX];
-       PDEBUG(D_V4L2, "Read gain %d", *val);
-
+       *val = sensor_settings[AUTO_EXPOSURE_IDX];
+       PDEBUG(D_V4L2, "Read auto exposure control %d", *val);
        return 0;
 }
 
-int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev,
+                                   __s32 val)
 {
        int err;
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
        s32 *sensor_settings = sd->sensor_priv;
 
-       PDEBUG(D_V4L2, "Set gain to %d", val);
-
-       sensor_settings[GAIN_IDX] = val;
+       PDEBUG(D_V4L2, "Set auto exposure control to %d", val);
 
-       /* Read the OV9650_VREF register first to avoid
-               corrupting the VREF high and low bits */
-       err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
-       if (err < 0)
-               return err;
-
-       /* Mask away all uninteresting bits */
-       i2c_data = ((val & 0x0300) >> 2) | (i2c_data & 0x3F);
-       err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
+       sensor_settings[AUTO_EXPOSURE_IDX] = val;
+       err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
        if (err < 0)
                return err;
 
-       /* The 8 LSBs */
-       i2c_data = val & 0xff;
-       err = m5602_write_sensor(sd, OV9650_GAIN, &i2c_data, 1);
+       i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0));
 
-       return err;
+       return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
 }
 
-int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev,
+                                        __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        s32 *sensor_settings = sd->sensor_priv;
@@ -735,7 +797,8 @@ int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
-int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
+                                        __s32 val)
 {
        int err;
        u8 i2c_data;
@@ -755,7 +818,7 @@ int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
-int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
        s32 *sensor_settings = sd->sensor_priv;
@@ -765,7 +828,7 @@ int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
        return 0;
 }
 
-int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 i2c_data;
@@ -780,9 +843,8 @@ int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
                return err;
 
        i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2));
-       err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
 
-       return err;
+       return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
 }
 
 static void ov9650_dump_registers(struct sd *sd)
index fcc54e4c0f4f33d8e764f85960a4d93fa9229b65..c98c40d69e05e8c95ed666c0ef9479525c79962a 100644 (file)
 #define OV9650_SOFT_SLEEP              (1 << 4)
 #define OV9650_OUTPUT_DRIVE_2X         (1 << 0)
 
+#define OV9650_DENOISE_ENABLE          (1 << 5)
+#define OV9650_WHITE_PIXEL_ENABLE      (1 << 1)
+#define OV9650_WHITE_PIXEL_OPTION      (1 << 0)
+
 #define OV9650_LEFT_OFFSET             0x62
 
 #define GAIN_DEFAULT                   0x14
@@ -137,29 +141,9 @@ int ov9650_probe(struct sd *sd);
 int ov9650_init(struct sd *sd);
 int ov9650_start(struct sd *sd);
 int ov9650_stop(struct sd *sd);
-int ov9650_power_down(struct sd *sd);
 void ov9650_disconnect(struct sd *sd);
 
-int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
-int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
-int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
-int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
-int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
-int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
-int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
-int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val);
-int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val);
-int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
-int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
-
-const static struct m5602_sensor ov9650 = {
+static const struct m5602_sensor ov9650 = {
        .name = "OV9650",
        .i2c_slave_id = 0x60,
        .i2c_regW = 1,
@@ -167,7 +151,6 @@ const static struct m5602_sensor ov9650 = {
        .init = ov9650_init,
        .start = ov9650_start,
        .stop = ov9650_stop,
-       .power_down = ov9650_power_down,
        .disconnect = ov9650_disconnect,
 };
 
@@ -219,7 +202,7 @@ static const unsigned char init_ov9650[][3] =
        /* Reset chip */
        {SENSOR, OV9650_COM7, OV9650_REGISTER_RESET},
        /* One extra reset is needed in order to make the sensor behave
-          properly when resuming from ram */
+          properly when resuming from ram, could be a timing issue */
        {SENSOR, OV9650_COM7, OV9650_REGISTER_RESET},
 
        /* Enable double clock */
@@ -229,8 +212,7 @@ static const unsigned char init_ov9650[][3] =
 
        /* Set fast AGC/AEC algorithm with unlimited step size */
        {SENSOR, OV9650_COM8, OV9650_FAST_AGC_AEC |
-                             OV9650_AEC_UNLIM_STEP_SIZE |
-                             OV9650_AWB_EN | OV9650_AGC_EN},
+                             OV9650_AEC_UNLIM_STEP_SIZE},
 
        {SENSOR, OV9650_CHLF, 0x10},
        {SENSOR, OV9650_ARBLM, 0xbf},
@@ -301,8 +283,11 @@ static const unsigned char init_ov9650[][3] =
        {SENSOR, OV9650_VREF, 0x10},
        {SENSOR, OV9650_ADC, 0x04},
        {SENSOR, OV9650_HV, 0x40},
+
        /* Enable denoise, and white-pixel erase */
-       {SENSOR, OV9650_COM22, 0x23},
+       {SENSOR, OV9650_COM22, OV9650_DENOISE_ENABLE |
+                OV9650_WHITE_PIXEL_ENABLE |
+                OV9650_WHITE_PIXEL_OPTION},
 
        /* Enable VARIOPIXEL */
        {SENSOR, OV9650_COM3, OV9650_VARIOPIXEL},
@@ -312,26 +297,6 @@ static const unsigned char init_ov9650[][3] =
        {SENSOR, OV9650_COM2, OV9650_SOFT_SLEEP | OV9650_OUTPUT_DRIVE_2X},
 };
 
-static const unsigned char power_down_ov9650[][3] =
-{
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
-       {SENSOR, OV9650_COM7, 0x80},
-       {SENSOR, OV9650_OFON, 0xf4},
-       {SENSOR, OV9650_MVFP, 0x80},
-       {SENSOR, OV9650_DBLV, 0x3f},
-       {SENSOR, OV9650_RSVD36, 0x49},
-       {SENSOR, OV9650_COM7, 0x05},
-
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0x06},
-       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
-};
-
 static const unsigned char res_init_ov9650[][3] =
 {
        {SENSOR, OV9650_COM2, OV9650_OUTPUT_DRIVE_2X},
index eaddf488bad1033d1bd7ed8f3f5190317919f925..8d74d8065b7977cb126d3fb23922830b317671f9 100644 (file)
 
 #include "m5602_po1030.h"
 
+static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
+static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev,
+                                        __s32 val);
+static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev,
+                                        __s32 *val);
+static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,
+                                        __s32 val);
+static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev,
+                                        __s32 *val);
+
 static struct v4l2_pix_format po1030_modes[] = {
        {
                640,
@@ -27,11 +50,12 @@ static struct v4l2_pix_format po1030_modes[] = {
                .sizeimage = 640 * 480,
                .bytesperline = 640,
                .colorspace = V4L2_COLORSPACE_SRGB,
-               .priv = 0
+               .priv = 2
        }
 };
 
-const static struct ctrl po1030_ctrls[] = {
+static const struct ctrl po1030_ctrls[] = {
+#define GAIN_IDX 0
        {
                {
                        .id             = V4L2_CID_GAIN,
@@ -45,7 +69,9 @@ const static struct ctrl po1030_ctrls[] = {
                },
                .set = po1030_set_gain,
                .get = po1030_get_gain
-       }, {
+       },
+#define EXPOSURE_IDX 1
+       {
                {
                        .id             = V4L2_CID_EXPOSURE,
                        .type           = V4L2_CTRL_TYPE_INTEGER,
@@ -58,7 +84,9 @@ const static struct ctrl po1030_ctrls[] = {
                },
                .set = po1030_set_exposure,
                .get = po1030_get_exposure
-       }, {
+       },
+#define RED_BALANCE_IDX 2
+       {
                {
                        .id             = V4L2_CID_RED_BALANCE,
                        .type           = V4L2_CTRL_TYPE_INTEGER,
@@ -71,7 +99,9 @@ const static struct ctrl po1030_ctrls[] = {
                },
                .set = po1030_set_red_balance,
                .get = po1030_get_red_balance
-       }, {
+       },
+#define BLUE_BALANCE_IDX 3
+       {
                {
                        .id             = V4L2_CID_BLUE_BALANCE,
                        .type           = V4L2_CTRL_TYPE_INTEGER,
@@ -84,7 +114,9 @@ const static struct ctrl po1030_ctrls[] = {
                },
                .set = po1030_set_blue_balance,
                .get = po1030_get_blue_balance
-       }, {
+       },
+#define HFLIP_IDX 4
+       {
                {
                        .id             = V4L2_CID_HFLIP,
                        .type           = V4L2_CTRL_TYPE_BOOLEAN,
@@ -96,7 +128,9 @@ const static struct ctrl po1030_ctrls[] = {
                },
                .set = po1030_set_hflip,
                .get = po1030_get_hflip
-       }, {
+       },
+#define VFLIP_IDX 5
+       {
                {
                        .id             = V4L2_CID_VFLIP,
                        .type           = V4L2_CTRL_TYPE_BOOLEAN,
@@ -108,14 +142,58 @@ const static struct ctrl po1030_ctrls[] = {
                },
                .set = po1030_set_vflip,
                .get = po1030_get_vflip
-       }
+       },
+#define AUTO_WHITE_BALANCE_IDX 6
+       {
+               {
+                       .id             = V4L2_CID_AUTO_WHITE_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "auto white balance",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0,
+               },
+               .set = po1030_set_auto_white_balance,
+               .get = po1030_get_auto_white_balance
+       },
+#define AUTO_EXPOSURE_IDX 7
+       {
+               {
+                       .id             = V4L2_CID_EXPOSURE_AUTO,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "auto exposure",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 0,
+               },
+               .set = po1030_set_auto_exposure,
+               .get = po1030_get_auto_exposure
+       },
+#define GREEN_BALANCE_IDX 8
+       {
+               {
+                       .id             = M5602_V4L2_CID_GREEN_BALANCE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "green balance",
+                       .minimum        = 0x00,
+                       .maximum        = 0xff,
+                       .step           = 0x1,
+                       .default_value  = PO1030_GREEN_GAIN_DEFAULT,
+                       .flags          = V4L2_CTRL_FLAG_SLIDER
+               },
+               .set = po1030_set_green_balance,
+               .get = po1030_get_green_balance
+       },
 };
 
 static void po1030_dump_registers(struct sd *sd);
 
 int po1030_probe(struct sd *sd)
 {
-       u8 prod_id = 0, ver_id = 0, i;
+       u8 dev_id_h = 0, i;
+       s32 *sensor_settings;
 
        if (force_sensor) {
                if (force_sensor == PO1030_SENSOR) {
@@ -139,28 +217,36 @@ int po1030_probe(struct sd *sd)
                        m5602_write_bridge(sd, preinit_po1030[i][1], data);
        }
 
-       if (m5602_read_sensor(sd, 0x3, &prod_id, 1))
+       if (m5602_read_sensor(sd, PO1030_DEVID_H, &dev_id_h, 1))
                return -ENODEV;
 
-       if (m5602_read_sensor(sd, 0x4, &ver_id, 1))
-               return -ENODEV;
-
-       if ((prod_id == 0x02) && (ver_id == 0xef)) {
+       if (dev_id_h == 0x30) {
                info("Detected a po1030 sensor");
                goto sensor_found;
        }
        return -ENODEV;
 
 sensor_found:
+       sensor_settings = kmalloc(
+               ARRAY_SIZE(po1030_ctrls) * sizeof(s32), GFP_KERNEL);
+       if (!sensor_settings)
+               return -ENOMEM;
+
        sd->gspca_dev.cam.cam_mode = po1030_modes;
        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(po1030_modes);
        sd->desc->ctrls = po1030_ctrls;
        sd->desc->nctrls = ARRAY_SIZE(po1030_ctrls);
+
+       for (i = 0; i < ARRAY_SIZE(po1030_ctrls); i++)
+               sensor_settings[i] = po1030_ctrls[i].qctrl.default_value;
+       sd->sensor_priv = sensor_settings;
+
        return 0;
 }
 
 int po1030_init(struct sd *sd)
 {
+       s32 *sensor_settings = sd->sensor_priv;
        int i, err = 0;
 
        /* Init the sensor */
@@ -185,47 +271,206 @@ int po1030_init(struct sd *sd)
                        return -EINVAL;
                }
        }
+       if (err < 0)
+               return err;
 
        if (dump_sensor)
                po1030_dump_registers(sd);
 
+       err = po1030_set_exposure(&sd->gspca_dev,
+                                  sensor_settings[EXPOSURE_IDX]);
+       if (err < 0)
+               return err;
+
+       err = po1030_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
+       if (err < 0)
+               return err;
+
+       err = po1030_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
+       if (err < 0)
+               return err;
+
+       err = po1030_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
+       if (err < 0)
+               return err;
+
+       err = po1030_set_red_balance(&sd->gspca_dev,
+                                     sensor_settings[RED_BALANCE_IDX]);
+       if (err < 0)
+               return err;
+
+       err = po1030_set_blue_balance(&sd->gspca_dev,
+                                     sensor_settings[BLUE_BALANCE_IDX]);
+       if (err < 0)
+               return err;
+
+       err = po1030_set_green_balance(&sd->gspca_dev,
+                                      sensor_settings[GREEN_BALANCE_IDX]);
+       if (err < 0)
+               return err;
+
+       err = po1030_set_auto_white_balance(&sd->gspca_dev,
+                               sensor_settings[AUTO_WHITE_BALANCE_IDX]);
+       if (err < 0)
+               return err;
+
+       err = po1030_set_auto_exposure(&sd->gspca_dev,
+                               sensor_settings[AUTO_EXPOSURE_IDX]);
        return err;
 }
 
-int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+int po1030_start(struct sd *sd)
 {
-       struct sd *sd = (struct sd *) gspca_dev;
-       u8 i2c_data;
-       int err;
+       struct cam *cam = &sd->gspca_dev.cam;
+       int i, err = 0;
+       int width = cam->cam_mode[sd->gspca_dev.curr_mode].width;
+       int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
+       int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
+       u8 data;
+
+       switch (width) {
+       case 320:
+               data = PO1030_SUBSAMPLING;
+               err = m5602_write_sensor(sd, PO1030_CONTROL3, &data, 1);
+               if (err < 0)
+                       return err;
+
+               data = ((width + 3) >> 8) & 0xff;
+               err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_H, &data, 1);
+               if (err < 0)
+                       return err;
+
+               data = (width + 3) & 0xff;
+               err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_L, &data, 1);
+               if (err < 0)
+                       return err;
+
+               data = ((height + 1) >> 8) & 0xff;
+               err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_H, &data, 1);
+               if (err < 0)
+                       return err;
+
+               data = (height + 1) & 0xff;
+               err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_L, &data, 1);
+
+               height += 6;
+               width -= 1;
+               break;
+
+       case 640:
+               data = 0;
+               err = m5602_write_sensor(sd, PO1030_CONTROL3, &data, 1);
+               if (err < 0)
+                       return err;
+
+               data = ((width + 7) >> 8) & 0xff;
+               err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_H, &data, 1);
+               if (err < 0)
+                       return err;
+
+               data = (width + 7) & 0xff;
+               err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_L, &data, 1);
+               if (err < 0)
+                       return err;
+
+               data = ((height + 3) >> 8) & 0xff;
+               err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_H, &data, 1);
+               if (err < 0)
+                       return err;
+
+               data = (height + 3) & 0xff;
+               err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_L, &data, 1);
+
+               height += 12;
+               width -= 2;
+               break;
+       }
+       err = m5602_write_bridge(sd, M5602_XB_SENSOR_TYPE, 0x0c);
+       if (err < 0)
+               return err;
 
-       err = m5602_read_sensor(sd, PO1030_REG_INTEGLINES_H,
-                                &i2c_data, 1);
+       err = m5602_write_bridge(sd, M5602_XB_LINE_OF_FRAME_H, 0x81);
        if (err < 0)
                return err;
-       *val = (i2c_data << 8);
 
-       err = m5602_read_sensor(sd, PO1030_REG_INTEGLINES_M,
-                                &i2c_data, 1);
-       *val |= i2c_data;
+       err = m5602_write_bridge(sd, M5602_XB_PIX_OF_LINE_H, 0x82);
+       if (err < 0)
+               return err;
 
-       PDEBUG(D_V4L2, "Exposure read as %d", *val);
+       err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0x01);
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA,
+                                ((ver_offs >> 8) & 0xff));
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (ver_offs & 0xff));
+       if (err < 0)
+               return err;
+
+       for (i = 0; i < 2 && !err; i++)
+               err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff);
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff));
+       if (err < 0)
+               return err;
+
+       for (i = 0; i < 2 && !err; i++)
+               err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
+
+       for (i = 0; i < 2 && !err; i++)
+               err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
+
+       for (i = 0; i < 2 && !err; i++)
+               err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 0);
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (width >> 8) & 0xff);
+       if (err < 0)
+               return err;
 
+       err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (width & 0xff));
+       if (err < 0)
+               return err;
+
+       err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
        return err;
 }
 
-int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[EXPOSURE_IDX];
+       PDEBUG(D_V4L2, "Exposure read as %d", *val);
+       return 0;
+}
+
+static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 i2c_data;
        int err;
 
+       sensor_settings[EXPOSURE_IDX] = val;
        PDEBUG(D_V4L2, "Set exposure to %d", val & 0xffff);
 
        i2c_data = ((val & 0xff00) >> 8);
        PDEBUG(D_V4L2, "Set exposure to high byte to 0x%x",
               i2c_data);
 
-       err = m5602_write_sensor(sd, PO1030_REG_INTEGLINES_H,
+       err = m5602_write_sensor(sd, PO1030_INTEGLINES_H,
                                  &i2c_data, 1);
        if (err < 0)
                return err;
@@ -233,167 +478,256 @@ int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
        i2c_data = (val & 0xff);
        PDEBUG(D_V4L2, "Set exposure to low byte to 0x%x",
               i2c_data);
-       err = m5602_write_sensor(sd, PO1030_REG_INTEGLINES_M,
+       err = m5602_write_sensor(sd, PO1030_INTEGLINES_M,
                                  &i2c_data, 1);
 
        return err;
 }
 
-int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       u8 i2c_data;
-       int err;
+       s32 *sensor_settings = sd->sensor_priv;
 
-       err = m5602_read_sensor(sd, PO1030_REG_GLOBALGAIN,
-                                &i2c_data, 1);
-       *val = i2c_data;
+       *val = sensor_settings[GAIN_IDX];
        PDEBUG(D_V4L2, "Read global gain %d", *val);
-
-       return err;
+       return 0;
 }
 
-int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 i2c_data;
        int err;
 
-       err = m5602_read_sensor(sd, PO1030_REG_CONTROL2,
+       sensor_settings[GAIN_IDX] = val;
+
+       i2c_data = val & 0xff;
+       PDEBUG(D_V4L2, "Set global gain to %d", i2c_data);
+       err = m5602_write_sensor(sd, PO1030_GLOBALGAIN,
                                 &i2c_data, 1);
+       return err;
+}
 
-       *val = (i2c_data >> 7) & 0x01 ;
+static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
 
+       *val = sensor_settings[HFLIP_IDX];
        PDEBUG(D_V4L2, "Read hflip %d", *val);
 
-       return err;
+       return 0;
 }
 
-int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 i2c_data;
        int err;
 
+       sensor_settings[HFLIP_IDX] = val;
+
        PDEBUG(D_V4L2, "Set hflip %d", val);
-       err = m5602_read_sensor(sd, PO1030_REG_CONTROL2, &i2c_data, 1);
+       err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1);
        if (err < 0)
                return err;
 
        i2c_data = (0x7f & i2c_data) | ((val & 0x01) << 7);
 
-       err = m5602_write_sensor(sd, PO1030_REG_CONTROL2,
+       err = m5602_write_sensor(sd, PO1030_CONTROL2,
                                 &i2c_data, 1);
 
        return err;
 }
 
-int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       u8 i2c_data;
-       int err;
-
-       err = m5602_read_sensor(sd, PO1030_REG_GLOBALGAIN,
-                                &i2c_data, 1);
-
-       *val = (i2c_data >> 6) & 0x01;
+       s32 *sensor_settings = sd->sensor_priv;
 
+       *val = sensor_settings[VFLIP_IDX];
        PDEBUG(D_V4L2, "Read vflip %d", *val);
 
-       return err;
+       return 0;
 }
 
-int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 i2c_data;
        int err;
 
+       sensor_settings[VFLIP_IDX] = val;
+
        PDEBUG(D_V4L2, "Set vflip %d", val);
-       err = m5602_read_sensor(sd, PO1030_REG_CONTROL2, &i2c_data, 1);
+       err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1);
        if (err < 0)
                return err;
 
        i2c_data = (i2c_data & 0xbf) | ((val & 0x01) << 6);
 
-       err = m5602_write_sensor(sd, PO1030_REG_CONTROL2,
+       err = m5602_write_sensor(sd, PO1030_CONTROL2,
                                 &i2c_data, 1);
 
        return err;
 }
 
-int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[RED_BALANCE_IDX];
+       PDEBUG(D_V4L2, "Read red gain %d", *val);
+       return 0;
+}
+
+static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 i2c_data;
        int err;
 
+       sensor_settings[RED_BALANCE_IDX] = val;
+
        i2c_data = val & 0xff;
-       PDEBUG(D_V4L2, "Set global gain to %d", i2c_data);
-       err = m5602_write_sensor(sd, PO1030_REG_GLOBALGAIN,
+       PDEBUG(D_V4L2, "Set red gain to %d", i2c_data);
+       err = m5602_write_sensor(sd, PO1030_RED_GAIN,
                                  &i2c_data, 1);
        return err;
 }
 
-int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       u8 i2c_data;
-       int err;
+       s32 *sensor_settings = sd->sensor_priv;
 
-       err = m5602_read_sensor(sd, PO1030_REG_RED_GAIN,
-                                &i2c_data, 1);
-       *val = i2c_data;
-       PDEBUG(D_V4L2, "Read red gain %d", *val);
-       return err;
+       *val = sensor_settings[BLUE_BALANCE_IDX];
+       PDEBUG(D_V4L2, "Read blue gain %d", *val);
+
+       return 0;
 }
 
-int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
+static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 i2c_data;
        int err;
 
+       sensor_settings[BLUE_BALANCE_IDX] = val;
+
        i2c_data = val & 0xff;
-       PDEBUG(D_V4L2, "Set red gain to %d", i2c_data);
-       err = m5602_write_sensor(sd, PO1030_REG_RED_GAIN,
+       PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data);
+       err = m5602_write_sensor(sd, PO1030_BLUE_GAIN,
                                  &i2c_data, 1);
+
        return err;
 }
 
-int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[GREEN_BALANCE_IDX];
+       PDEBUG(D_V4L2, "Read green gain %d", *val);
+
+       return 0;
+}
+
+static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 i2c_data;
        int err;
 
-       err = m5602_read_sensor(sd, PO1030_REG_BLUE_GAIN,
+       sensor_settings[GREEN_BALANCE_IDX] = val;
+       i2c_data = val & 0xff;
+       PDEBUG(D_V4L2, "Set green gain to %d", i2c_data);
+
+       err = m5602_write_sensor(sd, PO1030_GREEN_1_GAIN,
+                          &i2c_data, 1);
+       if (err < 0)
+               return err;
+
+       return m5602_write_sensor(sd, PO1030_GREEN_2_GAIN,
                                 &i2c_data, 1);
-       *val = i2c_data;
-       PDEBUG(D_V4L2, "Read blue gain %d", *val);
+}
 
-       return err;
+static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev,
+                                        __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
+       PDEBUG(D_V4L2, "Auto white balancing is %d", *val);
+
+       return 0;
 }
 
-int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
+static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev,
+                                        __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 i2c_data;
        int err;
-       i2c_data = val & 0xff;
-       PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data);
-       err = m5602_write_sensor(sd, PO1030_REG_BLUE_GAIN,
-                                 &i2c_data, 1);
 
+       sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
+
+       err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
+       if (err < 0)
+               return err;
+
+       PDEBUG(D_V4L2, "Set auto white balance to %d", val);
+       i2c_data = (i2c_data & 0xfe) | (val & 0x01);
+       err = m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
        return err;
 }
 
-int po1030_power_down(struct sd *sd)
+static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev,
+                                   __s32 *val)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[AUTO_EXPOSURE_IDX];
+       PDEBUG(D_V4L2, "Auto exposure is %d", *val);
        return 0;
 }
 
+static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,
+                                   __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+       u8 i2c_data;
+       int err;
+
+       sensor_settings[AUTO_EXPOSURE_IDX] = val;
+       err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
+       if (err < 0)
+               return err;
+
+       PDEBUG(D_V4L2, "Set auto exposure to %d", val);
+       i2c_data = (i2c_data & 0xfd) | ((val & 0x01) << 1);
+       return m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
+}
+
+void po1030_disconnect(struct sd *sd)
+{
+       sd->sensor = NULL;
+       kfree(sd->sensor_priv);
+}
+
 static void po1030_dump_registers(struct sd *sd)
 {
        int address;
index c10b12335818f1dc65fe53eda77545dda403f692..1ea380b2bbe73ee49c6734883a38a2d80b74d816 100644 (file)
 
 /*****************************************************************************/
 
-#define PO1030_REG_DEVID_H             0x00
-#define PO1030_REG_DEVID_L             0x01
-#define PO1030_REG_FRAMEWIDTH_H                0x04
-#define PO1030_REG_FRAMEWIDTH_L                0x05
-#define PO1030_REG_FRAMEHEIGHT_H       0x06
-#define PO1030_REG_FRAMEHEIGHT_L       0x07
-#define PO1030_REG_WINDOWX_H           0x08
-#define PO1030_REG_WINDOWX_L           0x09
-#define PO1030_REG_WINDOWY_H           0x0a
-#define PO1030_REG_WINDOWY_L           0x0b
-#define PO1030_REG_WINDOWWIDTH_H       0x0c
-#define PO1030_REG_WINDOWWIDTH_L       0x0d
-#define PO1030_REG_WINDOWHEIGHT_H      0x0e
-#define PO1030_REG_WINDOWHEIGHT_L      0x0f
-
-#define PO1030_REG_GLOBALIBIAS         0x12
-#define PO1030_REG_PIXELIBIAS          0x13
-
-#define PO1030_REG_GLOBALGAIN          0x15
-#define PO1030_REG_RED_GAIN            0x16
-#define PO1030_REG_GREEN_1_GAIN                0x17
-#define PO1030_REG_BLUE_GAIN           0x18
-#define PO1030_REG_GREEN_2_GAIN                0x19
-
-#define PO1030_REG_INTEGLINES_H                0x1a
-#define PO1030_REG_INTEGLINES_M                0x1b
-#define PO1030_REG_INTEGLINES_L                0x1c
-
-#define PO1030_REG_CONTROL1            0x1d
-#define PO1030_REG_CONTROL2            0x1e
-#define PO1030_REG_CONTROL3            0x1f
-#define PO1030_REG_CONTROL4            0x20
-
-#define PO1030_REG_PERIOD50_H          0x23
-#define PO1030_REG_PERIOD50_L          0x24
-#define PO1030_REG_PERIOD60_H          0x25
-#define PO1030_REG_PERIOD60_L          0x26
-#define PO1030_REG_REGCLK167           0x27
-#define PO1030_REG_DELTA50             0x28
-#define PO1030_REG_DELTA60             0x29
-
-#define PO1030_REG_ADCOFFSET           0x2c
+#define PO1030_DEVID_H         0x00
+#define PO1030_DEVID_L         0x01
+#define PO1030_FRAMEWIDTH_H    0x04
+#define PO1030_FRAMEWIDTH_L    0x05
+#define PO1030_FRAMEHEIGHT_H   0x06
+#define PO1030_FRAMEHEIGHT_L   0x07
+#define PO1030_WINDOWX_H       0x08
+#define PO1030_WINDOWX_L       0x09
+#define PO1030_WINDOWY_H       0x0a
+#define PO1030_WINDOWY_L       0x0b
+#define PO1030_WINDOWWIDTH_H   0x0c
+#define PO1030_WINDOWWIDTH_L   0x0d
+#define PO1030_WINDOWHEIGHT_H  0x0e
+#define PO1030_WINDOWHEIGHT_L  0x0f
+
+#define PO1030_GLOBALIBIAS     0x12
+#define PO1030_PIXELIBIAS      0x13
+
+#define PO1030_GLOBALGAIN      0x15
+#define PO1030_RED_GAIN                0x16
+#define PO1030_GREEN_1_GAIN    0x17
+#define PO1030_BLUE_GAIN       0x18
+#define PO1030_GREEN_2_GAIN    0x19
+
+#define PO1030_INTEGLINES_H    0x1a
+#define PO1030_INTEGLINES_M    0x1b
+#define PO1030_INTEGLINES_L    0x1c
+
+#define PO1030_CONTROL1                0x1d
+#define PO1030_CONTROL2                0x1e
+#define PO1030_CONTROL3                0x1f
+#define PO1030_CONTROL4                0x20
+
+#define PO1030_PERIOD50_H      0x23
+#define PO1030_PERIOD50_L      0x24
+#define PO1030_PERIOD60_H      0x25
+#define PO1030_PERIOD60_L      0x26
+#define PO1030_REGCLK167       0x27
+#define PO1030_FLICKER_DELTA50 0x28
+#define PO1030_FLICKERDELTA60  0x29
+
+#define PO1030_ADCOFFSET       0x2c
 
 /* Gamma Correction Coeffs */
-#define PO1030_REG_GC0                 0x2d
-#define PO1030_REG_GC1                 0x2e
-#define PO1030_REG_GC2                 0x2f
-#define PO1030_REG_GC3                 0x30
-#define PO1030_REG_GC4                 0x31
-#define PO1030_REG_GC5                 0x32
-#define PO1030_REG_GC6                 0x33
-#define PO1030_REG_GC7                 0x34
+#define PO1030_GC0             0x2d
+#define PO1030_GC1             0x2e
+#define PO1030_GC2             0x2f
+#define PO1030_GC3             0x30
+#define PO1030_GC4             0x31
+#define PO1030_GC5             0x32
+#define PO1030_GC6             0x33
+#define PO1030_GC7             0x34
 
 /* Color Transform Matrix */
-#define PO1030_REG_CT0                 0x35
-#define PO1030_REG_CT1                 0x36
-#define PO1030_REG_CT2                 0x37
-#define PO1030_REG_CT3                 0x38
-#define PO1030_REG_CT4                 0x39
-#define PO1030_REG_CT5                 0x3a
-#define PO1030_REG_CT6                 0x3b
-#define PO1030_REG_CT7                 0x3c
-#define PO1030_REG_CT8                 0x3d
-
-#define PO1030_REG_AUTOCTRL1           0x3e
-#define PO1030_REG_AUTOCTRL2           0x3f
-
-#define PO1030_REG_YTARGET             0x40
-#define PO1030_REG_GLOBALGAINMIN       0x41
-#define PO1030_REG_GLOBALGAINMAX       0x42
+#define PO1030_CT0             0x35
+#define PO1030_CT1             0x36
+#define PO1030_CT2             0x37
+#define PO1030_CT3             0x38
+#define PO1030_CT4             0x39
+#define PO1030_CT5             0x3a
+#define PO1030_CT6             0x3b
+#define PO1030_CT7             0x3c
+#define PO1030_CT8             0x3d
+
+#define PO1030_AUTOCTRL1       0x3e
+#define PO1030_AUTOCTRL2       0x3f
+
+#define PO1030_YTARGET         0x40
+#define PO1030_GLOBALGAINMIN   0x41
+#define PO1030_GLOBALGAINMAX   0x42
+
+#define PO1030_AWB_RED_TUNING  0x47
+#define PO1030_AWB_BLUE_TUNING 0x48
 
 /* Output format control */
-#define PO1030_REG_OUTFORMCTRL1                0x5a
-#define PO1030_REG_OUTFORMCTRL2                0x5b
-#define PO1030_REG_OUTFORMCTRL3                0x5c
-#define PO1030_REG_OUTFORMCTRL4                0x5d
-#define PO1030_REG_OUTFORMCTRL5                0x5e
+#define PO1030_OUTFORMCTRL1    0x5a
+#define PO1030_OUTFORMCTRL2    0x5b
+#define PO1030_OUTFORMCTRL3    0x5c
+#define PO1030_OUTFORMCTRL4    0x5d
+#define PO1030_OUTFORMCTRL5    0x5e
 
-/* Imaging coefficients */
-#define PO1030_REG_YBRIGHT             0x73
-#define PO1030_REG_YCONTRAST           0x74
-#define PO1030_REG_YSATURATION         0x75
+#define PO1030_EDGE_ENH_OFF    0x5f
+#define PO1030_EGA             0x60
 
-#define PO1030_HFLIP                   (1 << 7)
-#define PO1030_VFLIP                   (1 << 6)
+#define PO1030_Cb_U_GAIN       0x63
+#define PO1030_Cr_V_GAIN       0x64
+
+#define PO1030_YCONTRAST       0x74
+#define PO1030_YSATURATION     0x75
+
+#define PO1030_HFLIP           (1 << 7)
+#define PO1030_VFLIP           (1 << 6)
+
+#define PO1030_HREF_ENABLE     (1 << 6)
+
+#define PO1030_RAW_RGB_BAYER   0x4
+
+#define PO1030_FRAME_EQUAL     (1 << 3)
+#define PO1030_AUTO_SUBSAMPLING (1 << 4)
+
+#define PO1030_WEIGHT_WIN_2X   (1 << 3)
+
+#define PO1030_SHUTTER_MODE    (1 << 6)
+#define PO1030_AUTO_SUBSAMPLING        (1 << 4)
+#define PO1030_FRAME_EQUAL     (1 << 3)
+
+#define PO1030_SENSOR_RESET    (1 << 5)
+
+#define PO1030_SUBSAMPLING     (1 << 6)
 
 /*****************************************************************************/
 
 #define PO1030_GLOBAL_GAIN_DEFAULT     0x12
 #define PO1030_EXPOSURE_DEFAULT                0x0085
-#define PO1030_BLUE_GAIN_DEFAULT       0x40
-#define PO1030_RED_GAIN_DEFAULT        0x40
+#define PO1030_BLUE_GAIN_DEFAULT       0x36
+#define PO1030_RED_GAIN_DEFAULT        0x36
+#define PO1030_GREEN_GAIN_DEFAULT      0x40
 
 /*****************************************************************************/
 
@@ -126,20 +151,8 @@ extern int dump_sensor;
 
 int po1030_probe(struct sd *sd);
 int po1030_init(struct sd *sd);
-int po1030_power_down(struct sd *sd);
-
-int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
-int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
-int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
-int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
-int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
-int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+int po1030_start(struct sd *sd);
+void po1030_disconnect(struct sd *sd);
 
 static const struct m5602_sensor po1030 = {
        .name = "PO1030",
@@ -149,7 +162,8 @@ static const struct m5602_sensor po1030 = {
 
        .probe = po1030_probe,
        .init = po1030_init,
-       .power_down = po1030_power_down,
+       .start = po1030_start,
+       .disconnect = po1030_disconnect,
 };
 
 static const unsigned char preinit_po1030[][3] =
@@ -159,248 +173,103 @@ static const unsigned char preinit_po1030[][3] =
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
        {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d},
        {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
        {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
-
-       {SENSOR, PO1030_REG_AUTOCTRL2, 0x24},
-
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
-       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
-       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
        {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
-       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81},
-       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
-       {BRIDGE, M5602_XB_SIG_INI, 0x01},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x02},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0xec},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x02},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x87},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00},
-
-       {SENSOR, PO1030_REG_AUTOCTRL2, 0x24},
-
        {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
        {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
        {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
        {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
        {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
+
+       {SENSOR, PO1030_AUTOCTRL2, PO1030_SENSOR_RESET | (1 << 2)},
+
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
        {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
        {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
        {BRIDGE, M5602_XB_GPIO_DAT, 0x00}
 };
 
-static const unsigned char init_po1030[][4] =
+static const unsigned char init_po1030[][3] =
 {
        {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
        {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
-       /*sequence 1*/
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
        {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d},
-
        {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
        {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
-       /*end of sequence 1*/
-
-       /*sequence 2 (same as stop sequence)*/
-       {SENSOR, PO1030_REG_AUTOCTRL2, 0x24},
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
-       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
-       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
-
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
-       /*end of sequence 2*/
 
-       /*sequence 5*/
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
-       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81},
-       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
-       {BRIDGE, M5602_XB_SIG_INI, 0x01},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x02},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0xec},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x02},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x87},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00},
-       /*end of sequence 5*/
-
-       /*sequence 2 stop */
-       {SENSOR, PO1030_REG_AUTOCTRL2, 0x24},
+       {SENSOR, PO1030_AUTOCTRL2, PO1030_SENSOR_RESET | (1 << 2)},
 
        {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
        {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
        {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
        {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
        {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
-       /*end of sequence 2 stop */
-
-/* ---------------------------------
- * end of init - begin of start
- * --------------------------------- */
-
-       /*sequence 3*/
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
-       /*end of sequence 3*/
-       /*sequence 4*/
        {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
        {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
 
-       {SENSOR, PO1030_REG_AUTOCTRL2, 0x04},
+       {SENSOR, PO1030_AUTOCTRL2, 0x04},
+
+       {SENSOR, PO1030_OUTFORMCTRL2, PO1030_RAW_RGB_BAYER},
+       {SENSOR, PO1030_AUTOCTRL1, PO1030_WEIGHT_WIN_2X},
+
+       {SENSOR, PO1030_CONTROL2, 0x03},
+       {SENSOR, 0x21, 0x90},
+       {SENSOR, PO1030_YTARGET, 0x60},
+       {SENSOR, 0x59, 0x13},
+       {SENSOR, PO1030_OUTFORMCTRL1, PO1030_HREF_ENABLE},
+       {SENSOR, PO1030_EDGE_ENH_OFF, 0x00},
+       {SENSOR, PO1030_EGA, 0x80},
+       {SENSOR, 0x78, 0x14},
+       {SENSOR, 0x6f, 0x01},
+       {SENSOR, PO1030_GLOBALGAINMAX, 0x14},
+       {SENSOR, PO1030_Cb_U_GAIN, 0x38},
+       {SENSOR, PO1030_Cr_V_GAIN, 0x38},
+       {SENSOR, PO1030_CONTROL1, PO1030_SHUTTER_MODE |
+                                 PO1030_AUTO_SUBSAMPLING |
+                                 PO1030_FRAME_EQUAL},
+       {SENSOR, PO1030_GC0, 0x10},
+       {SENSOR, PO1030_GC1, 0x20},
+       {SENSOR, PO1030_GC2, 0x40},
+       {SENSOR, PO1030_GC3, 0x60},
+       {SENSOR, PO1030_GC4, 0x80},
+       {SENSOR, PO1030_GC5, 0xa0},
+       {SENSOR, PO1030_GC6, 0xc0},
+       {SENSOR, PO1030_GC7, 0xff},
 
        /* Set the width to 751 */
-       {SENSOR, PO1030_REG_FRAMEWIDTH_H, 0x02},
-       {SENSOR, PO1030_REG_FRAMEWIDTH_L, 0xef},
+       {SENSOR, PO1030_FRAMEWIDTH_H, 0x02},
+       {SENSOR, PO1030_FRAMEWIDTH_L, 0xef},
 
        /* Set the height to 540 */
-       {SENSOR, PO1030_REG_FRAMEHEIGHT_H, 0x02},
-       {SENSOR, PO1030_REG_FRAMEHEIGHT_L, 0x1c},
+       {SENSOR, PO1030_FRAMEHEIGHT_H, 0x02},
+       {SENSOR, PO1030_FRAMEHEIGHT_L, 0x1c},
 
        /* Set the x window to 1 */
-       {SENSOR, PO1030_REG_WINDOWX_H, 0x00},
-       {SENSOR, PO1030_REG_WINDOWX_L, 0x01},
+       {SENSOR, PO1030_WINDOWX_H, 0x00},
+       {SENSOR, PO1030_WINDOWX_L, 0x01},
 
        /* Set the y window to 1 */
-       {SENSOR, PO1030_REG_WINDOWY_H, 0x00},
-       {SENSOR, PO1030_REG_WINDOWY_L, 0x01},
-
-       {SENSOR, PO1030_REG_WINDOWWIDTH_H, 0x02},
-       {SENSOR, PO1030_REG_WINDOWWIDTH_L, 0x87},
-       {SENSOR, PO1030_REG_WINDOWHEIGHT_H, 0x01},
-       {SENSOR, PO1030_REG_WINDOWHEIGHT_L, 0xe3},
-
-       {SENSOR, PO1030_REG_OUTFORMCTRL2, 0x04},
-       {SENSOR, PO1030_REG_OUTFORMCTRL2, 0x04},
-       {SENSOR, PO1030_REG_AUTOCTRL1, 0x08},
-       {SENSOR, PO1030_REG_CONTROL2, 0x03},
-       {SENSOR, 0x21, 0x90},
-       {SENSOR, PO1030_REG_YTARGET, 0x60},
-       {SENSOR, 0x59, 0x13},
-       {SENSOR, PO1030_REG_OUTFORMCTRL1, 0x40},
-       {SENSOR, 0x5f, 0x00},
-       {SENSOR, 0x60, 0x80},
-       {SENSOR, 0x78, 0x14},
-       {SENSOR, 0x6f, 0x01},
-       {SENSOR, PO1030_REG_CONTROL1, 0x18},
-       {SENSOR, PO1030_REG_GLOBALGAINMAX, 0x14},
-       {SENSOR, 0x63, 0x38},
-       {SENSOR, 0x64, 0x38},
-       {SENSOR, PO1030_REG_CONTROL1, 0x58},
-       {SENSOR, PO1030_REG_RED_GAIN, 0x30},
-       {SENSOR, PO1030_REG_GREEN_1_GAIN, 0x30},
-       {SENSOR, PO1030_REG_BLUE_GAIN, 0x30},
-       {SENSOR, PO1030_REG_GREEN_2_GAIN, 0x30},
-       {SENSOR, PO1030_REG_GC0, 0x10},
-       {SENSOR, PO1030_REG_GC1, 0x20},
-       {SENSOR, PO1030_REG_GC2, 0x40},
-       {SENSOR, PO1030_REG_GC3, 0x60},
-       {SENSOR, PO1030_REG_GC4, 0x80},
-       {SENSOR, PO1030_REG_GC5, 0xa0},
-       {SENSOR, PO1030_REG_GC6, 0xc0},
-       {SENSOR, PO1030_REG_GC7, 0xff},
-       /*end of sequence 4*/
-       /*sequence 5*/
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
-       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81},
-       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
-       {BRIDGE, M5602_XB_SIG_INI, 0x01},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x02},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0xec},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x7e},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00},
-       /*end of sequence 5*/
-
-       /*sequence 6*/
-       /* Changing 40 in f0 the image becomes green in bayer mode and red in
-        * rgb mode */
-       {SENSOR, PO1030_REG_RED_GAIN, PO1030_RED_GAIN_DEFAULT},
-       /* in changing 40 in f0 the image becomes green in bayer mode and red in
-        * rgb mode */
-       {SENSOR, PO1030_REG_BLUE_GAIN, PO1030_BLUE_GAIN_DEFAULT},
+       {SENSOR, PO1030_WINDOWY_H, 0x00},
+       {SENSOR, PO1030_WINDOWY_L, 0x01},
 
        /* with a very low lighted environment increase the exposure but
         * decrease the FPS (Frame Per Second) */
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
 
-       /* Controls high exposure more than SENSOR_LOW_EXPOSURE, use only in
-        * low lighted environment (f0 is more than ff ?)*/
-       {SENSOR, PO1030_REG_INTEGLINES_H, ((PO1030_EXPOSURE_DEFAULT >> 2)
-               & 0xff)},
-
-       /* Controls middle exposure, use only in high lighted environment */
-       {SENSOR, PO1030_REG_INTEGLINES_M, PO1030_EXPOSURE_DEFAULT & 0xff},
-
-       /* Controls clarity (not sure) */
-       {SENSOR, PO1030_REG_INTEGLINES_L, 0x00},
-       /* Controls gain (the image is more lighted) */
-       {SENSOR, PO1030_REG_GLOBALGAIN, PO1030_GLOBAL_GAIN_DEFAULT},
-
-       /* Sets the width */
-       {SENSOR, PO1030_REG_FRAMEWIDTH_H, 0x02},
-       {SENSOR, PO1030_REG_FRAMEWIDTH_L, 0xef}
-       /*end of sequence 6*/
+       {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
+       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
 };
 
 #endif
index 4306d596056db72a66587a8da4ad25a22b35d46a..191bcd7189798351e5a171767c86fd5e7b8686b1 100644 (file)
 
 #include "m5602_s5k4aa.h"
 
+static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
+
 static
     const
        struct dmi_system_id s5k4aa_vflip_dmi_table[] = {
@@ -46,6 +59,18 @@ static
                        DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700")
                }
+       }, {
+               .ident = "MSI L735",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X")
+               }
+       }, {
+               .ident = "Lenovo Y300",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "L3000 Y300"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Y300")
+               }
        },
        { }
 };
@@ -61,10 +86,22 @@ static struct v4l2_pix_format s5k4aa_modes[] = {
                .bytesperline = 640,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 0
+       },
+       {
+               1280,
+               1024,
+               V4L2_PIX_FMT_SBGGR8,
+               V4L2_FIELD_NONE,
+               .sizeimage =
+                       1280 * 1024,
+               .bytesperline = 1280,
+               .colorspace = V4L2_COLORSPACE_SRGB,
+               .priv = 0
        }
 };
 
-const static struct ctrl s5k4aa_ctrls[] = {
+static const struct ctrl s5k4aa_ctrls[] = {
+#define VFLIP_IDX 0
        {
                {
                        .id             = V4L2_CID_VFLIP,
@@ -77,8 +114,9 @@ const static struct ctrl s5k4aa_ctrls[] = {
                },
                .set = s5k4aa_set_vflip,
                .get = s5k4aa_get_vflip
-
-       }, {
+       },
+#define HFLIP_IDX 1
+       {
                {
                        .id             = V4L2_CID_HFLIP,
                        .type           = V4L2_CTRL_TYPE_BOOLEAN,
@@ -90,8 +128,9 @@ const static struct ctrl s5k4aa_ctrls[] = {
                },
                .set = s5k4aa_set_hflip,
                .get = s5k4aa_get_hflip
-
-       }, {
+       },
+#define GAIN_IDX 2
+       {
                {
                        .id             = V4L2_CID_GAIN,
                        .type           = V4L2_CTRL_TYPE_INTEGER,
@@ -99,12 +138,14 @@ const static struct ctrl s5k4aa_ctrls[] = {
                        .minimum        = 0,
                        .maximum        = 127,
                        .step           = 1,
-                       .default_value  = 0xa0,
+                       .default_value  = S5K4AA_DEFAULT_GAIN,
                        .flags          = V4L2_CTRL_FLAG_SLIDER
                },
                .set = s5k4aa_set_gain,
                .get = s5k4aa_get_gain
-       }, {
+       },
+#define EXPOSURE_IDX 3
+       {
                {
                        .id             = V4L2_CID_EXPOSURE,
                        .type           = V4L2_CTRL_TYPE_INTEGER,
@@ -117,7 +158,36 @@ const static struct ctrl s5k4aa_ctrls[] = {
                },
                .set = s5k4aa_set_exposure,
                .get = s5k4aa_get_exposure
-       }
+       },
+#define NOISE_SUPP_IDX 4
+       {
+               {
+                       .id             = V4L2_CID_PRIVATE_BASE,
+                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name           = "Noise suppression (smoothing)",
+                       .minimum        = 0,
+                       .maximum        = 1,
+                       .step           = 1,
+                       .default_value  = 1,
+               },
+                       .set = s5k4aa_set_noise,
+                       .get = s5k4aa_get_noise
+       },
+#define BRIGHTNESS_IDX 5
+       {
+               {
+                       .id             = V4L2_CID_BRIGHTNESS,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "Brightness",
+                       .minimum        = 0,
+                       .maximum        = 0x1f,
+                       .step           = 1,
+                       .default_value  = S5K4AA_DEFAULT_BRIGHTNESS,
+               },
+                       .set = s5k4aa_set_brightness,
+                       .get = s5k4aa_get_brightness
+       },
+
 };
 
 static void s5k4aa_dump_registers(struct sd *sd);
@@ -127,6 +197,7 @@ int s5k4aa_probe(struct sd *sd)
        u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
        const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
        int i, err = 0;
+       s32 *sensor_settings;
 
        if (force_sensor) {
                if (force_sensor == S5K4AA_SENSOR) {
@@ -185,10 +256,20 @@ int s5k4aa_probe(struct sd *sd)
                info("Detected a s5k4aa sensor");
 
 sensor_found:
+       sensor_settings = kmalloc(
+               ARRAY_SIZE(s5k4aa_ctrls) * sizeof(s32), GFP_KERNEL);
+       if (!sensor_settings)
+               return -ENOMEM;
+
        sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
        sd->desc->ctrls = s5k4aa_ctrls;
        sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls);
+
+       for (i = 0; i < ARRAY_SIZE(s5k4aa_ctrls); i++)
+               sensor_settings[i] = s5k4aa_ctrls[i].qctrl.default_value;
+       sd->sensor_priv = sensor_settings;
+
        return 0;
 }
 
@@ -197,9 +278,45 @@ int s5k4aa_start(struct sd *sd)
        int i, err = 0;
        u8 data[2];
        struct cam *cam = &sd->gspca_dev.cam;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
+       case 1280:
+               PDEBUG(D_V4L2, "Configuring camera for SXGA mode");
+
+               for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) {
+                       switch (SXGA_s5k4aa[i][0]) {
+                       case BRIDGE:
+                               err = m5602_write_bridge(sd,
+                                                SXGA_s5k4aa[i][1],
+                                                SXGA_s5k4aa[i][2]);
+                       break;
+
+                       case SENSOR:
+                               data[0] = SXGA_s5k4aa[i][2];
+                               err = m5602_write_sensor(sd,
+                                                SXGA_s5k4aa[i][1],
+                                                data, 1);
+                       break;
+
+                       case SENSOR_LONG:
+                               data[0] = SXGA_s5k4aa[i][2];
+                               data[1] = SXGA_s5k4aa[i][3];
+                               err = m5602_write_sensor(sd,
+                                                 SXGA_s5k4aa[i][1],
+                                                 data, 2);
+                       break;
+
+                       default:
+                               err("Invalid stream command, exiting init");
+                               return -EINVAL;
+                       }
+               }
+               err = s5k4aa_set_noise(&sd->gspca_dev, 0);
+               if (err < 0)
+                       return err;
+               break;
 
-       switch (cam->cam_mode[sd->gspca_dev.curr_mode].width)
-       {
        case 640:
                PDEBUG(D_V4L2, "Configuring camera for VGA mode");
 
@@ -231,8 +348,37 @@ int s5k4aa_start(struct sd *sd)
                                return -EINVAL;
                        }
                }
+               err = s5k4aa_set_noise(&sd->gspca_dev, 1);
+               if (err < 0)
+                       return err;
+               break;
        }
-       return err;
+       if (err < 0)
+               return err;
+
+       err = s5k4aa_set_exposure(&sd->gspca_dev,
+                                  sensor_settings[EXPOSURE_IDX]);
+       if (err < 0)
+               return err;
+
+       err = s5k4aa_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
+       if (err < 0)
+               return err;
+
+       err = s5k4aa_set_brightness(&sd->gspca_dev,
+                                    sensor_settings[BRIGHTNESS_IDX]);
+       if (err < 0)
+               return err;
+
+       err = s5k4aa_set_noise(&sd->gspca_dev, sensor_settings[NOISE_SUPP_IDX]);
+       if (err < 0)
+               return err;
+
+       err = s5k4aa_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
+       if (err < 0)
+               return err;
+
+       return s5k4aa_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
 }
 
 int s5k4aa_init(struct sd *sd)
@@ -270,62 +416,28 @@ int s5k4aa_init(struct sd *sd)
        if (dump_sensor)
                s5k4aa_dump_registers(sd);
 
-       if (!err && dmi_check_system(s5k4aa_vflip_dmi_table)) {
-               u8 data = 0x02;
-               info("vertical flip quirk active");
-               m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
-               m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
-               data |= S5K4AA_RM_V_FLIP;
-               data &= ~S5K4AA_RM_H_FLIP;
-               m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
-
-               /* Decrement COLSTART to preserve color order (BGGR) */
-               m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
-               data--;
-               m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
-
-               /* Increment ROWSTART to preserve color order (BGGR) */
-               m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
-               data++;
-               m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
-       }
-
-       return (err < 0) ? err : 0;
-}
-
-int s5k4aa_power_down(struct sd *sd)
-{
-       return 0;
+       return err;
 }
 
-int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       u8 data = S5K4AA_PAGE_MAP_2;
-       int err;
-
-       err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
-       if (err < 0)
-               return err;
+       s32 *sensor_settings = sd->sensor_priv;
 
-       err = m5602_read_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
-       if (err < 0)
-               return err;
-
-       *val = data << 8;
-       err = m5602_read_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
-       *val |= data;
+       *val = sensor_settings[EXPOSURE_IDX];
        PDEBUG(D_V4L2, "Read exposure %d", *val);
 
-       return err;
+       return 0;
 }
 
-int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 data = S5K4AA_PAGE_MAP_2;
        int err;
 
+       sensor_settings[EXPOSURE_IDX] = val;
        PDEBUG(D_V4L2, "Set exposure to %d", val);
        err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
@@ -340,29 +452,26 @@ int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
-int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       u8 data = S5K4AA_PAGE_MAP_2;
-       int err;
-
-       err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
-       if (err < 0)
-               return err;
+       s32 *sensor_settings = sd->sensor_priv;
 
-       err = m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
-       *val = (data & S5K4AA_RM_V_FLIP) >> 7;
+       *val = sensor_settings[VFLIP_IDX];
        PDEBUG(D_V4L2, "Read vertical flip %d", *val);
 
-       return err;
+       return 0;
 }
 
-int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 data = S5K4AA_PAGE_MAP_2;
        int err;
 
+       sensor_settings[VFLIP_IDX] = val;
+
        PDEBUG(D_V4L2, "Set vertical flip to %d", val);
        err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
@@ -370,56 +479,48 @@ int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
        err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
        if (err < 0)
                return err;
-       data = ((data & ~S5K4AA_RM_V_FLIP)
-                       | ((val & 0x01) << 7));
-       err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+
+       err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
        if (err < 0)
                return err;
 
-       if (val) {
-               err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
-               if (err < 0)
-                       return err;
-
-               data++;
-               err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
-       } else {
-               err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
-               if (err < 0)
-                       return err;
+       if (dmi_check_system(s5k4aa_vflip_dmi_table))
+               val = !val;
 
-               data--;
-               err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
-       }
+       data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7));
+       err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+       if (err < 0)
+               return err;
 
+       err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+       if (err < 0)
+               return err;
+       data = (data & 0xfe) | !val;
+       err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
        return err;
 }
 
-int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       u8 data = S5K4AA_PAGE_MAP_2;
-       int err;
-
-       err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
-       if (err < 0)
-               return err;
+       s32 *sensor_settings = sd->sensor_priv;
 
-       err = m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
-       *val = (data & S5K4AA_RM_H_FLIP) >> 6;
+       *val = sensor_settings[HFLIP_IDX];
        PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
 
-       return err;
+       return 0;
 }
 
-int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 data = S5K4AA_PAGE_MAP_2;
        int err;
 
-       PDEBUG(D_V4L2, "Set horizontal flip to %d",
-              val);
+       sensor_settings[HFLIP_IDX] = val;
+
+       PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
        err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
                return err;
@@ -427,62 +528,116 @@ int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
        if (err < 0)
                return err;
 
+       err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+       if (err < 0)
+               return err;
+
+       if (dmi_check_system(s5k4aa_vflip_dmi_table))
+               val = !val;
+
        data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
        err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
        if (err < 0)
                return err;
 
-       if (val) {
-               err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
-               if (err < 0)
-                       return err;
-               data++;
-               err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
-               if (err < 0)
-                       return err;
-       } else {
-               err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
-               if (err < 0)
-                       return err;
-               data--;
-               err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
-       }
-
+       err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+       if (err < 0)
+               return err;
+       data = (data & 0xfe) | !val;
+       err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
        return err;
 }
 
-int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[GAIN_IDX];
+       PDEBUG(D_V4L2, "Read gain %d", *val);
+       return 0;
+}
+
+static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 data = S5K4AA_PAGE_MAP_2;
        int err;
 
+       sensor_settings[GAIN_IDX] = val;
+
+       PDEBUG(D_V4L2, "Set gain to %d", val);
        err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
                return err;
 
-       err = m5602_read_sensor(sd, S5K4AA_GAIN_2, &data, 1);
-       *val = data;
-       PDEBUG(D_V4L2, "Read gain %d", *val);
+       data = val & 0xff;
+       err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1);
 
        return err;
 }
 
-int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[BRIGHTNESS_IDX];
+       PDEBUG(D_V4L2, "Read brightness %d", *val);
+       return 0;
+}
+
+static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
        u8 data = S5K4AA_PAGE_MAP_2;
        int err;
 
-       PDEBUG(D_V4L2, "Set gain to %d", val);
+       sensor_settings[BRIGHTNESS_IDX] = val;
+
+       PDEBUG(D_V4L2, "Set brightness to %d", val);
        err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
                return err;
 
        data = val & 0xff;
-       err = m5602_write_sensor(sd, S5K4AA_GAIN_2, &data, 1);
+       return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
+}
 
-       return err;
+static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[NOISE_SUPP_IDX];
+       PDEBUG(D_V4L2, "Read noise %d", *val);
+       return 0;
+}
+
+static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+       u8 data = S5K4AA_PAGE_MAP_2;
+       int err;
+
+       sensor_settings[NOISE_SUPP_IDX] = val;
+
+       PDEBUG(D_V4L2, "Set noise to %d", val);
+       err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+       if (err < 0)
+               return err;
+
+       data = val & 0x01;
+       return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
+}
+
+void s5k4aa_disconnect(struct sd *sd)
+{
+       sd->sensor = NULL;
+       kfree(sd->sensor_priv);
 }
 
 static void s5k4aa_dump_registers(struct sd *sd)
index ca854d4f9475e94ddce7ea164870133632db8792..4440da4e7f0ff3595fde22eabf7b3e4add002fd9 100644 (file)
@@ -47,8 +47,9 @@
 #define S5K4AA_H_BLANK_LO__            0x1e
 #define S5K4AA_EXPOSURE_HI             0x17
 #define S5K4AA_EXPOSURE_LO             0x18
-#define S5K4AA_GAIN_1                  0x1f /* (digital?) gain : 5 bits */
-#define S5K4AA_GAIN_2                  0x20 /* (analogue?) gain : 7 bits */
+#define S5K4AA_BRIGHTNESS              0x1f /* (digital?) gain : 5 bits */
+#define S5K4AA_GAIN                    0x20 /* (analogue?) gain : 7 bits */
+#define S5K4AA_NOISE_SUPP              0x37
 
 #define S5K4AA_RM_ROW_SKIP_4X          0x08
 #define S5K4AA_RM_ROW_SKIP_2X          0x04
@@ -57,6 +58,9 @@
 #define S5K4AA_RM_H_FLIP               0x40
 #define S5K4AA_RM_V_FLIP               0x80
 
+#define S5K4AA_DEFAULT_GAIN            0x5f
+#define S5K4AA_DEFAULT_BRIGHTNESS      0x10
+
 /*****************************************************************************/
 
 /* Kernel module parameters */
@@ -66,25 +70,17 @@ extern int dump_sensor;
 int s5k4aa_probe(struct sd *sd);
 int s5k4aa_init(struct sd *sd);
 int s5k4aa_start(struct sd *sd);
-int s5k4aa_power_down(struct sd *sd);
-
-int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
-int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+void s5k4aa_disconnect(struct sd *sd);
 
 static const struct m5602_sensor s5k4aa = {
        .name = "S5K4AA",
+       .i2c_slave_id = 0x5a,
+       .i2c_regW = 2,
+
        .probe = s5k4aa_probe,
        .init = s5k4aa_init,
        .start = s5k4aa_start,
-       .power_down = s5k4aa_power_down,
-       .i2c_slave_id = 0x5a,
-       .i2c_regW = 2,
+       .disconnect = s5k4aa_disconnect,
 };
 
 static const unsigned char preinit_s5k4aa[][4] =
@@ -179,30 +175,12 @@ static const unsigned char init_s5k4aa[][4] =
        {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
        {SENSOR, 0x0c, 0x05, 0x00},
        {SENSOR, 0x02, 0x0e, 0x00},
-       {SENSOR, S5K4AA_GAIN_1, 0x0f, 0x00},
-       {SENSOR, S5K4AA_GAIN_2, 0x00, 0x00},
-       {SENSOR, S5K4AA_GLOBAL_GAIN__, 0x01, 0x00},
-       {SENSOR, 0x11, 0x00, 0x00},
-       {SENSOR, 0x12, 0x00, 0x00},
-       {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
        {SENSOR, S5K4AA_READ_MODE, 0xa0, 0x00},
        {SENSOR, 0x37, 0x00, 0x00},
-       {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00},
-       {SENSOR, S5K4AA_ROWSTART_LO, 0x2a, 0x00},
-       {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00},
-       {SENSOR, S5K4AA_COLSTART_LO, 0x0b, 0x00},
-       {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x03, 0x00},
-       {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0xc4, 0x00},
-       {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00},
-       {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x08, 0x00},
-       {SENSOR, S5K4AA_H_BLANK_HI__, 0x00, 0x00},
-       {SENSOR, S5K4AA_H_BLANK_LO__, 0x48, 0x00},
-       {SENSOR, S5K4AA_EXPOSURE_HI, 0x00, 0x00},
-       {SENSOR, S5K4AA_EXPOSURE_LO, 0x43, 0x00},
-       {SENSOR, 0x11, 0x04, 0x00},
-       {SENSOR, 0x12, 0xc3, 0x00},
-       {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
+};
 
+static const unsigned char VGA_s5k4aa[][4] =
+{
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
        {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
@@ -238,7 +216,7 @@ static const unsigned char init_s5k4aa[][4] =
        {SENSOR, 0x37, 0x01, 0x00},
        /* ROWSTART_HI, ROWSTART_LO : 10 + (1024-960)/2 = 42 = 0x002a */
        {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00},
-       {SENSOR, S5K4AA_ROWSTART_LO, 0x2a, 0x00},
+       {SENSOR, S5K4AA_ROWSTART_LO, 0x29, 0x00},
        {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00},
        {SENSOR, S5K4AA_COLSTART_LO, 0x0c, 0x00},
        /* window_height_hi, window_height_lo : 960 = 0x03c0 */
@@ -255,12 +233,9 @@ static const unsigned char init_s5k4aa[][4] =
        {SENSOR, 0x12, 0xc3, 0x00},
        {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
        {SENSOR, 0x02, 0x0e, 0x00},
-       {SENSOR_LONG, S5K4AA_GLOBAL_GAIN__, 0x0f, 0x00},
-       {SENSOR, S5K4AA_GAIN_1, 0x0b, 0x00},
-       {SENSOR, S5K4AA_GAIN_2, 0xa0, 0x00}
 };
 
-static const unsigned char VGA_s5k4aa[][4] =
+static const unsigned char SXGA_s5k4aa[][4] =
 {
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
@@ -273,50 +248,42 @@ static const unsigned char VGA_s5k4aa[][4] =
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       /* VSYNC_PARA, VSYNC_PARA : img height 480 = 0x01e0 */
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0, 0x00},
+       /* VSYNC_PARA, VSYNC_PARA : img height 1024 = 0x0400 */
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
        {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
        {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       /* HSYNC_PARA, HSYNC_PARA : img width 640 = 0x0280 */
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x80, 0x00},
+       /* HSYNC_PARA, HSYNC_PARA : img width 1280 = 0x0500 */
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, /* 48 MHz */
 
        {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
-       {SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP | S5K4AA_RM_ROW_SKIP_2X
-               | S5K4AA_RM_COL_SKIP_2X, 0x00},
-       /* 0x37 : Fix image stability when light is too bright and improves
-        * image quality in 640x480, but worsens it in 1280x1024 */
+       {SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP, 0x00},
        {SENSOR, 0x37, 0x01, 0x00},
-       /* ROWSTART_HI, ROWSTART_LO : 10 + (1024-960)/2 = 42 = 0x002a */
        {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00},
-       {SENSOR, S5K4AA_ROWSTART_LO, 0x2a, 0x00},
+       {SENSOR, S5K4AA_ROWSTART_LO, 0x09, 0x00},
        {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00},
-       {SENSOR, S5K4AA_COLSTART_LO, 0x0c, 0x00},
-       /* window_height_hi, window_height_lo : 960 = 0x03c0 */
-       {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x03, 0x00},
-       {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0xc0, 0x00},
-       /* window_width_hi, window_width_lo : 1280 = 0x0500 */
+       {SENSOR, S5K4AA_COLSTART_LO, 0x0a, 0x00},
+       {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x04, 0x00},
+       {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0x00, 0x00},
        {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00},
        {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x00, 0x00},
-       {SENSOR, S5K4AA_H_BLANK_HI__, 0x00, 0x00},
-       {SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00}, /* helps to sync... */
+       {SENSOR, S5K4AA_H_BLANK_HI__, 0x01, 0x00},
+       {SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00},
        {SENSOR, S5K4AA_EXPOSURE_HI, 0x01, 0x00},
        {SENSOR, S5K4AA_EXPOSURE_LO, 0x00, 0x00},
        {SENSOR, 0x11, 0x04, 0x00},
        {SENSOR, 0x12, 0xc3, 0x00},
        {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
        {SENSOR, 0x02, 0x0e, 0x00},
-       {SENSOR_LONG, S5K4AA_GLOBAL_GAIN__, 0x0f, 0x00},
-       {SENSOR, S5K4AA_GAIN_1, 0x0b, 0x00},
-       {SENSOR, S5K4AA_GAIN_2, 0xa0, 0x00}
 };
 
+
 #endif
index 42c86aa4dc8d073ca9931a6b256101f0dbcc85c8..7127321ace8cbe35e893dd40025bbb901e60ee51 100644 (file)
  *
  */
 
+#include <linux/kthread.h>
 #include "m5602_s5k83a.h"
 
+static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+
 static struct v4l2_pix_format s5k83a_modes[] = {
        {
                640,
@@ -32,68 +44,77 @@ static struct v4l2_pix_format s5k83a_modes[] = {
        }
 };
 
-const static struct ctrl s5k83a_ctrls[] = {
+static const struct ctrl s5k83a_ctrls[] = {
+#define GAIN_IDX 0
        {
                {
-                       .id = V4L2_CID_BRIGHTNESS,
+                       .id = V4L2_CID_GAIN,
                        .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "brightness",
+                       .name = "gain",
                        .minimum = 0x00,
                        .maximum = 0xff,
                        .step = 0x01,
-                       .default_value = S5K83A_DEFAULT_BRIGHTNESS,
+                       .default_value = S5K83A_DEFAULT_GAIN,
                        .flags = V4L2_CTRL_FLAG_SLIDER
                },
-                       .set = s5k83a_set_brightness,
-                       .get = s5k83a_get_brightness
+                       .set = s5k83a_set_gain,
+                       .get = s5k83a_get_gain
 
-       }, {
+       },
+#define BRIGHTNESS_IDX 1
+       {
                {
-                       .id = V4L2_CID_WHITENESS,
+                       .id = V4L2_CID_BRIGHTNESS,
                        .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "whiteness",
+                       .name = "brightness",
                        .minimum = 0x00,
                        .maximum = 0xff,
                        .step = 0x01,
-                       .default_value = S5K83A_DEFAULT_WHITENESS,
+                       .default_value = S5K83A_DEFAULT_BRIGHTNESS,
                        .flags = V4L2_CTRL_FLAG_SLIDER
                },
-                       .set = s5k83a_set_whiteness,
-                       .get = s5k83a_get_whiteness,
-       }, {
+                       .set = s5k83a_set_brightness,
+                       .get = s5k83a_get_brightness,
+       },
+#define EXPOSURE_IDX 2
+       {
                {
-                       .id = V4L2_CID_GAIN,
+                       .id = V4L2_CID_EXPOSURE,
                        .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "gain",
+                       .name = "exposure",
                        .minimum = 0x00,
-                       .maximum = S5K83A_MAXIMUM_GAIN,
+                       .maximum = S5K83A_MAXIMUM_EXPOSURE,
                        .step = 0x01,
-                       .default_value = S5K83A_DEFAULT_GAIN,
+                       .default_value = S5K83A_DEFAULT_EXPOSURE,
                        .flags = V4L2_CTRL_FLAG_SLIDER
                },
-                       .set = s5k83a_set_gain,
-                       .get = s5k83a_get_gain
-       }, {
+                       .set = s5k83a_set_exposure,
+                       .get = s5k83a_get_exposure
+       },
+#define HFLIP_IDX 3
+       {
                {
-                       .id         = V4L2_CID_HFLIP,
-                       .type       = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name       = "horizontal flip",
-                       .minimum    = 0,
-                       .maximum    = 1,
-                       .step       = 1,
-                       .default_value  = 0
+                       .id = V4L2_CID_HFLIP,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "horizontal flip",
+                       .minimum = 0,
+                       .maximum = 1,
+                       .step = 1,
+                       .default_value = 0
                },
                        .set = s5k83a_set_hflip,
                        .get = s5k83a_get_hflip
-       }, {
+       },
+#define VFLIP_IDX 4
+       {
                {
-                .id         = V4L2_CID_VFLIP,
-               .type       = V4L2_CTRL_TYPE_BOOLEAN,
-               .name       = "vertical flip",
-               .minimum    = 0,
-               .maximum    = 1,
-               .step       = 1,
-               .default_value  = 0
+                       .id = V4L2_CID_VFLIP,
+                       .type = V4L2_CTRL_TYPE_BOOLEAN,
+                       .name = "vertical flip",
+                       .minimum = 0,
+                       .maximum = 1,
+                       .step = 1,
+                       .default_value = 0
                },
                .set = s5k83a_set_vflip,
                .get = s5k83a_get_vflip
@@ -101,9 +122,14 @@ const static struct ctrl s5k83a_ctrls[] = {
 };
 
 static void s5k83a_dump_registers(struct sd *sd);
+static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data);
+static int s5k83a_set_led_indication(struct sd *sd, u8 val);
+static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
+                               __s32 vflip, __s32 hflip);
 
 int s5k83a_probe(struct sd *sd)
 {
+       struct s5k83a_priv *sens_priv;
        u8 prod_id = 0, ver_id = 0;
        int i, err = 0;
 
@@ -145,16 +171,36 @@ int s5k83a_probe(struct sd *sd)
                info("Detected a s5k83a sensor");
 
 sensor_found:
+       sens_priv = kmalloc(
+               sizeof(struct s5k83a_priv), GFP_KERNEL);
+       if (!sens_priv)
+               return -ENOMEM;
+
+       sens_priv->settings =
+       kmalloc(sizeof(s32)*ARRAY_SIZE(s5k83a_ctrls), GFP_KERNEL);
+       if (!sens_priv->settings)
+               return -ENOMEM;
+
        sd->gspca_dev.cam.cam_mode = s5k83a_modes;
        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes);
        sd->desc->ctrls = s5k83a_ctrls;
        sd->desc->nctrls = ARRAY_SIZE(s5k83a_ctrls);
+
+       /* null the pointer! thread is't running now */
+       sens_priv->rotation_thread = NULL;
+
+       for (i = 0; i < ARRAY_SIZE(s5k83a_ctrls); i++)
+               sens_priv->settings[i] = s5k83a_ctrls[i].qctrl.default_value;
+
+       sd->sensor_priv = sens_priv;
        return 0;
 }
 
 int s5k83a_init(struct sd *sd)
 {
        int i, err = 0;
+       s32 *sensor_settings =
+                       ((struct s5k83a_priv *) sd->sensor_priv)->settings;
 
        for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) {
                u8 data[2] = {0x00, 0x00};
@@ -187,87 +233,138 @@ int s5k83a_init(struct sd *sd)
        if (dump_sensor)
                s5k83a_dump_registers(sd);
 
-       return (err < 0) ? err : 0;
-}
+       err = s5k83a_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
+       if (err < 0)
+               return err;
 
-int s5k83a_start(struct sd *sd)
-{
-       return s5k83a_set_led_indication(sd, 1);
-}
+       err = s5k83a_set_brightness(&sd->gspca_dev,
+                                    sensor_settings[BRIGHTNESS_IDX]);
+       if (err < 0)
+               return err;
 
-int s5k83a_stop(struct sd *sd)
-{
-       return s5k83a_set_led_indication(sd, 0);
+       err = s5k83a_set_exposure(&sd->gspca_dev,
+                                  sensor_settings[EXPOSURE_IDX]);
+       if (err < 0)
+               return err;
+
+       err = s5k83a_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
+       if (err < 0)
+               return err;
+
+       err = s5k83a_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
+
+       return err;
 }
 
-int s5k83a_power_down(struct sd *sd)
+static int rotation_thread_function(void *data)
 {
+       struct sd *sd = (struct sd *) data;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
+       u8 reg, previous_rotation = 0;
+       __s32 vflip, hflip;
+
+       set_current_state(TASK_INTERRUPTIBLE);
+       while (!schedule_timeout(100)) {
+               if (mutex_lock_interruptible(&sd->gspca_dev.usb_lock))
+                       break;
+
+               s5k83a_get_rotation(sd, &reg);
+               if (previous_rotation != reg) {
+                       previous_rotation = reg;
+                       info("Camera was flipped");
+
+                       s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
+                       s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
+
+                       if (reg) {
+                               vflip = !vflip;
+                               hflip = !hflip;
+                       }
+                       s5k83a_set_flip_real((struct gspca_dev *) sd,
+                                             vflip, hflip);
+               }
+
+               mutex_unlock(&sd->gspca_dev.usb_lock);
+               set_current_state(TASK_INTERRUPTIBLE);
+       }
+
+       /* return to "front" flip */
+       if (previous_rotation) {
+               s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
+               s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
+               s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip);
+       }
+
+       sens_priv->rotation_thread = NULL;
        return 0;
 }
 
-static void s5k83a_dump_registers(struct sd *sd)
+int s5k83a_start(struct sd *sd)
 {
-       int address;
-       u8 page, old_page;
-       m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
+       int i, err = 0;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
 
-       for (page = 0; page < 16; page++) {
-               m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
-               info("Dumping the s5k83a register state for page 0x%x", page);
-               for (address = 0; address <= 0xff; address++) {
-                       u8 val = 0;
-                       m5602_read_sensor(sd, address, &val, 1);
-                       info("register 0x%x contains 0x%x",
-                            address, val);
-               }
+       /* Create another thread, polling the GPIO ports of the camera to check
+          if it got rotated. This is how the windows driver does it so we have
+          to assume that there is no better way of accomplishing this */
+       sens_priv->rotation_thread = kthread_create(rotation_thread_function,
+                                                   sd, "rotation thread");
+       wake_up_process(sens_priv->rotation_thread);
+
+       /* Preinit the sensor */
+       for (i = 0; i < ARRAY_SIZE(start_s5k83a) && !err; i++) {
+               u8 data[2] = {start_s5k83a[i][2], start_s5k83a[i][3]};
+               if (start_s5k83a[i][0] == SENSOR)
+                       err = m5602_write_sensor(sd, start_s5k83a[i][1],
+                               data, 2);
+               else
+                       err = m5602_write_bridge(sd, start_s5k83a[i][1],
+                               data[0]);
        }
-       info("s5k83a register state dump complete");
+       if (err < 0)
+               return err;
 
-       for (page = 0; page < 16; page++) {
-               m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
-               info("Probing for which registers that are read/write "
-                     "for page 0x%x", page);
-               for (address = 0; address <= 0xff; address++) {
-                       u8 old_val, ctrl_val, test_val = 0xff;
+       return s5k83a_set_led_indication(sd, 1);
+}
 
-                       m5602_read_sensor(sd, address, &old_val, 1);
-                       m5602_write_sensor(sd, address, &test_val, 1);
-                       m5602_read_sensor(sd, address, &ctrl_val, 1);
+int s5k83a_stop(struct sd *sd)
+{
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
 
-                       if (ctrl_val == test_val)
-                               info("register 0x%x is writeable", address);
-                       else
-                               info("register 0x%x is read only", address);
+       if (sens_priv->rotation_thread)
+               kthread_stop(sens_priv->rotation_thread);
 
-                       /* Restore original val */
-                       m5602_write_sensor(sd, address, &old_val, 1);
-               }
-       }
-       info("Read/write register probing complete");
-       m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
+       return s5k83a_set_led_indication(sd, 0);
 }
 
-int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
+void s5k83a_disconnect(struct sd *sd)
 {
-       int err;
-       u8 data[2];
-       struct sd *sd = (struct sd *) gspca_dev;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
 
-       err = m5602_read_sensor(sd, S5K83A_BRIGHTNESS, data, 2);
-       if (err < 0)
-               return err;
+       s5k83a_stop(sd);
+
+       sd->sensor = NULL;
+       kfree(sens_priv->settings);
+       kfree(sens_priv);
+}
 
-       data[1] = data[1] << 1;
-       *val = data[1];
+static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
 
-       return err;
+       *val = sens_priv->settings[GAIN_IDX];
+       return 0;
 }
 
-int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 data[2];
        struct sd *sd = (struct sd *) gspca_dev;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
+
+       sens_priv->settings[GAIN_IDX] = val;
 
        data[0] = 0x00;
        data[1] = 0x20;
@@ -283,89 +380,69 @@ int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
 
        /* FIXME: This is not sane, we need to figure out the composition
                  of these registers */
-       data[0] = val >> 3; /* brightness, high 5 bits */
-       data[1] = val >> 1; /* brightness, high 7 bits */
-       err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 2);
+       data[0] = val >> 3; /* gain, high 5 bits */
+       data[1] = val >> 1; /* gain, high 7 bits */
+       err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2);
 
        return err;
 }
 
-int s5k83a_get_whiteness(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
 {
-       int err;
-       u8 data;
        struct sd *sd = (struct sd *) gspca_dev;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
 
-       err = m5602_read_sensor(sd, S5K83A_WHITENESS, &data, 1);
-       if (err < 0)
-               return err;
-
-       *val = data;
-
-       return err;
+       *val = sens_priv->settings[BRIGHTNESS_IDX];
+       return 0;
 }
 
-int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 data[1];
        struct sd *sd = (struct sd *) gspca_dev;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
 
+       sens_priv->settings[BRIGHTNESS_IDX] = val;
        data[0] = val;
-       err = m5602_write_sensor(sd, S5K83A_WHITENESS, data, 1);
-
+       err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1);
        return err;
 }
 
-int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
 {
-       int err;
-       u8 data[2];
        struct sd *sd = (struct sd *) gspca_dev;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
 
-       err = m5602_read_sensor(sd, S5K83A_GAIN, data, 2);
-       if (err < 0)
-               return err;
-
-       data[1] = data[1] & 0x3f;
-       if (data[1] > S5K83A_MAXIMUM_GAIN)
-               data[1] = S5K83A_MAXIMUM_GAIN;
-
-       *val = data[1];
-
-       return err;
+       *val = sens_priv->settings[EXPOSURE_IDX];
+       return 0;
 }
 
-int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 data[2];
        struct sd *sd = (struct sd *) gspca_dev;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
 
+       sens_priv->settings[EXPOSURE_IDX] = val;
        data[0] = 0;
        data[1] = val;
-       err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2);
+       err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2);
        return err;
 }
 
-int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
 {
-       int err;
-       u8 data[1];
        struct sd *sd = (struct sd *) gspca_dev;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
 
-       data[0] = 0x05;
-       err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
-       if (err < 0)
-               return err;
-
-       err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
-       *val = (data[0] | 0x40) ? 1 : 0;
-
-       return err;
+       *val = sens_priv->settings[VFLIP_IDX];
+       return 0;
 }
 
-int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
+                               __s32 vflip, __s32 hflip)
 {
        int err;
        u8 data[1];
@@ -376,69 +453,83 @@ int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
        if (err < 0)
                return err;
 
-       err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
-       if (err < 0)
-               return err;
+       /* six bit is vflip, seven is hflip */
+       data[0] = S5K83A_FLIP_MASK;
+       data[0] = (vflip) ? data[0] | 0x40 : data[0];
+       data[0] = (hflip) ? data[0] | 0x80 : data[0];
 
-       /* set or zero six bit, seven is hflip */
-       data[0] = (val) ? (data[0] & 0x80) | 0x40 | S5K83A_FLIP_MASK
-                       : (data[0] & 0x80) | S5K83A_FLIP_MASK;
        err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
        if (err < 0)
                return err;
 
-       data[0] = (val) ? 0x0b : 0x0a;
+       data[0] = (vflip) ? 0x0b : 0x0a;
        err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1);
+       if (err < 0)
+               return err;
 
+       data[0] = (hflip) ? 0x0a : 0x0b;
+       err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
        return err;
 }
 
-int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
-       u8 data[1];
+       u8 reg;
+       __s32 hflip;
        struct sd *sd = (struct sd *) gspca_dev;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
 
-       data[0] = 0x05;
-       err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
+       sens_priv->settings[VFLIP_IDX] = val;
+
+       s5k83a_get_hflip(gspca_dev, &hflip);
+
+       err = s5k83a_get_rotation(sd, &reg);
        if (err < 0)
                return err;
+       if (reg) {
+               val = !val;
+               hflip = !hflip;
+       }
 
-       err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
-       *val = (data[0] | 0x80) ? 1 : 0;
-
+       err = s5k83a_set_flip_real(gspca_dev, val, hflip);
        return err;
 }
 
-int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
+
+       *val = sens_priv->settings[HFLIP_IDX];
+       return 0;
+}
+
+static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
-       u8 data[1];
+       u8 reg;
+       __s32 vflip;
        struct sd *sd = (struct sd *) gspca_dev;
+       struct s5k83a_priv *sens_priv = sd->sensor_priv;
 
-       data[0] = 0x05;
-       err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
-       if (err < 0)
-               return err;
+       sens_priv->settings[HFLIP_IDX] = val;
 
-       err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
-       if (err < 0)
-               return err;
+       s5k83a_get_vflip(gspca_dev, &vflip);
 
-       /* set or zero seven bit, six is vflip */
-       data[0] = (val) ? (data[0] & 0x40) | 0x80 | S5K83A_FLIP_MASK
-                       : (data[0] & 0x40) | S5K83A_FLIP_MASK;
-       err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
+       err = s5k83a_get_rotation(sd, &reg);
        if (err < 0)
                return err;
+       if (reg) {
+               val = !val;
+               vflip = !vflip;
+       }
 
-       data[0] = (val) ? 0x0a : 0x0b;
-       err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
-
+       err = s5k83a_set_flip_real(gspca_dev, vflip, val);
        return err;
 }
 
-int s5k83a_set_led_indication(struct sd *sd, u8 val)
+static int s5k83a_set_led_indication(struct sd *sd, u8 val)
 {
        int err = 0;
        u8 data[1];
@@ -454,5 +545,55 @@ int s5k83a_set_led_indication(struct sd *sd, u8 val)
 
        err = m5602_write_bridge(sd, M5602_XB_GPIO_DAT, data[0]);
 
-       return (err < 0) ? err : 0;
+       return err;
+}
+
+/* Get camera rotation on Acer notebooks */
+static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data)
+{
+       int err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, reg_data);
+       *reg_data = (*reg_data & S5K83A_GPIO_ROTATION_MASK) ? 0 : 1;
+       return err;
+}
+
+static void s5k83a_dump_registers(struct sd *sd)
+{
+       int address;
+       u8 page, old_page;
+       m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
+
+       for (page = 0; page < 16; page++) {
+               m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
+               info("Dumping the s5k83a register state for page 0x%x", page);
+               for (address = 0; address <= 0xff; address++) {
+                       u8 val = 0;
+                       m5602_read_sensor(sd, address, &val, 1);
+                       info("register 0x%x contains 0x%x",
+                            address, val);
+               }
+       }
+       info("s5k83a register state dump complete");
+
+       for (page = 0; page < 16; page++) {
+               m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
+               info("Probing for which registers that are read/write "
+                               "for page 0x%x", page);
+               for (address = 0; address <= 0xff; address++) {
+                       u8 old_val, ctrl_val, test_val = 0xff;
+
+                       m5602_read_sensor(sd, address, &old_val, 1);
+                       m5602_write_sensor(sd, address, &test_val, 1);
+                       m5602_read_sensor(sd, address, &ctrl_val, 1);
+
+                       if (ctrl_val == test_val)
+                               info("register 0x%x is writeable", address);
+                       else
+                               info("register 0x%x is read only", address);
+
+                       /* Restore original val */
+                       m5602_write_sensor(sd, address, &old_val, 1);
+               }
+       }
+       info("Read/write register probing complete");
+       m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
 }
index 819ab25272bee72c9319e19663ee1c657584313b..7814b078acde3ca4cdd0aba521102000866dcc66 100644 (file)
 
 #include "m5602_sensor.h"
 
-#define S5K83A_FLIP                            0x01
-#define S5K83A_HFLIP_TUNE                      0x03
-#define S5K83A_VFLIP_TUNE                      0x05
-#define S5K83A_WHITENESS                       0x0a
-#define S5K83A_GAIN                            0x18
-#define S5K83A_BRIGHTNESS                      0x1b
-#define S5K83A_PAGE_MAP                                0xec
-
-#define S5K83A_DEFAULT_BRIGHTNESS              0x71
-#define S5K83A_DEFAULT_WHITENESS               0x7e
-#define S5K83A_DEFAULT_GAIN                    0x00
-#define S5K83A_MAXIMUM_GAIN                    0x3c
-#define S5K83A_FLIP_MASK                       0x10
+#define S5K83A_FLIP                    0x01
+#define S5K83A_HFLIP_TUNE              0x03
+#define S5K83A_VFLIP_TUNE              0x05
+#define S5K83A_BRIGHTNESS              0x0a
+#define S5K83A_EXPOSURE                        0x18
+#define S5K83A_GAIN                    0x1b
+#define S5K83A_PAGE_MAP                        0xec
+
+#define S5K83A_DEFAULT_GAIN            0x71
+#define S5K83A_DEFAULT_BRIGHTNESS      0x7e
+#define S5K83A_DEFAULT_EXPOSURE                0x00
+#define S5K83A_MAXIMUM_EXPOSURE                0x3c
+#define S5K83A_FLIP_MASK               0x10
 #define S5K83A_GPIO_LED_MASK           0x10
+#define S5K83A_GPIO_ROTATION_MASK      0x40
 
 /*****************************************************************************/
 
@@ -46,20 +47,7 @@ int s5k83a_probe(struct sd *sd);
 int s5k83a_init(struct sd *sd);
 int s5k83a_start(struct sd *sd);
 int s5k83a_stop(struct sd *sd);
-int s5k83a_power_down(struct sd *sd);
-
-int s5k83a_set_led_indication(struct sd *sd, u8 val);
-
-int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
-int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
-int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val);
-int s5k83a_get_whiteness(struct gspca_dev *gspca_dev, __s32 *val);
-int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+void s5k83a_disconnect(struct sd *sd);
 
 static const struct m5602_sensor s5k83a = {
        .name = "S5K83A",
@@ -67,11 +55,18 @@ static const struct m5602_sensor s5k83a = {
        .init = s5k83a_init,
        .start = s5k83a_start,
        .stop = s5k83a_stop,
-       .power_down = s5k83a_power_down,
+       .disconnect = s5k83a_disconnect,
        .i2c_slave_id = 0x5a,
        .i2c_regW = 2,
 };
 
+struct s5k83a_priv {
+       /* We use another thread periodically
+          probing the orientation of the camera */
+       struct task_struct *rotation_thread;
+       s32 *settings;
+};
+
 static const unsigned char preinit_s5k83a[][4] =
 {
        {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
@@ -108,8 +103,6 @@ static const unsigned char preinit_s5k83a[][4] =
        {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
        {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
        {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
-
-       {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00}
 };
 
 /* This could probably be considerably shortened.
@@ -117,86 +110,8 @@ static const unsigned char preinit_s5k83a[][4] =
 */
 static const unsigned char init_s5k83a[][4] =
 {
-       {SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00},
-       {SENSOR, 0xaf, 0x01, 0x00},
-       {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, 0x7b, 0xff, 0x00},
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
-       {SENSOR, 0x01, 0x50, 0x00},
-       {SENSOR, 0x12, 0x20, 0x00},
-       {SENSOR, 0x17, 0x40, 0x00},
-       {SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00},
-       {SENSOR, 0x1c, 0x00, 0x00},
-       {SENSOR, 0x02, 0x70, 0x00},
-       {SENSOR, 0x03, 0x0b, 0x00},
-       {SENSOR, 0x04, 0xf0, 0x00},
-       {SENSOR, 0x05, 0x0b, 0x00},
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
-
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
-       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x87, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
-       {SENSOR, 0x06, 0x71, 0x00},
-       {SENSOR, 0x07, 0xe8, 0x00},
-       {SENSOR, 0x08, 0x02, 0x00},
-       {SENSOR, 0x09, 0x88, 0x00},
-       {SENSOR, 0x14, 0x00, 0x00},
-       {SENSOR, 0x15, 0x20, 0x00},
-       {SENSOR, 0x19, 0x00, 0x00},
-       {SENSOR, 0x1a, 0x98, 0x00},
-       {SENSOR, 0x0f, 0x02, 0x00},
-       {SENSOR, 0x10, 0xe5, 0x00},
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
-       {SENSOR_LONG, 0x14, 0x00, 0x20},
-       {SENSOR_LONG, 0x0d, 0x00, 0x7d},
-       {SENSOR_LONG, 0x1b, 0x0d, 0x05},
-
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
-       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x87, 0x00},
-
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+       /* The following sequence is useless after a clean boot
+          but is necessary after resume from suspend */
        {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
        {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
        {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
@@ -216,7 +131,7 @@ static const unsigned char init_s5k83a[][4] =
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
        {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
+       {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
        {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
        {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
        {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
@@ -225,109 +140,34 @@ static const unsigned char init_s5k83a[][4] =
 
        {SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00},
        {SENSOR, 0xaf, 0x01, 0x00},
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
-       /* ff ( init value )is very dark) || 71 and f0 better */
+       {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00},
        {SENSOR, 0x7b, 0xff, 0x00},
        {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
        {SENSOR, 0x01, 0x50, 0x00},
        {SENSOR, 0x12, 0x20, 0x00},
        {SENSOR, 0x17, 0x40, 0x00},
-       {SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00},
        {SENSOR, 0x1c, 0x00, 0x00},
        {SENSOR, 0x02, 0x70, 0x00},
-       /* some values like 0x10 give a blue-purple image */
        {SENSOR, 0x03, 0x0b, 0x00},
        {SENSOR, 0x04, 0xf0, 0x00},
        {SENSOR, 0x05, 0x0b, 0x00},
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
-
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
-       /* under 80 don't work, highter depend on value */
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
-       {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00},
-
-       {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
        {SENSOR, 0x06, 0x71, 0x00},
-       {SENSOR, 0x07, 0xe8, 0x00},
+       {SENSOR, 0x07, 0xe8, 0x00}, /* 488 */
        {SENSOR, 0x08, 0x02, 0x00},
-       {SENSOR, 0x09, 0x88, 0x00},
+       {SENSOR, 0x09, 0x88, 0x00}, /* 648 */
        {SENSOR, 0x14, 0x00, 0x00},
-       {SENSOR, 0x15, 0x20, 0x00},
+       {SENSOR, 0x15, 0x20, 0x00}, /* 32 */
        {SENSOR, 0x19, 0x00, 0x00},
-       {SENSOR, 0x1a, 0x98, 0x00},
+       {SENSOR, 0x1a, 0x98, 0x00}, /* 152 */
        {SENSOR, 0x0f, 0x02, 0x00},
-       {SENSOR, 0x10, 0xe5, 0x00},
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
-       {SENSOR_LONG, 0x14, 0x00, 0x20},
-       {SENSOR_LONG, 0x0d, 0x00, 0x7d},
-       {SENSOR_LONG, 0x1b, 0x0d, 0x05},
-
-       /* The following sequence is useless after a clean boot
-          but is necessary after resume from suspend */
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
-       {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
-       {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
-       {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
-       {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
-       {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
-       {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
-       {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
-
-       {SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00},
-       {SENSOR, 0xaf, 0x01, 0x00},
-       {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00},
-       {SENSOR, 0x7b, 0xff, 0x00},
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
-       {SENSOR, 0x01, 0x50, 0x00},
-       {SENSOR, 0x12, 0x20, 0x00},
-       {SENSOR, 0x17, 0x40, 0x00},
-       {SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00},
-       {SENSOR, 0x1c, 0x00, 0x00},
-       {SENSOR, 0x02, 0x70, 0x00},
-       {SENSOR, 0x03, 0x0b, 0x00},
-       {SENSOR, 0x04, 0xf0, 0x00},
-       {SENSOR, 0x05, 0x0b, 0x00},
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+       {SENSOR, 0x10, 0xe5, 0x00}, /* 741 */
+       /* normal colors
+       (this is value after boot, but after tries can be different) */
+       {SENSOR, 0x00, 0x06, 0x00},
+};
 
+static const unsigned char start_s5k83a[][4] =
+{
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
        {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
@@ -340,7 +180,7 @@ static const unsigned char init_s5k83a[][4] =
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
-       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00},
+       {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00}, /* 484 */
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
@@ -348,50 +188,10 @@ static const unsigned char init_s5k83a[][4] =
        {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
        {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00},
-       {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00},
+       {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00}, /* 639 */
        {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
        {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
-       {SENSOR, 0x06, 0x71, 0x00},
-       {SENSOR, 0x07, 0xe8, 0x00},
-       {SENSOR, 0x08, 0x02, 0x00},
-       {SENSOR, 0x09, 0x88, 0x00},
-       {SENSOR, 0x14, 0x00, 0x00},
-       {SENSOR, 0x15, 0x20, 0x00},
-       {SENSOR, 0x19, 0x00, 0x00},
-       {SENSOR, 0x1a, 0x98, 0x00},
-       {SENSOR, 0x0f, 0x02, 0x00},
-
-       {SENSOR, 0x10, 0xe5, 0x00},
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
-       {SENSOR_LONG, 0x14, 0x00, 0x20},
-       {SENSOR_LONG, 0x0d, 0x00, 0x7d},
-       {SENSOR_LONG, 0x1b, 0x0d, 0x05},
-
-       /* normal colors
-          (this is value after boot, but after tries can be different) */
-       {SENSOR, 0x00, 0x06, 0x00},
-
-       /* set default brightness */
-       {SENSOR_LONG, 0x14, 0x00, 0x20},
-       {SENSOR_LONG, 0x0d, 0x01, 0x00},
-       {SENSOR_LONG, 0x1b, S5K83A_DEFAULT_BRIGHTNESS >> 3,
-                           S5K83A_DEFAULT_BRIGHTNESS >> 1},
-
-       /* set default whiteness */
-       {SENSOR, S5K83A_WHITENESS, S5K83A_DEFAULT_WHITENESS, 0x00},
-
-       /* set default gain */
-       {SENSOR_LONG, 0x18, 0x00, S5K83A_DEFAULT_GAIN},
-
-       /* set default flip */
-       {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
-       {SENSOR, S5K83A_FLIP, 0x00 | S5K83A_FLIP_MASK, 0x00},
-       {SENSOR, S5K83A_HFLIP_TUNE, 0x0b, 0x00},
-       {SENSOR, S5K83A_VFLIP_TUNE, 0x0a, 0x00}
-
 };
 
 #endif
index 0d3026936f2e90a8d4b842df62b73d03f0039581..edff4f1f586fdcef4c463834ca8523e6e2297241 100644 (file)
 
 #include "m5602_bridge.h"
 
+#define M5602_V4L2_CID_GREEN_BALANCE   (V4L2_CID_PRIVATE_BASE + 0)
+#define M5602_V4L2_CID_NOISE_SUPPRESION        (V4L2_CID_PRIVATE_BASE + 1)
+
 /* Enumerates all supported sensors */
 enum sensors {
        OV9650_SENSOR   = 1,
        S5K83A_SENSOR   = 2,
        S5K4AA_SENSOR   = 3,
        MT9M111_SENSOR  = 4,
-       PO1030_SENSOR   = 5
+       PO1030_SENSOR   = 5,
+       OV7660_SENSOR   = 6,
 };
 
 /* Enumerates all possible instruction types */
@@ -61,9 +65,6 @@ struct m5602_sensor {
 
        /* Executed when the device is disconnected */
        void (*disconnect)(struct sd *sd);
-
-       /* Performs a power down sequence */
-       int (*power_down)(struct sd *sd);
 };
 
 #endif
index 2a901a4a6f0039c54f607073b67282ffc7409874..30132513400cbc266209320e2c915252b6e1af8b 100644 (file)
@@ -321,6 +321,7 @@ static const struct sd_desc sd_desc = {
 /* -- module initialisation -- */
 static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x08ca, 0x0111)},
+       {USB_DEVICE(0x093a, 0x010f)},
        {}
 };
 MODULE_DEVICE_TABLE(usb, device_table);
@@ -347,8 +348,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       if (usb_register(&sd_driver) < 0)
-               return -1;
+       int ret;
+
+       ret = usb_register(&sd_driver);
+       if (ret < 0)
+               return ret;
        PDEBUG(D_PROBE, "registered");
        return 0;
 }
index 1fff37b79891253bbe24a88d761dd30b1ab2eb8b..188866ac6cefb8b96045ad497fecfbb3e32421b9 100644 (file)
@@ -50,6 +50,13 @@ static int i2c_detect_tries = 10;
 struct sd {
        struct gspca_dev gspca_dev;             /* !! must be the first item */
 
+       char bridge;
+#define BRIDGE_OV511           0
+#define BRIDGE_OV511PLUS       1
+#define BRIDGE_OV518           2
+#define BRIDGE_OV518PLUS       3
+#define BRIDGE_OV519           4
+
        /* Determined by sensor type */
        __u8 sif;
 
@@ -87,6 +94,9 @@ static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
+static void setbrightness(struct gspca_dev *gspca_dev);
+static void setcontrast(struct gspca_dev *gspca_dev);
+static void setcolors(struct gspca_dev *gspca_dev);
 
 static struct ctrl sd_ctrls[] = {
        {
@@ -164,7 +174,7 @@ static struct ctrl sd_ctrls[] = {
        },
 };
 
-static const struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format ov519_vga_mode[] = {
        {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 320,
                .sizeimage = 320 * 240 * 3 / 8 + 590,
@@ -176,7 +186,7 @@ static const struct v4l2_pix_format vga_mode[] = {
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 0},
 };
-static const struct v4l2_pix_format sif_mode[] = {
+static const struct v4l2_pix_format ov519_sif_mode[] = {
        {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 176,
                .sizeimage = 176 * 144 * 3 / 8 + 590,
@@ -189,6 +199,47 @@ static const struct v4l2_pix_format sif_mode[] = {
                .priv = 0},
 };
 
+static const struct v4l2_pix_format ov518_vga_mode[] = {
+       {320, 240, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
+               .bytesperline = 320,
+               .sizeimage = 320 * 240 * 3 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 1},
+       {640, 480, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
+               .bytesperline = 640,
+               .sizeimage = 640 * 480 * 3 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 0},
+};
+static const struct v4l2_pix_format ov518_sif_mode[] = {
+       {176, 144, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
+               .bytesperline = 176,
+               .sizeimage = 40000,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 1},
+       {352, 288, V4L2_PIX_FMT_OV518, V4L2_FIELD_NONE,
+               .bytesperline = 352,
+               .sizeimage = 352 * 288 * 3 / 8 + 590,
+               .colorspace = V4L2_COLORSPACE_JPEG,
+               .priv = 0},
+};
+
+
+/* Registers common to OV511 / OV518 */
+#define R51x_SYS_RESET                 0x50
+#define R51x_SYS_INIT                  0x53
+#define R51x_SYS_SNAP                  0x52
+#define R51x_SYS_CUST_ID               0x5F
+#define R51x_COMP_LUT_BEGIN            0x80
+
+/* OV511 Camera interface register numbers */
+#define R511_SYS_LED_CTL               0x55    /* OV511+ only */
+#define        OV511_RESET_NOREGS              0x3F    /* All but OV511 & regs */
+
+/* OV518 Camera interface register numbers */
+#define R518_GPIO_OUT                  0x56    /* OV518(+) only */
+#define R518_GPIO_CTL                  0x57    /* OV518(+) only */
+
 /* OV519 Camera interface register numbers */
 #define OV519_R10_H_SIZE               0x10
 #define OV519_R11_V_SIZE               0x11
@@ -224,6 +275,8 @@ static const struct v4l2_pix_format sif_mode[] = {
 
 /* OV7610 registers */
 #define OV7610_REG_GAIN                0x00    /* gain setting (5:0) */
+#define OV7610_REG_BLUE                0x01    /* blue channel balance */
+#define OV7610_REG_RED         0x02    /* red channel balance */
 #define OV7610_REG_SAT         0x03    /* saturation */
 #define OV8610_REG_HUE         0x04    /* 04 reserved */
 #define OV7610_REG_CNT         0x05    /* Y contrast */
@@ -846,11 +899,12 @@ static unsigned char ov7670_abs_to_sm(unsigned char v)
 static int reg_w(struct sd *sd, __u16 index, __u8 value)
 {
        int ret;
+       int req = (sd->bridge <= BRIDGE_OV511PLUS) ? 2 : 1;
 
        sd->gspca_dev.usb_buf[0] = value;
        ret = usb_control_msg(sd->gspca_dev.dev,
                        usb_sndctrlpipe(sd->gspca_dev.dev, 0),
-                       1,                      /* REQ_IO (ov518/519) */
+                       req,
                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        0, index,
                        sd->gspca_dev.usb_buf, 1, 500);
@@ -864,10 +918,11 @@ static int reg_w(struct sd *sd, __u16 index, __u8 value)
 static int reg_r(struct sd *sd, __u16 index)
 {
        int ret;
+       int req = (sd->bridge <= BRIDGE_OV511PLUS) ? 3 : 1;
 
        ret = usb_control_msg(sd->gspca_dev.dev,
                        usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
-                       1,                      /* REQ_IO */
+                       req,
                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                        0, index, sd->gspca_dev.usb_buf, 1, 500);
 
@@ -923,6 +978,28 @@ static int reg_w_mask(struct sd *sd,
        return reg_w(sd, index, value);
 }
 
+/*
+ * Writes multiple (n) byte value to a single register. Only valid with certain
+ * registers (0x30 and 0xc4 - 0xce).
+ */
+static int ov518_reg_w32(struct sd *sd, __u16 index, u32 value, int n)
+{
+       int ret;
+
+       *((u32 *)sd->gspca_dev.usb_buf) = __cpu_to_le32(value);
+
+       ret = usb_control_msg(sd->gspca_dev.dev,
+                       usb_sndctrlpipe(sd->gspca_dev.dev, 0),
+                       1 /* REG_IO */,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0, index,
+                       sd->gspca_dev.usb_buf, n, 500);
+       if (ret < 0)
+               PDEBUG(D_ERR, "Write reg32 [%02x] %08x failed", index, value);
+       return ret;
+}
+
+
 /*
  * The OV518 I2C I/O procedure is different, hence, this function.
  * This is normally only called from i2c_w(). Note that this function
@@ -1014,20 +1091,47 @@ static inline int ov51x_stop(struct sd *sd)
 {
        PDEBUG(D_STREAM, "stopping");
        sd->stopped = 1;
-       return reg_w(sd, OV519_SYS_RESET1, 0x0f);
+       switch (sd->bridge) {
+       case BRIDGE_OV511:
+       case BRIDGE_OV511PLUS:
+               return reg_w(sd, R51x_SYS_RESET, 0x3d);
+       case BRIDGE_OV518:
+       case BRIDGE_OV518PLUS:
+               return reg_w_mask(sd, R51x_SYS_RESET, 0x3a, 0x3a);
+       case BRIDGE_OV519:
+               return reg_w(sd, OV519_SYS_RESET1, 0x0f);
+       }
+
+       return 0;
 }
 
 /* Restarts OV511 after ov511_stop() is called. Has no effect if it is not
  * actually stopped (for performance). */
 static inline int ov51x_restart(struct sd *sd)
 {
+       int rc;
+
        PDEBUG(D_STREAM, "restarting");
        if (!sd->stopped)
                return 0;
        sd->stopped = 0;
 
        /* Reinitialize the stream */
-       return reg_w(sd, OV519_SYS_RESET1, 0x00);
+       switch (sd->bridge) {
+       case BRIDGE_OV511:
+       case BRIDGE_OV511PLUS:
+               return reg_w(sd, R51x_SYS_RESET, 0x00);
+       case BRIDGE_OV518:
+       case BRIDGE_OV518PLUS:
+               rc = reg_w(sd, 0x2f, 0x80);
+               if (rc < 0)
+                       return rc;
+               return reg_w(sd, R51x_SYS_RESET, 0x00);
+       case BRIDGE_OV519:
+               return reg_w(sd, OV519_SYS_RESET1, 0x00);
+       }
+
+       return 0;
 }
 
 /* This does an initial reset of an OmniVision sensor and ensures that I2C
@@ -1287,16 +1391,161 @@ static int ov6xx0_configure(struct sd *sd)
 /* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */
 static void ov51x_led_control(struct sd *sd, int on)
 {
-       reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1);   /* 0 / 1 */
+       switch (sd->bridge) {
+       /* OV511 has no LED control */
+       case BRIDGE_OV511PLUS:
+               reg_w(sd, R511_SYS_LED_CTL, on ? 1 : 0);
+               break;
+       case BRIDGE_OV518:
+       case BRIDGE_OV518PLUS:
+               reg_w_mask(sd, R518_GPIO_OUT, on ? 0x02 : 0x00, 0x02);
+               break;
+       case BRIDGE_OV519:
+               reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1);   /* 0 / 1 */
+               break;
+       }
 }
 
-/* this function is called at probe time */
-static int sd_config(struct gspca_dev *gspca_dev,
-                       const struct usb_device_id *id)
+/* OV518 quantization tables are 8x4 (instead of 8x8) */
+static int ov518_upload_quan_tables(struct sd *sd)
+{
+       const unsigned char yQuanTable518[] = {
+               5, 4, 5, 6, 6, 7, 7, 7,
+               5, 5, 5, 5, 6, 7, 7, 7,
+               6, 6, 6, 6, 7, 7, 7, 8,
+               7, 7, 6, 7, 7, 7, 8, 8
+       };
+
+       const unsigned char uvQuanTable518[] = {
+               6, 6, 6, 7, 7, 7, 7, 7,
+               6, 6, 6, 7, 7, 7, 7, 7,
+               6, 6, 6, 7, 7, 7, 7, 8,
+               7, 7, 7, 7, 7, 7, 8, 8
+       };
+
+       const unsigned char *pYTable = yQuanTable518;
+       const unsigned char *pUVTable = uvQuanTable518;
+       unsigned char val0, val1;
+       int i, rc, reg = R51x_COMP_LUT_BEGIN;
+
+       PDEBUG(D_PROBE, "Uploading quantization tables");
+
+       for (i = 0; i < 16; i++) {
+               val0 = *pYTable++;
+               val1 = *pYTable++;
+               val0 &= 0x0f;
+               val1 &= 0x0f;
+               val0 |= val1 << 4;
+               rc = reg_w(sd, reg, val0);
+               if (rc < 0)
+                       return rc;
+
+               val0 = *pUVTable++;
+               val1 = *pUVTable++;
+               val0 &= 0x0f;
+               val1 &= 0x0f;
+               val0 |= val1 << 4;
+               rc = reg_w(sd, reg + 16, val0);
+               if (rc < 0)
+                       return rc;
+
+               reg++;
+       }
+
+       return 0;
+}
+
+/* This initializes the OV518/OV518+ and the sensor */
+static int ov518_configure(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       struct cam *cam;
+       int rc;
+
+       /* For 518 and 518+ */
+       static struct ov_regvals init_518[] = {
+               { R51x_SYS_RESET,       0x40 },
+               { R51x_SYS_INIT,        0xe1 },
+               { R51x_SYS_RESET,       0x3e },
+               { R51x_SYS_INIT,        0xe1 },
+               { R51x_SYS_RESET,       0x00 },
+               { R51x_SYS_INIT,        0xe1 },
+               { 0x46,                 0x00 },
+               { 0x5d,                 0x03 },
+       };
+
+       static struct ov_regvals norm_518[] = {
+               { R51x_SYS_SNAP,        0x02 }, /* Reset */
+               { R51x_SYS_SNAP,        0x01 }, /* Enable */
+               { 0x31,                 0x0f },
+               { 0x5d,                 0x03 },
+               { 0x24,                 0x9f },
+               { 0x25,                 0x90 },
+               { 0x20,                 0x00 },
+               { 0x51,                 0x04 },
+               { 0x71,                 0x19 },
+               { 0x2f,                 0x80 },
+       };
+
+       static struct ov_regvals norm_518_p[] = {
+               { R51x_SYS_SNAP,        0x02 }, /* Reset */
+               { R51x_SYS_SNAP,        0x01 }, /* Enable */
+               { 0x31,                 0x0f },
+               { 0x5d,                 0x03 },
+               { 0x24,                 0x9f },
+               { 0x25,                 0x90 },
+               { 0x20,                 0x60 },
+               { 0x51,                 0x02 },
+               { 0x71,                 0x19 },
+               { 0x40,                 0xff },
+               { 0x41,                 0x42 },
+               { 0x46,                 0x00 },
+               { 0x33,                 0x04 },
+               { 0x21,                 0x19 },
+               { 0x3f,                 0x10 },
+               { 0x2f,                 0x80 },
+       };
+
+       /* First 5 bits of custom ID reg are a revision ID on OV518 */
+       PDEBUG(D_PROBE, "Device revision %d",
+              0x1F & reg_r(sd, R51x_SYS_CUST_ID));
+
+       rc = write_regvals(sd, init_518, ARRAY_SIZE(init_518));
+       if (rc < 0)
+               return rc;
+
+       /* Set LED GPIO pin to output mode */
+       rc = reg_w_mask(sd, R518_GPIO_CTL, 0x00, 0x02);
+       if (rc < 0)
+               return rc;
 
+       switch (sd->bridge) {
+       case BRIDGE_OV518:
+               rc = write_regvals(sd, norm_518, ARRAY_SIZE(norm_518));
+               if (rc < 0)
+                       return rc;
+               break;
+       case BRIDGE_OV518PLUS:
+               rc = write_regvals(sd, norm_518_p, ARRAY_SIZE(norm_518_p));
+               if (rc < 0)
+                       return rc;
+               break;
+       }
+
+       rc = ov518_upload_quan_tables(sd);
+       if (rc < 0) {
+               PDEBUG(D_ERR, "Error uploading quantization tables");
+               return rc;
+       }
+
+       rc = reg_w(sd, 0x2f, 0x80);
+       if (rc < 0)
+               return rc;
+
+       return 0;
+}
+
+static int ov519_configure(struct sd *sd)
+{
        static const struct ov_regvals init_519[] = {
                { 0x5a,  0x6d }, /* EnableSystem */
                { 0x53,  0x9b },
@@ -1313,8 +1562,32 @@ static int sd_config(struct gspca_dev *gspca_dev,
                /* windows reads 0x55 at this point*/
        };
 
-       if (write_regvals(sd, init_519, ARRAY_SIZE(init_519)))
+       return write_regvals(sd, init_519, ARRAY_SIZE(init_519));
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+                       const struct usb_device_id *id)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       struct cam *cam;
+       int ret = 0;
+
+       sd->bridge = id->driver_info;
+
+       switch (sd->bridge) {
+       case BRIDGE_OV518:
+       case BRIDGE_OV518PLUS:
+               ret = ov518_configure(gspca_dev);
+               break;
+       case BRIDGE_OV519:
+               ret = ov519_configure(sd);
+               break;
+       }
+
+       if (ret)
                goto error;
+
        ov51x_led_control(sd, 0);       /* turn LED off */
 
        /* Test for 76xx */
@@ -1360,12 +1633,26 @@ static int sd_config(struct gspca_dev *gspca_dev,
        }
 
        cam = &gspca_dev->cam;
-       if (!sd->sif) {
-               cam->cam_mode = vga_mode;
-               cam->nmodes = ARRAY_SIZE(vga_mode);
-       } else {
-               cam->cam_mode = sif_mode;
-               cam->nmodes = ARRAY_SIZE(sif_mode);
+       switch (sd->bridge) {
+       case BRIDGE_OV518:
+       case BRIDGE_OV518PLUS:
+               if (!sd->sif) {
+                       cam->cam_mode = ov518_vga_mode;
+                       cam->nmodes = ARRAY_SIZE(ov518_vga_mode);
+               } else {
+                       cam->cam_mode = ov518_sif_mode;
+                       cam->nmodes = ARRAY_SIZE(ov518_sif_mode);
+               }
+               break;
+       case BRIDGE_OV519:
+               if (!sd->sif) {
+                       cam->cam_mode = ov519_vga_mode;
+                       cam->nmodes = ARRAY_SIZE(ov519_vga_mode);
+               } else {
+                       cam->cam_mode = ov519_sif_mode;
+                       cam->nmodes = ARRAY_SIZE(ov519_sif_mode);
+               }
+               break;
        }
        sd->brightness = BRIGHTNESS_DEF;
        sd->contrast = CONTRAST_DEF;
@@ -1422,6 +1709,106 @@ static int sd_init(struct gspca_dev *gspca_dev)
        return 0;
 }
 
+/* Sets up the OV518/OV518+ with the given image parameters
+ *
+ * OV518 needs a completely different approach, until we can figure out what
+ * the individual registers do. Also, only 15 FPS is supported now.
+ *
+ * Do not put any sensor-specific code in here (including I2C I/O functions)
+ */
+static int ov518_mode_init_regs(struct sd *sd)
+{
+       int hsegs, vsegs;
+
+       /******** Set the mode ********/
+
+       reg_w(sd, 0x2b, 0);
+       reg_w(sd, 0x2c, 0);
+       reg_w(sd, 0x2d, 0);
+       reg_w(sd, 0x2e, 0);
+       reg_w(sd, 0x3b, 0);
+       reg_w(sd, 0x3c, 0);
+       reg_w(sd, 0x3d, 0);
+       reg_w(sd, 0x3e, 0);
+
+       if (sd->bridge == BRIDGE_OV518) {
+               /* Set 8-bit (YVYU) input format */
+               reg_w_mask(sd, 0x20, 0x08, 0x08);
+
+               /* Set 12-bit (4:2:0) output format */
+               reg_w_mask(sd, 0x28, 0x80, 0xf0);
+               reg_w_mask(sd, 0x38, 0x80, 0xf0);
+       } else {
+               reg_w(sd, 0x28, 0x80);
+               reg_w(sd, 0x38, 0x80);
+       }
+
+       hsegs = sd->gspca_dev.width / 16;
+       vsegs = sd->gspca_dev.height / 4;
+
+       reg_w(sd, 0x29, hsegs);
+       reg_w(sd, 0x2a, vsegs);
+
+       reg_w(sd, 0x39, hsegs);
+       reg_w(sd, 0x3a, vsegs);
+
+       /* Windows driver does this here; who knows why */
+       reg_w(sd, 0x2f, 0x80);
+
+       /******** Set the framerate (to 30 FPS) ********/
+       if (sd->bridge == BRIDGE_OV518PLUS)
+               sd->clockdiv = 1;
+       else
+               sd->clockdiv = 0;
+
+       /* Mode independent, but framerate dependent, regs */
+       reg_w(sd, 0x51, 0x04);  /* Clock divider; lower==faster */
+       reg_w(sd, 0x22, 0x18);
+       reg_w(sd, 0x23, 0xff);
+
+       if (sd->bridge == BRIDGE_OV518PLUS)
+               reg_w(sd, 0x21, 0x19);
+       else
+               reg_w(sd, 0x71, 0x17);  /* Compression-related? */
+
+       /* FIXME: Sensor-specific */
+       /* Bit 5 is what matters here. Of course, it is "reserved" */
+       i2c_w(sd, 0x54, 0x23);
+
+       reg_w(sd, 0x2f, 0x80);
+
+       if (sd->bridge == BRIDGE_OV518PLUS) {
+               reg_w(sd, 0x24, 0x94);
+               reg_w(sd, 0x25, 0x90);
+               ov518_reg_w32(sd, 0xc4,    400, 2);     /* 190h   */
+               ov518_reg_w32(sd, 0xc6,    540, 2);     /* 21ch   */
+               ov518_reg_w32(sd, 0xc7,    540, 2);     /* 21ch   */
+               ov518_reg_w32(sd, 0xc8,    108, 2);     /* 6ch    */
+               ov518_reg_w32(sd, 0xca, 131098, 3);     /* 2001ah */
+               ov518_reg_w32(sd, 0xcb,    532, 2);     /* 214h   */
+               ov518_reg_w32(sd, 0xcc,   2400, 2);     /* 960h   */
+               ov518_reg_w32(sd, 0xcd,     32, 2);     /* 20h    */
+               ov518_reg_w32(sd, 0xce,    608, 2);     /* 260h   */
+       } else {
+               reg_w(sd, 0x24, 0x9f);
+               reg_w(sd, 0x25, 0x90);
+               ov518_reg_w32(sd, 0xc4,    400, 2);     /* 190h   */
+               ov518_reg_w32(sd, 0xc6,    381, 2);     /* 17dh   */
+               ov518_reg_w32(sd, 0xc7,    381, 2);     /* 17dh   */
+               ov518_reg_w32(sd, 0xc8,    128, 2);     /* 80h    */
+               ov518_reg_w32(sd, 0xca, 183331, 3);     /* 2cc23h */
+               ov518_reg_w32(sd, 0xcb,    746, 2);     /* 2eah   */
+               ov518_reg_w32(sd, 0xcc,   1750, 2);     /* 6d6h   */
+               ov518_reg_w32(sd, 0xcd,     45, 2);     /* 2dh    */
+               ov518_reg_w32(sd, 0xce,    851, 2);     /* 353h   */
+       }
+
+       reg_w(sd, 0x2f, 0x80);
+
+       return 0;
+}
+
+
 /* Sets up the OV519 with the given image parameters
  *
  * OV519 needs a completely different approach, until we can figure out what
@@ -1740,6 +2127,11 @@ static int set_ov_sensor_window(struct sd *sd)
                hwebase = 0x3a;
                vwsbase = 0x05;
                vwebase = 0x06;
+               if (qvga) {
+                       /* HDG: this fixes U and V getting swapped */
+                       hwsbase--;
+                       vwsbase--;
+               }
                break;
        case SEN_OV7620:
                hwsbase = 0x2f;         /* From 7620.SET (spec is wrong) */
@@ -1855,15 +2247,28 @@ static int set_ov_sensor_window(struct sd *sd)
 static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int ret;
+       int ret = 0;
 
-       ret = ov519_mode_init_regs(sd);
+       switch (sd->bridge) {
+       case BRIDGE_OV518:
+       case BRIDGE_OV518PLUS:
+               ret = ov518_mode_init_regs(sd);
+               break;
+       case BRIDGE_OV519:
+               ret = ov519_mode_init_regs(sd);
+               break;
+       }
        if (ret < 0)
                goto out;
+
        ret = set_ov_sensor_window(sd);
        if (ret < 0)
                goto out;
 
+       setcontrast(gspca_dev);
+       setbrightness(gspca_dev);
+       setcolors(gspca_dev);
+
        ret = ov51x_restart(sd);
        if (ret < 0)
                goto out;
@@ -1882,7 +2287,30 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
        ov51x_led_control(sd, 0);
 }
 
-static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+static void ov518_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,      /* target */
+                       __u8 *data,                     /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       PDEBUG(D_STREAM, "ov518_pkt_scan: %d bytes", len);
+
+       if (len & 7) {
+               len--;
+               PDEBUG(D_STREAM, "packet number: %d\n", (int)data[len]);
+       }
+
+       /* A false positive here is likely, until OVT gives me
+        * the definitive SOF/EOF format */
+       if ((!(data[0] | data[1] | data[2] | data[3] | data[5])) && data[6]) {
+               gspca_frame_add(gspca_dev, LAST_PACKET, frame, data, 0);
+               gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, 0);
+       }
+
+       /* intermediate packet */
+       gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
+}
+
+static void ov519_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
                        __u8 *data,                     /* isoc packet */
                        int len)                        /* iso packet length */
@@ -1926,6 +2354,27 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        data, len);
 }
 
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+                       struct gspca_frame *frame,      /* target */
+                       __u8 *data,                     /* isoc packet */
+                       int len)                        /* iso packet length */
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       switch (sd->bridge) {
+       case BRIDGE_OV511:
+       case BRIDGE_OV511PLUS:
+               break;
+       case BRIDGE_OV518:
+       case BRIDGE_OV518PLUS:
+               ov518_pkt_scan(gspca_dev, frame, data, len);
+               break;
+       case BRIDGE_OV519:
+               ov519_pkt_scan(gspca_dev, frame, data, len);
+               break;
+       }
+}
+
 /* -- management routines -- */
 
 static void setbrightness(struct gspca_dev *gspca_dev)
@@ -1970,6 +2419,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
                break;
        case SEN_OV6630:
                i2c_w_mask(sd, OV7610_REG_CNT, val >> 4, 0x0f);
+               break;
        case SEN_OV8610: {
                static const __u8 ctab[] = {
                        0x03, 0x09, 0x0b, 0x0f, 0x53, 0x6f, 0x35, 0x7f
@@ -2136,19 +2586,21 @@ static const struct sd_desc sd_desc = {
 
 /* -- module initialisation -- */
 static const __devinitdata struct usb_device_id device_table[] = {
-       {USB_DEVICE(0x041e, 0x4052)},
-       {USB_DEVICE(0x041e, 0x405f)},
-       {USB_DEVICE(0x041e, 0x4060)},
-       {USB_DEVICE(0x041e, 0x4061)},
-       {USB_DEVICE(0x041e, 0x4064)},
-       {USB_DEVICE(0x041e, 0x4068)},
-       {USB_DEVICE(0x045e, 0x028c)},
-       {USB_DEVICE(0x054c, 0x0154)},
-       {USB_DEVICE(0x054c, 0x0155)},
-       {USB_DEVICE(0x05a9, 0x0519)},
-       {USB_DEVICE(0x05a9, 0x0530)},
-       {USB_DEVICE(0x05a9, 0x4519)},
-       {USB_DEVICE(0x05a9, 0x8519)},
+       {USB_DEVICE(0x041e, 0x4052), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x041e, 0x405f), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x041e, 0x4060), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x041e, 0x4061), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x041e, 0x4064), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x041e, 0x4068), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x045e, 0x028c), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x054c, 0x0154), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x054c, 0x0155), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x05a9, 0x0518), .driver_info = BRIDGE_OV518 },
+       {USB_DEVICE(0x05a9, 0x0519), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x05a9, 0x0530), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x05a9, 0x4519), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x05a9, 0x8519), .driver_info = BRIDGE_OV519 },
+       {USB_DEVICE(0x05a9, 0xa518), .driver_info = BRIDGE_OV518PLUS },
        {}
 };
 
index 19e0bc60de14aecf95708b7d6c922b49e063ce3a..4b528b37291188f858c6c130bcb20b71790d278a 100644 (file)
@@ -60,10 +60,23 @@ struct sd {
 static struct ctrl sd_ctrls[] = {
 };
 
-static const struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_yuyv_mode[] = {
        {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
         .bytesperline = 640 * 2,
         .sizeimage = 640 * 480 * 2,
+        .colorspace = V4L2_COLORSPACE_SRGB,
+        .priv = 0},
+};
+
+static const struct v4l2_pix_format vga_jpeg_mode[] = {
+       {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+        .bytesperline = 320,
+        .sizeimage = 320 * 240 * 3 / 8 + 590,
+        .colorspace = V4L2_COLORSPACE_JPEG,
+        .priv = 1},
+       {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+        .bytesperline = 640,
+        .sizeimage = 640 * 480 * 3 / 8 + 590,
         .colorspace = V4L2_COLORSPACE_JPEG,
         .priv = 0},
 };
@@ -244,7 +257,7 @@ static const u8 bridge_init_ov965x[][2] = {
 };
 
 static const u8 sensor_init_ov965x[][2] = {
-       {0x12, 0x80},   /* com7 - reset */
+       {0x12, 0x80},   /* com7 - SSCB reset */
        {0x00, 0x00},   /* gain */
        {0x01, 0x80},   /* blue */
        {0x02, 0x80},   /* red */
@@ -254,10 +267,10 @@ static const u8 sensor_init_ov965x[][2] = {
        {0x0e, 0x61},   /* com5 */
        {0x0f, 0x42},   /* com6 */
        {0x11, 0x00},   /* clkrc */
-       {0x12, 0x02},   /* com7 */
+       {0x12, 0x02},   /* com7 - 15fps VGA YUYV */
        {0x13, 0xe7},   /* com8 - everything (AGC, AWB and AEC) */
        {0x14, 0x28},   /* com9 */
-       {0x16, 0x24},   /* rsvd16 */
+       {0x16, 0x24},   /* reg16 */
        {0x17, 0x1d},   /* hstart*/
        {0x18, 0xbd},   /* hstop */
        {0x19, 0x01},   /* vstrt */
@@ -269,24 +282,24 @@ static const u8 sensor_init_ov965x[][2] = {
        {0x27, 0x08},   /* bbias */
        {0x28, 0x08},   /* gbbias */
        {0x29, 0x15},   /* gr com */
-       {0x2a, 0x00},
-       {0x2b, 0x00},
+       {0x2a, 0x00},   /* exhch */
+       {0x2b, 0x00},   /* exhcl */
        {0x2c, 0x08},   /* rbias */
        {0x32, 0xff},   /* href */
        {0x33, 0x00},   /* chlf */
-       {0x34, 0x3f},   /* arblm */
-       {0x35, 0x00},   /* rsvd35 */
-       {0x36, 0xf8},   /* rsvd36 */
-       {0x38, 0x72},   /* acom38 */
-       {0x39, 0x57},   /* ofon */
-       {0x3a, 0x80},   /* tslb */
-       {0x3b, 0xc4},
+       {0x34, 0x3f},   /* aref1 */
+       {0x35, 0x00},   /* aref2 */
+       {0x36, 0xf8},   /* aref3 */
+       {0x38, 0x72},   /* adc2 */
+       {0x39, 0x57},   /* aref4 */
+       {0x3a, 0x80},   /* tslb - yuyv */
+       {0x3b, 0xc4},   /* com11 - night mode 1/4 frame rate */
        {0x3d, 0x99},   /* com13 */
-       {0x3f, 0xc1},
+       {0x3f, 0xc1},   /* edge */
        {0x40, 0xc0},   /* com15 */
        {0x41, 0x40},   /* com16 */
-       {0x42, 0xc0},
-       {0x43, 0x0a},
+       {0x42, 0xc0},   /* com17 */
+       {0x43, 0x0a},   /* rsvd */
        {0x44, 0xf0},
        {0x45, 0x46},
        {0x46, 0x62},
@@ -297,22 +310,22 @@ static const u8 sensor_init_ov965x[][2] = {
        {0x4c, 0x7f},
        {0x4d, 0x7f},
        {0x4e, 0x7f},
-       {0x4f, 0x98},
+       {0x4f, 0x98},   /* matrix */
        {0x50, 0x98},
        {0x51, 0x00},
        {0x52, 0x28},
        {0x53, 0x70},
        {0x54, 0x98},
-       {0x58, 0x1a},
-       {0x59, 0x85},
+       {0x58, 0x1a},   /* matrix coef sign */
+       {0x59, 0x85},   /* AWB control */
        {0x5a, 0xa9},
        {0x5b, 0x64},
        {0x5c, 0x84},
        {0x5d, 0x53},
        {0x5e, 0x0e},
-       {0x5f, 0xf0},
-       {0x60, 0xf0},
-       {0x61, 0xf0},
+       {0x5f, 0xf0},   /* AWB blue limit */
+       {0x60, 0xf0},   /* AWB red limit */
+       {0x61, 0xf0},   /* AWB green limit */
        {0x62, 0x00},   /* lcc1 */
        {0x63, 0x00},   /* lcc2 */
        {0x64, 0x02},   /* lcc3 */
@@ -324,15 +337,15 @@ static const u8 sensor_init_ov965x[][2] = {
        {0x6d, 0x55},
        {0x6e, 0x00},
        {0x6f, 0x9d},
-       {0x70, 0x21},
+       {0x70, 0x21},   /* dnsth */
        {0x71, 0x78},
-       {0x72, 0x00},
-       {0x73, 0x01},
-       {0x74, 0x3a},
-       {0x75, 0x35},
+       {0x72, 0x00},   /* poidx */
+       {0x73, 0x01},   /* pckdv */
+       {0x74, 0x3a},   /* xindx */
+       {0x75, 0x35},   /* yindx */
        {0x76, 0x01},
        {0x77, 0x02},
-       {0x7a, 0x12},
+       {0x7a, 0x12},   /* gamma curve */
        {0x7b, 0x08},
        {0x7c, 0x16},
        {0x7d, 0x30},
@@ -349,33 +362,33 @@ static const u8 sensor_init_ov965x[][2] = {
        {0x88, 0xe6},
        {0x89, 0xf2},
        {0x8a, 0x03},
-       {0x8c, 0x89},
+       {0x8c, 0x89},   /* com19 */
        {0x14, 0x28},   /* com9 */
        {0x90, 0x7d},
        {0x91, 0x7b},
-       {0x9d, 0x03},
-       {0x9e, 0x04},
+       {0x9d, 0x03},   /* lcc6 */
+       {0x9e, 0x04},   /* lcc7 */
        {0x9f, 0x7a},
        {0xa0, 0x79},
        {0xa1, 0x40},   /* aechm */
-       {0xa4, 0x50},
+       {0xa4, 0x50},   /* com21 */
        {0xa5, 0x68},   /* com26 */
-       {0xa6, 0x4a},
-       {0xa8, 0xc1},   /* acoma8 */
-       {0xa9, 0xef},   /* acoma9 */
+       {0xa6, 0x4a},   /* AWB green */
+       {0xa8, 0xc1},   /* refa8 */
+       {0xa9, 0xef},   /* refa9 */
        {0xaa, 0x92},
        {0xab, 0x04},
-       {0xac, 0x80},
+       {0xac, 0x80},   /* black level control */
        {0xad, 0x80},
        {0xae, 0x80},
        {0xaf, 0x80},
        {0xb2, 0xf2},
        {0xb3, 0x20},
-       {0xb4, 0x20},
+       {0xb4, 0x20},   /* ctrlb4 */
        {0xb5, 0x00},
        {0xb6, 0xaf},
        {0xbb, 0xae},
-       {0xbc, 0x7f},
+       {0xbc, 0x7f},   /* ADC channel offsets */
        {0xdb, 0x7f},
        {0xbe, 0x7f},
        {0xbf, 0x7f},
@@ -384,7 +397,7 @@ static const u8 sensor_init_ov965x[][2] = {
        {0xc2, 0x01},
        {0xc3, 0x4e},
        {0xc6, 0x85},
-       {0xc7, 0x80},
+       {0xc7, 0x80},   /* com24 */
        {0xc9, 0xe0},
        {0xca, 0xe8},
        {0xcb, 0xf0},
@@ -399,11 +412,11 @@ static const u8 sensor_init_ov965x[][2] = {
        {0x58, 0x1a},
        {0xff, 0x41},   /* read 41, write ff 00 */
        {0x41, 0x40},   /* com16 */
-       {0xc5, 0x03},
-       {0x6a, 0x02},
+       {0xc5, 0x03},   /* 60 Hz banding filter */
+       {0x6a, 0x02},   /* 50 Hz banding filter */
 
-       {0x12, 0x62},   /* com7 - VGA + CIF */
-       {0x36, 0xfa},   /* rsvd36 */
+       {0x12, 0x62},   /* com7 - 30fps VGA YUV */
+       {0x36, 0xfa},   /* aref3 */
        {0x69, 0x0a},   /* hv */
        {0x8c, 0x89},   /* com22 */
        {0x14, 0x28},   /* com9 */
@@ -442,8 +455,8 @@ static const u8 bridge_init_ov965x_2[][2] = {
        {0x52, 0x3c},
        {0x53, 0x00},
        {0x54, 0x00},
-       {0x55, 0x00},
-       {0x57, 0x00},
+       {0x55, 0x00},   /* brightness */
+       {0x57, 0x00},   /* contrast 2 */
        {0x5c, 0x00},
        {0x5a, 0xa0},
        {0x5b, 0x78},
@@ -489,9 +502,66 @@ static const u8 sensor_init_ov965x_2[][2] = {
        {0x13, 0xe7},   /* com8 - everything (AGC, AWB and AEC) */
 };
 
+static const u8 sensor_start_ov965x[][2] = {
+       {0x12, 0x62},   /* com7 - 30fps VGA YUV */
+       {0x36, 0xfa},   /* aref3 */
+       {0x69, 0x0a},   /* hv */
+       {0x8c, 0x89},   /* com22 */
+       {0x14, 0x28},   /* com9 */
+       {0x3e, 0x0c},   /* com14 */
+       {0x41, 0x40},   /* com16 */
+       {0x72, 0x00},
+       {0x73, 0x00},
+       {0x74, 0x3a},
+       {0x75, 0x35},
+       {0x76, 0x01},
+       {0xc7, 0x80},   /* com24 */
+       {0x03, 0x12},   /* vref */
+       {0x17, 0x16},   /* hstart */
+       {0x18, 0x02},   /* hstop */
+       {0x19, 0x01},   /* vstrt */
+       {0x1a, 0x3d},   /* vstop */
+       {0x32, 0xff},   /* href */
+       {0xc0, 0xaa},
+       {}
+};
+
 static const u8 bridge_start_ov965x[][2] = {
+       {0x94, 0xaa},
+       {0xf1, 0x60},
+       {0xe5, 0x04},
+       {0xc0, 0x50},
+       {0xc1, 0x3c},
+       {0x8c, 0x00},
+       {0x8d, 0x1c},
+       {0x34, 0x05},
+       {}
+};
+
+static const u8 bridge_start_ov965x_vga[][2] = {
+       {0xc2, 0x0c},
+       {0xc3, 0xf9},
+       {0xda, 0x01},
+       {0x50, 0x00},
+       {0x51, 0xa0},
+       {0x52, 0x3c},
+       {0x53, 0x00},
+       {0x54, 0x00},
+       {0x55, 0x00},
+       {0x57, 0x00},
+       {0x5c, 0x00},
+       {0x5a, 0xa0},
+       {0x5b, 0x78},
+       {0x35, 0x02},
+       {0xd9, 0x10},
+       {0x94, 0x11},
+       {}
+};
+
+static const u8 bridge_start_ov965x_cif[][2] = {
        {0xc2, 0x4c},
        {0xc3, 0xf9},
+       {0xda, 0x00},
        {0x50, 0x00},
        {0x51, 0xa0},
        {0x52, 0x78},
@@ -500,30 +570,54 @@ static const u8 bridge_start_ov965x[][2] = {
        {0x55, 0x00},
        {0x57, 0x00},
        {0x5c, 0x00},
-       {0x5a, 0x28},
-       {0x5b, 0x1e},
-       {0x35, 0x00},
-       {0xd9, 0x21},
+       {0x5a, 0x50},
+       {0x5b, 0x3c},
+       {0x35, 0x02},
+       {0xd9, 0x10},
        {0x94, 0x11},
+       {}
 };
 
-static const u8 sensor_start_ov965x[][2] = {
-       {0x3b, 0xe4},
+static const u8 sensor_start_ov965x_vga[][2] = {
+       {0x3b, 0xc4},   /* com11 - night mode 1/4 frame rate */
+       {0x1e, 0x04},   /* mvfp */
+       {0x13, 0xe0},   /* com8 */
+       {0x00, 0x00},
+       {0x13, 0xe7},   /* com8 - everything (AGC, AWB and AEC) */
+       {0x11, 0x03},   /* clkrc */
+       {0x6b, 0x5a},   /* dblv */
+       {0x6a, 0x05},   /* 50 Hz banding filter */
+       {0xc5, 0x07},   /* 60 Hz banding filter */
+       {0xa2, 0x4b},   /* bd50 */
+       {0xa3, 0x3e},   /* bd60 */
+
+       {0x2d, 0x00},   /* advfl */
+       {}
+};
+
+static const u8 sensor_start_ov965x_cif[][2] = {
+       {0x3b, 0xe4},   /* com11 - night mode 1/4 frame rate */
        {0x1e, 0x04},   /* mvfp */
        {0x13, 0xe0},   /* com8 */
        {0x00, 0x00},
        {0x13, 0xe7},   /* com8 - everything (AGC, AWB and AEC) */
        {0x11, 0x01},   /* clkrc */
        {0x6b, 0x5a},   /* dblv */
-       {0x6a, 0x02},
-       {0xc5, 0x03},
-       {0xa2, 0x96},
-       {0xa3, 0x7d},
+       {0x6a, 0x02},   /* 50 Hz banding filter */
+       {0xc5, 0x03},   /* 60 Hz banding filter */
+       {0xa2, 0x96},   /* bd50 */
+       {0xa3, 0x7d},   /* bd60 */
+
        {0xff, 0x13},   /* read 13, write ff 00 */
        {0x13, 0xe7},
-       {0x3a, 0x80},
+       {0x3a, 0x80},   /* tslb - yuyv */
+       {}
+};
+
+static const u8 sensor_start_ov965x_2[][2] = {
        {0xff, 0x42},   /* read 42, write ff 00 */
-       {0x42, 0xc1},
+       {0x42, 0xc1},   /* com17 - 50 Hz filter */
+       {}
 };
 
 
@@ -705,11 +799,17 @@ static int sd_config(struct gspca_dev *gspca_dev,
 
        cam = &gspca_dev->cam;
 
-       cam->cam_mode = vga_mode;
-       cam->nmodes = ARRAY_SIZE(vga_mode);
+       if (sd->sensor == SENSOR_OV772X) {
+               cam->cam_mode = vga_yuyv_mode;
+               cam->nmodes = ARRAY_SIZE(vga_yuyv_mode);
 
-       cam->bulk_size = 16384;
-       cam->bulk_nurbs = 2;
+               cam->bulk = 1;
+               cam->bulk_size = 16384;
+               cam->bulk_nurbs = 2;
+       } else {                /* ov965x */
+               cam->cam_mode = vga_jpeg_mode;
+               cam->nmodes = ARRAY_SIZE(vga_jpeg_mode);
+       }
 
        return 0;
 }
@@ -778,6 +878,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
 static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
+       int mode;
 
        switch (sd->sensor) {
        case SENSOR_OV772X:
@@ -786,13 +887,28 @@ static int sd_start(struct gspca_dev *gspca_dev)
                break;
        default:
 /*     case SENSOR_OV965X: */
-               reg_w_array(gspca_dev, bridge_start_ov965x,
-                               ARRAY_SIZE(bridge_start_ov965x));
+
                sccb_w_array(gspca_dev, sensor_start_ov965x,
                                ARRAY_SIZE(sensor_start_ov965x));
+               reg_w_array(gspca_dev, bridge_start_ov965x,
+                               ARRAY_SIZE(bridge_start_ov965x));
+               mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+               if (mode != 0) {        /* 320x240 */
+                       reg_w_array(gspca_dev, bridge_start_ov965x_cif,
+                                       ARRAY_SIZE(bridge_start_ov965x_cif));
+                       sccb_w_array(gspca_dev, sensor_start_ov965x_cif,
+                                       ARRAY_SIZE(sensor_start_ov965x_cif));
+               } else {                /* 640x480 */
+                       reg_w_array(gspca_dev, bridge_start_ov965x_vga,
+                                       ARRAY_SIZE(bridge_start_ov965x_vga));
+                       sccb_w_array(gspca_dev, sensor_start_ov965x_vga,
+                                       ARRAY_SIZE(sensor_start_ov965x_vga));
+               }
+               sccb_w_array(gspca_dev, sensor_start_ov965x_2,
+                               ARRAY_SIZE(sensor_start_ov965x_2));
+               ov534_reg_write(gspca_dev, 0xe0, 0x00);
                ov534_reg_write(gspca_dev, 0xe0, 0x00);
                ov534_set_led(gspca_dev, 1);
-/*fixme: other sensor start omitted*/
        }
        return 0;
 }
@@ -832,9 +948,11 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame,
        __u32 this_pts;
        u16 this_fid;
        int remaining_len = len;
+       int payload_len;
 
+       payload_len = gspca_dev->cam.bulk ? 2048 : 2040;
        do {
-               len = min(remaining_len, 2040);         /*fixme: was 2048*/
+               len = min(remaining_len, payload_len);
 
                /* Payloads are prefixed with a UVC-style header.  We
                   consider a frame to start when the FID toggles, or the PTS
@@ -864,30 +982,27 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame,
 
                /* If PTS or FID has changed, start a new frame. */
                if (this_pts != sd->last_pts || this_fid != sd->last_fid) {
-                       gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
-                                       NULL, 0);
+                       if (gspca_dev->last_packet_type == INTER_PACKET)
+                               frame = gspca_frame_add(gspca_dev,
+                                                       LAST_PACKET, frame,
+                                                       NULL, 0);
                        sd->last_pts = this_pts;
                        sd->last_fid = this_fid;
-               }
-
-               /* Add the data from this payload */
-               gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+                       gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
                                        data + 12, len - 12);
-
                /* If this packet is marked as EOF, end the frame */
-               if (data[1] & UVC_STREAM_EOF) {
+               } else if (data[1] & UVC_STREAM_EOF) {
                        sd->last_pts = 0;
-
-                       if (frame->data_end - frame->data !=
-                           gspca_dev->width * gspca_dev->height * 2) {
-                               PDEBUG(D_PACK, "short frame");
-                               goto discard;
-                       }
-
                        frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
-                                               NULL, 0);
+                                               data + 12, len - 12);
+               } else {
+
+                       /* Add the data from this payload */
+                       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+                                               data + 12, len - 12);
                }
 
+
                /* Done this payload */
                goto scan_next;
 
index 153d0a91d4b5c94acb6a06903f0862a3b9196398..cf3af8de6e971ca2422ec38330a3b57081b8f69c 100644 (file)
@@ -877,6 +877,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
                cam->cam_mode = sif_mode;
                cam->nmodes = ARRAY_SIZE(sif_mode);
        }
+       cam->npkt = 36;                 /* 36 packets per ISOC message */
+
        sd->brightness = BRIGHTNESS_DEF;
        sd->gain = GAIN_DEF;
        sd->exposure = EXPOSURE_DEF;
index c72e19d3ac370bbb00e883f233c1b49378ff96fa..dc6a6f11354a260ee01f389859c3b352fcb2e6d9 100644 (file)
@@ -62,7 +62,6 @@ struct sd {
 #define BRIDGE_SN9C105 1
 #define BRIDGE_SN9C110 2
 #define BRIDGE_SN9C120 3
-#define BRIDGE_SN9C325 4
        u8 sensor;                      /* Type of image sensor chip */
 #define SENSOR_HV7131R 0
 #define SENSOR_MI0360 1
@@ -354,9 +353,9 @@ static const u8 sn_ov7648[0x1c] = {
 
 static const u8 sn_ov7660[0x1c] = {
 /*     reg0    reg1    reg2    reg3    reg4    reg5    reg6    reg7 */
-       0x00,   0x61,   0x40,   0x00,   0x1a,   0x20,   0x20,   0x20,
+       0x00,   0x61,   0x40,   0x00,   0x1a,   0x00,   0x00,   0x00,
 /*     reg8    reg9    rega    regb    regc    regd    rege    regf */
-       0x81,   0x21,   0x07,   0x00,   0x00,   0x00,   0x00,   0x10,
+       0x81,   0x21,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,
 /*     reg10   reg11   reg12   reg13   reg14   reg15   reg16   reg17 */
        0x03,   0x00,   0x01,   0x01,   0x08,   0x28,   0x1e,   0x20,
 /*     reg18   reg19   reg1a   reg1b */
@@ -757,6 +756,7 @@ static const u8 ov7660_sensor_init[][8] = {
        {0xc1, 0x21, 0x88, 0xaf, 0xc7, 0xdf, 0x00, 0x10}, /* gamma curve */
        {0xc1, 0x21, 0x8b, 0x99, 0x99, 0xcf, 0x00, 0x10}, /* reserved */
        {0xb1, 0x21, 0x92, 0x00, 0x00, 0x00, 0x00, 0x10}, /* DM_LNL/H */
+       {0xb1, 0x21, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x10},
 /****** (some exchanges in the win trace) ******/
        {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10}, /* MVFP */
                                                /* bits[3..0]reserved */
@@ -1065,9 +1065,9 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
        struct sd *sd = (struct sd *) gspca_dev;
        const u8 *reg9a;
        static const u8 reg9a_def[] =
-               {0x08, 0x40, 0x20, 0x10, 0x00, 0x04};
-       static const u8 reg9a_sn9c325[] =
-               {0x0a, 0x40, 0x38, 0x30, 0x00, 0x20};
+               {0x00, 0x40, 0x20, 0x00, 0x00, 0x00};
+       static const u8 reg9a_spec[] =
+               {0x00, 0x40, 0x38, 0x30, 0x00, 0x20};
        static const u8 regd4[] = {0x60, 0x00, 0x00};
 
        reg_w1(gspca_dev, 0xf1, 0x00);
@@ -1077,9 +1077,10 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
        reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2);
        reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2);
        reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5);      /* jfm len was 3 */
-       switch (sd->bridge) {
-       case BRIDGE_SN9C325:
-               reg9a = reg9a_sn9c325;
+       switch (sd->sensor) {
+       case SENSOR_OV7660:
+       case SENSOR_SP80708:
+               reg9a = reg9a_spec;
                break;
        default:
                reg9a = reg9a_def;
@@ -1104,7 +1105,6 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
                reg_w1(gspca_dev, 0x17, 0x64);
                reg_w1(gspca_dev, 0x01, 0x42);
                break;
-/*jfm: from win trace */
        case SENSOR_OV7630:
                reg_w1(gspca_dev, 0x01, 0x61);
                reg_w1(gspca_dev, 0x17, 0xe2);
@@ -1114,18 +1114,15 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
        case SENSOR_OV7648:
                reg_w1(gspca_dev, 0x01, 0x63);
                reg_w1(gspca_dev, 0x17, 0x20);
+               reg_w1(gspca_dev, 0x01, 0x62);
                reg_w1(gspca_dev, 0x01, 0x42);
                break;
-/*jfm: from win trace */
        case SENSOR_OV7660:
-               if (sd->bridge == BRIDGE_SN9C120) {
-                       reg_w1(gspca_dev, 0x01, 0x61);
-                       reg_w1(gspca_dev, 0x17, 0x20);
-                       reg_w1(gspca_dev, 0x01, 0x60);
-                       reg_w1(gspca_dev, 0x01, 0x40);
-                       break;
-               }
-               /* fall thru */
+               reg_w1(gspca_dev, 0x01, 0x61);
+               reg_w1(gspca_dev, 0x17, 0x20);
+               reg_w1(gspca_dev, 0x01, 0x60);
+               reg_w1(gspca_dev, 0x01, 0x40);
+               break;
        case SENSOR_SP80708:
                reg_w1(gspca_dev, 0x01, 0x63);
                reg_w1(gspca_dev, 0x17, 0x20);
@@ -1134,6 +1131,9 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
                mdelay(100);
                reg_w1(gspca_dev, 0x02, 0x62);
                break;
+/*     case SENSOR_HV7131R: */
+/*     case SENSOR_MI0360: */
+/*     case SENSOR_MO4000: */
        default:
                reg_w1(gspca_dev, 0x01, 0x43);
                reg_w1(gspca_dev, 0x17, 0x61);
@@ -1280,6 +1280,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
        cam = &gspca_dev->cam;
        cam->cam_mode = vga_mode;
        cam->nmodes = ARRAY_SIZE(vga_mode);
+       cam->npkt = 24;                 /* 24 packets per ISOC message */
 
        sd->bridge = id->driver_info >> 16;
        sd->sensor = id->driver_info >> 8;
@@ -1683,13 +1684,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
        case SENSOR_OV7648:
                reg17 = 0x20;
                break;
-/*jfm: from win trace */
        case SENSOR_OV7660:
-               if (sd->bridge == BRIDGE_SN9C120) {
-                       reg17 = 0xa0;
-                       break;
-               }
-               /* fall thru */
+               reg17 = 0xa0;
+               break;
        default:
                reg17 = 0x60;
                break;
@@ -1714,16 +1711,17 @@ static int sd_start(struct gspca_dev *gspca_dev)
                reg_w1(gspca_dev, 0x9a, 0x0a);
                reg_w1(gspca_dev, 0x99, 0x60);
                break;
+       case SENSOR_OV7660:
+               reg_w1(gspca_dev, 0x9a, 0x05);
+               if (sd->bridge == BRIDGE_SN9C105)
+                       reg_w1(gspca_dev, 0x99, 0xff);
+               else
+                       reg_w1(gspca_dev, 0x99, 0x5b);
+               break;
        case SENSOR_SP80708:
                reg_w1(gspca_dev, 0x9a, 0x05);
                reg_w1(gspca_dev, 0x99, 0x59);
                break;
-       case SENSOR_OV7660:
-               if (sd->bridge == BRIDGE_SN9C120) {
-                       reg_w1(gspca_dev, 0x9a, 0x05);
-                       break;
-               }
-               /* fall thru */
        default:
                reg_w1(gspca_dev, 0x9a, 0x08);
                reg_w1(gspca_dev, 0x99, 0x59);
@@ -2193,6 +2191,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
        {USB_DEVICE(0x0471, 0x0328), BSI(SN9C105, MI0360, 0x5d)},
        {USB_DEVICE(0x0471, 0x0330), BSI(SN9C105, MI0360, 0x5d)},
        {USB_DEVICE(0x06f8, 0x3004), BSI(SN9C105, OV7660, 0x21)},
+       {USB_DEVICE(0x06f8, 0x3008), BSI(SN9C105, OV7660, 0x21)},
        {USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, HV7131R, 0x11)},
 /* bw600.inf:
        {USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, MI0360, 0x5d)}, */
@@ -2211,7 +2210,12 @@ static const __devinitdata struct usb_device_id device_table[] = {
 #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
        {USB_DEVICE(0x0c45, 0x60fe), BSI(SN9C105, OV7630, 0x21)},
 #endif
+       {USB_DEVICE(0x0c45, 0x6100), BSI(SN9C120, MI0360, 0x5d)}, /*sn9c128*/
 /*     {USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6801, 0x??)}, */
+       {USB_DEVICE(0x0c45, 0x610a), BSI(SN9C120, OV7648, 0x21)}, /*sn9c128*/
+       {USB_DEVICE(0x0c45, 0x610b), BSI(SN9C120, OV7660, 0x21)}, /*sn9c128*/
+       {USB_DEVICE(0x0c45, 0x610c), BSI(SN9C120, HV7131R, 0x11)}, /*sn9c128*/
+       {USB_DEVICE(0x0c45, 0x610e), BSI(SN9C120, OV7630, 0x21)}, /*sn9c128*/
 /*     {USB_DEVICE(0x0c45, 0x6122), BSI(SN9C110, ICM105C, 0x??)}, */
 /*     {USB_DEVICE(0x0c45, 0x6123), BSI(SN9C110, SanyoCCD, 0x??)}, */
        {USB_DEVICE(0x0c45, 0x6128), BSI(SN9C110, OM6802, 0x21)}, /*sn9c325?*/
index 6f38fa6d86b6ac7a03d9035d247d49a3d4b6e7eb..8806b2ff82bece047379e53fe80ef92c1e629ba2 100644 (file)
@@ -32,9 +32,6 @@ MODULE_LICENSE("GPL");
 struct sd {
        struct gspca_dev gspca_dev;             /* !! must be the first item */
 
-       __u8 packet[ISO_MAX_SIZE + 128];
-                                /* !! no more than 128 ff in an ISO packet */
-
        unsigned char brightness;
        unsigned char contrast;
        unsigned char colors;
@@ -906,7 +903,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 {
        struct sd *sd = (struct sd *) gspca_dev;
        int i;
-       __u8 *s, *d;
        static __u8 ffd9[] = {0xff, 0xd9};
 
 /* frames are jpeg 4.1.1 without 0xff escape */
@@ -930,22 +926,19 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        }
 
        /* add 0x00 after 0xff */
-       for (i = len; --i >= 0; )
-               if (data[i] == 0xff)
-                       break;
-       if (i < 0) {                    /* no 0xff */
-               gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
-               return;
-       }
-       s = data;
-       d = sd->packet;
-       for (i = 0; i < len; i++) {
-               *d++ = *s++;
-               if (s[-1] == 0xff)
-                       *d++ = 0x00;
-       }
-       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
-                       sd->packet, d - sd->packet);
+       i = 0;
+       do {
+               if (data[i] == 0xff) {
+                       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+                                       data, i + 1);
+                       len -= i;
+                       data += i;
+                       *data = 0x00;
+                       i = 0;
+               }
+               i++;
+       } while (i < len);
+       gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
 }
 
 static void setbrightness(struct gspca_dev *gspca_dev)
index 2acec58b1b9734cb67512100d2323416f15f3dae..ea8c9fe2e96198b8197faad7c6127767ce604507 100644 (file)
@@ -637,19 +637,19 @@ static int sd_config(struct gspca_dev *gspca_dev,
                cam->nmodes = ARRAY_SIZE(vga_mode) - 1;
        sd->brightness = BRIGHTNESS_DEF;
 
-       if (sd->subtype == Nxultra) {
-               if (write_vector(gspca_dev, spca505b_init_data))
-                       return -EIO;
-       } else {
-               if (write_vector(gspca_dev, spca505_init_data))
-                       return -EIO;
-       }
        return 0;
 }
 
 /* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (write_vector(gspca_dev,
+                        sd->subtype == Nxultra
+                               ? spca505b_init_data
+                               : spca505_init_data))
+               return -EIO;
        return 0;
 }
 
index adacf8437661366a2c8d228f47fc499dd3479f02..2ed2669bac3ed178bdcfde8b36e50b7470ee3111 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * SPCA508 chip based cameras subdriver
  *
- * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2009 Jean-Francois Moine <http://moinejf.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
@@ -30,9 +30,9 @@ MODULE_LICENSE("GPL");
 struct sd {
        struct gspca_dev gspca_dev;             /* !! must be the first item */
 
-       unsigned char brightness;
+       u8 brightness;
 
-       char subtype;
+       u8 subtype;
 #define CreativeVista 0
 #define HamaUSBSightcam 1
 #define HamaUSBSightcam2 2
@@ -86,58 +86,34 @@ static const struct v4l2_pix_format sif_mode[] = {
 };
 
 /* Frame packet header offsets for the spca508 */
-#define SPCA508_OFFSET_TYPE 1
-#define SPCA508_OFFSET_COMPRESS 2
-#define SPCA508_OFFSET_FRAMSEQ 8
-#define SPCA508_OFFSET_WIN1LUM 11
 #define SPCA508_OFFSET_DATA 37
 
-#define SPCA508_SNAPBIT 0x20
-#define SPCA508_SNAPCTRL 0x40
-/*************** I2c ****************/
-#define SPCA508_INDEX_I2C_BASE 0x8800
-
 /*
  * Initialization data: this is the first set-up data written to the
  * device (before the open data).
  */
 static const u16 spca508_init_data[][2] =
 {
-       /*  line   URB      value, index */
-       /* 44274  1804 */ {0x0000, 0x870b},
-
-       /* 44299  1805 */ {0x0020, 0x8112},
-       /* Video drop enable, ISO streaming disable */
-       /* 44324  1806 */ {0x0003, 0x8111},
-       /* Reset compression & memory */
-       /* 44349  1807 */ {0x0000, 0x8110},
-       /* Disable all outputs */
-       /* 44372  1808 */ /* READ {0x0000, 0x8114} -> 0000: 00  */
-       /* 44398  1809 */ {0x0000, 0x8114},
-       /* SW GPIO data */
-       /* 44423  1810 */ {0x0008, 0x8110},
-       /* Enable charge pump output */
-       /* 44527  1811 */ {0x0002, 0x8116},
-       /* 200 kHz pump clock */
-       /* 44555  1812 */
-               /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE:) */
-       /* 44590  1813 */ {0x0003, 0x8111},
-       /* Reset compression & memory */
-       /* 44615  1814 */ {0x0000, 0x8111},
-       /* Normal mode (not reset) */
-       /* 44640  1815 */ {0x0098, 0x8110},
-       /* Enable charge pump output, sync.serial,external 2x clock */
-       /* 44665  1816 */ {0x000d, 0x8114},
-       /* SW GPIO data */
-       /* 44690  1817 */ {0x0002, 0x8116},
-       /* 200 kHz pump clock */
-       /* 44715  1818 */ {0x0020, 0x8112},
-       /* Video drop enable, ISO streaming disable */
+       {0x0000, 0x870b},
+
+       {0x0020, 0x8112},       /* Video drop enable, ISO streaming disable */
+       {0x0003, 0x8111},       /* Reset compression & memory */
+       {0x0000, 0x8110},       /* Disable all outputs */
+       /* READ {0x0000, 0x8114} -> 0000: 00  */
+       {0x0000, 0x8114},       /* SW GPIO data */
+       {0x0008, 0x8110},       /* Enable charge pump output */
+       {0x0002, 0x8116},       /* 200 kHz pump clock */
+       /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE:) */
+       {0x0003, 0x8111},       /* Reset compression & memory */
+       {0x0000, 0x8111},       /* Normal mode (not reset) */
+       {0x0098, 0x8110},
+               /* Enable charge pump output, sync.serial,external 2x clock */
+       {0x000d, 0x8114},       /* SW GPIO data */
+       {0x0002, 0x8116},       /* 200 kHz pump clock */
+       {0x0020, 0x8112},       /* Video drop enable, ISO streaming disable */
 /* --------------------------------------- */
-       /* 44740  1819 */ {0x000f, 0x8402},
-       /* memory bank */
-       /* 44765  1820 */ {0x0000, 0x8403},
-       /* ... address */
+       {0x000f, 0x8402},       /* memory bank */
+       {0x0000, 0x8403},       /* ... address */
 /* --------------------------------------- */
 /* 0x88__ is Synchronous Serial Interface. */
 /* TBD: This table could be expressed more compactly */
@@ -145,446 +121,384 @@ static const u16 spca508_init_data[][2] =
 /* TBD: Should see if the values in spca50x_i2c_data */
 /* would work with the VQ110 instead of the values */
 /* below. */
-       /* 44790  1821 */ {0x00c0, 0x8804},
-       /* SSI slave addr */
-       /* 44815  1822 */ {0x0008, 0x8802},
-       /* 375 Khz SSI clock */
-       /* 44838  1823 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 44862  1824 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 44888  1825 */ {0x0008, 0x8802},
-       /* 375 Khz SSI clock */
-       /* 44913  1826 */ {0x0012, 0x8801},
-       /* SSI reg addr */
-       /* 44938  1827 */ {0x0080, 0x8800},
-       /* SSI data to write */
-       /* 44961  1828 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 44985  1829 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45009  1830 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 45035  1831 */ {0x0008, 0x8802},
-       /* 375 Khz SSI clock */
-       /* 45060  1832 */ {0x0012, 0x8801},
-       /* SSI reg addr */
-       /* 45085  1833 */ {0x0000, 0x8800},
-       /* SSI data to write */
-       /* 45108  1834 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45132  1835 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45156  1836 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 45182  1837 */ {0x0008, 0x8802},
-       /* 375 Khz SSI clock */
-       /* 45207  1838 */ {0x0011, 0x8801},
-       /* SSI reg addr */
-       /* 45232  1839 */ {0x0040, 0x8800},
-       /* SSI data to write */
-       /* 45255  1840 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45279  1841 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45303  1842 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 45329  1843 */ {0x0008, 0x8802},
-       /* 45354  1844 */ {0x0013, 0x8801},
-       /* 45379  1845 */ {0x0000, 0x8800},
-       /* 45402  1846 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45426  1847 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45450  1848 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 45476  1849 */ {0x0008, 0x8802},
-       /* 45501  1850 */ {0x0014, 0x8801},
-       /* 45526  1851 */ {0x0000, 0x8800},
-       /* 45549  1852 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45573  1853 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45597  1854 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 45623  1855 */ {0x0008, 0x8802},
-       /* 45648  1856 */ {0x0015, 0x8801},
-       /* 45673  1857 */ {0x0001, 0x8800},
-       /* 45696  1858 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45720  1859 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45744  1860 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 45770  1861 */ {0x0008, 0x8802},
-       /* 45795  1862 */ {0x0016, 0x8801},
-       /* 45820  1863 */ {0x0003, 0x8800},
-       /* 45843  1864 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45867  1865 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 45891  1866 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 45917  1867 */ {0x0008, 0x8802},
-       /* 45942  1868 */ {0x0017, 0x8801},
-       /* 45967  1869 */ {0x0036, 0x8800},
-       /* 45990  1870 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46014  1871 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46038  1872 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 46064  1873 */ {0x0008, 0x8802},
-       /* 46089  1874 */ {0x0018, 0x8801},
-       /* 46114  1875 */ {0x00ec, 0x8800},
-       /* 46137  1876 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46161  1877 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46185  1878 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 46211  1879 */ {0x0008, 0x8802},
-       /* 46236  1880 */ {0x001a, 0x8801},
-       /* 46261  1881 */ {0x0094, 0x8800},
-       /* 46284  1882 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46308  1883 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46332  1884 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 46358  1885 */ {0x0008, 0x8802},
-       /* 46383  1886 */ {0x001b, 0x8801},
-       /* 46408  1887 */ {0x0000, 0x8800},
-       /* 46431  1888 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46455  1889 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46479  1890 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 46505  1891 */ {0x0008, 0x8802},
-       /* 46530  1892 */ {0x0027, 0x8801},
-       /* 46555  1893 */ {0x00a2, 0x8800},
-       /* 46578  1894 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46602  1895 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46626  1896 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 46652  1897 */ {0x0008, 0x8802},
-       /* 46677  1898 */ {0x0028, 0x8801},
-       /* 46702  1899 */ {0x0040, 0x8800},
-       /* 46725  1900 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46749  1901 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46773  1902 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 46799  1903 */ {0x0008, 0x8802},
-       /* 46824  1904 */ {0x002a, 0x8801},
-       /* 46849  1905 */ {0x0084, 0x8800},
-       /* 46872  1906 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 46896  1907 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
-       /* 46920  1908 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 46946  1909 */ {0x0008, 0x8802},
-       /* 46971  1910 */ {0x002b, 0x8801},
-       /* 46996  1911 */ {0x00a8, 0x8800},
-       /* 47019  1912 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47043  1913 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47067  1914 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 47093  1915 */ {0x0008, 0x8802},
-       /* 47118  1916 */ {0x002c, 0x8801},
-       /* 47143  1917 */ {0x00fe, 0x8800},
-       /* 47166  1918 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47190  1919 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47214  1920 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 47240  1921 */ {0x0008, 0x8802},
-       /* 47265  1922 */ {0x002d, 0x8801},
-       /* 47290  1923 */ {0x0003, 0x8800},
-       /* 47313  1924 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47337  1925 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47361  1926 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 47387  1927 */ {0x0008, 0x8802},
-       /* 47412  1928 */ {0x0038, 0x8801},
-       /* 47437  1929 */ {0x0083, 0x8800},
-       /* 47460  1930 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47484  1931 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47508  1932 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 47534  1933 */ {0x0008, 0x8802},
-       /* 47559  1934 */ {0x0033, 0x8801},
-       /* 47584  1935 */ {0x0081, 0x8800},
-       /* 47607  1936 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47631  1937 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47655  1938 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 47681  1939 */ {0x0008, 0x8802},
-       /* 47706  1940 */ {0x0034, 0x8801},
-       /* 47731  1941 */ {0x004a, 0x8800},
-       /* 47754  1942 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47778  1943 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47802  1944 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 47828  1945 */ {0x0008, 0x8802},
-       /* 47853  1946 */ {0x0039, 0x8801},
-       /* 47878  1947 */ {0x0000, 0x8800},
-       /* 47901  1948 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47925  1949 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 47949  1950 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 47975  1951 */ {0x0008, 0x8802},
-       /* 48000  1952 */ {0x0010, 0x8801},
-       /* 48025  1953 */ {0x00a8, 0x8800},
-       /* 48048  1954 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48072  1955 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48096  1956 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 48122  1957 */ {0x0008, 0x8802},
-       /* 48147  1958 */ {0x0006, 0x8801},
-       /* 48172  1959 */ {0x0058, 0x8800},
-       /* 48195  1960 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48219  1961 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
-       /* 48243  1962 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 48269  1963 */ {0x0008, 0x8802},
-       /* 48294  1964 */ {0x0000, 0x8801},
-       /* 48319  1965 */ {0x0004, 0x8800},
-       /* 48342  1966 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48366  1967 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48390  1968 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 48416  1969 */ {0x0008, 0x8802},
-       /* 48441  1970 */ {0x0040, 0x8801},
-       /* 48466  1971 */ {0x0080, 0x8800},
-       /* 48489  1972 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48513  1973 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48537  1974 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 48563  1975 */ {0x0008, 0x8802},
-       /* 48588  1976 */ {0x0041, 0x8801},
-       /* 48613  1977 */ {0x000c, 0x8800},
-       /* 48636  1978 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48660  1979 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48684  1980 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 48710  1981 */ {0x0008, 0x8802},
-       /* 48735  1982 */ {0x0042, 0x8801},
-       /* 48760  1983 */ {0x000c, 0x8800},
-       /* 48783  1984 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48807  1985 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48831  1986 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 48857  1987 */ {0x0008, 0x8802},
-       /* 48882  1988 */ {0x0043, 0x8801},
-       /* 48907  1989 */ {0x0028, 0x8800},
-       /* 48930  1990 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48954  1991 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 48978  1992 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 49004  1993 */ {0x0008, 0x8802},
-       /* 49029  1994 */ {0x0044, 0x8801},
-       /* 49054  1995 */ {0x0080, 0x8800},
-       /* 49077  1996 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49101  1997 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49125  1998 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 49151  1999 */ {0x0008, 0x8802},
-       /* 49176  2000 */ {0x0045, 0x8801},
-       /* 49201  2001 */ {0x0020, 0x8800},
-       /* 49224  2002 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49248  2003 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49272  2004 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 49298  2005 */ {0x0008, 0x8802},
-       /* 49323  2006 */ {0x0046, 0x8801},
-       /* 49348  2007 */ {0x0020, 0x8800},
-       /* 49371  2008 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49395  2009 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49419  2010 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 49445  2011 */ {0x0008, 0x8802},
-       /* 49470  2012 */ {0x0047, 0x8801},
-       /* 49495  2013 */ {0x0080, 0x8800},
-       /* 49518  2014 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49542  2015 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49566  2016 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 49592  2017 */ {0x0008, 0x8802},
-       /* 49617  2018 */ {0x0048, 0x8801},
-       /* 49642  2019 */ {0x004c, 0x8800},
-       /* 49665  2020 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49689  2021 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49713  2022 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 49739  2023 */ {0x0008, 0x8802},
-       /* 49764  2024 */ {0x0049, 0x8801},
-       /* 49789  2025 */ {0x0084, 0x8800},
-       /* 49812  2026 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49836  2027 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49860  2028 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 49886  2029 */ {0x0008, 0x8802},
-       /* 49911  2030 */ {0x004a, 0x8801},
-       /* 49936  2031 */ {0x0084, 0x8800},
-       /* 49959  2032 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 49983  2033 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 50007  2034 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 50033  2035 */ {0x0008, 0x8802},
-       /* 50058  2036 */ {0x004b, 0x8801},
-       /* 50083  2037 */ {0x0084, 0x8800},
-       /* 50106  2038 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       {0x00c0, 0x8804},       /* SSI slave addr */
+       {0x0008, 0x8802},       /* 375 Khz SSI clock */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},       /* 375 Khz SSI clock */
+       {0x0012, 0x8801},       /* SSI reg addr */
+       {0x0080, 0x8800},       /* SSI data to write */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},       /* 375 Khz SSI clock */
+       {0x0012, 0x8801},       /* SSI reg addr */
+       {0x0000, 0x8800},       /* SSI data to write */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},       /* 375 Khz SSI clock */
+       {0x0011, 0x8801},       /* SSI reg addr */
+       {0x0040, 0x8800},       /* SSI data to write */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0013, 0x8801},
+       {0x0000, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0014, 0x8801},
+       {0x0000, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0015, 0x8801},
+       {0x0001, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0016, 0x8801},
+       {0x0003, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0017, 0x8801},
+       {0x0036, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0018, 0x8801},
+       {0x00ec, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x001a, 0x8801},
+       {0x0094, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x001b, 0x8801},
+       {0x0000, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0027, 0x8801},
+       {0x00a2, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0028, 0x8801},
+       {0x0040, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x002a, 0x8801},
+       {0x0084, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x002b, 0x8801},
+       {0x00a8, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x002c, 0x8801},
+       {0x00fe, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x002d, 0x8801},
+       {0x0003, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0038, 0x8801},
+       {0x0083, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0033, 0x8801},
+       {0x0081, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0034, 0x8801},
+       {0x004a, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0039, 0x8801},
+       {0x0000, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0010, 0x8801},
+       {0x00a8, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0006, 0x8801},
+       {0x0058, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0000, 0x8801},
+       {0x0004, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0040, 0x8801},
+       {0x0080, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0041, 0x8801},
+       {0x000c, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0042, 0x8801},
+       {0x000c, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0043, 0x8801},
+       {0x0028, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0044, 0x8801},
+       {0x0080, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0045, 0x8801},
+       {0x0020, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0046, 0x8801},
+       {0x0020, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0047, 0x8801},
+       {0x0080, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0048, 0x8801},
+       {0x004c, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x0049, 0x8801},
+       {0x0084, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x004a, 0x8801},
+       {0x0084, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x0008, 0x8802},
+       {0x004b, 0x8801},
+       {0x0084, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
        /* --------------------------------------- */
-       /* 50132  2039 */ {0x0012, 0x8700},
-       /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
-       /* 50157  2040 */ {0x0000, 0x8701},
-       /* CKx1 clock delay adj */
-       /* 50182  2041 */ {0x0000, 0x8701},
-       /* CKx1 clock delay adj */
-       /* 50207  2042 */ {0x0001, 0x870c},
-       /* CKOx2 output */
+       {0x0012, 0x8700},       /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+       {0x0000, 0x8701},       /* CKx1 clock delay adj */
+       {0x0000, 0x8701},       /* CKx1 clock delay adj */
+       {0x0001, 0x870c},       /* CKOx2 output */
        /* --------------------------------------- */
-       /* 50232  2043 */ {0x0080, 0x8600},
-       /* Line memory read counter (L) */
-       /* 50257  2044 */ {0x0001, 0x8606},
-       /* reserved */
-       /* 50282  2045 */ {0x0064, 0x8607},
-       /* Line memory read counter (H) 0x6480=25,728 */
-       /* 50307  2046 */ {0x002a, 0x8601},
-       /* CDSP sharp interpolation mode,
+       {0x0080, 0x8600},       /* Line memory read counter (L) */
+       {0x0001, 0x8606},       /* reserved */
+       {0x0064, 0x8607},       /* Line memory read counter (H) 0x6480=25,728 */
+       {0x002a, 0x8601},       /* CDSP sharp interpolation mode,
         *                      line sel for color sep, edge enhance enab */
-       /* 50332  2047 */ {0x0000, 0x8602},
-       /* optical black level for user settng = 0 */
-       /* 50357  2048 */ {0x0080, 0x8600},
-       /* Line memory read counter (L) */
-       /* 50382  2049 */ {0x000a, 0x8603},
-       /* optical black level calc mode: auto; optical black offset = 10 */
-       /* 50407  2050 */ {0x00df, 0x865b},
-       /* Horiz offset for valid pixels (L)=0xdf */
-       /* 50432  2051 */ {0x0012, 0x865c},
-       /* Vert offset for valid lines (L)=0x12 */
+       {0x0000, 0x8602},       /* optical black level for user settng = 0 */
+       {0x0080, 0x8600},       /* Line memory read counter (L) */
+       {0x000a, 0x8603},       /* optical black level calc mode:
+                                * auto; optical black offset = 10 */
+       {0x00df, 0x865b},       /* Horiz offset for valid pixels (L)=0xdf */
+       {0x0012, 0x865c},       /* Vert offset for valid lines (L)=0x12 */
 
 /* The following two lines seem to be the "wrong" resolution. */
 /* But perhaps these indicate the actual size of the sensor */
 /* rather than the size of the current video mode. */
-       /* 50457  2052 */ {0x0058, 0x865d},
-       /* Horiz valid pixels (*4) (L) = 352 */
-       /* 50482  2053 */ {0x0048, 0x865e},
-       /* Vert valid lines (*4) (L) = 288 */
-
-       /* 50507  2054 */ {0x0015, 0x8608},
-       /* A11 Coef ... */
-       /* 50532  2055 */ {0x0030, 0x8609},
-       /* 50557  2056 */ {0x00fb, 0x860a},
-       /* 50582  2057 */ {0x003e, 0x860b},
-       /* 50607  2058 */ {0x00ce, 0x860c},
-       /* 50632  2059 */ {0x00f4, 0x860d},
-       /* 50657  2060 */ {0x00eb, 0x860e},
-       /* 50682  2061 */ {0x00dc, 0x860f},
-       /* 50707  2062 */ {0x0039, 0x8610},
-       /* 50732  2063 */ {0x0001, 0x8611},
-       /* R offset for white balance ... */
-       /* 50757  2064 */ {0x0000, 0x8612},
-       /* 50782  2065 */ {0x0001, 0x8613},
-       /* 50807  2066 */ {0x0000, 0x8614},
-       /* 50832  2067 */ {0x005b, 0x8651},
-       /* R gain for white balance ... */
-       /* 50857  2068 */ {0x0040, 0x8652},
-       /* 50882  2069 */ {0x0060, 0x8653},
-       /* 50907  2070 */ {0x0040, 0x8654},
-       /* 50932  2071 */ {0x0000, 0x8655},
-       /* 50957  2072 */ {0x0001, 0x863f},
-       /* Fixed gamma correction enable, USB control,
-        *                       lum filter disable, lum noise clip disable */
-       /* 50982  2073 */ {0x00a1, 0x8656},
-       /* Window1 size 256x256, Windows2 size 64x64,
-        *               gamma look-up disable, new edge enhancement enable */
-       /* 51007  2074 */ {0x0018, 0x8657},
-       /* Edge gain high thresh */
-       /* 51032  2075 */ {0x0020, 0x8658},
-       /* Edge gain low thresh */
-       /* 51057  2076 */ {0x000a, 0x8659},
-       /* Edge bandwidth high threshold */
-       /* 51082  2077 */ {0x0005, 0x865a},
-       /* Edge bandwidth low threshold */
+       {0x0058, 0x865d},       /* Horiz valid pixels (*4) (L) = 352 */
+       {0x0048, 0x865e},       /* Vert valid lines (*4) (L) = 288 */
+
+       {0x0015, 0x8608},       /* A11 Coef ... */
+       {0x0030, 0x8609},
+       {0x00fb, 0x860a},
+       {0x003e, 0x860b},
+       {0x00ce, 0x860c},
+       {0x00f4, 0x860d},
+       {0x00eb, 0x860e},
+       {0x00dc, 0x860f},
+       {0x0039, 0x8610},
+       {0x0001, 0x8611},       /* R offset for white balance ... */
+       {0x0000, 0x8612},
+       {0x0001, 0x8613},
+       {0x0000, 0x8614},
+       {0x005b, 0x8651},       /* R gain for white balance ... */
+       {0x0040, 0x8652},
+       {0x0060, 0x8653},
+       {0x0040, 0x8654},
+       {0x0000, 0x8655},
+       {0x0001, 0x863f},       /* Fixed gamma correction enable, USB control,
+                                * lum filter disable, lum noise clip disable */
+       {0x00a1, 0x8656},       /* Window1 size 256x256, Windows2 size 64x64,
+                                * gamma look-up disable,
+                                * new edge enhancement enable */
+       {0x0018, 0x8657},       /* Edge gain high thresh */
+       {0x0020, 0x8658},       /* Edge gain low thresh */
+       {0x000a, 0x8659},       /* Edge bandwidth high threshold */
+       {0x0005, 0x865a},       /* Edge bandwidth low threshold */
        /* -------------------------------- */
-       /* 51107  2078 */ {0x0030, 0x8112},
-       /* Video drop enable, ISO streaming enable */
-       /* 51130  2079 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 51154  2080 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 51180  2081 */ {0xa908, 0x8802},
-       /* 51205  2082 */ {0x0034, 0x8801},
-       /* SSI reg addr */
-       /* 51230  2083 */ {0x00ca, 0x8800},
+       {0x0030, 0x8112},       /* Video drop enable, ISO streaming enable */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0xa908, 0x8802},
+       {0x0034, 0x8801},       /* SSI reg addr */
+       {0x00ca, 0x8800},
        /* SSI data to write */
-       /* 51253  2084 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 51277  2085 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 51301  2086 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 51327  2087 */ {0x1f08, 0x8802},
-       /* 51352  2088 */ {0x0006, 0x8801},
-       /* 51377  2089 */ {0x0080, 0x8800},
-       /* 51400  2090 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0x1f08, 0x8802},
+       {0x0006, 0x8801},
+       {0x0080, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
 /* ----- Read back coefs we wrote earlier. */
-       /* 51424  2091 */ /* READ { 0, 0x0000, 0x8608 } -> 0000: 15  */
-       /* 51448  2092 */ /* READ { 0, 0x0000, 0x8609 } -> 0000: 30  */
-       /* 51472  2093 */ /* READ { 0, 0x0000, 0x860a } -> 0000: fb  */
-       /* 51496  2094 */ /* READ { 0, 0x0000, 0x860b } -> 0000: 3e  */
-       /* 51520  2095 */ /* READ { 0, 0x0000, 0x860c } -> 0000: ce  */
-       /* 51544  2096 */ /* READ { 0, 0x0000, 0x860d } -> 0000: f4  */
-       /* 51568  2097 */ /* READ { 0, 0x0000, 0x860e } -> 0000: eb  */
-       /* 51592  2098 */ /* READ { 0, 0x0000, 0x860f } -> 0000: dc  */
-       /* 51616  2099 */ /* READ { 0, 0x0000, 0x8610 } -> 0000: 39  */
-       /* 51640  2100 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 51664  2101 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08  */
-       /* 51690  2102 */ {0xb008, 0x8802},
-       /* 51715  2103 */ {0x0006, 0x8801},
-       /* 51740  2104 */ {0x007d, 0x8800},
-       /* 51763  2105 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0000, 0x8608 } -> 0000: 15  */
+       /* READ { 0x0000, 0x8609 } -> 0000: 30  */
+       /* READ { 0x0000, 0x860a } -> 0000: fb  */
+       /* READ { 0x0000, 0x860b } -> 0000: 3e  */
+       /* READ { 0x0000, 0x860c } -> 0000: ce  */
+       /* READ { 0x0000, 0x860d } -> 0000: f4  */
+       /* READ { 0x0000, 0x860e } -> 0000: eb  */
+       /* READ { 0x0000, 0x860f } -> 0000: dc  */
+       /* READ { 0x0000, 0x8610 } -> 0000: 39  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 08  */
+       {0xb008, 0x8802},
+       {0x0006, 0x8801},
+       {0x007d, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
 
        /* This chunk is seemingly redundant with */
        /* earlier commands (A11 Coef...), but if I disable it, */
        /* the image appears too dark.  Maybe there was some kind of */
        /* reset since the earlier commands, so this is necessary again. */
-       /* 51789  2106 */ {0x0015, 0x8608},
-       /* 51814  2107 */ {0x0030, 0x8609},
-       /* 51839  2108 */ {0xfffb, 0x860a},
-       /* 51864  2109 */ {0x003e, 0x860b},
-       /* 51889  2110 */ {0xffce, 0x860c},
-       /* 51914  2111 */ {0xfff4, 0x860d},
-       /* 51939  2112 */ {0xffeb, 0x860e},
-       /* 51964  2113 */ {0xffdc, 0x860f},
-       /* 51989  2114 */ {0x0039, 0x8610},
-       /* 52014  2115 */ {0x0018, 0x8657},
-
-       /* 52039  2116 */ {0x0000, 0x8508},
-       /* Disable compression. */
+       {0x0015, 0x8608},
+       {0x0030, 0x8609},
+       {0xfffb, 0x860a},
+       {0x003e, 0x860b},
+       {0xffce, 0x860c},
+       {0xfff4, 0x860d},
+       {0xffeb, 0x860e},
+       {0xffdc, 0x860f},
+       {0x0039, 0x8610},
+       {0x0018, 0x8657},
+
+       {0x0000, 0x8508},       /* Disable compression. */
        /* Previous line was:
-        * 52039  2116 *  { 0, 0x0021, 0x8508 },  * Enable compression. */
-       /* 52064  2117 */ {0x0032, 0x850b},
-       /* compression stuff */
-       /* 52089  2118 */ {0x0003, 0x8509},
-       /* compression stuff */
-       /* 52114  2119 */ {0x0011, 0x850a},
-       /* compression stuff */
-       /* 52139  2120 */ {0x0021, 0x850d},
-       /* compression stuff */
-       /* 52164  2121 */ {0x0010, 0x850c},
-       /* compression stuff */
-       /* 52189  2122 */ {0x0003, 0x8500},
-       /* *** Video mode: 160x120 */
-       /* 52214  2123 */ {0x0001, 0x8501},
-       /* Hardware-dominated snap control */
-       /* 52239  2124 */ {0x0061, 0x8656},
-       /* Window1 size 128x128, Windows2 size 128x128,
-        *              gamma look-up disable, new edge enhancement enable */
-       /* 52264  2125 */ {0x0018, 0x8617},
-       /* Window1 start X (*2) */
-       /* 52289  2126 */ {0x0008, 0x8618},
-       /* Window1 start Y (*2) */
-       /* 52314  2127 */ {0x0061, 0x8656},
-       /* Window1 size 128x128, Windows2 size 128x128,
-        *              gamma look-up disable, new edge enhancement enable */
-       /* 52339  2128 */ {0x0058, 0x8619},
-       /* Window2 start X (*2) */
-       /* 52364  2129 */ {0x0008, 0x861a},
-       /* Window2 start Y (*2) */
-       /* 52389  2130 */ {0x00ff, 0x8615},
-       /* High lum thresh for white balance */
-       /* 52414  2131 */ {0x0000, 0x8616},
-       /* Low lum thresh for white balance */
-       /* 52439  2132 */ {0x0012, 0x8700},
-       /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
-       /* 52464  2133 */ {0x0012, 0x8700},
-       /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
-       /* 52487  2134 */ /* READ { 0, 0x0000, 0x8656 } -> 0000: 61  */
-       /* 52513  2135 */ {0x0028, 0x8802},
-       /* 375 Khz SSI clock, SSI r/w sync with VSYNC */
-       /* 52536  2136 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 52560  2137 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28  */
-       /* 52586  2138 */ {0x1f28, 0x8802},
-       /* 375 Khz SSI clock, SSI r/w sync with VSYNC */
-       /* 52611  2139 */ {0x0010, 0x8801},
-       /* SSI reg addr */
-       /* 52636  2140 */ {0x003e, 0x8800},
-       /* SSI data to write */
-       /* 52659  2141 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 52685  2142 */ {0x0028, 0x8802},
-       /* 52708  2143 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 52732  2144 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28  */
-       /* 52758  2145 */ {0x1f28, 0x8802},
-       /* 52783  2146 */ {0x0000, 0x8801},
-       /* 52808  2147 */ {0x001f, 0x8800},
-       /* 52831  2148 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 52857  2149 */ {0x0001, 0x8602},
-       /* optical black level for user settning = 1 */
+       {0x0021, 0x8508},        * Enable compression. */
+       {0x0032, 0x850b},       /* compression stuff */
+       {0x0003, 0x8509},       /* compression stuff */
+       {0x0011, 0x850a},       /* compression stuff */
+       {0x0021, 0x850d},       /* compression stuff */
+       {0x0010, 0x850c},       /* compression stuff */
+       {0x0003, 0x8500},       /* *** Video mode: 160x120 */
+       {0x0001, 0x8501},       /* Hardware-dominated snap control */
+       {0x0061, 0x8656},       /* Window1 size 128x128, Windows2 size 128x128,
+                                * gamma look-up disable,
+                                * new edge enhancement enable */
+       {0x0018, 0x8617},       /* Window1 start X (*2) */
+       {0x0008, 0x8618},       /* Window1 start Y (*2) */
+       {0x0061, 0x8656},       /* Window1 size 128x128, Windows2 size 128x128,
+                                * gamma look-up disable,
+                                * new edge enhancement enable */
+       {0x0058, 0x8619},       /* Window2 start X (*2) */
+       {0x0008, 0x861a},       /* Window2 start Y (*2) */
+       {0x00ff, 0x8615},       /* High lum thresh for white balance */
+       {0x0000, 0x8616},       /* Low lum thresh for white balance */
+       {0x0012, 0x8700},       /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+       {0x0012, 0x8700},       /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+       /* READ { 0x0000, 0x8656 } -> 0000: 61  */
+       {0x0028, 0x8802},    /* 375 Khz SSI clock, SSI r/w sync with VSYNC */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 28  */
+       {0x1f28, 0x8802},    /* 375 Khz SSI clock, SSI r/w sync with VSYNC */
+       {0x0010, 0x8801},       /* SSI reg addr */
+       {0x003e, 0x8800},       /* SSI data to write */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       {0x0028, 0x8802},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 28  */
+       {0x1f28, 0x8802},
+       {0x0000, 0x8801},
+       {0x001f, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       {0x0001, 0x8602},    /* optical black level for user settning = 1 */
 
        /* Original: */
-       /* 52882  2150 */ {0x0023, 0x8700},
-       /* Clock speed 48Mhz/(3+2)/4= 2.4 Mhz */
-       /* 52907  2151 */ {0x000f, 0x8602},
-       /* optical black level for user settning = 15 */
-
-       /* 52932  2152 */ {0x0028, 0x8802},
-       /* 52955  2153 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 52979  2154 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28  */
-       /* 53005  2155 */ {0x1f28, 0x8802},
-       /* 53030  2156 */ {0x0010, 0x8801},
-       /* 53055  2157 */ {0x007b, 0x8800},
-       /* 53078  2158 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00  */
-       /* 53104  2159 */ {0x002f, 0x8651},
-       /* R gain for white balance ... */
-       /* 53129  2160 */ {0x0080, 0x8653},
-       /* 53152  2161 */ /* READ { 0, 0x0000, 0x8655 } -> 0000: 00  */
-       /* 53178  2162 */ {0x0000, 0x8655},
-
-       /* 53203  2163 */ {0x0030, 0x8112},
-       /* Video drop enable, ISO streaming enable */
-       /* 53228  2164 */ {0x0020, 0x8112},
-       /* Video drop enable, ISO streaming disable */
-       /* 53252  2165 */
-            /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE: (ALT=0) ) */
+       {0x0023, 0x8700},       /* Clock speed 48Mhz/(3+2)/4= 2.4 Mhz */
+       {0x000f, 0x8602},    /* optical black level for user settning = 15 */
+
+       {0x0028, 0x8802},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 28  */
+       {0x1f28, 0x8802},
+       {0x0010, 0x8801},
+       {0x007b, 0x8800},
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       {0x002f, 0x8651},       /* R gain for white balance ... */
+       {0x0080, 0x8653},
+       /* READ { 0x0000, 0x8655 } -> 0000: 00  */
+       {0x0000, 0x8655},
+
+       {0x0030, 0x8112},       /* Video drop enable, ISO streaming enable */
+       {0x0020, 0x8112},       /* Video drop enable, ISO streaming disable */
+       /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE: (ALT=0) ) */
        {}
 };
 
@@ -592,27 +506,27 @@ static const u16 spca508_init_data[][2] =
  * Initialization data for Intel EasyPC Camera CS110
  */
 static const u16 spca508cs110_init_data[][2] = {
-       {0x0000, 0x870b}, /* Reset CTL3 */
-       {0x0003, 0x8111}, /* Soft Reset compression, memory, TG & CDSP */
-       {0x0000, 0x8111}, /* Normal operation on reset */
+       {0x0000, 0x870b},       /* Reset CTL3 */
+       {0x0003, 0x8111},       /* Soft Reset compression, memory, TG & CDSP */
+       {0x0000, 0x8111},       /* Normal operation on reset */
        {0x0090, 0x8110},
                 /* External Clock 2x & Synchronous Serial Interface Output */
-       {0x0020, 0x8112}, /* Video Drop packet enable */
-       {0x0000, 0x8114}, /* Software GPIO output data */
+       {0x0020, 0x8112},       /* Video Drop packet enable */
+       {0x0000, 0x8114},       /* Software GPIO output data */
        {0x0001, 0x8114},
        {0x0001, 0x8114},
        {0x0001, 0x8114},
        {0x0003, 0x8114},
 
        /* Initial sequence Synchronous Serial Interface */
-       {0x000f, 0x8402}, /* Memory bank Address */
-       {0x0000, 0x8403}, /* Memory bank Address */
-       {0x00ba, 0x8804}, /* SSI Slave address */
-       {0x0010, 0x8802}, /* 93.75kHz SSI Clock Two DataByte */
-       {0x0010, 0x8802}, /* 93.75kHz SSI Clock two DataByte */
+       {0x000f, 0x8402},       /* Memory bank Address */
+       {0x0000, 0x8403},       /* Memory bank Address */
+       {0x00ba, 0x8804},       /* SSI Slave address */
+       {0x0010, 0x8802},       /* 93.75kHz SSI Clock Two DataByte */
+       {0x0010, 0x8802},       /* 93.75kHz SSI Clock two DataByte */
 
        {0x0001, 0x8801},
-       {0x000a, 0x8805},/* a - NWG: Dunno what this is about */
+       {0x000a, 0x8805},       /* a - NWG: Dunno what this is about */
        {0x0000, 0x8800},
        {0x0010, 0x8802},
 
@@ -646,459 +560,459 @@ static const u16 spca508cs110_init_data[][2] = {
        {0x0000, 0x8800},
        {0x0010, 0x8802},
 
-       {0x0002, 0x8704}, /* External input CKIx1 */
-       {0x0001, 0x8606}, /* 1 Line memory Read Counter (H) Result: (d)410 */
-       {0x009a, 0x8600}, /* Line memory Read Counter (L) */
-       {0x0001, 0x865b}, /* 1 Horizontal Offset for Valid Pixel(L) */
-       {0x0003, 0x865c}, /* 3 Vertical Offset for Valid Lines(L) */
-       {0x0058, 0x865d}, /* 58 Horizontal Valid Pixel Window(L) */
+       {0x0002, 0x8704},       /* External input CKIx1 */
+       {0x0001, 0x8606},    /* 1 Line memory Read Counter (H) Result: (d)410 */
+       {0x009a, 0x8600},       /* Line memory Read Counter (L) */
+       {0x0001, 0x865b},       /* 1 Horizontal Offset for Valid Pixel(L) */
+       {0x0003, 0x865c},       /* 3 Vertical Offset for Valid Lines(L) */
+       {0x0058, 0x865d},       /* 58 Horizontal Valid Pixel Window(L) */
 
-       {0x0006, 0x8660}, /* Nibble data + input order */
+       {0x0006, 0x8660},       /* Nibble data + input order */
 
-       {0x000a, 0x8602}, /* Optical black level set to 0x0a */
-/* 1945 */ {0x0000, 0x8603}, /* Optical black level Offset */
+       {0x000a, 0x8602},       /* Optical black level set to 0x0a */
+       {0x0000, 0x8603},       /* Optical black level Offset */
 
-/* 1962 *  {0, 0x0000, 0x8611},  * 0 R  Offset for white Balance */
-/* 1963 *  {0, 0x0000, 0x8612},  * 1 Gr Offset for white Balance */
-/* 1964 *  {0, 0x0000, 0x8613},  * 1f B  Offset for white Balance */
-/* 1965 *  {0, 0x0000, 0x8614},  * f0 Gb Offset for white Balance */
+/*     {0x0000, 0x8611},        * 0 R  Offset for white Balance */
+/*     {0x0000, 0x8612},        * 1 Gr Offset for white Balance */
+/*     {0x0000, 0x8613},        * 1f B  Offset for white Balance */
+/*     {0x0000, 0x8614},        * f0 Gb Offset for white Balance */
 
-       {0x0040, 0x8651}, /* 2b BLUE gain for white balance  good at all 60 */
-       {0x0030, 0x8652}, /* 41 Gr Gain for white Balance (L) */
-       {0x0035, 0x8653}, /* 26 RED gain for white balance */
-       {0x0035, 0x8654}, /* 40Gb Gain for white Balance (L) */
+       {0x0040, 0x8651},   /* 2b BLUE gain for white balance  good at all 60 */
+       {0x0030, 0x8652},       /* 41 Gr Gain for white Balance (L) */
+       {0x0035, 0x8653},       /* 26 RED gain for white balance */
+       {0x0035, 0x8654},       /* 40Gb Gain for white Balance (L) */
        {0x0041, 0x863f},
              /* Fixed Gamma correction enabled (makes colours look better) */
 
-/* 2422 */ {0x0000, 0x8655},
-       /* High bits for white balance*****brightness control*** */
+       {0x0000, 0x8655},
+               /* High bits for white balance*****brightness control*** */
        {}
 };
 
 static const u16 spca508_sightcam_init_data[][2] = {
 /* This line seems to setup the frame/canvas */
-       /*368  */ {0x000f, 0x8402},
+       {0x000f, 0x8402},
 
 /* Theese 6 lines are needed to startup the webcam */
-       /*398  */ {0x0090, 0x8110},
-       /*399  */ {0x0001, 0x8114},
-       /*400  */ {0x0001, 0x8114},
-       /*401  */ {0x0001, 0x8114},
-       /*402  */ {0x0003, 0x8114},
-       /*403  */ {0x0080, 0x8804},
+       {0x0090, 0x8110},
+       {0x0001, 0x8114},
+       {0x0001, 0x8114},
+       {0x0001, 0x8114},
+       {0x0003, 0x8114},
+       {0x0080, 0x8804},
 
 /* This part seems to make the pictures darker? (autobrightness?) */
-       /*436  */ {0x0001, 0x8801},
-       /*437  */ {0x0004, 0x8800},
-       /*439  */ {0x0003, 0x8801},
-       /*440  */ {0x00e0, 0x8800},
-       /*442  */ {0x0004, 0x8801},
-       /*443  */ {0x00b4, 0x8800},
-       /*445  */ {0x0005, 0x8801},
-       /*446  */ {0x0000, 0x8800},
-
-       /*448  */ {0x0006, 0x8801},
-       /*449  */ {0x00e0, 0x8800},
-       /*451  */ {0x0007, 0x8801},
-       /*452  */ {0x000c, 0x8800},
+       {0x0001, 0x8801},
+       {0x0004, 0x8800},
+       {0x0003, 0x8801},
+       {0x00e0, 0x8800},
+       {0x0004, 0x8801},
+       {0x00b4, 0x8800},
+       {0x0005, 0x8801},
+       {0x0000, 0x8800},
+
+       {0x0006, 0x8801},
+       {0x00e0, 0x8800},
+       {0x0007, 0x8801},
+       {0x000c, 0x8800},
 
 /* This section is just needed, it probably
  * does something like the previous section,
  * but the cam won't start if it's not included.
  */
-       /*484  */ {0x0014, 0x8801},
-       /*485  */ {0x0008, 0x8800},
-       /*487  */ {0x0015, 0x8801},
-       /*488  */ {0x0067, 0x8800},
-       /*490  */ {0x0016, 0x8801},
-       /*491  */ {0x0000, 0x8800},
-       /*493  */ {0x0017, 0x8801},
-       /*494  */ {0x0020, 0x8800},
-       /*496  */ {0x0018, 0x8801},
-       /*497  */ {0x0044, 0x8800},
+       {0x0014, 0x8801},
+       {0x0008, 0x8800},
+       {0x0015, 0x8801},
+       {0x0067, 0x8800},
+       {0x0016, 0x8801},
+       {0x0000, 0x8800},
+       {0x0017, 0x8801},
+       {0x0020, 0x8800},
+       {0x0018, 0x8801},
+       {0x0044, 0x8800},
 
 /* Makes the picture darker - and the
  * cam won't start if not included
  */
-       /*505  */ {0x001e, 0x8801},
-       /*506  */ {0x00ea, 0x8800},
-       /*508  */ {0x001f, 0x8801},
-       /*509  */ {0x0001, 0x8800},
-       /*511  */ {0x0003, 0x8801},
-       /*512  */ {0x00e0, 0x8800},
+       {0x001e, 0x8801},
+       {0x00ea, 0x8800},
+       {0x001f, 0x8801},
+       {0x0001, 0x8800},
+       {0x0003, 0x8801},
+       {0x00e0, 0x8800},
 
 /* seems to place the colors ontop of each other #1 */
-       /*517  */ {0x0006, 0x8704},
-       /*518  */ {0x0001, 0x870c},
-       /*519  */ {0x0016, 0x8600},
-       /*520  */ {0x0002, 0x8606},
+       {0x0006, 0x8704},
+       {0x0001, 0x870c},
+       {0x0016, 0x8600},
+       {0x0002, 0x8606},
 
 /* if not included the pictures becomes _very_ dark */
-       /*521  */ {0x0064, 0x8607},
-       /*522  */ {0x003a, 0x8601},
-       /*523  */ {0x0000, 0x8602},
+       {0x0064, 0x8607},
+       {0x003a, 0x8601},
+       {0x0000, 0x8602},
 
 /* seems to place the colors ontop of each other #2 */
-       /*524  */ {0x0016, 0x8600},
-       /*525  */ {0x0018, 0x8617},
-       /*526  */ {0x0008, 0x8618},
-       /*527  */ {0x00a1, 0x8656},
+       {0x0016, 0x8600},
+       {0x0018, 0x8617},
+       {0x0008, 0x8618},
+       {0x00a1, 0x8656},
 
 /* webcam won't start if not included */
-       /*528  */ {0x0007, 0x865b},
-       /*529  */ {0x0001, 0x865c},
-       /*530  */ {0x0058, 0x865d},
-       /*531  */ {0x0048, 0x865e},
+       {0x0007, 0x865b},
+       {0x0001, 0x865c},
+       {0x0058, 0x865d},
+       {0x0048, 0x865e},
 
 /* adjusts the colors */
-       /*541  */ {0x0049, 0x8651},
-       /*542  */ {0x0040, 0x8652},
-       /*543  */ {0x004c, 0x8653},
-       /*544  */ {0x0040, 0x8654},
+       {0x0049, 0x8651},
+       {0x0040, 0x8652},
+       {0x004c, 0x8653},
+       {0x0040, 0x8654},
        {}
 };
 
 static const u16 spca508_sightcam2_init_data[][2] = {
-/* 35 */ {0x0020, 0x8112},
-
-/* 36 */ {0x000f, 0x8402},
-/* 37 */ {0x0000, 0x8403},
-
-/* 38 */ {0x0008, 0x8201},
-/* 39 */ {0x0008, 0x8200},
-/* 40 */ {0x0001, 0x8200},
-/* 43 */ {0x0009, 0x8201},
-/* 44 */ {0x0008, 0x8200},
-/* 45 */ {0x0001, 0x8200},
-/* 48 */ {0x000a, 0x8201},
-/* 49 */ {0x0008, 0x8200},
-/* 50 */ {0x0001, 0x8200},
-/* 53 */ {0x000b, 0x8201},
-/* 54 */ {0x0008, 0x8200},
-/* 55 */ {0x0001, 0x8200},
-/* 58 */ {0x000c, 0x8201},
-/* 59 */ {0x0008, 0x8200},
-/* 60 */ {0x0001, 0x8200},
-/* 63 */ {0x000d, 0x8201},
-/* 64 */ {0x0008, 0x8200},
-/* 65 */ {0x0001, 0x8200},
-/* 68 */ {0x000e, 0x8201},
-/* 69 */ {0x0008, 0x8200},
-/* 70 */ {0x0001, 0x8200},
-/* 73 */ {0x0007, 0x8201},
-/* 74 */ {0x0008, 0x8200},
-/* 75 */ {0x0001, 0x8200},
-/* 78 */ {0x000f, 0x8201},
-/* 79 */ {0x0008, 0x8200},
-/* 80 */ {0x0001, 0x8200},
-
-/* 84 */ {0x0018, 0x8660},
-/* 85 */ {0x0010, 0x8201},
-
-/* 86 */ {0x0008, 0x8200},
-/* 87 */ {0x0001, 0x8200},
-/* 90 */ {0x0011, 0x8201},
-/* 91 */ {0x0008, 0x8200},
-/* 92 */ {0x0001, 0x8200},
-
-/* 95 */ {0x0000, 0x86b0},
-/* 96 */ {0x0034, 0x86b1},
-/* 97 */ {0x0000, 0x86b2},
-/* 98 */ {0x0049, 0x86b3},
-/* 99 */ {0x0000, 0x86b4},
-/* 100 */ {0x0000, 0x86b4},
-
-/* 101 */ {0x0012, 0x8201},
-/* 102 */ {0x0008, 0x8200},
-/* 103 */ {0x0001, 0x8200},
-/* 106 */ {0x0013, 0x8201},
-/* 107 */ {0x0008, 0x8200},
-/* 108 */ {0x0001, 0x8200},
-
-/* 111 */ {0x0001, 0x86b0},
-/* 112 */ {0x00aa, 0x86b1},
-/* 113 */ {0x0000, 0x86b2},
-/* 114 */ {0x00e4, 0x86b3},
-/* 115 */ {0x0000, 0x86b4},
-/* 116 */ {0x0000, 0x86b4},
-
-/* 118 */ {0x0018, 0x8660},
-
-/* 119 */ {0x0090, 0x8110},
-/* 120 */ {0x0001, 0x8114},
-/* 121 */ {0x0001, 0x8114},
-/* 122 */ {0x0001, 0x8114},
-/* 123 */ {0x0003, 0x8114},
-
-/* 124 */ {0x0080, 0x8804},
-/* 157 */ {0x0003, 0x8801},
-/* 158 */ {0x0012, 0x8800},
-/* 160 */ {0x0004, 0x8801},
-/* 161 */ {0x0005, 0x8800},
-/* 163 */ {0x0005, 0x8801},
-/* 164 */ {0x0000, 0x8800},
-/* 166 */ {0x0006, 0x8801},
-/* 167 */ {0x0000, 0x8800},
-/* 169 */ {0x0007, 0x8801},
-/* 170 */ {0x0000, 0x8800},
-/* 172 */ {0x0008, 0x8801},
-/* 173 */ {0x0005, 0x8800},
-/* 175 */ {0x000a, 0x8700},
-/* 176 */ {0x000e, 0x8801},
-/* 177 */ {0x0004, 0x8800},
-/* 179 */ {0x0005, 0x8801},
-/* 180 */ {0x0047, 0x8800},
-/* 182 */ {0x0006, 0x8801},
-/* 183 */ {0x0000, 0x8800},
-/* 185 */ {0x0007, 0x8801},
-/* 186 */ {0x00c0, 0x8800},
-/* 188 */ {0x0008, 0x8801},
-/* 189 */ {0x0003, 0x8800},
-/* 191 */ {0x0013, 0x8801},
-/* 192 */ {0x0001, 0x8800},
-/* 194 */ {0x0009, 0x8801},
-/* 195 */ {0x0000, 0x8800},
-/* 197 */ {0x000a, 0x8801},
-/* 198 */ {0x0000, 0x8800},
-/* 200 */ {0x000b, 0x8801},
-/* 201 */ {0x0000, 0x8800},
-/* 203 */ {0x000c, 0x8801},
-/* 204 */ {0x0000, 0x8800},
-/* 206 */ {0x000e, 0x8801},
-/* 207 */ {0x0004, 0x8800},
-/* 209 */ {0x000f, 0x8801},
-/* 210 */ {0x0000, 0x8800},
-/* 212 */ {0x0010, 0x8801},
-/* 213 */ {0x0006, 0x8800},
-/* 215 */ {0x0011, 0x8801},
-/* 216 */ {0x0006, 0x8800},
-/* 218 */ {0x0012, 0x8801},
-/* 219 */ {0x0000, 0x8800},
-/* 221 */ {0x0013, 0x8801},
-/* 222 */ {0x0001, 0x8800},
-
-/* 224 */ {0x000a, 0x8700},
-/* 225 */ {0x0000, 0x8702},
-/* 226 */ {0x0000, 0x8703},
-/* 227 */ {0x00c2, 0x8704},
-/* 228 */ {0x0001, 0x870c},
-
-/* 229 */ {0x0044, 0x8600},
-/* 230 */ {0x0002, 0x8606},
-/* 231 */ {0x0064, 0x8607},
-/* 232 */ {0x003a, 0x8601},
-/* 233 */ {0x0008, 0x8602},
-/* 234 */ {0x0044, 0x8600},
-/* 235 */ {0x0018, 0x8617},
-/* 236 */ {0x0008, 0x8618},
-/* 237 */ {0x00a1, 0x8656},
-/* 238 */ {0x0004, 0x865b},
-/* 239 */ {0x0002, 0x865c},
-/* 240 */ {0x0058, 0x865d},
-/* 241 */ {0x0048, 0x865e},
-/* 242 */ {0x0012, 0x8608},
-/* 243 */ {0x002c, 0x8609},
-/* 244 */ {0x0002, 0x860a},
-/* 245 */ {0x002c, 0x860b},
-/* 246 */ {0x00db, 0x860c},
-/* 247 */ {0x00f9, 0x860d},
-/* 248 */ {0x00f1, 0x860e},
-/* 249 */ {0x00e3, 0x860f},
-/* 250 */ {0x002c, 0x8610},
-/* 251 */ {0x006c, 0x8651},
-/* 252 */ {0x0041, 0x8652},
-/* 253 */ {0x0059, 0x8653},
-/* 254 */ {0x0040, 0x8654},
-/* 255 */ {0x00fa, 0x8611},
-/* 256 */ {0x00ff, 0x8612},
-/* 257 */ {0x00f8, 0x8613},
-/* 258 */ {0x0000, 0x8614},
-/* 259 */ {0x0001, 0x863f},
-/* 260 */ {0x0000, 0x8640},
-/* 261 */ {0x0026, 0x8641},
-/* 262 */ {0x0045, 0x8642},
-/* 263 */ {0x0060, 0x8643},
-/* 264 */ {0x0075, 0x8644},
-/* 265 */ {0x0088, 0x8645},
-/* 266 */ {0x009b, 0x8646},
-/* 267 */ {0x00b0, 0x8647},
-/* 268 */ {0x00c5, 0x8648},
-/* 269 */ {0x00d2, 0x8649},
-/* 270 */ {0x00dc, 0x864a},
-/* 271 */ {0x00e5, 0x864b},
-/* 272 */ {0x00eb, 0x864c},
-/* 273 */ {0x00f0, 0x864d},
-/* 274 */ {0x00f6, 0x864e},
-/* 275 */ {0x00fa, 0x864f},
-/* 276 */ {0x00ff, 0x8650},
-/* 277 */ {0x0060, 0x8657},
-/* 278 */ {0x0010, 0x8658},
-/* 279 */ {0x0018, 0x8659},
-/* 280 */ {0x0005, 0x865a},
-/* 281 */ {0x0018, 0x8660},
-/* 282 */ {0x0003, 0x8509},
-/* 283 */ {0x0011, 0x850a},
-/* 284 */ {0x0032, 0x850b},
-/* 285 */ {0x0010, 0x850c},
-/* 286 */ {0x0021, 0x850d},
-/* 287 */ {0x0001, 0x8500},
-/* 288 */ {0x0000, 0x8508},
-/* 289 */ {0x0012, 0x8608},
-/* 290 */ {0x002c, 0x8609},
-/* 291 */ {0x0002, 0x860a},
-/* 292 */ {0x0039, 0x860b},
-/* 293 */ {0x00d0, 0x860c},
-/* 294 */ {0x00f7, 0x860d},
-/* 295 */ {0x00ed, 0x860e},
-/* 296 */ {0x00db, 0x860f},
-/* 297 */ {0x0039, 0x8610},
-/* 298 */ {0x0012, 0x8657},
-/* 299 */ {0x000c, 0x8619},
-/* 300 */ {0x0004, 0x861a},
-/* 301 */ {0x00a1, 0x8656},
-/* 302 */ {0x00c8, 0x8615},
-/* 303 */ {0x0032, 0x8616},
-
-/* 306 */ {0x0030, 0x8112},
-/* 313 */ {0x0020, 0x8112},
-/* 314 */ {0x0020, 0x8112},
-/* 315 */ {0x000f, 0x8402},
-/* 316 */ {0x0000, 0x8403},
-
-/* 317 */ {0x0090, 0x8110},
-/* 318 */ {0x0001, 0x8114},
-/* 319 */ {0x0001, 0x8114},
-/* 320 */ {0x0001, 0x8114},
-/* 321 */ {0x0003, 0x8114},
-/* 322 */ {0x0080, 0x8804},
-
-/* 355 */ {0x0003, 0x8801},
-/* 356 */ {0x0012, 0x8800},
-/* 358 */ {0x0004, 0x8801},
-/* 359 */ {0x0005, 0x8800},
-/* 361 */ {0x0005, 0x8801},
-/* 362 */ {0x0047, 0x8800},
-/* 364 */ {0x0006, 0x8801},
-/* 365 */ {0x0000, 0x8800},
-/* 367 */ {0x0007, 0x8801},
-/* 368 */ {0x00c0, 0x8800},
-/* 370 */ {0x0008, 0x8801},
-/* 371 */ {0x0003, 0x8800},
-/* 373 */ {0x000a, 0x8700},
-/* 374 */ {0x000e, 0x8801},
-/* 375 */ {0x0004, 0x8800},
-/* 377 */ {0x0005, 0x8801},
-/* 378 */ {0x0047, 0x8800},
-/* 380 */ {0x0006, 0x8801},
-/* 381 */ {0x0000, 0x8800},
-/* 383 */ {0x0007, 0x8801},
-/* 384 */ {0x00c0, 0x8800},
-/* 386 */ {0x0008, 0x8801},
-/* 387 */ {0x0003, 0x8800},
-/* 389 */ {0x0013, 0x8801},
-/* 390 */ {0x0001, 0x8800},
-/* 392 */ {0x0009, 0x8801},
-/* 393 */ {0x0000, 0x8800},
-/* 395 */ {0x000a, 0x8801},
-/* 396 */ {0x0000, 0x8800},
-/* 398 */ {0x000b, 0x8801},
-/* 399 */ {0x0000, 0x8800},
-/* 401 */ {0x000c, 0x8801},
-/* 402 */ {0x0000, 0x8800},
-/* 404 */ {0x000e, 0x8801},
-/* 405 */ {0x0004, 0x8800},
-/* 407 */ {0x000f, 0x8801},
-/* 408 */ {0x0000, 0x8800},
-/* 410 */ {0x0010, 0x8801},
-/* 411 */ {0x0006, 0x8800},
-/* 413 */ {0x0011, 0x8801},
-/* 414 */ {0x0006, 0x8800},
-/* 416 */ {0x0012, 0x8801},
-/* 417 */ {0x0000, 0x8800},
-/* 419 */ {0x0013, 0x8801},
-/* 420 */ {0x0001, 0x8800},
-/* 422 */ {0x000a, 0x8700},
-/* 423 */ {0x0000, 0x8702},
-/* 424 */ {0x0000, 0x8703},
-/* 425 */ {0x00c2, 0x8704},
-/* 426 */ {0x0001, 0x870c},
-/* 427 */ {0x0044, 0x8600},
-/* 428 */ {0x0002, 0x8606},
-/* 429 */ {0x0064, 0x8607},
-/* 430 */ {0x003a, 0x8601},
-/* 431 */ {0x0008, 0x8602},
-/* 432 */ {0x0044, 0x8600},
-/* 433 */ {0x0018, 0x8617},
-/* 434 */ {0x0008, 0x8618},
-/* 435 */ {0x00a1, 0x8656},
-/* 436 */ {0x0004, 0x865b},
-/* 437 */ {0x0002, 0x865c},
-/* 438 */ {0x0058, 0x865d},
-/* 439 */ {0x0048, 0x865e},
-/* 440 */ {0x0012, 0x8608},
-/* 441 */ {0x002c, 0x8609},
-/* 442 */ {0x0002, 0x860a},
-/* 443 */ {0x002c, 0x860b},
-/* 444 */ {0x00db, 0x860c},
-/* 445 */ {0x00f9, 0x860d},
-/* 446 */ {0x00f1, 0x860e},
-/* 447 */ {0x00e3, 0x860f},
-/* 448 */ {0x002c, 0x8610},
-/* 449 */ {0x006c, 0x8651},
-/* 450 */ {0x0041, 0x8652},
-/* 451 */ {0x0059, 0x8653},
-/* 452 */ {0x0040, 0x8654},
-/* 453 */ {0x00fa, 0x8611},
-/* 454 */ {0x00ff, 0x8612},
-/* 455 */ {0x00f8, 0x8613},
-/* 456 */ {0x0000, 0x8614},
-/* 457 */ {0x0001, 0x863f},
-/* 458 */ {0x0000, 0x8640},
-/* 459 */ {0x0026, 0x8641},
-/* 460 */ {0x0045, 0x8642},
-/* 461 */ {0x0060, 0x8643},
-/* 462 */ {0x0075, 0x8644},
-/* 463 */ {0x0088, 0x8645},
-/* 464 */ {0x009b, 0x8646},
-/* 465 */ {0x00b0, 0x8647},
-/* 466 */ {0x00c5, 0x8648},
-/* 467 */ {0x00d2, 0x8649},
-/* 468 */ {0x00dc, 0x864a},
-/* 469 */ {0x00e5, 0x864b},
-/* 470 */ {0x00eb, 0x864c},
-/* 471 */ {0x00f0, 0x864d},
-/* 472 */ {0x00f6, 0x864e},
-/* 473 */ {0x00fa, 0x864f},
-/* 474 */ {0x00ff, 0x8650},
-/* 475 */ {0x0060, 0x8657},
-/* 476 */ {0x0010, 0x8658},
-/* 477 */ {0x0018, 0x8659},
-/* 478 */ {0x0005, 0x865a},
-/* 479 */ {0x0018, 0x8660},
-/* 480 */ {0x0003, 0x8509},
-/* 481 */ {0x0011, 0x850a},
-/* 482 */ {0x0032, 0x850b},
-/* 483 */ {0x0010, 0x850c},
-/* 484 */ {0x0021, 0x850d},
-/* 485 */ {0x0001, 0x8500},
-/* 486 */ {0x0000, 0x8508},
-
-/* 487 */ {0x0012, 0x8608},
-/* 488 */ {0x002c, 0x8609},
-/* 489 */ {0x0002, 0x860a},
-/* 490 */ {0x0039, 0x860b},
-/* 491 */ {0x00d0, 0x860c},
-/* 492 */ {0x00f7, 0x860d},
-/* 493 */ {0x00ed, 0x860e},
-/* 494 */ {0x00db, 0x860f},
-/* 495 */ {0x0039, 0x8610},
-/* 496 */ {0x0012, 0x8657},
-/* 497 */ {0x0064, 0x8619},
+       {0x0020, 0x8112},
+
+       {0x000f, 0x8402},
+       {0x0000, 0x8403},
+
+       {0x0008, 0x8201},
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+       {0x0009, 0x8201},
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+       {0x000a, 0x8201},
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+       {0x000b, 0x8201},
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+       {0x000c, 0x8201},
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+       {0x000d, 0x8201},
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+       {0x000e, 0x8201},
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+       {0x0007, 0x8201},
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+       {0x000f, 0x8201},
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+
+       {0x0018, 0x8660},
+       {0x0010, 0x8201},
+
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+       {0x0011, 0x8201},
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+
+       {0x0000, 0x86b0},
+       {0x0034, 0x86b1},
+       {0x0000, 0x86b2},
+       {0x0049, 0x86b3},
+       {0x0000, 0x86b4},
+       {0x0000, 0x86b4},
+
+       {0x0012, 0x8201},
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+       {0x0013, 0x8201},
+       {0x0008, 0x8200},
+       {0x0001, 0x8200},
+
+       {0x0001, 0x86b0},
+       {0x00aa, 0x86b1},
+       {0x0000, 0x86b2},
+       {0x00e4, 0x86b3},
+       {0x0000, 0x86b4},
+       {0x0000, 0x86b4},
+
+       {0x0018, 0x8660},
+
+       {0x0090, 0x8110},
+       {0x0001, 0x8114},
+       {0x0001, 0x8114},
+       {0x0001, 0x8114},
+       {0x0003, 0x8114},
+
+       {0x0080, 0x8804},
+       {0x0003, 0x8801},
+       {0x0012, 0x8800},
+       {0x0004, 0x8801},
+       {0x0005, 0x8800},
+       {0x0005, 0x8801},
+       {0x0000, 0x8800},
+       {0x0006, 0x8801},
+       {0x0000, 0x8800},
+       {0x0007, 0x8801},
+       {0x0000, 0x8800},
+       {0x0008, 0x8801},
+       {0x0005, 0x8800},
+       {0x000a, 0x8700},
+       {0x000e, 0x8801},
+       {0x0004, 0x8800},
+       {0x0005, 0x8801},
+       {0x0047, 0x8800},
+       {0x0006, 0x8801},
+       {0x0000, 0x8800},
+       {0x0007, 0x8801},
+       {0x00c0, 0x8800},
+       {0x0008, 0x8801},
+       {0x0003, 0x8800},
+       {0x0013, 0x8801},
+       {0x0001, 0x8800},
+       {0x0009, 0x8801},
+       {0x0000, 0x8800},
+       {0x000a, 0x8801},
+       {0x0000, 0x8800},
+       {0x000b, 0x8801},
+       {0x0000, 0x8800},
+       {0x000c, 0x8801},
+       {0x0000, 0x8800},
+       {0x000e, 0x8801},
+       {0x0004, 0x8800},
+       {0x000f, 0x8801},
+       {0x0000, 0x8800},
+       {0x0010, 0x8801},
+       {0x0006, 0x8800},
+       {0x0011, 0x8801},
+       {0x0006, 0x8800},
+       {0x0012, 0x8801},
+       {0x0000, 0x8800},
+       {0x0013, 0x8801},
+       {0x0001, 0x8800},
+
+       {0x000a, 0x8700},
+       {0x0000, 0x8702},
+       {0x0000, 0x8703},
+       {0x00c2, 0x8704},
+       {0x0001, 0x870c},
+
+       {0x0044, 0x8600},
+       {0x0002, 0x8606},
+       {0x0064, 0x8607},
+       {0x003a, 0x8601},
+       {0x0008, 0x8602},
+       {0x0044, 0x8600},
+       {0x0018, 0x8617},
+       {0x0008, 0x8618},
+       {0x00a1, 0x8656},
+       {0x0004, 0x865b},
+       {0x0002, 0x865c},
+       {0x0058, 0x865d},
+       {0x0048, 0x865e},
+       {0x0012, 0x8608},
+       {0x002c, 0x8609},
+       {0x0002, 0x860a},
+       {0x002c, 0x860b},
+       {0x00db, 0x860c},
+       {0x00f9, 0x860d},
+       {0x00f1, 0x860e},
+       {0x00e3, 0x860f},
+       {0x002c, 0x8610},
+       {0x006c, 0x8651},
+       {0x0041, 0x8652},
+       {0x0059, 0x8653},
+       {0x0040, 0x8654},
+       {0x00fa, 0x8611},
+       {0x00ff, 0x8612},
+       {0x00f8, 0x8613},
+       {0x0000, 0x8614},
+       {0x0001, 0x863f},
+       {0x0000, 0x8640},
+       {0x0026, 0x8641},
+       {0x0045, 0x8642},
+       {0x0060, 0x8643},
+       {0x0075, 0x8644},
+       {0x0088, 0x8645},
+       {0x009b, 0x8646},
+       {0x00b0, 0x8647},
+       {0x00c5, 0x8648},
+       {0x00d2, 0x8649},
+       {0x00dc, 0x864a},
+       {0x00e5, 0x864b},
+       {0x00eb, 0x864c},
+       {0x00f0, 0x864d},
+       {0x00f6, 0x864e},
+       {0x00fa, 0x864f},
+       {0x00ff, 0x8650},
+       {0x0060, 0x8657},
+       {0x0010, 0x8658},
+       {0x0018, 0x8659},
+       {0x0005, 0x865a},
+       {0x0018, 0x8660},
+       {0x0003, 0x8509},
+       {0x0011, 0x850a},
+       {0x0032, 0x850b},
+       {0x0010, 0x850c},
+       {0x0021, 0x850d},
+       {0x0001, 0x8500},
+       {0x0000, 0x8508},
+       {0x0012, 0x8608},
+       {0x002c, 0x8609},
+       {0x0002, 0x860a},
+       {0x0039, 0x860b},
+       {0x00d0, 0x860c},
+       {0x00f7, 0x860d},
+       {0x00ed, 0x860e},
+       {0x00db, 0x860f},
+       {0x0039, 0x8610},
+       {0x0012, 0x8657},
+       {0x000c, 0x8619},
+       {0x0004, 0x861a},
+       {0x00a1, 0x8656},
+       {0x00c8, 0x8615},
+       {0x0032, 0x8616},
+
+       {0x0030, 0x8112},
+       {0x0020, 0x8112},
+       {0x0020, 0x8112},
+       {0x000f, 0x8402},
+       {0x0000, 0x8403},
+
+       {0x0090, 0x8110},
+       {0x0001, 0x8114},
+       {0x0001, 0x8114},
+       {0x0001, 0x8114},
+       {0x0003, 0x8114},
+       {0x0080, 0x8804},
+
+       {0x0003, 0x8801},
+       {0x0012, 0x8800},
+       {0x0004, 0x8801},
+       {0x0005, 0x8800},
+       {0x0005, 0x8801},
+       {0x0047, 0x8800},
+       {0x0006, 0x8801},
+       {0x0000, 0x8800},
+       {0x0007, 0x8801},
+       {0x00c0, 0x8800},
+       {0x0008, 0x8801},
+       {0x0003, 0x8800},
+       {0x000a, 0x8700},
+       {0x000e, 0x8801},
+       {0x0004, 0x8800},
+       {0x0005, 0x8801},
+       {0x0047, 0x8800},
+       {0x0006, 0x8801},
+       {0x0000, 0x8800},
+       {0x0007, 0x8801},
+       {0x00c0, 0x8800},
+       {0x0008, 0x8801},
+       {0x0003, 0x8800},
+       {0x0013, 0x8801},
+       {0x0001, 0x8800},
+       {0x0009, 0x8801},
+       {0x0000, 0x8800},
+       {0x000a, 0x8801},
+       {0x0000, 0x8800},
+       {0x000b, 0x8801},
+       {0x0000, 0x8800},
+       {0x000c, 0x8801},
+       {0x0000, 0x8800},
+       {0x000e, 0x8801},
+       {0x0004, 0x8800},
+       {0x000f, 0x8801},
+       {0x0000, 0x8800},
+       {0x0010, 0x8801},
+       {0x0006, 0x8800},
+       {0x0011, 0x8801},
+       {0x0006, 0x8800},
+       {0x0012, 0x8801},
+       {0x0000, 0x8800},
+       {0x0013, 0x8801},
+       {0x0001, 0x8800},
+       {0x000a, 0x8700},
+       {0x0000, 0x8702},
+       {0x0000, 0x8703},
+       {0x00c2, 0x8704},
+       {0x0001, 0x870c},
+       {0x0044, 0x8600},
+       {0x0002, 0x8606},
+       {0x0064, 0x8607},
+       {0x003a, 0x8601},
+       {0x0008, 0x8602},
+       {0x0044, 0x8600},
+       {0x0018, 0x8617},
+       {0x0008, 0x8618},
+       {0x00a1, 0x8656},
+       {0x0004, 0x865b},
+       {0x0002, 0x865c},
+       {0x0058, 0x865d},
+       {0x0048, 0x865e},
+       {0x0012, 0x8608},
+       {0x002c, 0x8609},
+       {0x0002, 0x860a},
+       {0x002c, 0x860b},
+       {0x00db, 0x860c},
+       {0x00f9, 0x860d},
+       {0x00f1, 0x860e},
+       {0x00e3, 0x860f},
+       {0x002c, 0x8610},
+       {0x006c, 0x8651},
+       {0x0041, 0x8652},
+       {0x0059, 0x8653},
+       {0x0040, 0x8654},
+       {0x00fa, 0x8611},
+       {0x00ff, 0x8612},
+       {0x00f8, 0x8613},
+       {0x0000, 0x8614},
+       {0x0001, 0x863f},
+       {0x0000, 0x8640},
+       {0x0026, 0x8641},
+       {0x0045, 0x8642},
+       {0x0060, 0x8643},
+       {0x0075, 0x8644},
+       {0x0088, 0x8645},
+       {0x009b, 0x8646},
+       {0x00b0, 0x8647},
+       {0x00c5, 0x8648},
+       {0x00d2, 0x8649},
+       {0x00dc, 0x864a},
+       {0x00e5, 0x864b},
+       {0x00eb, 0x864c},
+       {0x00f0, 0x864d},
+       {0x00f6, 0x864e},
+       {0x00fa, 0x864f},
+       {0x00ff, 0x8650},
+       {0x0060, 0x8657},
+       {0x0010, 0x8658},
+       {0x0018, 0x8659},
+       {0x0005, 0x865a},
+       {0x0018, 0x8660},
+       {0x0003, 0x8509},
+       {0x0011, 0x850a},
+       {0x0032, 0x850b},
+       {0x0010, 0x850c},
+       {0x0021, 0x850d},
+       {0x0001, 0x8500},
+       {0x0000, 0x8508},
+
+       {0x0012, 0x8608},
+       {0x002c, 0x8609},
+       {0x0002, 0x860a},
+       {0x0039, 0x860b},
+       {0x00d0, 0x860c},
+       {0x00f7, 0x860d},
+       {0x00ed, 0x860e},
+       {0x00db, 0x860f},
+       {0x0039, 0x8610},
+       {0x0012, 0x8657},
+       {0x0064, 0x8619},
 
 /* This line starts it all, it is not needed here */
 /* since it has been build into the driver */
 /* jfm: don't start now */
-/* 590  *  {0x0030, 0x8112}, */
+/*     {0x0030, 0x8112}, */
        {}
 };
 
@@ -1109,14 +1023,14 @@ static const u16 spca508_vista_init_data[][2] = {
        {0x0008, 0x8200},       /* Clear register */
        {0x0000, 0x870b},       /* Reset CTL3 */
        {0x0020, 0x8112},       /* Video Drop packet enable */
-       {0x0003, 0x8111},  /* Soft Reset compression, memory, TG & CDSP */
+       {0x0003, 0x8111},       /* Soft Reset compression, memory, TG & CDSP */
        {0x0000, 0x8110},       /* Disable everything */
        {0x0000, 0x8114},       /* Software GPIO output data */
        {0x0000, 0x8114},
 
        {0x0003, 0x8111},
        {0x0000, 0x8111},
-       {0x0090, 0x8110},  /* Enable: SSI output, External 2X clock output */
+       {0x0090, 0x8110},    /* Enable: SSI output, External 2X clock output */
        {0x0020, 0x8112},
        {0x0000, 0x8114},
        {0x0001, 0x8114},
@@ -1129,191 +1043,143 @@ static const u16 spca508_vista_init_data[][2] = {
        {0x00ba, 0x8804},       /* SSI Slave address */
        {0x0010, 0x8802},       /* 93.75kHz SSI Clock Two DataByte */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},       /* Will write 2 bytes (DATA1+DATA2) */
        {0x0020, 0x8801},       /* Register address for SSI read/write */
        {0x0044, 0x8805},       /* DATA2 */
        {0x0004, 0x8800},       /* DATA1 -> write triggered */
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x0009, 0x8801},
        {0x0042, 0x8805},
        {0x0001, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x003c, 0x8801},
        {0x0001, 0x8805},
        {0x0000, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x0001, 0x8801},
        {0x000a, 0x8805},
        {0x0000, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x0002, 0x8801},
        {0x0000, 0x8805},
        {0x0000, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x0003, 0x8801},
        {0x0027, 0x8805},
        {0x0001, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x0004, 0x8801},
        {0x0065, 0x8805},
        {0x0001, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x0005, 0x8801},
        {0x0003, 0x8805},
        {0x0000, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x0006, 0x8801},
        {0x001c, 0x8805},
        {0x0000, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x0007, 0x8801},
        {0x002a, 0x8805},
        {0x0000, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x000e, 0x8801},
        {0x0000, 0x8805},
        {0x0000, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x0028, 0x8801},
        {0x002e, 0x8805},
        {0x0000, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x0039, 0x8801},
        {0x0013, 0x8805},
        {0x0000, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x003b, 0x8801},
        {0x000c, 0x8805},
        {0x0000, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x0035, 0x8801},
        {0x0028, 0x8805},
        {0x0000, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
-       /* READ { 0, 0x0001, 0x8802 } ->
-               0000: 10  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
+       /* READ { 0x0001, 0x8802 } -> 0000: 10  */
        {0x0010, 0x8802},
        {0x0009, 0x8801},
        {0x0042, 0x8805},
        {0x0001, 0x8800},
-       /* READ { 0, 0x0001, 0x8803 } ->
-               0000: 00  */
+       /* READ { 0x0001, 0x8803 } -> 0000: 00  */
 
        {0x0050, 0x8703},
        {0x0002, 0x8704},       /* External input CKIx1 */
        {0x0001, 0x870c},       /* Select CKOx2 output */
        {0x009a, 0x8600},       /* Line memory Read Counter (L) */
-       {0x0001, 0x8606},  /* 1 Line memory Read Counter (H) Result: (d)410 */
+       {0x0001, 0x8606},    /* 1 Line memory Read Counter (H) Result: (d)410 */
        {0x0023, 0x8601},
        {0x0010, 0x8602},
        {0x000a, 0x8603},
-       {0x009A, 0x8600},
+       {0x009a, 0x8600},
        {0x0001, 0x865b},       /* 1 Horizontal Offset for Valid Pixel(L) */
        {0x0003, 0x865c},       /* Vertical offset for valid lines (L) */
        {0x0058, 0x865d},       /* Horizontal valid pixels window (L) */
@@ -1329,7 +1195,7 @@ static const u16 spca508_vista_init_data[][2] = {
        {0x0005, 0x860a},       /* ... */
        {0x0025, 0x860b},
        {0x00e1, 0x860c},
-       {0x00fa, 0x860D},
+       {0x00fa, 0x860d},
        {0x00f4, 0x860e},
        {0x00e8, 0x860f},
        {0x0025, 0x8610},       /* A33 Coef. */
@@ -1344,11 +1210,12 @@ static const u16 spca508_vista_init_data[][2] = {
        {0x0040, 0x8654},       /* Gb gain for white balance (L) */
        {0x0001, 0x863f},       /* Enable fixed gamma correction */
 
-       {0x00a1, 0x8656},       /* Size - Window1: 256x256, Window2: 128x128 */
-       /* UV division: UV no change, Enable New edge enhancement */
+       {0x00a1, 0x8656},       /* Size - Window1: 256x256, Window2: 128x128,
+                                * UV division: UV no change,
+                                * Enable New edge enhancement */
        {0x0018, 0x8657},       /* Edge gain high threshold */
        {0x0020, 0x8658},       /* Edge gain low threshold */
-       {0x000A, 0x8659},       /* Edge bandwidth high threshold */
+       {0x000a, 0x8659},       /* Edge bandwidth high threshold */
        {0x0005, 0x865a},       /* Edge bandwidth low threshold */
        {0x0064, 0x8607},       /* UV filter enable */
 
@@ -1384,29 +1251,20 @@ static const u16 spca508_vista_init_data[][2] = {
        {0x0000, 0x86b4},
        {0x001e, 0x8660},
 
-       /* READ { 0, 0x0000, 0x8608 } ->
-               0000: 13  */
-       /* READ { 0, 0x0000, 0x8609 } ->
-               0000: 28  */
-       /* READ { 0, 0x0000, 0x8610 } ->
-               0000: 05  */
-       /* READ { 0, 0x0000, 0x8611 } ->
-               0000: 25  */
-       /* READ { 0, 0x0000, 0x8612 } ->
-               0000: e1  */
-       /* READ { 0, 0x0000, 0x8613 } ->
-               0000: fa  */
-       /* READ { 0, 0x0000, 0x8614 } ->
-               0000: f4  */
-       /* READ { 0, 0x0000, 0x8615 } ->
-               0000: e8  */
-       /* READ { 0, 0x0000, 0x8616 } ->
-               0000: 25  */
+       /* READ { 0x0000, 0x8608 } -> 0000: 13  */
+       /* READ { 0x0000, 0x8609 } -> 0000: 28  */
+       /* READ { 0x0000, 0x8610 } -> 0000: 05  */
+       /* READ { 0x0000, 0x8611 } -> 0000: 25  */
+       /* READ { 0x0000, 0x8612 } -> 0000: e1  */
+       /* READ { 0x0000, 0x8613 } -> 0000: fa  */
+       /* READ { 0x0000, 0x8614 } -> 0000: f4  */
+       /* READ { 0x0000, 0x8615 } -> 0000: e8  */
+       /* READ { 0x0000, 0x8616 } -> 0000: 25  */
        {}
 };
 
 static int reg_write(struct usb_device *dev,
-                       __u16 index, __u16 value)
+                       u16 index, u16 value)
 {
        int ret;
 
@@ -1425,7 +1283,7 @@ static int reg_write(struct usb_device *dev,
 /* read 1 byte */
 /* returns: negative is error, pos or zero is data */
 static int reg_read(struct gspca_dev *gspca_dev,
-                       __u16 index)    /* wIndex */
+                       u16 index)      /* wIndex */
 {
        int ret;
 
@@ -1447,16 +1305,16 @@ static int reg_read(struct gspca_dev *gspca_dev,
 }
 
 static int write_vector(struct gspca_dev *gspca_dev,
-                       const u16 data[][2])
+                       const u16 (*data)[2])
 {
        struct usb_device *dev = gspca_dev->dev;
-       int ret, i = 0;
+       int ret;
 
-       while (data[i][1] != 0) {
-               ret = reg_write(dev, data[i][1], data[i][0]);
+       while ((*data)[1] != 0) {
+               ret = reg_write(dev, (*data)[1], (*data)[0]);
                if (ret < 0)
                        return ret;
-               i++;
+               data++;
        }
        return 0;
 }
@@ -1468,6 +1326,15 @@ static int sd_config(struct gspca_dev *gspca_dev,
        struct sd *sd = (struct sd *) gspca_dev;
        struct cam *cam;
        int data1, data2;
+       const u16 (*init_data)[2];
+       static const u16 (*(init_data_tb[]))[2] = {
+               spca508_vista_init_data,        /* CreativeVista 0 */
+               spca508_sightcam_init_data,     /* HamaUSBSightcam 1 */
+               spca508_sightcam2_init_data,    /* HamaUSBSightcam2 2 */
+               spca508cs110_init_data,         /* IntelEasyPCCamera 3 */
+               spca508cs110_init_data,         /* MicroInnovationIC200 4 */
+               spca508_init_data,              /* ViewQuestVQ110 5 */
+       };
 
        /* Read from global register the USB product and vendor IDs, just to
         * prove that we can communicate with the device.  This works, which
@@ -1491,37 +1358,13 @@ static int sd_config(struct gspca_dev *gspca_dev,
        sd->subtype = id->driver_info;
        sd->brightness = BRIGHTNESS_DEF;
 
-       switch (sd->subtype) {
-       case ViewQuestVQ110:
-               if (write_vector(gspca_dev, spca508_init_data))
-                       return -1;
-               break;
-       default:
-/*     case MicroInnovationIC200: */
-/*     case IntelEasyPCCamera: */
-               if (write_vector(gspca_dev, spca508cs110_init_data))
-                       return -1;
-               break;
-       case HamaUSBSightcam:
-               if (write_vector(gspca_dev, spca508_sightcam_init_data))
-                       return -1;
-               break;
-       case HamaUSBSightcam2:
-               if (write_vector(gspca_dev, spca508_sightcam2_init_data))
-                       return -1;
-               break;
-       case CreativeVista:
-               if (write_vector(gspca_dev, spca508_vista_init_data))
-                       return -1;
-               break;
-       }
-       return 0;                       /* success */
+       init_data = init_data_tb[sd->subtype];
+       return write_vector(gspca_dev, init_data);
 }
 
 /* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
-/*     write_vector(gspca_dev, spca508_open_data); */
        return 0;
 }
 
@@ -1529,7 +1372,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
 {
        int mode;
 
-       mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+       mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
        reg_write(gspca_dev->dev, 0x8500, mode);
        switch (mode) {
        case 0:
@@ -1554,7 +1397,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        struct gspca_frame *frame,      /* target */
-                       __u8 *data,                     /* isoc packet */
+                       u8 *data,                       /* isoc packet */
                        int len)                        /* iso packet length */
 {
        switch (data[0]) {
@@ -1567,7 +1410,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                                data, len);
                break;
        case 0xff:                      /* drop */
-/*             gspca_dev->last_packet_type = DISCARD_PACKET; */
                break;
        default:
                data += 1;
@@ -1581,7 +1423,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 static void setbrightness(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       __u8 brightness = sd->brightness;
+       u8 brightness = sd->brightness;
 
        /* MX seem contrast */
        reg_write(gspca_dev->dev, 0x8651, brightness);
index c99c5e34e211d6ada81910d0d0b5bf981b11ac08..27e82b35f3e7f15be7a3ea60337b58519d85cd44 100644 (file)
@@ -34,8 +34,8 @@ struct sd {
 
        __u16 exposure;                 /* rev12a only */
 #define EXPOSURE_MIN 1
-#define EXPOSURE_DEF 200
-#define EXPOSURE_MAX (4095 - 900) /* see set_exposure */
+#define EXPOSURE_DEF 700               /* == 10 fps */
+#define EXPOSURE_MAX (2047 + 325)      /* see setexposure */
 
        __u8 contrast;                  /* rev72a only */
 #define CONTRAST_MIN 0x00
@@ -48,9 +48,9 @@ struct sd {
 #define BRIGHTNESS_MAX 0x3f
 
        __u8 white;
-#define WHITE_MIN 1
-#define WHITE_DEF 0x40
-#define WHITE_MAX 0x7f
+#define HUE_MIN 1
+#define HUE_DEF 0x40
+#define HUE_MAX 0x7f
 
        __u8 autogain;
 #define AUTOGAIN_MIN 0
@@ -58,9 +58,9 @@ struct sd {
 #define AUTOGAIN_MAX 1
 
        __u8 gain;                      /* rev12a only */
-#define GAIN_MIN 0x0
-#define GAIN_DEF 0x24
-#define GAIN_MAX 0x24
+#define GAIN_MIN 0
+#define GAIN_DEF 63
+#define GAIN_MAX 255
 
 #define EXPO12A_DEF 3
        __u8 expo12a;           /* expo/gain? for rev 12a */
@@ -461,7 +461,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
        }
        sd->brightness = BRIGHTNESS_DEF;
        sd->contrast = CONTRAST_DEF;
-       sd->white = WHITE_DEF;
+       sd->white = HUE_DEF;
        sd->exposure = EXPOSURE_DEF;
        sd->autogain = AUTOGAIN_DEF;
        sd->gain = GAIN_DEF;
@@ -549,8 +549,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
 static void setexposure(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int expo;
-       int clock_divider;
+       int i, expo = 0;
 
        /* Register 0x8309 controls exposure for the spca561,
           the basic exposure setting goes from 1-2047, where 1 is completely
@@ -564,16 +563,22 @@ static void setexposure(struct gspca_dev *gspca_dev)
           configure a divider for the base framerate which us used at the
           exposure setting of 1-300. These bits configure the base framerate
           according to the following formula: fps = 60 / (value + 2) */
-       if (sd->exposure < 2048) {
-               expo = sd->exposure;
-               clock_divider = 0;
-       } else {
-               /* Add 900 to make the 0 setting of the second part of the
-                  exposure equal to the 2047 setting of the first part. */
-               expo = (sd->exposure - 2048) + 900;
-               clock_divider = 3;
+
+       /* We choose to use the high bits setting the fixed framerate divisor
+          asap, as setting high basic exposure setting without the fixed
+          divider in combination with high gains makes the cam stop */
+       int table[] =  { 0, 450, 550, 625, EXPOSURE_MAX };
+
+       for (i = 0; i < ARRAY_SIZE(table) - 1; i++) {
+               if (sd->exposure <= table[i + 1]) {
+                       expo  = sd->exposure - table[i];
+                       if (i)
+                               expo += 300;
+                       expo |= i << 11;
+                       break;
+               }
        }
-       expo |= clock_divider << 11;
+
        gspca_dev->usb_buf[0] = expo;
        gspca_dev->usb_buf[1] = expo >> 8;
        reg_w_buf(gspca_dev, 0x8309, 2);
@@ -584,7 +589,16 @@ static void setgain(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       gspca_dev->usb_buf[0] = sd->gain;
+       /* gain reg low 6 bits  0-63 gain, bit 6 and 7, both double the
+          sensitivity when set, so 31 + one of them set == 63, and 15
+          with both of them set == 63 */
+       if (sd->gain < 64)
+               gspca_dev->usb_buf[0] = sd->gain;
+       else if (sd->gain < 128)
+               gspca_dev->usb_buf[0] = (sd->gain / 2) | 0x40;
+       else
+               gspca_dev->usb_buf[0] = (sd->gain / 4) | 0xC0;
+
        gspca_dev->usb_buf[1] = 0;
        reg_w_buf(gspca_dev, 0x8335, 2);
 }
@@ -629,8 +643,7 @@ static int sd_start_12a(struct gspca_dev *gspca_dev)
        reg_w_buf(gspca_dev, 0x8391, 8);
        reg_w_buf(gspca_dev, 0x8390, 8);
        setwhite(gspca_dev);
-       setautogain(gspca_dev);
-/*     setgain(gspca_dev);             */
+       setgain(gspca_dev);
        setexposure(gspca_dev);
        return 0;
 }
@@ -762,18 +775,6 @@ static void do_autogain(struct gspca_dev *gspca_dev)
                        i2c_write(gspca_dev, expotimes | pixelclk, 0x09);
                }
                break;
-       case Rev012A:
-               reg_r(gspca_dev, 0x8330, 2);
-               if (gspca_dev->usb_buf[1] > 0x08) {
-                       gspca_dev->usb_buf[0] = ++sd->expo12a;
-                       gspca_dev->usb_buf[1] = 0;
-                       reg_w_buf(gspca_dev, 0x8339, 2);
-               } else if (gspca_dev->usb_buf[1] < 0x02) {
-                       gspca_dev->usb_buf[0] = --sd->expo12a;
-                       gspca_dev->usb_buf[1] = 0;
-                       reg_w_buf(gspca_dev, 0x8339, 2);
-               }
-               break;
        }
 }
 
@@ -928,13 +929,13 @@ static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
 static struct ctrl sd_ctrls_12a[] = {
        {
            {
-               .id = V4L2_CID_DO_WHITE_BALANCE,
+               .id = V4L2_CID_HUE,
                .type = V4L2_CTRL_TYPE_INTEGER,
-               .name = "White Balance",
-               .minimum = WHITE_MIN,
-               .maximum = WHITE_MAX,
+               .name = "Hue",
+               .minimum = HUE_MIN,
+               .maximum = HUE_MAX,
                .step = 1,
-               .default_value = WHITE_DEF,
+               .default_value = HUE_DEF,
            },
            .set = sd_setwhite,
            .get = sd_getwhite,
@@ -952,19 +953,6 @@ static struct ctrl sd_ctrls_12a[] = {
            .set = sd_setexposure,
            .get = sd_getexposure,
        },
-       {
-           {
-               .id = V4L2_CID_AUTOGAIN,
-               .type = V4L2_CTRL_TYPE_BOOLEAN,
-               .name = "Auto Gain",
-               .minimum = AUTOGAIN_MIN,
-               .maximum = AUTOGAIN_MAX,
-               .step = 1,
-               .default_value = AUTOGAIN_DEF,
-           },
-           .set = sd_setautogain,
-           .get = sd_getautogain,
-       },
        {
            {
                .id = V4L2_CID_GAIN,
@@ -983,13 +971,13 @@ static struct ctrl sd_ctrls_12a[] = {
 static struct ctrl sd_ctrls_72a[] = {
        {
            {
-               .id = V4L2_CID_DO_WHITE_BALANCE,
+               .id = V4L2_CID_HUE,
                .type = V4L2_CTRL_TYPE_INTEGER,
-               .name = "White Balance",
-               .minimum = WHITE_MIN,
-               .maximum = WHITE_MAX,
+               .name = "Hue",
+               .minimum = HUE_MIN,
+               .maximum = HUE_MAX,
                .step = 1,
-               .default_value = WHITE_DEF,
+               .default_value = HUE_DEF,
            },
            .set = sd_setwhite,
            .get = sd_getwhite,
@@ -1046,7 +1034,6 @@ static const struct sd_desc sd_desc_12a = {
        .stopN = sd_stopN,
        .stop0 = sd_stop0,
        .pkt_scan = sd_pkt_scan,
-/*     .dq_callback = do_autogain,      * fixme */
 };
 static const struct sd_desc sd_desc_72a = {
        .name = MODULE_NAME,
index 2e1cdf068fda896043f2222622ac17a3798a982f..715a68f0156eb6128fa4ab5f7cb44ade79edf6d5 100644 (file)
@@ -309,6 +309,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
        struct sd *dev = (struct sd *) gspca_dev;
 
        /* We don't use the buffer gspca allocates so make it small. */
+       cam->bulk = 1;
        cam->bulk_size = 64;
 
        INIT_WORK(&dev->work_struct, sq905_dostream);
index 0bcb74a1b143425592ea5957dc6ae826bb2fa421..9168925054328229f0c2ff7dad6d9a53381d2383 100644 (file)
@@ -206,6 +206,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
                cam->nmodes = 1;
        /* We don't use the buffer gspca allocates so make it small. */
        cam->bulk_size = 32;
+       cam->bulk = 1;
        INIT_WORK(&dev->work_struct, sq905c_dostream);
        return 0;
 }
index 9dff2e65b116680b15b0d0e04383ce03918f9b12..e573c3406324bf7f5a71a2da4804e4cd73b540c9 100644 (file)
@@ -293,8 +293,6 @@ static void stv06xx_stopN(struct gspca_dev *gspca_dev)
                goto out;
 
        err = sd->sensor->stop(sd);
-       if (err < 0)
-               goto out;
 
 out:
        if (err < 0)
index 69c77c932fc027b16e2d1d0d0d61962233f44b9c..11a0c002f5dcb579dc2047d8ec5b024a7b1da253 100644 (file)
@@ -80,12 +80,26 @@ static const struct ctrl vv6410_ctrl[] = {
                        .minimum        = 0,
                        .maximum        = 15,
                        .step           = 1,
-                       .default_value  = 0
+                       .default_value  = 10
                },
                .set = vv6410_set_analog_gain,
                .get = vv6410_get_analog_gain
+       },
+#define EXPOSURE_IDX 3
+       {
+               {
+                       .id             = V4L2_CID_EXPOSURE,
+                       .type           = V4L2_CTRL_TYPE_INTEGER,
+                       .name           = "exposure",
+                       .minimum        = 0,
+                       .maximum        = 32768,
+                       .step           = 1,
+                       .default_value  = 20000
+               },
+               .set = vv6410_set_exposure,
+               .get = vv6410_get_exposure
        }
-};
+       };
 
 static int vv6410_probe(struct sd *sd)
 {
@@ -121,6 +135,7 @@ static int vv6410_probe(struct sd *sd)
 static int vv6410_init(struct sd *sd)
 {
        int err = 0, i;
+       s32 *sensor_settings = sd->sensor_priv;
 
        for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++) {
                /* if NULL then len contains single value */
@@ -142,6 +157,16 @@ static int vv6410_init(struct sd *sd)
 
        err = stv06xx_write_sensor_bytes(sd, (u8 *) vv6410_sensor_init,
                                         ARRAY_SIZE(vv6410_sensor_init));
+       if (err < 0)
+               return err;
+
+       err = vv6410_set_exposure(&sd->gspca_dev,
+                                  sensor_settings[EXPOSURE_IDX]);
+       if (err < 0)
+               return err;
+
+       err = vv6410_set_analog_gain(&sd->gspca_dev,
+                                     sensor_settings[GAIN_IDX]);
 
        return (err < 0) ? err : 0;
 }
@@ -318,3 +343,50 @@ static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val)
 
        return (err < 0) ? err : 0;
 }
+
+static int vv6410_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+
+       *val = sensor_settings[EXPOSURE_IDX];
+
+       PDEBUG(D_V4L2, "Read exposure %d", *val);
+
+       return 0;
+}
+
+static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+       int err;
+       struct sd *sd = (struct sd *) gspca_dev;
+       s32 *sensor_settings = sd->sensor_priv;
+       unsigned int fine, coarse;
+
+       sensor_settings[EXPOSURE_IDX] = val;
+
+       val = (val * val >> 14) + val / 4;
+
+       fine = val % VV6410_CIF_LINELENGTH;
+       coarse = min(512, val / VV6410_CIF_LINELENGTH);
+
+       PDEBUG(D_V4L2, "Set coarse exposure to %d, fine expsure to %d",
+              coarse, fine);
+
+       err = stv06xx_write_sensor(sd, VV6410_FINEH, fine >> 8);
+       if (err < 0)
+               goto out;
+
+       err = stv06xx_write_sensor(sd, VV6410_FINEL, fine & 0xff);
+       if (err < 0)
+               goto out;
+
+       err = stv06xx_write_sensor(sd, VV6410_COARSEH, coarse >> 8);
+       if (err < 0)
+               goto out;
+
+       err = stv06xx_write_sensor(sd, VV6410_COARSEL, coarse & 0xff);
+
+out:
+       return err;
+}
index 95ac55891bd427c9a02b9252f07b5c906359dca6..487d40555343f7581148c4656829f282d88bff0b 100644 (file)
 #define VV6410_SUBSAMPLE               0x01
 #define VV6410_CROP_TO_QVGA            0x02
 
+#define VV6410_CIF_LINELENGTH          415
+
 static int vv6410_probe(struct sd *sd);
 static int vv6410_start(struct sd *sd);
 static int vv6410_init(struct sd *sd);
@@ -187,6 +189,8 @@ static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
 static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
 static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val);
 static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int vv6410_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
 
 const struct stv06xx_sensor stv06xx_sensor_vv6410 = {
        .name = "ST VV6410",
@@ -242,12 +246,6 @@ static const u8 vv6410_sensor_init[][2] = {
        /* Pre-clock generator divide off */
        {VV6410_DATAFORMAT,     BIT(7) | BIT(0)},
 
-       /* Exposure registers */
-       {VV6410_FINEH,          VV6410_FINE_EXPOSURE >> 8},
-       {VV6410_FINEL,          VV6410_FINE_EXPOSURE & 0xff},
-       {VV6410_COARSEH,        VV6410_COARSE_EXPOSURE >> 8},
-       {VV6410_COARSEL,        VV6410_COARSE_EXPOSURE & 0xff},
-       {VV6410_ANALOGGAIN,     0xf0 | VV6410_DEFAULT_GAIN},
        {VV6410_CLKDIV,         VV6410_CLK_DIV_2},
 
        /* System registers */
index c2b8c10c075add3bc79f5e83c4a36b2fd8cd5125..9623f294bdac1aada92418a7b58f0cbf80a21819 100644 (file)
@@ -32,9 +32,6 @@ MODULE_LICENSE("GPL");
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
 
-       __u8 packet[ISO_MAX_SIZE + 128];
-                               /* !! no more than 128 ff in an ISO packet */
-
        unsigned char brightness;
        unsigned char contrast;
        unsigned char colors;
@@ -1103,7 +1100,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 {
        struct sd *sd = (struct sd *) gspca_dev;
        int i, sof = 0;
-       unsigned char *s, *d;
        static unsigned char ffd9[] = {0xff, 0xd9};
 
 /* frames are jpeg 4.1.1 without 0xff escape */
@@ -1177,22 +1173,19 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        }
 
        /* add 0x00 after 0xff */
-       for (i = len; --i >= 0; )
-               if (data[i] == 0xff)
-                       break;
-       if (i < 0) {                    /* no 0xff */
-               gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
-               return;
-       }
-       s = data;
-       d = sd->packet;
-       for (i = 0; i < len; i++) {
-               *d++ = *s++;
-               if (s[-1] == 0xff)
-                       *d++ = 0x00;
-       }
-       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
-                       sd->packet, d - sd->packet);
+       i = 0;
+       do {
+               if (data[i] == 0xff) {
+                       gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+                                       data, i + 1);
+                       len -= i;
+                       data += i;
+                       *data = 0x00;
+                       i = 0;
+               }
+               i++;
+       } while (i < len);
+       gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
 }
 
 static void setbrightness(struct gspca_dev *gspca_dev)
index f63e37e2e4fdd3c4031b69fd12c7bcd849b16978..404214b8cd2bed98d22e036f6d71bd8b4672add9 100644 (file)
@@ -697,7 +697,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
                return -EINVAL;
        }
 
-       if (sd->sensor != SENSOR_OTHER) {
+       if (sd->sensor == SENSOR_OM6802) {
                reg_w_buf(gspca_dev, n1, sizeof n1);
                i = 5;
                while (--i >= 0) {
index e4e933c400bccd49a7def89c29d4a6038b20e880..26dd155efcc32d39be0b67619a925c0acb856af7 100644 (file)
@@ -42,7 +42,7 @@ struct sd {
        char bridge;
 #define BRIDGE_VC0321 0
 #define BRIDGE_VC0323 1
-       char sensor;
+       u8 sensor;
 #define SENSOR_HV7131R 0
 #define SENSOR_MI0360 1
 #define SENSOR_MI1310_SOC 2
@@ -159,17 +159,17 @@ static const struct v4l2_pix_format vc0323_mode[] = {
                .priv = 2},
 };
 static const struct v4l2_pix_format bi_mode[] = {
-       {320, 240, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
+       {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
                .bytesperline = 320,
                .sizeimage = 320 * 240 * 2,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 2},
-       {640, 480, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
+       {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
                .bytesperline = 640,
                .sizeimage = 640 * 480 * 2,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 1},
-       {1280, 1024, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
+       {1280, 1024, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
                .bytesperline = 1280,
                .sizeimage = 1280 * 1024 * 2,
                .colorspace = V4L2_COLORSPACE_SRGB,
@@ -2453,6 +2453,17 @@ static int sd_config(struct gspca_dev *gspca_dev,
        struct usb_device *dev = gspca_dev->dev;
        struct cam *cam;
        int sensor;
+       static u8 npkt[] = {    /* number of packets per ISOC message */
+               64,             /* HV7131R 0 */
+               32,             /* MI0360 1 */
+               32,             /* MI1310_SOC 2 */
+               64,             /* MI1320 3 */
+               128,            /* MI1320_SOC 4 */
+               32,             /* OV7660 5 */
+               64,             /* OV7670 6 */
+               128,            /* PO1200 7 */
+               128,            /* PO3130NC 8 */
+       };
 
        cam = &gspca_dev->cam;
        sd->bridge = id->driver_info;
@@ -2508,6 +2519,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
                case SENSOR_MI1320_SOC:
                        cam->cam_mode = bi_mode;
                        cam->nmodes = ARRAY_SIZE(bi_mode);
+                       cam->input_flags = V4L2_IN_ST_VFLIP |
+                                          V4L2_IN_ST_HFLIP;
                        break;
                default:
                        cam->cam_mode = vc0323_mode;
@@ -2515,6 +2528,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
                        break;
                }
        }
+       cam->npkt = npkt[sd->sensor];
 
        sd->hflip = HFLIP_DEF;
        sd->vflip = VFLIP_DEF;
index 4fe01d8b6c87e542d6e4655d55c4ab4567fc369f..08422d315e68023a10c94570b192dffa8e8c2503 100644 (file)
@@ -6307,7 +6307,7 @@ static __u16 i2c_read(struct gspca_dev *gspca_dev,
        retbyte = reg_r_i(gspca_dev, 0x0091);           /* read status */
        retval = reg_r_i(gspca_dev, 0x0095);            /* read Lowbyte */
        retval |= reg_r_i(gspca_dev, 0x0096) << 8;      /* read Hightbyte */
-       PDEBUG(D_USBO, "i2c r [%02x] -> %04x (%02x)",
+       PDEBUG(D_USBI, "i2c r [%02x] -> %04x (%02x)",
                        reg, retval, retbyte);
        return retval;
 }
@@ -6868,7 +6868,6 @@ static const struct sensor_by_chipset_revision chipset_revision_sensor[] = {
        {0x8001, 0x13},
        {0x8000, 0x14},         /* CS2102K */
        {0x8400, 0x15},         /* TAS5130K */
-       {0x4001, 0x16},         /* ADCM2700 */
 };
 
 static int vga_3wr_probe(struct gspca_dev *gspca_dev)
@@ -6904,12 +6903,15 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
        retword |= reg_r(gspca_dev, 0x000a);
        PDEBUG(D_PROBE, "probe 3wr vga 1 0x%04x", retword);
        reg_r(gspca_dev, 0x0010);
-       /* this is tested only once anyway */
-       for (i = 0; i < ARRAY_SIZE(chipset_revision_sensor); i++) {
-               if (chipset_revision_sensor[i].revision == retword) {
-                       sd->chip_revision = retword;
-                       send_unknown(dev, SENSOR_PB0330);
-                       return chipset_revision_sensor[i].internal_sensor_id;
+       /* value 0x4001 is meaningless */
+       if (retword != 0x4001) {
+               for (i = 0; i < ARRAY_SIZE(chipset_revision_sensor); i++) {
+                       if (chipset_revision_sensor[i].revision == retword) {
+                               sd->chip_revision = retword;
+                               send_unknown(dev, SENSOR_PB0330);
+                               return chipset_revision_sensor[i]
+                                                       .internal_sensor_id;
+                       }
                }
        }
 
@@ -6980,12 +6982,12 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
        reg_w(dev, 0x01, 0x0001);
        reg_w(dev, 0x03, 0x0012);
        reg_w(dev, 0x01, 0x0012);
-       reg_w(dev, 0x05, 0x0001);
+       reg_w(dev, 0x05, 0x0012);
        reg_w(dev, 0xd3, 0x008b);
        retword = i2c_read(gspca_dev, 0x01);
        if (retword != 0) {
                PDEBUG(D_PROBE, "probe 3wr vga type 0a ? ret: %04x", retword);
-               return retword;
+               return 0x16;                    /* adcm2700 (6100/6200) */
        }
        return -1;
 }
index 8e1463ee1b6420c0e9e652850a05293900bdf150..71c211402eb5e3bd9c6759904299a80fa1cb2544 100644 (file)
@@ -224,7 +224,7 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
 {
        DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
 
-       if (i->index < 0 || i->index >= HEXIUM_INPUTS)
+       if (i->index >= HEXIUM_INPUTS)
                return -EINVAL;
 
        memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
index 2bc39f62845527dda7391c253d2aa6c0d29b148a..39d65ca41c627026a83ebc899a84fdb08d71b438 100644 (file)
@@ -325,7 +325,7 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
 {
        DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
 
-       if (i->index < 0 || i->index >= HEXIUM_INPUTS)
+       if (i->index >= HEXIUM_INPUTS)
                return -EINVAL;
 
        memcpy(i, &hexium_inputs[i->index], sizeof(struct v4l2_input));
index 092c7da0f37a7a534351536cd2f57ee15b01a4ab..86f2fefe1edf28a9db5b93b9c13af6696dbf8e5d 100644 (file)
@@ -74,7 +74,7 @@ static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
        int start, range, toggle, dev, code, ircode;
 
        /* poll IR chip */
-       if (size != i2c_master_recv(&ir->c,buf,size))
+       if (size != i2c_master_recv(ir->c, buf, size))
                return -EIO;
 
        /* split rc5 data block ... */
@@ -137,7 +137,7 @@ static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        unsigned char b;
 
        /* poll IR chip */
-       if (1 != i2c_master_recv(&ir->c,&b,1)) {
+       if (1 != i2c_master_recv(ir->c, &b, 1)) {
                dprintk(1,"read error\n");
                return -EIO;
        }
@@ -151,7 +151,7 @@ static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        unsigned char b;
 
        /* poll IR chip */
-       if (1 != i2c_master_recv(&ir->c,&b,1)) {
+       if (1 != i2c_master_recv(ir->c, &b, 1)) {
                dprintk(1,"read error\n");
                return -EIO;
        }
@@ -171,7 +171,7 @@ static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        unsigned char buf[4];
 
        /* poll IR chip */
-       if (4 != i2c_master_recv(&ir->c,buf,4)) {
+       if (4 != i2c_master_recv(ir->c, buf, 4)) {
                dprintk(1,"read error\n");
                return -EIO;
        }
@@ -195,7 +195,7 @@ static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        unsigned char b;
 
        /* poll IR chip */
-       if (1 != i2c_master_recv(&ir->c,&b,1)) {
+       if (1 != i2c_master_recv(ir->c, &b, 1)) {
                dprintk(1,"read error\n");
                return -EIO;
        }
@@ -222,12 +222,12 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir,
                                     u32 *ir_key, u32 *ir_raw)
 {
        unsigned char subaddr, key, keygroup;
-       struct i2c_msg msg[] = { { .addr = ir->c.addr, .flags = 0,
+       struct i2c_msg msg[] = { { .addr = ir->c->addr, .flags = 0,
                                   .buf = &subaddr, .len = 1},
-                                { .addr = ir->c.addr, .flags = I2C_M_RD,
+                                { .addr = ir->c->addr, .flags = I2C_M_RD,
                                  .buf = &key, .len = 1} };
        subaddr = 0x0d;
-       if (2 != i2c_transfer(ir->c.adapter, msg, 2)) {
+       if (2 != i2c_transfer(ir->c->adapter, msg, 2)) {
                dprintk(1, "read error\n");
                return -EIO;
        }
@@ -237,7 +237,7 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir,
 
        subaddr = 0x0b;
        msg[1].buf = &keygroup;
-       if (2 != i2c_transfer(ir->c.adapter, msg, 2)) {
+       if (2 != i2c_transfer(ir->c->adapter, msg, 2)) {
                dprintk(1, "read error\n");
                return -EIO;
        }
@@ -286,7 +286,7 @@ static void ir_work(struct work_struct *work)
 
        /* MSI TV@nywhere Plus requires more frequent polling
           otherwise it will miss some keypresses */
-       if (ir->c.adapter->id == I2C_HW_SAA7134 && ir->c.addr == 0x30)
+       if (ir->c->adapter->id == I2C_HW_SAA7134 && ir->c->addr == 0x30)
                polling_interval = 50;
 
        ir_key_poll(ir);
@@ -295,34 +295,15 @@ static void ir_work(struct work_struct *work)
 
 /* ----------------------------------------------------------------------- */
 
-static int ir_attach(struct i2c_adapter *adap, int addr,
-                     unsigned short flags, int kind);
-static int ir_detach(struct i2c_client *client);
-static int ir_probe(struct i2c_adapter *adap);
-
-static struct i2c_driver driver = {
-       .driver = {
-               .name   = "ir-kbd-i2c",
-       },
-       .id             = I2C_DRIVERID_INFRARED,
-       .attach_adapter = ir_probe,
-       .detach_client  = ir_detach,
-};
-
-static struct i2c_client client_template =
-{
-       .name = "unset",
-       .driver = &driver
-};
-
-static int ir_attach(struct i2c_adapter *adap, int addr,
-                    unsigned short flags, int kind)
+static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
        IR_KEYTAB_TYPE *ir_codes = NULL;
-       char *name;
+       const char *name = NULL;
        int ir_type;
        struct IR_i2c *ir;
        struct input_dev *input_dev;
+       struct i2c_adapter *adap = client->adapter;
+       unsigned short addr = client->addr;
        int err;
 
        ir = kzalloc(sizeof(struct IR_i2c),GFP_KERNEL);
@@ -332,13 +313,9 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
                goto err_out_free;
        }
 
-       ir->c = client_template;
+       ir->c = client;
        ir->input = input_dev;
-
-       ir->c.adapter = adap;
-       ir->c.addr    = addr;
-
-       i2c_set_clientdata(&ir->c, ir);
+       i2c_set_clientdata(client, ir);
 
        switch(addr) {
        case 0x64:
@@ -403,44 +380,46 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
                ir_codes    = ir_codes_avermedia_cardbus;
                break;
        default:
-               /* shouldn't happen */
-               printk(DEVNAME ": Huh? unknown i2c address (0x%02x)?\n", addr);
+               dprintk(1, DEVNAME ": Unsupported 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;
+       /* Let the caller override settings */
+       if (client->dev.platform_data) {
+               const struct IR_i2c_init_data *init_data =
+                                               client->dev.platform_data;
 
-       /* register i2c device
-        * At device register, IR codes may be changed to be
-        * board dependent.
-        */
-       err = i2c_attach_client(&ir->c);
-       if (err)
-               goto err_out_free;
+               ir_codes = init_data->ir_codes;
+               name = init_data->name;
+               ir->get_key = init_data->get_key;
+       }
 
-       /* If IR not supported or disabled, unregisters driver */
-       if (ir->get_key == NULL) {
+       /* Make sure we are all setup before going on */
+       if (!name || !ir->get_key || !ir_codes) {
+               dprintk(1, DEVNAME ": Unsupported device at address 0x%02x\n",
+                       addr);
                err = -ENODEV;
-               goto err_out_detach;
+               goto err_out_free;
        }
 
-       /* Phys addr can only be set after attaching (for ir->c.dev) */
+       /* Sets name */
+       snprintf(ir->name, sizeof(ir->name), "i2c IR (%s)", name);
+       ir->ir_codes = ir_codes;
+
        snprintf(ir->phys, sizeof(ir->phys), "%s/%s/ir0",
-                dev_name(&ir->c.adapter->dev),
-                dev_name(&ir->c.dev));
+                dev_name(&adap->dev),
+                dev_name(&client->dev));
 
        /* init + register input device */
        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->name       = ir->name;
        input_dev->phys       = ir->phys;
 
        err = input_register_device(ir->input);
        if (err)
-               goto err_out_detach;
+               goto err_out_free;
 
        printk(DEVNAME ": %s detected at %s [%s]\n",
               ir->input->name, ir->input->phys, adap->name);
@@ -451,135 +430,42 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
 
        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)
+static int ir_remove(struct i2c_client *client)
 {
        struct IR_i2c *ir = i2c_get_clientdata(client);
 
        /* kill outstanding polls */
        cancel_delayed_work_sync(&ir->work);
 
-       /* unregister devices */
+       /* unregister device */
        input_unregister_device(ir->input);
-       i2c_detach_client(&ir->c);
 
        /* free memory */
        kfree(ir);
        return 0;
 }
 
-static int ir_probe(struct i2c_adapter *adap)
-{
-
-       /* The external IR receiver is at i2c address 0x34 (0x35 for
-          reads).  Future Hauppauge cards will have an internal
-          receiver at 0x30 (0x31 for reads).  In theory, both can be
-          fitted, and Hauppauge suggest an external overrides an
-          internal.
-
-          That's why we probe 0x1a (~0x34) first. CB
-       */
-
-       static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1};
-       static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, 0x2d, -1 };
-       static const int probe_em28XX[] = { 0x30, 0x47, -1 };
-       static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 };
-       static const int probe_cx23885[] = { 0x6b, -1 };
-       const int *probe;
-       struct i2c_msg msg = {
-               .flags = I2C_M_RD,
-               .len = 0,
-               .buf = NULL,
-       };
-       int i, rc;
-
-       switch (adap->id) {
-       case I2C_HW_B_BT848:
-               probe = probe_bttv;
-               break;
-       case I2C_HW_B_CX2341X:
-               probe = probe_bttv;
-               break;
-       case I2C_HW_SAA7134:
-               probe = probe_saa7134;
-               break;
-       case I2C_HW_B_EM28XX:
-               probe = probe_em28XX;
-               break;
-       case I2C_HW_B_CX2388x:
-               probe = probe_cx88;
-               break;
-       case I2C_HW_B_CX23885:
-               probe = probe_cx23885;
-               break;
-       default:
-               return 0;
-       }
-
-       for (i = 0; -1 != probe[i]; i++) {
-               msg.addr = probe[i];
-               rc = i2c_transfer(adap, &msg, 1);
-               dprintk(1,"probe 0x%02x @ %s: %s\n",
-                       probe[i], adap->name,
-                       (1 == rc) ? "yes" : "no");
-               if (1 == rc) {
-                       ir_attach(adap, probe[i], 0, 0);
-                       return 0;
-               }
-       }
-
-       /* Special case for MSI TV@nywhere Plus remote */
-       if (adap->id == I2C_HW_SAA7134) {
-               u8 temp;
-
-               /* MSI TV@nywhere Plus controller doesn't seem to
-                  respond to probes unless we read something from
-                  an existing device. Weird... */
-
-               msg.addr = 0x50;
-               rc = i2c_transfer(adap, &msg, 1);
-                       dprintk(1, "probe 0x%02x @ %s: %s\n",
-                       msg.addr, adap->name,
-                       (1 == rc) ? "yes" : "no");
-
-               /* Now do the probe. The controller does not respond
-                  to 0-byte reads, so we use a 1-byte read instead. */
-               msg.addr = 0x30;
-               msg.len = 1;
-               msg.buf = &temp;
-               rc = i2c_transfer(adap, &msg, 1);
-               dprintk(1, "probe 0x%02x @ %s: %s\n",
-                       msg.addr, adap->name,
-                       (1 == rc) ? "yes" : "no");
-               if (1 == rc)
-                       ir_attach(adap, msg.addr, 0, 0);
-       }
-
-       /* Special case for AVerMedia Cardbus remote */
-       if (adap->id == I2C_HW_SAA7134) {
-               unsigned char subaddr, data;
-               struct i2c_msg msg[] = { { .addr = 0x40, .flags = 0,
-                                          .buf = &subaddr, .len = 1},
-                                        { .addr = 0x40, .flags = I2C_M_RD,
-                                          .buf = &data, .len = 1} };
-               subaddr = 0x0d;
-               rc = i2c_transfer(adap, msg, 2);
-               dprintk(1, "probe 0x%02x/0x%02x @ %s: %s\n",
-                       msg[0].addr, subaddr, adap->name,
-                       (2 == rc) ? "yes" : "no");
-               if (2 == rc)
-                       ir_attach(adap, msg[0].addr, 0, 0);
-       }
+static const struct i2c_device_id ir_kbd_id[] = {
+       /* Generic entry for any IR receiver */
+       { "ir_video", 0 },
+       /* IR device specific entries could be added here */
+       { }
+};
 
-       return 0;
-}
+static struct i2c_driver driver = {
+       .driver = {
+               .name   = "ir-kbd-i2c",
+       },
+       .probe          = ir_probe,
+       .remove         = ir_remove,
+       .id_table       = ir_kbd_id,
+};
 
 /* ----------------------------------------------------------------------- */
 
index db2ac9a99acd68b96f5af3e439acd4206ed3e01a..558f8a837ff4f14bd04721a5cdd554add2d03cbe 100644 (file)
@@ -455,7 +455,7 @@ static void ivtv_process_eeprom(struct ivtv *itv)
                        break;
        }
        if (tv.tuner_type == TUNER_ABSENT)
-               IVTV_ERR("tveeprom cannot autodetect tuner!");
+               IVTV_ERR("tveeprom cannot autodetect tuner!\n");
 
        if (itv->options.tuner == -1)
                itv->options.tuner = tv.tuner_type;
@@ -946,17 +946,14 @@ static int __devinit ivtv_probe(struct pci_dev *pdev,
        if (itv == NULL)
                return -ENOMEM;
        itv->pdev = pdev;
-       itv->instance = atomic_inc_return(&ivtv_instance) - 1;
+       itv->instance = v4l2_device_set_name(&itv->v4l2_dev, "ivtv",
+                                               &ivtv_instance);
 
        retval = v4l2_device_register(&pdev->dev, &itv->v4l2_dev);
        if (retval) {
                kfree(itv);
                return retval;
        }
-       /* "ivtv + PCI ID" is a bit of a mouthful, so use
-          "ivtv + instance" instead. */
-       snprintf(itv->v4l2_dev.name, sizeof(itv->v4l2_dev.name),
-                       "ivtv%d", itv->instance);
        IVTV_INFO("Initializing card %d\n", itv->instance);
 
        ivtv_process_options(itv);
index 9e3d32b8004c0e571b2b92e3db4363bab2f7b1fd..e52aa322b13426dc3139aff85f5af87927cd5f7d 100644 (file)
@@ -579,9 +579,11 @@ static struct i2c_client ivtv_i2c_client_template = {
        .name = "ivtv internal",
 };
 
-/* init + register i2c algo-bit adapter */
+/* init + register i2c adapter + instantiate IR receiver */
 int init_ivtv_i2c(struct ivtv *itv)
 {
+       int retval;
+
        IVTV_DEBUG_I2C("i2c init\n");
 
        /* Sanity checks for the I2C hardware arrays. They must be the
@@ -619,9 +621,37 @@ int init_ivtv_i2c(struct ivtv *itv)
        ivtv_setsda(itv, 1);
 
        if (itv->options.newi2c > 0)
-               return i2c_add_adapter(&itv->i2c_adap);
+               retval = i2c_add_adapter(&itv->i2c_adap);
        else
-               return i2c_bit_add_bus(&itv->i2c_adap);
+               retval = i2c_bit_add_bus(&itv->i2c_adap);
+
+       /* Instantiate the IR receiver device, if present */
+       if (retval == 0) {
+               struct i2c_board_info info;
+               /* The external IR receiver is at i2c address 0x34 (0x35 for
+                  reads).  Future Hauppauge cards will have an internal
+                  receiver at 0x30 (0x31 for reads).  In theory, both can be
+                  fitted, and Hauppauge suggest an external overrides an
+                  internal.
+
+                  That's why we probe 0x1a (~0x34) first. CB
+               */
+               const unsigned short addr_list[] = {
+                       0x1a,   /* Hauppauge IR external */
+                       0x18,   /* Hauppauge IR internal */
+                       0x71,   /* Hauppauge IR (PVR150) */
+                       0x64,   /* Pixelview IR */
+                       0x30,   /* KNC ONE IR */
+                       0x6b,   /* Adaptec IR */
+                       I2C_CLIENT_END
+               };
+
+               memset(&info, 0, sizeof(struct i2c_board_info));
+               strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+               i2c_new_probed_device(&itv->i2c_adap, &info, addr_list);
+       }
+
+       return retval;
 }
 
 void exit_ivtv_i2c(struct ivtv *itv)
index c342a9fe983eab8246c912ac60070f25923a48bd..99f3c39a118b428ea04e4878f3c58a0ebc5da52d 100644 (file)
@@ -709,7 +709,7 @@ static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg)
        else if (itv->has_cx23415 && regs->reg >= IVTV_DECODER_OFFSET &&
                        regs->reg < IVTV_DECODER_OFFSET + IVTV_DECODER_SIZE)
                reg_start = itv->dec_mem - IVTV_DECODER_OFFSET;
-       else if (regs->reg >= 0 && regs->reg < IVTV_ENCODER_SIZE)
+       else if (regs->reg < IVTV_ENCODER_SIZE)
                reg_start = itv->enc_mem;
        else
                return -EINVAL;
index 684f62fa7897586152db543a6a3c95069dea7cf0..459c04cbf69dd0fb9b23efeb869cda79d7135e15 100644 (file)
@@ -75,53 +75,50 @@ struct mt9m001 {
        unsigned char autoexposure;
 };
 
-static int reg_read(struct soc_camera_device *icd, const u8 reg)
+static int reg_read(struct i2c_client *client, const u8 reg)
 {
-       struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
-       struct i2c_client *client = mt9m001->client;
        s32 data = i2c_smbus_read_word_data(client, reg);
        return data < 0 ? data : swab16(data);
 }
 
-static int reg_write(struct soc_camera_device *icd, const u8 reg,
+static int reg_write(struct i2c_client *client, const u8 reg,
                     const u16 data)
 {
-       struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
-       return i2c_smbus_write_word_data(mt9m001->client, reg, swab16(data));
+       return i2c_smbus_write_word_data(client, reg, swab16(data));
 }
 
-static int reg_set(struct soc_camera_device *icd, const u8 reg,
+static int reg_set(struct i2c_client *client, const u8 reg,
                   const u16 data)
 {
        int ret;
 
-       ret = reg_read(icd, reg);
+       ret = reg_read(client, reg);
        if (ret < 0)
                return ret;
-       return reg_write(icd, reg, ret | data);
+       return reg_write(client, reg, ret | data);
 }
 
-static int reg_clear(struct soc_camera_device *icd, const u8 reg,
+static int reg_clear(struct i2c_client *client, const u8 reg,
                     const u16 data)
 {
        int ret;
 
-       ret = reg_read(icd, reg);
+       ret = reg_read(client, reg);
        if (ret < 0)
                return ret;
-       return reg_write(icd, reg, ret & ~data);
+       return reg_write(client, reg, ret & ~data);
 }
 
 static int mt9m001_init(struct soc_camera_device *icd)
 {
-       struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
-       struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
+       struct i2c_client *client = to_i2c_client(icd->control);
+       struct soc_camera_link *icl = client->dev.platform_data;
        int ret;
 
        dev_dbg(icd->vdev->parent, "%s\n", __func__);
 
        if (icl->power) {
-               ret = icl->power(&mt9m001->client->dev, 1);
+               ret = icl->power(&client->dev, 1);
                if (ret < 0) {
                        dev_err(icd->vdev->parent,
                                "Platform failed to power-on the camera.\n");
@@ -131,49 +128,53 @@ static int mt9m001_init(struct soc_camera_device *icd)
 
        /* The camera could have been already on, we reset it additionally */
        if (icl->reset)
-               ret = icl->reset(&mt9m001->client->dev);
+               ret = icl->reset(&client->dev);
        else
                ret = -ENODEV;
 
        if (ret < 0) {
                /* Either no platform reset, or platform reset failed */
-               ret = reg_write(icd, MT9M001_RESET, 1);
+               ret = reg_write(client, MT9M001_RESET, 1);
                if (!ret)
-                       ret = reg_write(icd, MT9M001_RESET, 0);
+                       ret = reg_write(client, MT9M001_RESET, 0);
        }
        /* Disable chip, synchronous option update */
        if (!ret)
-               ret = reg_write(icd, MT9M001_OUTPUT_CONTROL, 0);
+               ret = reg_write(client, MT9M001_OUTPUT_CONTROL, 0);
 
        return ret;
 }
 
 static int mt9m001_release(struct soc_camera_device *icd)
 {
-       struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
-       struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
+       struct i2c_client *client = to_i2c_client(icd->control);
+       struct soc_camera_link *icl = client->dev.platform_data;
 
        /* Disable the chip */
-       reg_write(icd, MT9M001_OUTPUT_CONTROL, 0);
+       reg_write(client, MT9M001_OUTPUT_CONTROL, 0);
 
        if (icl->power)
-               icl->power(&mt9m001->client->dev, 0);
+               icl->power(&client->dev, 0);
 
        return 0;
 }
 
 static int mt9m001_start_capture(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
+
        /* Switch to master "normal" mode */
-       if (reg_write(icd, MT9M001_OUTPUT_CONTROL, 2) < 0)
+       if (reg_write(client, MT9M001_OUTPUT_CONTROL, 2) < 0)
                return -EIO;
        return 0;
 }
 
 static int mt9m001_stop_capture(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
+
        /* Stop sensor readout */
-       if (reg_write(icd, MT9M001_OUTPUT_CONTROL, 0) < 0)
+       if (reg_write(client, MT9M001_OUTPUT_CONTROL, 0) < 0)
                return -EIO;
        return 0;
 }
@@ -222,28 +223,29 @@ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
 static int mt9m001_set_crop(struct soc_camera_device *icd,
                            struct v4l2_rect *rect)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
        int ret;
        const u16 hblank = 9, vblank = 25;
 
        /* Blanking and start values - default... */
-       ret = reg_write(icd, MT9M001_HORIZONTAL_BLANKING, hblank);
+       ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank);
        if (!ret)
-               ret = reg_write(icd, MT9M001_VERTICAL_BLANKING, vblank);
+               ret = reg_write(client, MT9M001_VERTICAL_BLANKING, vblank);
 
        /* The caller provides a supported format, as verified per
         * call to icd->try_fmt() */
        if (!ret)
-               ret = reg_write(icd, MT9M001_COLUMN_START, rect->left);
+               ret = reg_write(client, MT9M001_COLUMN_START, rect->left);
        if (!ret)
-               ret = reg_write(icd, MT9M001_ROW_START, rect->top);
+               ret = reg_write(client, MT9M001_ROW_START, rect->top);
        if (!ret)
-               ret = reg_write(icd, MT9M001_WINDOW_WIDTH, rect->width - 1);
+               ret = reg_write(client, MT9M001_WINDOW_WIDTH, rect->width - 1);
        if (!ret)
-               ret = reg_write(icd, MT9M001_WINDOW_HEIGHT,
+               ret = reg_write(client, MT9M001_WINDOW_HEIGHT,
                                rect->height + icd->y_skip_top - 1);
        if (!ret && mt9m001->autoexposure) {
-               ret = reg_write(icd, MT9M001_SHUTTER_WIDTH,
+               ret = reg_write(client, MT9M001_SHUTTER_WIDTH,
                                rect->height + icd->y_skip_top + vblank);
                if (!ret) {
                        const struct v4l2_queryctrl *qctrl =
@@ -312,16 +314,16 @@ static int mt9m001_get_chip_id(struct soc_camera_device *icd,
 static int mt9m001_get_register(struct soc_camera_device *icd,
                                struct v4l2_dbg_register *reg)
 {
-       struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+       struct i2c_client *client = to_i2c_client(icd->control);
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
                return -EINVAL;
 
-       if (reg->match.addr != mt9m001->client->addr)
+       if (reg->match.addr != client->addr)
                return -ENODEV;
 
        reg->size = 2;
-       reg->val = reg_read(icd, reg->reg);
+       reg->val = reg_read(client, reg->reg);
 
        if (reg->val > 0xffff)
                return -EIO;
@@ -332,15 +334,15 @@ static int mt9m001_get_register(struct soc_camera_device *icd,
 static int mt9m001_set_register(struct soc_camera_device *icd,
                                struct v4l2_dbg_register *reg)
 {
-       struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+       struct i2c_client *client = to_i2c_client(icd->control);
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
                return -EINVAL;
 
-       if (reg->match.addr != mt9m001->client->addr)
+       if (reg->match.addr != client->addr)
                return -ENODEV;
 
-       if (reg_write(icd, reg->reg, reg->val) < 0)
+       if (reg_write(client, reg->reg, reg->val) < 0)
                return -EIO;
 
        return 0;
@@ -416,12 +418,13 @@ static struct soc_camera_ops mt9m001_ops = {
 
 static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
        int data;
 
        switch (ctrl->id) {
        case V4L2_CID_VFLIP:
-               data = reg_read(icd, MT9M001_READ_OPTIONS2);
+               data = reg_read(client, MT9M001_READ_OPTIONS2);
                if (data < 0)
                        return -EIO;
                ctrl->value = !!(data & 0x8000);
@@ -435,6 +438,7 @@ static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_contro
 
 static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
        const struct v4l2_queryctrl *qctrl;
        int data;
@@ -447,9 +451,9 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
        switch (ctrl->id) {
        case V4L2_CID_VFLIP:
                if (ctrl->value)
-                       data = reg_set(icd, MT9M001_READ_OPTIONS2, 0x8000);
+                       data = reg_set(client, MT9M001_READ_OPTIONS2, 0x8000);
                else
-                       data = reg_clear(icd, MT9M001_READ_OPTIONS2, 0x8000);
+                       data = reg_clear(client, MT9M001_READ_OPTIONS2, 0x8000);
                if (data < 0)
                        return -EIO;
                break;
@@ -463,7 +467,7 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
                        data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range;
 
                        dev_dbg(&icd->dev, "Setting gain %d\n", data);
-                       data = reg_write(icd, MT9M001_GLOBAL_GAIN, data);
+                       data = reg_write(client, MT9M001_GLOBAL_GAIN, data);
                        if (data < 0)
                                return -EIO;
                } else {
@@ -481,8 +485,8 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
                                data = ((gain - 64) * 7 + 28) / 56 + 96;
 
                        dev_dbg(&icd->dev, "Setting gain from %d to %d\n",
-                                reg_read(icd, MT9M001_GLOBAL_GAIN), data);
-                       data = reg_write(icd, MT9M001_GLOBAL_GAIN, data);
+                                reg_read(client, MT9M001_GLOBAL_GAIN), data);
+                       data = reg_write(client, MT9M001_GLOBAL_GAIN, data);
                        if (data < 0)
                                return -EIO;
                }
@@ -500,8 +504,8 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
                                                 range / 2) / range + 1;
 
                        dev_dbg(&icd->dev, "Setting shutter width from %d to %lu\n",
-                                reg_read(icd, MT9M001_SHUTTER_WIDTH), shutter);
-                       if (reg_write(icd, MT9M001_SHUTTER_WIDTH, shutter) < 0)
+                                reg_read(client, MT9M001_SHUTTER_WIDTH), shutter);
+                       if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0)
                                return -EIO;
                        icd->exposure = ctrl->value;
                        mt9m001->autoexposure = 0;
@@ -510,7 +514,7 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
        case V4L2_CID_EXPOSURE_AUTO:
                if (ctrl->value) {
                        const u16 vblank = 25;
-                       if (reg_write(icd, MT9M001_SHUTTER_WIDTH, icd->height +
+                       if (reg_write(client, MT9M001_SHUTTER_WIDTH, icd->height +
                                      icd->y_skip_top + vblank) < 0)
                                return -EIO;
                        qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
@@ -529,8 +533,9 @@ static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_contro
  * this wasn't our capture interface, so, we wait for the right one */
 static int mt9m001_video_probe(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
-       struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
+       struct soc_camera_link *icl = client->dev.platform_data;
        s32 data;
        int ret;
        unsigned long flags;
@@ -542,11 +547,11 @@ static int mt9m001_video_probe(struct soc_camera_device *icd)
                return -ENODEV;
 
        /* Enable the chip */
-       data = reg_write(icd, MT9M001_CHIP_ENABLE, 1);
+       data = reg_write(client, MT9M001_CHIP_ENABLE, 1);
        dev_dbg(&icd->dev, "write: %d\n", data);
 
        /* Read out the chip version register */
-       data = reg_read(icd, MT9M001_CHIP_VERSION);
+       data = reg_read(client, MT9M001_CHIP_VERSION);
 
        /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */
        switch (data) {
@@ -604,10 +609,13 @@ ei2c:
 static void mt9m001_video_remove(struct soc_camera_device *icd)
 {
        struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+       struct soc_camera_link *icl = mt9m001->client->dev.platform_data;
 
        dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m001->client->addr,
                icd->dev.parent, icd->vdev);
        soc_camera_video_stop(icd);
+       if (icl->free_bus)
+               icl->free_bus(icl);
 }
 
 static int mt9m001_probe(struct i2c_client *client,
index cdd1ddb513881a3ec982454bc052c8a267346dc3..fc5e2de037663abcc3fd84e9c5d32bca71183ef9 100644 (file)
  * mt9m111: Camera control register addresses (0x200..0x2ff not implemented)
  */
 
-#define reg_read(reg) mt9m111_reg_read(icd, MT9M111_##reg)
-#define reg_write(reg, val) mt9m111_reg_write(icd, MT9M111_##reg, (val))
-#define reg_set(reg, val) mt9m111_reg_set(icd, MT9M111_##reg, (val))
-#define reg_clear(reg, val) mt9m111_reg_clear(icd, MT9M111_##reg, (val))
+#define reg_read(reg) mt9m111_reg_read(client, MT9M111_##reg)
+#define reg_write(reg, val) mt9m111_reg_write(client, MT9M111_##reg, (val))
+#define reg_set(reg, val) mt9m111_reg_set(client, MT9M111_##reg, (val))
+#define reg_clear(reg, val) mt9m111_reg_clear(client, MT9M111_##reg, (val))
 
 #define MT9M111_MIN_DARK_ROWS  8
 #define MT9M111_MIN_DARK_COLS  24
@@ -184,58 +184,55 @@ static int reg_page_map_set(struct i2c_client *client, const u16 reg)
        return ret;
 }
 
-static int mt9m111_reg_read(struct soc_camera_device *icd, const u16 reg)
+static int mt9m111_reg_read(struct i2c_client *client, const u16 reg)
 {
-       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
-       struct i2c_client *client = mt9m111->client;
        int ret;
 
        ret = reg_page_map_set(client, reg);
        if (!ret)
                ret = swab16(i2c_smbus_read_word_data(client, (reg & 0xff)));
 
-       dev_dbg(&icd->dev, "read  reg.%03x -> %04x\n", reg, ret);
+       dev_dbg(&client->dev, "read  reg.%03x -> %04x\n", reg, ret);
        return ret;
 }
 
-static int mt9m111_reg_write(struct soc_camera_device *icd, const u16 reg,
+static int mt9m111_reg_write(struct i2c_client *client, const u16 reg,
                             const u16 data)
 {
-       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
-       struct i2c_client *client = mt9m111->client;
        int ret;
 
        ret = reg_page_map_set(client, reg);
        if (!ret)
-               ret = i2c_smbus_write_word_data(mt9m111->client, (reg & 0xff),
+               ret = i2c_smbus_write_word_data(client, (reg & 0xff),
                                                swab16(data));
-       dev_dbg(&icd->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret);
+       dev_dbg(&client->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret);
        return ret;
 }
 
-static int mt9m111_reg_set(struct soc_camera_device *icd, const u16 reg,
+static int mt9m111_reg_set(struct i2c_client *client, const u16 reg,
                           const u16 data)
 {
        int ret;
 
-       ret = mt9m111_reg_read(icd, reg);
+       ret = mt9m111_reg_read(client, reg);
        if (ret >= 0)
-               ret = mt9m111_reg_write(icd, reg, ret | data);
+               ret = mt9m111_reg_write(client, reg, ret | data);
        return ret;
 }
 
-static int mt9m111_reg_clear(struct soc_camera_device *icd, const u16 reg,
+static int mt9m111_reg_clear(struct i2c_client *client, const u16 reg,
                             const u16 data)
 {
        int ret;
 
-       ret = mt9m111_reg_read(icd, reg);
-       return mt9m111_reg_write(icd, reg, ret & ~data);
+       ret = mt9m111_reg_read(client, reg);
+       return mt9m111_reg_write(client, reg, ret & ~data);
 }
 
 static int mt9m111_set_context(struct soc_camera_device *icd,
                               enum mt9m111_context ctxt)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B
                | MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B
                | MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B
@@ -252,6 +249,7 @@ static int mt9m111_set_context(struct soc_camera_device *icd,
 static int mt9m111_setup_rect(struct soc_camera_device *icd,
                              struct v4l2_rect *rect)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
        int ret, is_raw_format;
        int width = rect->width;
@@ -296,6 +294,7 @@ static int mt9m111_setup_rect(struct soc_camera_device *icd,
 
 static int mt9m111_setup_pixfmt(struct soc_camera_device *icd, u16 outfmt)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        int ret;
 
        ret = reg_write(OUTPUT_FORMAT_CTRL2_A, outfmt);
@@ -357,12 +356,13 @@ static int mt9m111_setfmt_yuv(struct soc_camera_device *icd)
 
 static int mt9m111_enable(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
-       struct soc_camera_link *icl = mt9m111->client->dev.platform_data;
+       struct soc_camera_link *icl = client->dev.platform_data;
        int ret;
 
        if (icl->power) {
-               ret = icl->power(&mt9m111->client->dev, 1);
+               ret = icl->power(&client->dev, 1);
                if (ret < 0) {
                        dev_err(icd->vdev->parent,
                                "Platform failed to power-on the camera.\n");
@@ -378,8 +378,9 @@ static int mt9m111_enable(struct soc_camera_device *icd)
 
 static int mt9m111_disable(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
-       struct soc_camera_link *icl = mt9m111->client->dev.platform_data;
+       struct soc_camera_link *icl = client->dev.platform_data;
        int ret;
 
        ret = reg_clear(RESET, MT9M111_RESET_CHIP_ENABLE);
@@ -387,15 +388,15 @@ static int mt9m111_disable(struct soc_camera_device *icd)
                mt9m111->powered = 0;
 
        if (icl->power)
-               icl->power(&mt9m111->client->dev, 0);
+               icl->power(&client->dev, 0);
 
        return ret;
 }
 
 static int mt9m111_reset(struct soc_camera_device *icd)
 {
-       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
-       struct soc_camera_link *icl = mt9m111->client->dev.platform_data;
+       struct i2c_client *client = to_i2c_client(icd->control);
+       struct soc_camera_link *icl = client->dev.platform_data;
        int ret;
 
        ret = reg_set(RESET, MT9M111_RESET_RESET_MODE);
@@ -406,7 +407,7 @@ static int mt9m111_reset(struct soc_camera_device *icd)
                                | MT9M111_RESET_RESET_SOC);
 
        if (icl->reset)
-               icl->reset(&mt9m111->client->dev);
+               icl->reset(&client->dev);
 
        return ret;
 }
@@ -562,15 +563,14 @@ static int mt9m111_get_register(struct soc_camera_device *icd,
                                struct v4l2_dbg_register *reg)
 {
        int val;
-
-       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       struct i2c_client *client = to_i2c_client(icd->control);
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
                return -EINVAL;
-       if (reg->match.addr != mt9m111->client->addr)
+       if (reg->match.addr != client->addr)
                return -ENODEV;
 
-       val = mt9m111_reg_read(icd, reg->reg);
+       val = mt9m111_reg_read(client, reg->reg);
        reg->size = 2;
        reg->val = (u64)val;
 
@@ -583,15 +583,15 @@ static int mt9m111_get_register(struct soc_camera_device *icd,
 static int mt9m111_set_register(struct soc_camera_device *icd,
                                struct v4l2_dbg_register *reg)
 {
-       struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
+       struct i2c_client *client = to_i2c_client(icd->control);
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
                return -EINVAL;
 
-       if (reg->match.addr != mt9m111->client->addr)
+       if (reg->match.addr != client->addr)
                return -ENODEV;
 
-       if (mt9m111_reg_write(icd, reg->reg, reg->val) < 0)
+       if (mt9m111_reg_write(client, reg->reg, reg->val) < 0)
                return -EIO;
 
        return 0;
@@ -672,6 +672,7 @@ static struct soc_camera_ops mt9m111_ops = {
 
 static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
        int ret;
 
@@ -692,6 +693,7 @@ static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask)
 
 static int mt9m111_get_global_gain(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        int data;
 
        data = reg_read(GLOBAL_GAIN);
@@ -703,6 +705,7 @@ static int mt9m111_get_global_gain(struct soc_camera_device *icd)
 
 static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        u16 val;
 
        if (gain > 63 * 2 * 2)
@@ -721,6 +724,7 @@ static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain)
 
 static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
        int ret;
 
@@ -737,6 +741,7 @@ static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on)
 
 static int mt9m111_set_autowhitebalance(struct soc_camera_device *icd, int on)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
        int ret;
 
@@ -754,6 +759,7 @@ static int mt9m111_set_autowhitebalance(struct soc_camera_device *icd, int on)
 static int mt9m111_get_control(struct soc_camera_device *icd,
                               struct v4l2_control *ctrl)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
        int data;
 
@@ -898,6 +904,7 @@ static int mt9m111_release(struct soc_camera_device *icd)
  */
 static int mt9m111_video_probe(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd);
        s32 data;
        int ret;
index 2b0927bfd217b1226366f370f6e09d4ee5c57dde..f72aeb7c4deb974afa6241566fd8b922858c9090 100644 (file)
@@ -76,64 +76,61 @@ struct mt9t031 {
        u16 yskip;
 };
 
-static int reg_read(struct soc_camera_device *icd, const u8 reg)
+static int reg_read(struct i2c_client *client, const u8 reg)
 {
-       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
-       struct i2c_client *client = mt9t031->client;
        s32 data = i2c_smbus_read_word_data(client, reg);
        return data < 0 ? data : swab16(data);
 }
 
-static int reg_write(struct soc_camera_device *icd, const u8 reg,
+static int reg_write(struct i2c_client *client, const u8 reg,
                     const u16 data)
 {
-       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
-       return i2c_smbus_write_word_data(mt9t031->client, reg, swab16(data));
+       return i2c_smbus_write_word_data(client, reg, swab16(data));
 }
 
-static int reg_set(struct soc_camera_device *icd, const u8 reg,
+static int reg_set(struct i2c_client *client, const u8 reg,
                   const u16 data)
 {
        int ret;
 
-       ret = reg_read(icd, reg);
+       ret = reg_read(client, reg);
        if (ret < 0)
                return ret;
-       return reg_write(icd, reg, ret | data);
+       return reg_write(client, reg, ret | data);
 }
 
-static int reg_clear(struct soc_camera_device *icd, const u8 reg,
+static int reg_clear(struct i2c_client *client, const u8 reg,
                     const u16 data)
 {
        int ret;
 
-       ret = reg_read(icd, reg);
+       ret = reg_read(client, reg);
        if (ret < 0)
                return ret;
-       return reg_write(icd, reg, ret & ~data);
+       return reg_write(client, reg, ret & ~data);
 }
 
-static int set_shutter(struct soc_camera_device *icd, const u32 data)
+static int set_shutter(struct i2c_client *client, const u32 data)
 {
        int ret;
 
-       ret = reg_write(icd, MT9T031_SHUTTER_WIDTH_UPPER, data >> 16);
+       ret = reg_write(client, MT9T031_SHUTTER_WIDTH_UPPER, data >> 16);
 
        if (ret >= 0)
-               ret = reg_write(icd, MT9T031_SHUTTER_WIDTH, data & 0xffff);
+               ret = reg_write(client, MT9T031_SHUTTER_WIDTH, data & 0xffff);
 
        return ret;
 }
 
-static int get_shutter(struct soc_camera_device *icd, u32 *data)
+static int get_shutter(struct i2c_client *client, u32 *data)
 {
        int ret;
 
-       ret = reg_read(icd, MT9T031_SHUTTER_WIDTH_UPPER);
+       ret = reg_read(client, MT9T031_SHUTTER_WIDTH_UPPER);
        *data = ret << 16;
 
        if (ret >= 0)
-               ret = reg_read(icd, MT9T031_SHUTTER_WIDTH);
+               ret = reg_read(client, MT9T031_SHUTTER_WIDTH);
        *data |= ret & 0xffff;
 
        return ret < 0 ? ret : 0;
@@ -141,12 +138,12 @@ static int get_shutter(struct soc_camera_device *icd, u32 *data)
 
 static int mt9t031_init(struct soc_camera_device *icd)
 {
-       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
-       struct soc_camera_link *icl = mt9t031->client->dev.platform_data;
+       struct i2c_client *client = to_i2c_client(icd->control);
+       struct soc_camera_link *icl = client->dev.platform_data;
        int ret;
 
        if (icl->power) {
-               ret = icl->power(&mt9t031->client->dev, 1);
+               ret = icl->power(&client->dev, 1);
                if (ret < 0) {
                        dev_err(icd->vdev->parent,
                                "Platform failed to power-on the camera.\n");
@@ -155,44 +152,48 @@ static int mt9t031_init(struct soc_camera_device *icd)
        }
 
        /* Disable chip output, synchronous option update */
-       ret = reg_write(icd, MT9T031_RESET, 1);
+       ret = reg_write(client, MT9T031_RESET, 1);
        if (ret >= 0)
-               ret = reg_write(icd, MT9T031_RESET, 0);
+               ret = reg_write(client, MT9T031_RESET, 0);
        if (ret >= 0)
-               ret = reg_clear(icd, MT9T031_OUTPUT_CONTROL, 2);
+               ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2);
 
        if (ret < 0 && icl->power)
-               icl->power(&mt9t031->client->dev, 0);
+               icl->power(&client->dev, 0);
 
        return ret >= 0 ? 0 : -EIO;
 }
 
 static int mt9t031_release(struct soc_camera_device *icd)
 {
-       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
-       struct soc_camera_link *icl = mt9t031->client->dev.platform_data;
+       struct i2c_client *client = to_i2c_client(icd->control);
+       struct soc_camera_link *icl = client->dev.platform_data;
 
        /* Disable the chip */
-       reg_clear(icd, MT9T031_OUTPUT_CONTROL, 2);
+       reg_clear(client, MT9T031_OUTPUT_CONTROL, 2);
 
        if (icl->power)
-               icl->power(&mt9t031->client->dev, 0);
+               icl->power(&client->dev, 0);
 
        return 0;
 }
 
 static int mt9t031_start_capture(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
+
        /* Switch to master "normal" mode */
-       if (reg_set(icd, MT9T031_OUTPUT_CONTROL, 2) < 0)
+       if (reg_set(client, MT9T031_OUTPUT_CONTROL, 2) < 0)
                return -EIO;
        return 0;
 }
 
 static int mt9t031_stop_capture(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
+
        /* Stop sensor readout */
-       if (reg_clear(icd, MT9T031_OUTPUT_CONTROL, 2) < 0)
+       if (reg_clear(client, MT9T031_OUTPUT_CONTROL, 2) < 0)
                return -EIO;
        return 0;
 }
@@ -200,14 +201,16 @@ static int mt9t031_stop_capture(struct soc_camera_device *icd)
 static int mt9t031_set_bus_param(struct soc_camera_device *icd,
                                 unsigned long flags)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
+
        /* The caller should have queried our parameters, check anyway */
        if (flags & ~MT9T031_BUS_PARAM)
                return -EINVAL;
 
        if (flags & SOCAM_PCLK_SAMPLE_FALLING)
-               reg_clear(icd, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
+               reg_clear(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
        else
-               reg_set(icd, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
+               reg_set(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
 
        return 0;
 }
@@ -235,6 +238,7 @@ static void recalculate_limits(struct soc_camera_device *icd,
 static int mt9t031_set_params(struct soc_camera_device *icd,
                              struct v4l2_rect *rect, u16 xskip, u16 yskip)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
        int ret;
        u16 xbin, ybin, width, height, left, top;
@@ -277,22 +281,22 @@ static int mt9t031_set_params(struct soc_camera_device *icd,
        }
 
        /* Disable register update, reconfigure atomically */
-       ret = reg_set(icd, MT9T031_OUTPUT_CONTROL, 1);
+       ret = reg_set(client, MT9T031_OUTPUT_CONTROL, 1);
        if (ret < 0)
                return ret;
 
        /* Blanking and start values - default... */
-       ret = reg_write(icd, MT9T031_HORIZONTAL_BLANKING, hblank);
+       ret = reg_write(client, MT9T031_HORIZONTAL_BLANKING, hblank);
        if (ret >= 0)
-               ret = reg_write(icd, MT9T031_VERTICAL_BLANKING, vblank);
+               ret = reg_write(client, MT9T031_VERTICAL_BLANKING, vblank);
 
        if (yskip != mt9t031->yskip || xskip != mt9t031->xskip) {
                /* Binning, skipping */
                if (ret >= 0)
-                       ret = reg_write(icd, MT9T031_COLUMN_ADDRESS_MODE,
+                       ret = reg_write(client, MT9T031_COLUMN_ADDRESS_MODE,
                                        ((xbin - 1) << 4) | (xskip - 1));
                if (ret >= 0)
-                       ret = reg_write(icd, MT9T031_ROW_ADDRESS_MODE,
+                       ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE,
                                        ((ybin - 1) << 4) | (yskip - 1));
        }
        dev_dbg(&icd->dev, "new physical left %u, top %u\n", left, top);
@@ -300,16 +304,16 @@ static int mt9t031_set_params(struct soc_camera_device *icd,
        /* The caller provides a supported format, as guaranteed by
         * icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() */
        if (ret >= 0)
-               ret = reg_write(icd, MT9T031_COLUMN_START, left);
+               ret = reg_write(client, MT9T031_COLUMN_START, left);
        if (ret >= 0)
-               ret = reg_write(icd, MT9T031_ROW_START, top);
+               ret = reg_write(client, MT9T031_ROW_START, top);
        if (ret >= 0)
-               ret = reg_write(icd, MT9T031_WINDOW_WIDTH, width - 1);
+               ret = reg_write(client, MT9T031_WINDOW_WIDTH, width - 1);
        if (ret >= 0)
-               ret = reg_write(icd, MT9T031_WINDOW_HEIGHT,
+               ret = reg_write(client, MT9T031_WINDOW_HEIGHT,
                                height + icd->y_skip_top - 1);
        if (ret >= 0 && mt9t031->autoexposure) {
-               ret = set_shutter(icd, height + icd->y_skip_top + vblank);
+               ret = set_shutter(client, height + icd->y_skip_top + vblank);
                if (ret >= 0) {
                        const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank;
                        const struct v4l2_queryctrl *qctrl =
@@ -324,7 +328,7 @@ static int mt9t031_set_params(struct soc_camera_device *icd,
 
        /* Re-enable register update, commit all changes */
        if (ret >= 0)
-               ret = reg_clear(icd, MT9T031_OUTPUT_CONTROL, 1);
+               ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 1);
 
        return ret < 0 ? ret : 0;
 }
@@ -417,15 +421,15 @@ static int mt9t031_get_chip_id(struct soc_camera_device *icd,
 static int mt9t031_get_register(struct soc_camera_device *icd,
                                struct v4l2_dbg_register *reg)
 {
-       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+       struct i2c_client *client = to_i2c_client(icd->control);
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
                return -EINVAL;
 
-       if (reg->match.addr != mt9t031->client->addr)
+       if (reg->match.addr != client->addr)
                return -ENODEV;
 
-       reg->val = reg_read(icd, reg->reg);
+       reg->val = reg_read(client, reg->reg);
 
        if (reg->val > 0xffff)
                return -EIO;
@@ -436,15 +440,15 @@ static int mt9t031_get_register(struct soc_camera_device *icd,
 static int mt9t031_set_register(struct soc_camera_device *icd,
                                struct v4l2_dbg_register *reg)
 {
-       struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+       struct i2c_client *client = to_i2c_client(icd->control);
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
                return -EINVAL;
 
-       if (reg->match.addr != mt9t031->client->addr)
+       if (reg->match.addr != client->addr)
                return -ENODEV;
 
-       if (reg_write(icd, reg->reg, reg->val) < 0)
+       if (reg_write(client, reg->reg, reg->val) < 0)
                return -EIO;
 
        return 0;
@@ -528,18 +532,19 @@ static struct soc_camera_ops mt9t031_ops = {
 
 static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
        int data;
 
        switch (ctrl->id) {
        case V4L2_CID_VFLIP:
-               data = reg_read(icd, MT9T031_READ_MODE_2);
+               data = reg_read(client, MT9T031_READ_MODE_2);
                if (data < 0)
                        return -EIO;
                ctrl->value = !!(data & 0x8000);
                break;
        case V4L2_CID_HFLIP:
-               data = reg_read(icd, MT9T031_READ_MODE_2);
+               data = reg_read(client, MT9T031_READ_MODE_2);
                if (data < 0)
                        return -EIO;
                ctrl->value = !!(data & 0x4000);
@@ -553,6 +558,7 @@ static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_contro
 
 static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
        const struct v4l2_queryctrl *qctrl;
        int data;
@@ -565,17 +571,17 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
        switch (ctrl->id) {
        case V4L2_CID_VFLIP:
                if (ctrl->value)
-                       data = reg_set(icd, MT9T031_READ_MODE_2, 0x8000);
+                       data = reg_set(client, MT9T031_READ_MODE_2, 0x8000);
                else
-                       data = reg_clear(icd, MT9T031_READ_MODE_2, 0x8000);
+                       data = reg_clear(client, MT9T031_READ_MODE_2, 0x8000);
                if (data < 0)
                        return -EIO;
                break;
        case V4L2_CID_HFLIP:
                if (ctrl->value)
-                       data = reg_set(icd, MT9T031_READ_MODE_2, 0x4000);
+                       data = reg_set(client, MT9T031_READ_MODE_2, 0x4000);
                else
-                       data = reg_clear(icd, MT9T031_READ_MODE_2, 0x4000);
+                       data = reg_clear(client, MT9T031_READ_MODE_2, 0x4000);
                if (data < 0)
                        return -EIO;
                break;
@@ -589,7 +595,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
                        data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range;
 
                        dev_dbg(&icd->dev, "Setting gain %d\n", data);
-                       data = reg_write(icd, MT9T031_GLOBAL_GAIN, data);
+                       data = reg_write(client, MT9T031_GLOBAL_GAIN, data);
                        if (data < 0)
                                return -EIO;
                } else {
@@ -609,8 +615,8 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
                                data = (((gain - 64 + 7) * 32) & 0xff00) | 0x60;
 
                        dev_dbg(&icd->dev, "Setting gain from 0x%x to 0x%x\n",
-                               reg_read(icd, MT9T031_GLOBAL_GAIN), data);
-                       data = reg_write(icd, MT9T031_GLOBAL_GAIN, data);
+                               reg_read(client, MT9T031_GLOBAL_GAIN), data);
+                       data = reg_write(client, MT9T031_GLOBAL_GAIN, data);
                        if (data < 0)
                                return -EIO;
                }
@@ -628,10 +634,10 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
                                             range / 2) / range + 1;
                        u32 old;
 
-                       get_shutter(icd, &old);
+                       get_shutter(client, &old);
                        dev_dbg(&icd->dev, "Setting shutter width from %u to %u\n",
                                old, shutter);
-                       if (set_shutter(icd, shutter) < 0)
+                       if (set_shutter(client, shutter) < 0)
                                return -EIO;
                        icd->exposure = ctrl->value;
                        mt9t031->autoexposure = 0;
@@ -641,7 +647,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
                if (ctrl->value) {
                        const u16 vblank = MT9T031_VERTICAL_BLANK;
                        const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank;
-                       if (set_shutter(icd, icd->height +
+                       if (set_shutter(client, icd->height +
                                        icd->y_skip_top + vblank) < 0)
                                return -EIO;
                        qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
@@ -661,6 +667,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
  * this wasn't our capture interface, so, we wait for the right one */
 static int mt9t031_video_probe(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
        s32 data;
        int ret;
@@ -672,11 +679,11 @@ static int mt9t031_video_probe(struct soc_camera_device *icd)
                return -ENODEV;
 
        /* Enable the chip */
-       data = reg_write(icd, MT9T031_CHIP_ENABLE, 1);
+       data = reg_write(client, MT9T031_CHIP_ENABLE, 1);
        dev_dbg(&icd->dev, "write: %d\n", data);
 
        /* Read out the chip version register */
-       data = reg_read(icd, MT9T031_CHIP_VERSION);
+       data = reg_read(client, MT9T031_CHIP_VERSION);
 
        switch (data) {
        case 0x1621:
index 4d3b4813c322e67dc46c2c8c272a8db1ba1c728f..be20d312b1dc5784f8c85a63a367c2e219d467c0 100644 (file)
@@ -91,51 +91,49 @@ struct mt9v022 {
        u16 chip_control;
 };
 
-static int reg_read(struct soc_camera_device *icd, const u8 reg)
+static int reg_read(struct i2c_client *client, const u8 reg)
 {
-       struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
-       struct i2c_client *client = mt9v022->client;
        s32 data = i2c_smbus_read_word_data(client, reg);
        return data < 0 ? data : swab16(data);
 }
 
-static int reg_write(struct soc_camera_device *icd, const u8 reg,
+static int reg_write(struct i2c_client *client, const u8 reg,
                     const u16 data)
 {
-       struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
-       return i2c_smbus_write_word_data(mt9v022->client, reg, swab16(data));
+       return i2c_smbus_write_word_data(client, reg, swab16(data));
 }
 
-static int reg_set(struct soc_camera_device *icd, const u8 reg,
+static int reg_set(struct i2c_client *client, const u8 reg,
                   const u16 data)
 {
        int ret;
 
-       ret = reg_read(icd, reg);
+       ret = reg_read(client, reg);
        if (ret < 0)
                return ret;
-       return reg_write(icd, reg, ret | data);
+       return reg_write(client, reg, ret | data);
 }
 
-static int reg_clear(struct soc_camera_device *icd, const u8 reg,
+static int reg_clear(struct i2c_client *client, const u8 reg,
                     const u16 data)
 {
        int ret;
 
-       ret = reg_read(icd, reg);
+       ret = reg_read(client, reg);
        if (ret < 0)
                return ret;
-       return reg_write(icd, reg, ret & ~data);
+       return reg_write(client, reg, ret & ~data);
 }
 
 static int mt9v022_init(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
-       struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
+       struct soc_camera_link *icl = client->dev.platform_data;
        int ret;
 
        if (icl->power) {
-               ret = icl->power(&mt9v022->client->dev, 1);
+               ret = icl->power(&client->dev, 1);
                if (ret < 0) {
                        dev_err(icd->vdev->parent,
                                "Platform failed to power-on the camera.\n");
@@ -148,27 +146,27 @@ static int mt9v022_init(struct soc_camera_device *icd)
         * if available. Soft reset is done in video_probe().
         */
        if (icl->reset)
-               icl->reset(&mt9v022->client->dev);
+               icl->reset(&client->dev);
 
        /* Almost the default mode: master, parallel, simultaneous, and an
         * undocumented bit 0x200, which is present in table 7, but not in 8,
         * plus snapshot mode to disable scan for now */
        mt9v022->chip_control |= 0x10;
-       ret = reg_write(icd, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
+       ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
        if (!ret)
-               ret = reg_write(icd, MT9V022_READ_MODE, 0x300);
+               ret = reg_write(client, MT9V022_READ_MODE, 0x300);
 
        /* All defaults */
        if (!ret)
                /* AEC, AGC on */
-               ret = reg_set(icd, MT9V022_AEC_AGC_ENABLE, 0x3);
+               ret = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x3);
        if (!ret)
-               ret = reg_write(icd, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480);
+               ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480);
        if (!ret)
                /* default - auto */
-               ret = reg_clear(icd, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1);
+               ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1);
        if (!ret)
-               ret = reg_write(icd, MT9V022_DIGITAL_TEST_PATTERN, 0);
+               ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0);
 
        return ret;
 }
@@ -186,10 +184,11 @@ static int mt9v022_release(struct soc_camera_device *icd)
 
 static int mt9v022_start_capture(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
        /* Switch to master "normal" mode */
        mt9v022->chip_control &= ~0x10;
-       if (reg_write(icd, MT9V022_CHIP_CONTROL,
+       if (reg_write(client, MT9V022_CHIP_CONTROL,
                      mt9v022->chip_control) < 0)
                return -EIO;
        return 0;
@@ -197,10 +196,11 @@ static int mt9v022_start_capture(struct soc_camera_device *icd)
 
 static int mt9v022_stop_capture(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
        /* Switch to snapshot mode */
        mt9v022->chip_control |= 0x10;
-       if (reg_write(icd, MT9V022_CHIP_CONTROL,
+       if (reg_write(client, MT9V022_CHIP_CONTROL,
                      mt9v022->chip_control) < 0)
                return -EIO;
        return 0;
@@ -209,8 +209,9 @@ static int mt9v022_stop_capture(struct soc_camera_device *icd)
 static int mt9v022_set_bus_param(struct soc_camera_device *icd,
                                 unsigned long flags)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
-       struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
+       struct soc_camera_link *icl = client->dev.platform_data;
        unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
        int ret;
        u16 pixclk = 0;
@@ -243,14 +244,14 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd,
        if (!(flags & SOCAM_VSYNC_ACTIVE_HIGH))
                pixclk |= 0x2;
 
-       ret = reg_write(icd, MT9V022_PIXCLK_FV_LV, pixclk);
+       ret = reg_write(client, MT9V022_PIXCLK_FV_LV, pixclk);
        if (ret < 0)
                return ret;
 
        if (!(flags & SOCAM_MASTER))
                mt9v022->chip_control &= ~0x8;
 
-       ret = reg_write(icd, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
+       ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
        if (ret < 0)
                return ret;
 
@@ -282,35 +283,36 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
 static int mt9v022_set_crop(struct soc_camera_device *icd,
                            struct v4l2_rect *rect)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        int ret;
 
        /* Like in example app. Contradicts the datasheet though */
-       ret = reg_read(icd, MT9V022_AEC_AGC_ENABLE);
+       ret = reg_read(client, MT9V022_AEC_AGC_ENABLE);
        if (ret >= 0) {
                if (ret & 1) /* Autoexposure */
-                       ret = reg_write(icd, MT9V022_MAX_TOTAL_SHUTTER_WIDTH,
+                       ret = reg_write(client, MT9V022_MAX_TOTAL_SHUTTER_WIDTH,
                                        rect->height + icd->y_skip_top + 43);
                else
-                       ret = reg_write(icd, MT9V022_TOTAL_SHUTTER_WIDTH,
+                       ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
                                        rect->height + icd->y_skip_top + 43);
        }
        /* Setup frame format: defaults apart from width and height */
        if (!ret)
-               ret = reg_write(icd, MT9V022_COLUMN_START, rect->left);
+               ret = reg_write(client, MT9V022_COLUMN_START, rect->left);
        if (!ret)
-               ret = reg_write(icd, MT9V022_ROW_START, rect->top);
+               ret = reg_write(client, MT9V022_ROW_START, rect->top);
        if (!ret)
                /* Default 94, Phytec driver says:
                 * "width + horizontal blank >= 660" */
-               ret = reg_write(icd, MT9V022_HORIZONTAL_BLANKING,
+               ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING,
                                rect->width > 660 - 43 ? 43 :
                                660 - rect->width);
        if (!ret)
-               ret = reg_write(icd, MT9V022_VERTICAL_BLANKING, 45);
+               ret = reg_write(client, MT9V022_VERTICAL_BLANKING, 45);
        if (!ret)
-               ret = reg_write(icd, MT9V022_WINDOW_WIDTH, rect->width);
+               ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect->width);
        if (!ret)
-               ret = reg_write(icd, MT9V022_WINDOW_HEIGHT,
+               ret = reg_write(client, MT9V022_WINDOW_HEIGHT,
                                rect->height + icd->y_skip_top);
 
        if (ret < 0)
@@ -396,16 +398,16 @@ static int mt9v022_get_chip_id(struct soc_camera_device *icd,
 static int mt9v022_get_register(struct soc_camera_device *icd,
                                struct v4l2_dbg_register *reg)
 {
-       struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+       struct i2c_client *client = to_i2c_client(icd->control);
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
                return -EINVAL;
 
-       if (reg->match.addr != mt9v022->client->addr)
+       if (reg->match.addr != client->addr)
                return -ENODEV;
 
        reg->size = 2;
-       reg->val = reg_read(icd, reg->reg);
+       reg->val = reg_read(client, reg->reg);
 
        if (reg->val > 0xffff)
                return -EIO;
@@ -416,15 +418,15 @@ static int mt9v022_get_register(struct soc_camera_device *icd,
 static int mt9v022_set_register(struct soc_camera_device *icd,
                                struct v4l2_dbg_register *reg)
 {
-       struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+       struct i2c_client *client = to_i2c_client(icd->control);
 
        if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
                return -EINVAL;
 
-       if (reg->match.addr != mt9v022->client->addr)
+       if (reg->match.addr != client->addr)
                return -ENODEV;
 
-       if (reg_write(icd, reg->reg, reg->val) < 0)
+       if (reg_write(client, reg->reg, reg->val) < 0)
                return -EIO;
 
        return 0;
@@ -517,29 +519,30 @@ static struct soc_camera_ops mt9v022_ops = {
 static int mt9v022_get_control(struct soc_camera_device *icd,
                               struct v4l2_control *ctrl)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        int data;
 
        switch (ctrl->id) {
        case V4L2_CID_VFLIP:
-               data = reg_read(icd, MT9V022_READ_MODE);
+               data = reg_read(client, MT9V022_READ_MODE);
                if (data < 0)
                        return -EIO;
                ctrl->value = !!(data & 0x10);
                break;
        case V4L2_CID_HFLIP:
-               data = reg_read(icd, MT9V022_READ_MODE);
+               data = reg_read(client, MT9V022_READ_MODE);
                if (data < 0)
                        return -EIO;
                ctrl->value = !!(data & 0x20);
                break;
        case V4L2_CID_EXPOSURE_AUTO:
-               data = reg_read(icd, MT9V022_AEC_AGC_ENABLE);
+               data = reg_read(client, MT9V022_AEC_AGC_ENABLE);
                if (data < 0)
                        return -EIO;
                ctrl->value = !!(data & 0x1);
                break;
        case V4L2_CID_AUTOGAIN:
-               data = reg_read(icd, MT9V022_AEC_AGC_ENABLE);
+               data = reg_read(client, MT9V022_AEC_AGC_ENABLE);
                if (data < 0)
                        return -EIO;
                ctrl->value = !!(data & 0x2);
@@ -552,6 +555,7 @@ static int mt9v022_set_control(struct soc_camera_device *icd,
                               struct v4l2_control *ctrl)
 {
        int data;
+       struct i2c_client *client = to_i2c_client(icd->control);
        const struct v4l2_queryctrl *qctrl;
 
        qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id);
@@ -562,17 +566,17 @@ static int mt9v022_set_control(struct soc_camera_device *icd,
        switch (ctrl->id) {
        case V4L2_CID_VFLIP:
                if (ctrl->value)
-                       data = reg_set(icd, MT9V022_READ_MODE, 0x10);
+                       data = reg_set(client, MT9V022_READ_MODE, 0x10);
                else
-                       data = reg_clear(icd, MT9V022_READ_MODE, 0x10);
+                       data = reg_clear(client, MT9V022_READ_MODE, 0x10);
                if (data < 0)
                        return -EIO;
                break;
        case V4L2_CID_HFLIP:
                if (ctrl->value)
-                       data = reg_set(icd, MT9V022_READ_MODE, 0x20);
+                       data = reg_set(client, MT9V022_READ_MODE, 0x20);
                else
-                       data = reg_clear(icd, MT9V022_READ_MODE, 0x20);
+                       data = reg_clear(client, MT9V022_READ_MODE, 0x20);
                if (data < 0)
                        return -EIO;
                break;
@@ -593,12 +597,12 @@ static int mt9v022_set_control(struct soc_camera_device *icd,
                        /* The user wants to set gain manually, hope, she
                         * knows, what she's doing... Switch AGC off. */
 
-                       if (reg_clear(icd, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
+                       if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
                                return -EIO;
 
                        dev_info(&icd->dev, "Setting gain from %d to %lu\n",
-                                reg_read(icd, MT9V022_ANALOG_GAIN), gain);
-                       if (reg_write(icd, MT9V022_ANALOG_GAIN, gain) < 0)
+                                reg_read(client, MT9V022_ANALOG_GAIN), gain);
+                       if (reg_write(client, MT9V022_ANALOG_GAIN, gain) < 0)
                                return -EIO;
                        icd->gain = ctrl->value;
                }
@@ -614,13 +618,13 @@ static int mt9v022_set_control(struct soc_camera_device *icd,
                        /* The user wants to set shutter width manually, hope,
                         * she knows, what she's doing... Switch AEC off. */
 
-                       if (reg_clear(icd, MT9V022_AEC_AGC_ENABLE, 0x1) < 0)
+                       if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1) < 0)
                                return -EIO;
 
                        dev_dbg(&icd->dev, "Shutter width from %d to %lu\n",
-                               reg_read(icd, MT9V022_TOTAL_SHUTTER_WIDTH),
+                               reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH),
                                shutter);
-                       if (reg_write(icd, MT9V022_TOTAL_SHUTTER_WIDTH,
+                       if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
                                      shutter) < 0)
                                return -EIO;
                        icd->exposure = ctrl->value;
@@ -628,17 +632,17 @@ static int mt9v022_set_control(struct soc_camera_device *icd,
                break;
        case V4L2_CID_AUTOGAIN:
                if (ctrl->value)
-                       data = reg_set(icd, MT9V022_AEC_AGC_ENABLE, 0x2);
+                       data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2);
                else
-                       data = reg_clear(icd, MT9V022_AEC_AGC_ENABLE, 0x2);
+                       data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2);
                if (data < 0)
                        return -EIO;
                break;
        case V4L2_CID_EXPOSURE_AUTO:
                if (ctrl->value)
-                       data = reg_set(icd, MT9V022_AEC_AGC_ENABLE, 0x1);
+                       data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1);
                else
-                       data = reg_clear(icd, MT9V022_AEC_AGC_ENABLE, 0x1);
+                       data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1);
                if (data < 0)
                        return -EIO;
                break;
@@ -650,8 +654,9 @@ static int mt9v022_set_control(struct soc_camera_device *icd,
  * this wasn't our capture interface, so, we wait for the right one */
 static int mt9v022_video_probe(struct soc_camera_device *icd)
 {
+       struct i2c_client *client = to_i2c_client(icd->control);
        struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
-       struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
+       struct soc_camera_link *icl = client->dev.platform_data;
        s32 data;
        int ret;
        unsigned long flags;
@@ -661,7 +666,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
                return -ENODEV;
 
        /* Read out the chip version register */
-       data = reg_read(icd, MT9V022_CHIP_VERSION);
+       data = reg_read(client, MT9V022_CHIP_VERSION);
 
        /* must be 0x1311 or 0x1313 */
        if (data != 0x1311 && data != 0x1313) {
@@ -672,12 +677,12 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
        }
 
        /* Soft reset */
-       ret = reg_write(icd, MT9V022_RESET, 1);
+       ret = reg_write(client, MT9V022_RESET, 1);
        if (ret < 0)
                goto ei2c;
        /* 15 clock cycles */
        udelay(200);
-       if (reg_read(icd, MT9V022_RESET)) {
+       if (reg_read(client, MT9V022_RESET)) {
                dev_err(&icd->dev, "Resetting MT9V022 failed!\n");
                goto ei2c;
        }
@@ -685,11 +690,11 @@ static int mt9v022_video_probe(struct soc_camera_device *icd)
        /* Set monochrome or colour sensor type */
        if (sensor_type && (!strcmp("colour", sensor_type) ||
                            !strcmp("color", sensor_type))) {
-               ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11);
+               ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11);
                mt9v022->model = V4L2_IDENT_MT9V022IX7ATC;
                icd->formats = mt9v022_colour_formats;
        } else {
-               ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 0x11);
+               ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 0x11);
                mt9v022->model = V4L2_IDENT_MT9V022IX7ATM;
                icd->formats = mt9v022_monochrome_formats;
        }
@@ -735,10 +740,13 @@ ei2c:
 static void mt9v022_video_remove(struct soc_camera_device *icd)
 {
        struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+       struct soc_camera_link *icl = mt9v022->client->dev.platform_data;
 
        dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9v022->client->addr,
                icd->dev.parent, icd->vdev);
        soc_camera_video_stop(icd);
+       if (icl->free_bus)
+               icl->free_bus(icl);
 }
 
 static int mt9v022_probe(struct i2c_client *client,
index 86fab56c5a203abb884f0940bcd07a039f6f2180..2d075205bdfe4b724e22882aa5e6a636edf81cef 100644 (file)
@@ -102,10 +102,10 @@ struct mx1_buffer {
  * Interface. If anyone ever builds hardware to enable more than
  * one camera, they will have to modify this driver too */
 struct mx1_camera_dev {
+       struct soc_camera_host          soc_host;
        struct soc_camera_device        *icd;
        struct mx1_camera_pdata         *pdata;
        struct mx1_buffer               *active;
-       struct device                   *dev;
        struct resource                 *res;
        struct clk                      *clk;
        struct list_head                capture;
@@ -219,7 +219,7 @@ static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev)
        int ret;
 
        if (unlikely(!pcdev->active)) {
-               dev_err(pcdev->dev, "DMA End IRQ with no active buffer\n");
+               dev_err(pcdev->soc_host.dev, "DMA End IRQ with no active buffer\n");
                return -EFAULT;
        }
 
@@ -229,7 +229,7 @@ static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev)
                vbuf->size, pcdev->res->start +
                CSIRXR, DMA_MODE_READ);
        if (unlikely(ret))
-               dev_err(pcdev->dev, "Failed to setup DMA sg list\n");
+               dev_err(pcdev->soc_host.dev, "Failed to setup DMA sg list\n");
 
        return ret;
 }
@@ -338,14 +338,14 @@ static void mx1_camera_dma_irq(int channel, void *data)
        imx_dma_disable(channel);
 
        if (unlikely(!pcdev->active)) {
-               dev_err(pcdev->dev, "DMA End IRQ with no active buffer\n");
+               dev_err(pcdev->soc_host.dev, "DMA End IRQ with no active buffer\n");
                goto out;
        }
 
        vb = &pcdev->active->vb;
        buf = container_of(vb, struct mx1_buffer, vb);
        WARN_ON(buf->inwork || list_empty(&vb->queue));
-       dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+       dev_dbg(pcdev->soc_host.dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
                vb, vb->baddr, vb->bsize);
 
        mx1_camera_wakeup(pcdev, vb, buf);
@@ -366,7 +366,7 @@ static void mx1_camera_init_videobuf(struct videobuf_queue *q,
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct mx1_camera_dev *pcdev = ici->priv;
 
-       videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, pcdev->dev,
+       videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, ici->dev,
                                        &pcdev->lock,
                                        V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                        V4L2_FIELD_NONE,
@@ -385,7 +385,7 @@ static int mclk_get_divisor(struct mx1_camera_dev *pcdev)
         * they get a nice Oops */
        div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1;
 
-       dev_dbg(pcdev->dev, "System clock %lukHz, target freq %dkHz, "
+       dev_dbg(pcdev->soc_host.dev, "System clock %lukHz, target freq %dkHz, "
                "divisor %lu\n", lcdclk / 1000, mclk / 1000, div);
 
        return div;
@@ -395,7 +395,7 @@ static void mx1_camera_activate(struct mx1_camera_dev *pcdev)
 {
        unsigned int csicr1 = CSICR1_EN;
 
-       dev_dbg(pcdev->dev, "Activate device\n");
+       dev_dbg(pcdev->soc_host.dev, "Activate device\n");
 
        clk_enable(pcdev->clk);
 
@@ -411,7 +411,7 @@ static void mx1_camera_activate(struct mx1_camera_dev *pcdev)
 
 static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev)
 {
-       dev_dbg(pcdev->dev, "Deactivate device\n");
+       dev_dbg(pcdev->soc_host.dev, "Deactivate device\n");
 
        /* Disable all CSI interface */
        __raw_writel(0x00, pcdev->base + CSICR1);
@@ -550,7 +550,7 @@ static int mx1_camera_set_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
        if (!xlate) {
-               dev_warn(&ici->dev, "Format %x not found\n", pix->pixelformat);
+               dev_warn(ici->dev, "Format %x not found\n", pix->pixelformat);
                return -EINVAL;
        }
 
@@ -633,12 +633,6 @@ static struct soc_camera_host_ops mx1_soc_camera_host_ops = {
        .querycap       = mx1_camera_querycap,
 };
 
-/* Should be allocated dynamically too, but we have only one. */
-static struct soc_camera_host mx1_soc_camera_host = {
-       .drv_name       = DRIVER_NAME,
-       .ops            = &mx1_soc_camera_host_ops,
-};
-
 static struct fiq_handler fh = {
        .name           = "csi_sof"
 };
@@ -673,7 +667,6 @@ static int __init mx1_camera_probe(struct platform_device *pdev)
                goto exit_put_clk;
        }
 
-       dev_set_drvdata(&pdev->dev, pcdev);
        pcdev->res = res;
        pcdev->clk = clk;
 
@@ -707,16 +700,15 @@ static int __init mx1_camera_probe(struct platform_device *pdev)
        }
        pcdev->irq = irq;
        pcdev->base = base;
-       pcdev->dev = &pdev->dev;
 
        /* request dma */
        pcdev->dma_chan = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_HIGH);
        if (pcdev->dma_chan < 0) {
-               dev_err(pcdev->dev, "Can't request DMA for MX1 CSI\n");
+               dev_err(&pdev->dev, "Can't request DMA for MX1 CSI\n");
                err = -EBUSY;
                goto exit_iounmap;
        }
-       dev_dbg(pcdev->dev, "got DMA channel %d\n", pcdev->dma_chan);
+       dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_chan);
 
        imx_dma_setup_handlers(pcdev->dma_chan, mx1_camera_dma_irq, NULL,
                               pcdev);
@@ -729,7 +721,7 @@ static int __init mx1_camera_probe(struct platform_device *pdev)
        /* request irq */
        err = claim_fiq(&fh);
        if (err) {
-               dev_err(pcdev->dev, "Camera interrupt register failed \n");
+               dev_err(&pdev->dev, "Camera interrupt register failed \n");
                goto exit_free_dma;
        }
 
@@ -746,10 +738,12 @@ static int __init mx1_camera_probe(struct platform_device *pdev)
        mxc_set_irq_fiq(irq, 1);
        enable_fiq(irq);
 
-       mx1_soc_camera_host.priv        = pcdev;
-       mx1_soc_camera_host.dev.parent  = &pdev->dev;
-       mx1_soc_camera_host.nr          = pdev->id;
-       err = soc_camera_host_register(&mx1_soc_camera_host);
+       pcdev->soc_host.drv_name        = DRIVER_NAME;
+       pcdev->soc_host.ops             = &mx1_soc_camera_host_ops;
+       pcdev->soc_host.priv            = pcdev;
+       pcdev->soc_host.dev             = &pdev->dev;
+       pcdev->soc_host.nr              = pdev->id;
+       err = soc_camera_host_register(&pcdev->soc_host);
        if (err)
                goto exit_free_irq;
 
@@ -777,7 +771,9 @@ exit:
 
 static int __exit mx1_camera_remove(struct platform_device *pdev)
 {
-       struct mx1_camera_dev *pcdev = platform_get_drvdata(pdev);
+       struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+       struct mx1_camera_dev *pcdev = container_of(soc_host,
+                                       struct mx1_camera_dev, soc_host);
        struct resource *res;
 
        imx_dma_free(pcdev->dma_chan);
@@ -787,7 +783,7 @@ static int __exit mx1_camera_remove(struct platform_device *pdev)
 
        clk_put(pcdev->clk);
 
-       soc_camera_host_unregister(&mx1_soc_camera_host);
+       soc_camera_host_unregister(soc_host);
 
        iounmap(pcdev->base);
 
index 2d0781118eb06f3498238accddb4b5c1f6049af2..e605c076ed89d43ae5533e98d5d4dc60009dfd19 100644 (file)
@@ -87,7 +87,6 @@ struct mx3_camera_buffer {
  * @soc_host:          embedded soc_host object
  */
 struct mx3_camera_dev {
-       struct device           *dev;
        /*
         * i.MX3x is only supposed to handle one camera on its Camera Sensor
         * Interface. If anyone ever builds hardware to enable more than one
@@ -431,7 +430,7 @@ static void mx3_camera_init_videobuf(struct videobuf_queue *q,
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct mx3_camera_dev *mx3_cam = ici->priv;
 
-       videobuf_queue_dma_contig_init(q, &mx3_videobuf_ops, mx3_cam->dev,
+       videobuf_queue_dma_contig_init(q, &mx3_videobuf_ops, ici->dev,
                                       &mx3_cam->lock,
                                       V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                       V4L2_FIELD_NONE,
@@ -599,7 +598,8 @@ static int test_platform_param(struct mx3_camera_dev *mx3_cam,
                *flags |= SOCAM_DATAWIDTH_4;
                break;
        default:
-               dev_info(mx3_cam->dev, "Unsupported bus width %d\n", buswidth);
+               dev_info(mx3_cam->soc_host.dev, "Unsupported bus width %d\n",
+                        buswidth);
                return -EINVAL;
        }
 
@@ -614,7 +614,7 @@ static int mx3_camera_try_bus_param(struct soc_camera_device *icd,
        unsigned long bus_flags, camera_flags;
        int ret = test_platform_param(mx3_cam, depth, &bus_flags);
 
-       dev_dbg(&ici->dev, "requested bus width %d bit: %d\n", depth, ret);
+       dev_dbg(ici->dev, "requested bus width %d bit: %d\n", depth, ret);
 
        if (ret < 0)
                return ret;
@@ -637,7 +637,7 @@ static bool chan_filter(struct dma_chan *chan, void *arg)
        if (!rq)
                return false;
 
-       pdata = rq->mx3_cam->dev->platform_data;
+       pdata = rq->mx3_cam->soc_host.dev->platform_data;
 
        return rq->id == chan->chan_id &&
                pdata->dma_dev == chan->device->dev;
@@ -697,7 +697,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx,
                        xlate->cam_fmt = icd->formats + idx;
                        xlate->buswidth = buswidth;
                        xlate++;
-                       dev_dbg(&ici->dev, "Providing format %s using %s\n",
+                       dev_dbg(ici->dev, "Providing format %s using %s\n",
                                mx3_camera_formats[0].name,
                                icd->formats[idx].name);
                }
@@ -709,7 +709,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx,
                        xlate->cam_fmt = icd->formats + idx;
                        xlate->buswidth = buswidth;
                        xlate++;
-                       dev_dbg(&ici->dev, "Providing format %s using %s\n",
+                       dev_dbg(ici->dev, "Providing format %s using %s\n",
                                mx3_camera_formats[0].name,
                                icd->formats[idx].name);
                }
@@ -722,7 +722,7 @@ passthrough:
                        xlate->cam_fmt = icd->formats + idx;
                        xlate->buswidth = buswidth;
                        xlate++;
-                       dev_dbg(&ici->dev,
+                       dev_dbg(ici->dev,
                                "Providing format %s in pass-through mode\n",
                                icd->formats[idx].name);
                }
@@ -829,7 +829,7 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
        if (!xlate) {
-               dev_warn(&ici->dev, "Format %x not found\n", pix->pixelformat);
+               dev_warn(ici->dev, "Format %x not found\n", pix->pixelformat);
                return -EINVAL;
        }
 
@@ -866,7 +866,7 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
        if (pixfmt && !xlate) {
-               dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+               dev_warn(ici->dev, "Format %x not found\n", pixfmt);
                return -EINVAL;
        }
 
@@ -933,11 +933,11 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
 
        xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
        if (!xlate) {
-               dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+               dev_warn(ici->dev, "Format %x not found\n", pixfmt);
                return -EINVAL;
        }
 
-       dev_dbg(&ici->dev, "requested bus width %d bit: %d\n",
+       dev_dbg(ici->dev, "requested bus width %d bit: %d\n",
                icd->buswidth, ret);
 
        if (ret < 0)
@@ -947,7 +947,7 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
 
        common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags);
        if (!common_flags) {
-               dev_dbg(&ici->dev, "no common flags: camera %lx, host %lx\n",
+               dev_dbg(ici->dev, "no common flags: camera %lx, host %lx\n",
                        camera_flags, bus_flags);
                return -EINVAL;
        }
@@ -1054,7 +1054,7 @@ static int mx3_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
 
        csi_reg_write(mx3_cam, sens_conf | dw, CSI_SENS_CONF);
 
-       dev_dbg(&ici->dev, "Set SENS_CONF to %x\n", sens_conf | dw);
+       dev_dbg(ici->dev, "Set SENS_CONF to %x\n", sens_conf | dw);
 
        return 0;
 }
@@ -1074,7 +1074,7 @@ static struct soc_camera_host_ops mx3_soc_camera_host_ops = {
        .set_bus_param  = mx3_camera_set_bus_param,
 };
 
-static int mx3_camera_probe(struct platform_device *pdev)
+static int __devinit mx3_camera_probe(struct platform_device *pdev)
 {
        struct mx3_camera_dev *mx3_cam;
        struct resource *res;
@@ -1102,8 +1102,6 @@ static int mx3_camera_probe(struct platform_device *pdev)
                goto eclkget;
        }
 
-       dev_set_drvdata(&pdev->dev, mx3_cam);
-
        mx3_cam->pdata = pdev->dev.platform_data;
        mx3_cam->platform_flags = mx3_cam->pdata->flags;
        if (!(mx3_cam->platform_flags & (MX3_CAMERA_DATAWIDTH_4 |
@@ -1135,14 +1133,14 @@ static int mx3_camera_probe(struct platform_device *pdev)
        }
 
        mx3_cam->base   = base;
-       mx3_cam->dev    = &pdev->dev;
 
        soc_host                = &mx3_cam->soc_host;
        soc_host->drv_name      = MX3_CAM_DRV_NAME;
        soc_host->ops           = &mx3_soc_camera_host_ops;
        soc_host->priv          = mx3_cam;
-       soc_host->dev.parent    = &pdev->dev;
+       soc_host->dev           = &pdev->dev;
        soc_host->nr            = pdev->id;
+
        err = soc_camera_host_register(soc_host);
        if (err)
                goto ecamhostreg;
@@ -1165,11 +1163,13 @@ egetres:
 
 static int __devexit mx3_camera_remove(struct platform_device *pdev)
 {
-       struct mx3_camera_dev *mx3_cam = platform_get_drvdata(pdev);
+       struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+       struct mx3_camera_dev *mx3_cam = container_of(soc_host,
+                                       struct mx3_camera_dev, soc_host);
 
        clk_put(mx3_cam->clk);
 
-       soc_camera_host_unregister(&mx3_cam->soc_host);
+       soc_camera_host_unregister(soc_host);
 
        iounmap(mx3_cam->base);
 
@@ -1194,11 +1194,11 @@ static struct platform_driver mx3_camera_driver = {
                .name   = MX3_CAM_DRV_NAME,
        },
        .probe          = mx3_camera_probe,
-       .remove         = __exit_p(mx3_camera_remove),
+       .remove         = __devexit_p(mx3_camera_remove),
 };
 
 
-static int __devinit mx3_camera_init(void)
+static int __init mx3_camera_init(void)
 {
        return platform_driver_register(&mx3_camera_driver);
 }
index 3be5a71bdac284b5ccc866bd1d6eff39f4dc0246..35890e8b2431740a63a16cb3dd8ac377a50640c2 100644 (file)
@@ -453,7 +453,7 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
 static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
 {
        DEB_EE(("VIDIOC_ENUMINPUT %d.\n", i->index));
-       if (i->index < 0 || i->index >= MXB_INPUTS)
+       if (i->index >= MXB_INPUTS)
                return -EINVAL;
        memcpy(i, &mxb_inputs[i->index], sizeof(struct v4l2_input));
        return 0;
@@ -616,7 +616,7 @@ static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
        struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
        struct mxb *mxb = (struct mxb *)dev->ext_priv;
 
-       if (a->index < 0 || a->index > MXB_INPUTS) {
+       if (a->index > MXB_INPUTS) {
                DEB_D(("VIDIOC_G_AUDIO %d out of range.\n", a->index));
                return -EINVAL;
        }
index 9af5532db1423eb1d7971e5a00396a49c03f1959..08cfd3e4ae8abe8c6b96059b35c76fb42f1db94b 100644 (file)
@@ -112,6 +112,8 @@ static int framedrop                = -1;
 static int fastset;
 static int force_palette;
 static int backlight;
+/* Bitmask marking allocated devices from 0 to OV511_MAX_UNIT_VIDEO */
+static unsigned long ov511_devused;
 static int unit_video[OV511_MAX_UNIT_VIDEO];
 static int remove_zeros;
 static int mirror;
@@ -5720,7 +5722,7 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
        struct usb_device *dev = interface_to_usbdev(intf);
        struct usb_interface_descriptor *idesc;
        struct usb_ov511 *ov;
-       int i;
+       int i, rc, nr;
 
        PDEBUG(1, "probing for device...");
 
@@ -5845,33 +5847,41 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
        ov->vdev->parent = &intf->dev;
        video_set_drvdata(ov->vdev, ov);
 
-       for (i = 0; i < OV511_MAX_UNIT_VIDEO; i++) {
-               /* Minor 0 cannot be specified; assume user wants autodetect */
-               if (unit_video[i] == 0)
-                       break;
+       mutex_lock(&ov->lock);
 
-               if (video_register_device(ov->vdev, VFL_TYPE_GRABBER,
-                       unit_video[i]) >= 0) {
-                       break;
-               }
-       }
+       /* Check to see next free device and mark as used */
+       nr = find_first_zero_bit(&ov511_devused, OV511_MAX_UNIT_VIDEO);
+
+       /* Registers device */
+       if (unit_video[nr] != 0)
+               rc = video_register_device(ov->vdev, VFL_TYPE_GRABBER,
+                                          unit_video[nr]);
+       else
+               rc = video_register_device(ov->vdev, VFL_TYPE_GRABBER, -1);
 
-       /* Use the next available one */
-       if ((ov->vdev->minor == -1) &&
-           video_register_device(ov->vdev, VFL_TYPE_GRABBER, -1) < 0) {
+       if (rc < 0) {
                err("video_register_device failed");
+               mutex_unlock(&ov->lock);
                goto error;
        }
 
+       /* Mark device as used */
+       ov511_devused |= 1 << nr;
+       ov->nr = nr;
+
        dev_info(&intf->dev, "Device at %s registered to minor %d\n",
                 ov->usb_path, ov->vdev->minor);
 
        usb_set_intfdata(intf, ov);
        if (ov_create_sysfs(ov->vdev)) {
                err("ov_create_sysfs failed");
+               ov511_devused &= ~(1 << nr);
+               mutex_unlock(&ov->lock);
                goto error;
        }
 
+       mutex_lock(&ov->lock);
+
        return 0;
 
 error:
@@ -5906,10 +5916,16 @@ ov51x_disconnect(struct usb_interface *intf)
 
        PDEBUG(3, "");
 
+       mutex_lock(&ov->lock);
        usb_set_intfdata (intf, NULL);
 
-       if (!ov)
+       if (!ov) {
+               mutex_unlock(&ov->lock);
                return;
+       }
+
+       /* Free device number */
+       ov511_devused &= ~(1 << ov->nr);
 
        if (ov->vdev)
                video_unregister_device(ov->vdev);
@@ -5927,6 +5943,7 @@ ov51x_disconnect(struct usb_interface *intf)
 
        ov->streaming = 0;
        ov51x_unlink_isoc(ov);
+       mutex_unlock(&ov->lock);
 
        ov->dev = NULL;
 
index 70d99e52329d53ff457d9d335982808e92171d8f..c450c92468da58c4dbb5e403d605d125faaf6054 100644 (file)
@@ -494,6 +494,9 @@ struct usb_ov511 {
        int has_decoder;        /* Device has a video decoder */
        int pal;                /* Device is designed for PAL resolution */
 
+       /* ov511 device number ID */
+       int nr;                 /* Stores a device number */
+
        /* I2C interface */
        struct mutex i2c_lock;    /* Protect I2C controller regs */
        unsigned char primary_i2c_slave;  /* I2C write id of sensor */
index c0d911252862935b80a5a9215aff0a67ab55d5c8..0bce255168bdfbb154cecb715df2d9774669c837 100644 (file)
@@ -1067,10 +1067,12 @@ static int ov772x_probe(struct i2c_client *client,
        struct i2c_adapter        *adapter = to_i2c_adapter(client->dev.parent);
        int                        ret;
 
-       info = client->dev.platform_data;
-       if (!info)
+       if (!client->dev.platform_data)
                return -EINVAL;
 
+       info = container_of(client->dev.platform_data,
+                           struct ov772x_camera_info, link);
+
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
                dev_err(&adapter->dev,
                        "I2C-Adapter doesn't support "
index 1cb6a260e8b00056940c4200348ce9461cd1e16c..336a20eded0f25e5a294a93bf1294ec7249222fa 100644 (file)
@@ -71,6 +71,7 @@ static const struct pvr2_device_desc pvr2_device_29xxx = {
                .flag_has_svideo = !0,
                .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
                .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
+               .ir_scheme = PVR2_IR_SCHEME_29XXX,
 };
 
 
@@ -284,6 +285,11 @@ static struct tda10048_config hauppauge_tda10048_config = {
        .output_mode    = TDA10048_PARALLEL_OUTPUT,
        .fwbulkwritelen = TDA10048_BULKWRITE_50,
        .inversion      = TDA10048_INVERSION_ON,
+       .dtv6_if_freq_khz = TDA10048_IF_3300,
+       .dtv7_if_freq_khz = TDA10048_IF_3800,
+       .dtv8_if_freq_khz = TDA10048_IF_4300,
+       .clk_freq_khz   = TDA10048_CLK_16000,
+       .disable_gate_access = 1,
 };
 
 static struct tda829x_config tda829x_no_probe = {
index 3e553389cbc34c4c8f94c3d2db7be1d8afd84c32..ea04ecf8aa39a0a33d291c5726f8fc52d3526fce 100644 (file)
@@ -69,6 +69,7 @@ struct pvr2_string_table {
 #define PVR2_ROUTING_SCHEME_HAUPPAUGE 0
 #define PVR2_ROUTING_SCHEME_GOTVIEW 1
 #define PVR2_ROUTING_SCHEME_ONAIR 2
+#define PVR2_ROUTING_SCHEME_AV400 3
 
 #define PVR2_DIGITAL_SCHEME_NONE 0
 #define PVR2_DIGITAL_SCHEME_HAUPPAUGE 1
@@ -78,8 +79,10 @@ struct pvr2_string_table {
 #define PVR2_LED_SCHEME_HAUPPAUGE 1
 
 #define PVR2_IR_SCHEME_NONE 0
-#define PVR2_IR_SCHEME_24XXX 1
-#define PVR2_IR_SCHEME_ZILOG 2
+#define PVR2_IR_SCHEME_24XXX 1 /* FX2-controlled IR */
+#define PVR2_IR_SCHEME_ZILOG 2 /* HVR-1950 style (must be taken out of reset) */
+#define PVR2_IR_SCHEME_24XXX_MCE 3 /* 24xxx MCE device */
+#define PVR2_IR_SCHEME_29XXX 4 /* Original 29xxx device */
 
 /* This describes a particular hardware type (except for the USB device ID
    which must live in a separate structure due to environmental
@@ -162,19 +165,9 @@ struct pvr2_device_desc {
           ensure that it is found. */
        unsigned int flag_has_wm8775:1;
 
-       /* Indicate any specialized IR scheme that might need to be
-          supported by this driver.  If not set, then it is assumed that
-          IR can work without help from the driver (which is frequently
-          the case).  This is otherwise set to one of
-          PVR2_IR_SCHEME_xxxx.  For "xxxx", the value "24XXX" indicates a
-          Hauppauge 24xxx class device which has an FPGA-hosted IR
-          receiver that can only be reached via FX2 command codes.  In
-          that case the pvrusb2 driver will emulate the behavior of the
-          older 29xxx device's IR receiver (a "virtual" I2C chip) in terms
-          of those command codes.  For the value "ZILOG", we're dealing
-          with an IR chip that must be taken out of reset via another FX2
-          command code (which is the case for HVR-1950 devices). */
-       unsigned int ir_scheme:2;
+       /* Indicate IR scheme of hardware.  If not set, then it is assumed
+          that IR can work without any help from the driver. */
+       unsigned int ir_scheme:3;
 
        /* These bits define which kinds of sources the device can handle.
           Note: Digital tuner presence is inferred by the
index 5d75eb5211b1a774067b34338c41a153a29aef45..5b152ff20bd0a3d94ad3dc9045538a2187db3422 100644 (file)
@@ -200,6 +200,9 @@ struct pvr2_hdw {
        int i2c_cx25840_hack_state;
        int i2c_linked;
 
+       /* IR related */
+       unsigned int ir_scheme_active; /* IR scheme as seen from the outside */
+
        /* Frequency table */
        unsigned int freqTable[FREQTABLE_SIZE];
        unsigned int freqProgSlot;
index add3395d324804aa974afb992003d374fcd09f21..0c745b142fb73999c77067aa83ff7eccd29d8bbf 100644 (file)
@@ -142,6 +142,15 @@ static const unsigned char *module_i2c_addresses[] = {
 };
 
 
+static const char *ir_scheme_names[] = {
+       [PVR2_IR_SCHEME_NONE] = "none",
+       [PVR2_IR_SCHEME_29XXX] = "29xxx",
+       [PVR2_IR_SCHEME_24XXX] = "24xxx (29xxx emulation)",
+       [PVR2_IR_SCHEME_24XXX_MCE] = "24xxx (MCE device)",
+       [PVR2_IR_SCHEME_ZILOG] = "Zilog",
+};
+
+
 /* Define the list of additional controls we'll dynamically construct based
    on query of the cx2341x module. */
 struct pvr2_mpeg_ids {
@@ -2170,7 +2179,7 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
        }
 
        /* Take the IR chip out of reset, if appropriate */
-       if (hdw->hdw_desc->ir_scheme == PVR2_IR_SCHEME_ZILOG) {
+       if (hdw->ir_scheme_active == PVR2_IR_SCHEME_ZILOG) {
                pvr2_issue_simple_cmd(hdw,
                                      FX2CMD_HCW_ZILOG_RESET |
                                      (1 << 8) |
@@ -2451,6 +2460,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
                                GFP_KERNEL);
        if (!hdw->controls) goto fail;
        hdw->hdw_desc = hdw_desc;
+       hdw->ir_scheme_active = hdw->hdw_desc->ir_scheme;
        for (idx = 0; idx < hdw->control_cnt; idx++) {
                cptr = hdw->controls + idx;
                cptr->hdw = hdw;
@@ -4809,6 +4819,12 @@ static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which,
                        stats.buffers_processed,
                        stats.buffers_failed);
        }
+       case 6: {
+               unsigned int id = hdw->ir_scheme_active;
+               return scnprintf(buf, acnt, "ir scheme: id=%d %s", id,
+                                (id >= ARRAY_SIZE(ir_scheme_names) ?
+                                 "?" : ir_scheme_names[id]));
+       }
        default: break;
        }
        return 0;
@@ -4825,65 +4841,35 @@ static unsigned int pvr2_hdw_report_clients(struct pvr2_hdw *hdw,
        unsigned int tcnt = 0;
        unsigned int ccnt;
        struct i2c_client *client;
-       struct list_head *item;
-       void *cd;
        const char *p;
        unsigned int id;
 
-       ccnt = scnprintf(buf, acnt, "Associated v4l2-subdev drivers:");
+       ccnt = scnprintf(buf, acnt, "Associated v4l2-subdev drivers and I2C clients:\n");
        tcnt += ccnt;
        v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) {
                id = sd->grp_id;
                p = NULL;
                if (id < ARRAY_SIZE(module_names)) p = module_names[id];
                if (p) {
-                       ccnt = scnprintf(buf + tcnt, acnt - tcnt, " %s", p);
+                       ccnt = scnprintf(buf + tcnt, acnt - tcnt, "  %s:", p);
                        tcnt += ccnt;
                } else {
                        ccnt = scnprintf(buf + tcnt, acnt - tcnt,
-                                        " (unknown id=%u)", id);
+                                        "  (unknown id=%u):", id);
                        tcnt += ccnt;
                }
-       }
-       ccnt = scnprintf(buf + tcnt, acnt - tcnt, "\n");
-       tcnt += ccnt;
-
-       ccnt = scnprintf(buf + tcnt, acnt - tcnt, "I2C clients:\n");
-       tcnt += ccnt;
-
-       mutex_lock(&hdw->i2c_adap.clist_lock);
-       list_for_each(item, &hdw->i2c_adap.clients) {
-               client = list_entry(item, struct i2c_client, list);
-               ccnt = scnprintf(buf + tcnt, acnt - tcnt,
-                                "  %s: i2c=%02x", client->name, client->addr);
-               tcnt += ccnt;
-               cd = i2c_get_clientdata(client);
-               v4l2_device_for_each_subdev(sd, &hdw->v4l2_dev) {
-                       if (cd == sd) {
-                               id = sd->grp_id;
-                               p = NULL;
-                               if (id < ARRAY_SIZE(module_names)) {
-                                       p = module_names[id];
-                               }
-                               if (p) {
-                                       ccnt = scnprintf(buf + tcnt,
-                                                        acnt - tcnt,
-                                                        " subdev=%s", p);
-                                       tcnt += ccnt;
-                               } else {
-                                       ccnt = scnprintf(buf + tcnt,
-                                                        acnt - tcnt,
-                                                        " subdev= id %u)",
-                                                        id);
-                                       tcnt += ccnt;
-                               }
-                               break;
-                       }
+               client = v4l2_get_subdevdata(sd);
+               if (client) {
+                       ccnt = scnprintf(buf + tcnt, acnt - tcnt,
+                                        " %s @ %02x\n", client->name,
+                                        client->addr);
+                       tcnt += ccnt;
+               } else {
+                       ccnt = scnprintf(buf + tcnt, acnt - tcnt,
+                                        " no i2c client\n");
+                       tcnt += ccnt;
                }
-               ccnt = scnprintf(buf + tcnt, acnt - tcnt, "\n");
-               tcnt += ccnt;
        }
-       mutex_unlock(&hdw->i2c_adap.clist_lock);
        return tcnt;
 }
 
index 9af282f9e76544b8206aecc40505ab38a431e1bb..610bd848df246537ddd3b65da677c0643a4d8037 100644 (file)
@@ -42,6 +42,18 @@ static int ir_mode[PVR_NUM] = { [0 ... PVR_NUM-1] = 1 };
 module_param_array(ir_mode, int, NULL, 0444);
 MODULE_PARM_DESC(ir_mode,"specify: 0=disable IR reception, 1=normal IR");
 
+static int pvr2_disable_ir_video;
+module_param_named(disable_autoload_ir_video, pvr2_disable_ir_video,
+                  int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(disable_autoload_ir_video,
+                "1=do not try to autoload ir_video IR receiver");
+
+/* Mapping of IR schemes to known I2C addresses - if any */
+static const unsigned char ir_video_addresses[] = {
+       [PVR2_IR_SCHEME_29XXX] = 0x18,
+       [PVR2_IR_SCHEME_24XXX] = 0x18,
+};
+
 static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */
                          u8 i2c_addr,      /* I2C address we're talking to */
                          u8 *data,         /* Data to write */
@@ -559,6 +571,31 @@ static void do_i2c_scan(struct pvr2_hdw *hdw)
        printk(KERN_INFO "%s: i2c scan done.\n", hdw->name);
 }
 
+static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw)
+{
+       struct i2c_board_info info;
+       unsigned char addr = 0;
+       if (pvr2_disable_ir_video) {
+               pvr2_trace(PVR2_TRACE_INFO,
+                          "Automatic binding of ir_video has been disabled.");
+               return;
+       }
+       if (hdw->ir_scheme_active < ARRAY_SIZE(ir_video_addresses)) {
+               addr = ir_video_addresses[hdw->ir_scheme_active];
+       }
+       if (!addr) {
+               /* The device either doesn't support I2C-based IR or we
+                  don't know (yet) how to operate IR on the device. */
+               return;
+       }
+       pvr2_trace(PVR2_TRACE_INFO,
+                  "Binding ir_video to i2c address 0x%02x.", addr);
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+       info.addr = addr;
+       i2c_new_device(&hdw->i2c_adap, &info);
+}
+
 void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
 {
        unsigned int idx;
@@ -574,7 +611,9 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
                printk(KERN_INFO "%s: IR disabled\n",hdw->name);
                hdw->i2c_func[0x18] = i2c_black_hole;
        } else if (ir_mode[hdw->unit_number] == 1) {
-               if (hdw->hdw_desc->ir_scheme == PVR2_IR_SCHEME_24XXX) {
+               if (hdw->ir_scheme_active == PVR2_IR_SCHEME_24XXX) {
+                       /* Set up translation so that our IR looks like a
+                          29xxx device */
                        hdw->i2c_func[0x18] = i2c_24xxx_ir;
                }
        }
@@ -597,15 +636,23 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
        i2c_add_adapter(&hdw->i2c_adap);
        if (hdw->i2c_func[0x18] == i2c_24xxx_ir) {
                /* Probe for a different type of IR receiver on this
-                  device.  If present, disable the emulated IR receiver. */
+                  device.  This is really the only way to differentiate
+                  older 24xxx devices from 24xxx variants that include an
+                  IR blaster.  If the IR blaster is present, the IR
+                  receiver is part of that chip and thus we must disable
+                  the emulated IR receiver. */
                if (do_i2c_probe(hdw, 0x71)) {
                        pvr2_trace(PVR2_TRACE_INFO,
                                   "Device has newer IR hardware;"
                                   " disabling unneeded virtual IR device");
                        hdw->i2c_func[0x18] = NULL;
+                       /* Remember that this is a different device... */
+                       hdw->ir_scheme_active = PVR2_IR_SCHEME_24XXX_MCE;
                }
        }
        if (i2c_scan) do_i2c_scan(hdw);
+
+       pvr2_i2c_register_ir(hdw);
 }
 
 void pvr2_i2c_core_done(struct pvr2_hdw *hdw)
index 299c1cbc38329ca5c87423b4af78e0a2123ae638..6c23456e0bda2c2661030deb5737fb8ca120e2a5 100644 (file)
@@ -539,7 +539,7 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp)
                                         &sfp->attr_unit_number);
        }
        pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev);
-       sfp->class_dev->driver_data = NULL;
+       dev_set_drvdata(sfp->class_dev, NULL);
        device_unregister(sfp->class_dev);
        sfp->class_dev = NULL;
 }
@@ -549,7 +549,7 @@ static ssize_t v4l_minor_number_show(struct device *class_dev,
                                     struct device_attribute *attr, char *buf)
 {
        struct pvr2_sysfs *sfp;
-       sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+       sfp = dev_get_drvdata(class_dev);
        if (!sfp) return -EINVAL;
        return scnprintf(buf,PAGE_SIZE,"%d\n",
                         pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,
@@ -561,7 +561,7 @@ static ssize_t bus_info_show(struct device *class_dev,
                             struct device_attribute *attr, char *buf)
 {
        struct pvr2_sysfs *sfp;
-       sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+       sfp = dev_get_drvdata(class_dev);
        if (!sfp) return -EINVAL;
        return scnprintf(buf,PAGE_SIZE,"%s\n",
                         pvr2_hdw_get_bus_info(sfp->channel.hdw));
@@ -572,7 +572,7 @@ static ssize_t hdw_name_show(struct device *class_dev,
                             struct device_attribute *attr, char *buf)
 {
        struct pvr2_sysfs *sfp;
-       sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+       sfp = dev_get_drvdata(class_dev);
        if (!sfp) return -EINVAL;
        return scnprintf(buf,PAGE_SIZE,"%s\n",
                         pvr2_hdw_get_type(sfp->channel.hdw));
@@ -583,7 +583,7 @@ static ssize_t hdw_desc_show(struct device *class_dev,
                             struct device_attribute *attr, char *buf)
 {
        struct pvr2_sysfs *sfp;
-       sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+       sfp = dev_get_drvdata(class_dev);
        if (!sfp) return -EINVAL;
        return scnprintf(buf,PAGE_SIZE,"%s\n",
                         pvr2_hdw_get_desc(sfp->channel.hdw));
@@ -595,7 +595,7 @@ static ssize_t v4l_radio_minor_number_show(struct device *class_dev,
                                           char *buf)
 {
        struct pvr2_sysfs *sfp;
-       sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+       sfp = dev_get_drvdata(class_dev);
        if (!sfp) return -EINVAL;
        return scnprintf(buf,PAGE_SIZE,"%d\n",
                         pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,
@@ -607,7 +607,7 @@ static ssize_t unit_number_show(struct device *class_dev,
                                struct device_attribute *attr, char *buf)
 {
        struct pvr2_sysfs *sfp;
-       sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+       sfp = dev_get_drvdata(class_dev);
        if (!sfp) return -EINVAL;
        return scnprintf(buf,PAGE_SIZE,"%d\n",
                         pvr2_hdw_get_unit_number(sfp->channel.hdw));
@@ -635,7 +635,7 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
        class_dev->parent = &usb_dev->dev;
 
        sfp->class_dev = class_dev;
-       class_dev->driver_data = sfp;
+       dev_set_drvdata(class_dev, sfp);
        ret = device_register(class_dev);
        if (ret) {
                pvr2_trace(PVR2_TRACE_ERROR_LEGS,
@@ -792,7 +792,7 @@ static ssize_t debuginfo_show(struct device *class_dev,
                              struct device_attribute *attr, char *buf)
 {
        struct pvr2_sysfs *sfp;
-       sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+       sfp = dev_get_drvdata(class_dev);
        if (!sfp) return -EINVAL;
        pvr2_hdw_trigger_module_log(sfp->channel.hdw);
        return pvr2_debugifc_print_info(sfp->channel.hdw,buf,PAGE_SIZE);
@@ -803,7 +803,7 @@ static ssize_t debugcmd_show(struct device *class_dev,
                             struct device_attribute *attr, char *buf)
 {
        struct pvr2_sysfs *sfp;
-       sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+       sfp = dev_get_drvdata(class_dev);
        if (!sfp) return -EINVAL;
        return pvr2_debugifc_print_status(sfp->channel.hdw,buf,PAGE_SIZE);
 }
@@ -816,7 +816,7 @@ static ssize_t debugcmd_store(struct device *class_dev,
        struct pvr2_sysfs *sfp;
        int ret;
 
-       sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+       sfp = dev_get_drvdata(class_dev);
        if (!sfp) return -EINVAL;
 
        ret = pvr2_debugifc_docmd(sfp->channel.hdw,buf,count);
index 9e0f2b07b93b277bed1123220b77eeb222956a02..2d8825e5b1bef5f3e319fa7dc8a1df4d3629a856 100644 (file)
@@ -90,7 +90,7 @@ static struct v4l2_capability pvr_capability ={
        .driver         = "pvrusb2",
        .card           = "Hauppauge WinTV pvr-usb2",
        .bus_info       = "usb",
-       .version        = KERNEL_VERSION(0,8,0),
+       .version        = KERNEL_VERSION(0, 9, 0),
        .capabilities   = (V4L2_CAP_VIDEO_CAPTURE |
                           V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
                           V4L2_CAP_READWRITE),
@@ -267,7 +267,7 @@ static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                memset(&tmp,0,sizeof(tmp));
                tmp.index = vi->index;
                ret = 0;
-               if ((vi->index < 0) || (vi->index >= fh->input_cnt)) {
+               if (vi->index >= fh->input_cnt) {
                        ret = -EINVAL;
                        break;
                }
@@ -331,7 +331,7 @@ static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        case VIDIOC_S_INPUT:
        {
                struct v4l2_input *vi = (struct v4l2_input *)arg;
-               if ((vi->index < 0) || (vi->index >= fh->input_cnt)) {
+               if (vi->index >= fh->input_cnt) {
                        ret = -ERANGE;
                        break;
                }
index 7c542caf248e40ff1647bf0b4c6d6345448affd5..db25c3034c11be4e7deb4cc98bf41006b4e860f7 100644 (file)
@@ -601,7 +601,7 @@ static void pwc_snapshot_button(struct pwc_device *pdev, int down)
 
 #ifdef CONFIG_USB_PWC_INPUT_EVDEV
        if (pdev->button_dev) {
-               input_report_key(pdev->button_dev, BTN_0, down);
+               input_report_key(pdev->button_dev, KEY_CAMERA, down);
                input_sync(pdev->button_dev);
        }
 #endif
@@ -1783,7 +1783,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
                return -ENOMEM;
        }
        memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
-       pdev->vdev->parent = &(udev->dev);
+       pdev->vdev->parent = &intf->dev;
        strcpy(pdev->vdev->name, name);
        video_set_drvdata(pdev->vdev, pdev);
 
@@ -1847,7 +1847,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        usb_to_input_id(pdev->udev, &pdev->button_dev->id);
        pdev->button_dev->dev.parent = &pdev->udev->dev;
        pdev->button_dev->evbit[0] = BIT_MASK(EV_KEY);
-       pdev->button_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
+       pdev->button_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA);
 
        rc = input_register_device(pdev->button_dev);
        if (rc) {
index bc0a464295c59d511128b8526c445419c808e7b3..2876ce08451095fc275b151c129529744673ef93 100644 (file)
@@ -1107,7 +1107,7 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                                return -EINVAL;
                        if (buf->memory != V4L2_MEMORY_MMAP)
                                return -EINVAL;
-                       if (buf->index < 0 || buf->index >= pwc_mbufs)
+                       if (buf->index >= pwc_mbufs)
                                return -EINVAL;
 
                        buf->flags |= V4L2_BUF_FLAG_QUEUED;
index c639845460fff8df6a327bf1f7e21ebbb954ac34..f60de40fd21f79d17274dc0fe3769a84639d9f6a 100644 (file)
@@ -202,7 +202,7 @@ struct pxa_buffer {
 };
 
 struct pxa_camera_dev {
-       struct device           *dev;
+       struct soc_camera_host  soc_host;
        /* PXA27x is only supposed to handle one camera on its Quick Capture
         * interface. If anyone ever builds hardware to enable more than
         * one camera, they will have to modify this driver too */
@@ -261,7 +261,6 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
 {
        struct soc_camera_device *icd = vq->priv_data;
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
-       struct pxa_camera_dev *pcdev = ici->priv;
        struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
        int i;
 
@@ -278,7 +277,7 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
 
        for (i = 0; i < ARRAY_SIZE(buf->dmas); i++) {
                if (buf->dmas[i].sg_cpu)
-                       dma_free_coherent(pcdev->dev, buf->dmas[i].sg_size,
+                       dma_free_coherent(ici->dev, buf->dmas[i].sg_size,
                                          buf->dmas[i].sg_cpu,
                                          buf->dmas[i].sg_dma);
                buf->dmas[i].sg_cpu = NULL;
@@ -338,14 +337,14 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
        int dma_len = 0, xfer_len = 0;
 
        if (pxa_dma->sg_cpu)
-               dma_free_coherent(pcdev->dev, pxa_dma->sg_size,
+               dma_free_coherent(pcdev->soc_host.dev, pxa_dma->sg_size,
                                  pxa_dma->sg_cpu, pxa_dma->sg_dma);
 
        sglen = calculate_dma_sglen(*sg_first, dma->sglen,
                                    *sg_first_ofs, size);
 
        pxa_dma->sg_size = (sglen + 1) * sizeof(struct pxa_dma_desc);
-       pxa_dma->sg_cpu = dma_alloc_coherent(pcdev->dev, pxa_dma->sg_size,
+       pxa_dma->sg_cpu = dma_alloc_coherent(pcdev->soc_host.dev, pxa_dma->sg_size,
                                             &pxa_dma->sg_dma, GFP_KERNEL);
        if (!pxa_dma->sg_cpu)
                return -ENOMEM;
@@ -353,7 +352,7 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
        pxa_dma->sglen = sglen;
        offset = *sg_first_ofs;
 
-       dev_dbg(pcdev->dev, "DMA: sg_first=%p, sglen=%d, ofs=%d, dma.desc=%x\n",
+       dev_dbg(pcdev->soc_host.dev, "DMA: sg_first=%p, sglen=%d, ofs=%d, dma.desc=%x\n",
                *sg_first, sglen, *sg_first_ofs, pxa_dma->sg_dma);
 
 
@@ -376,7 +375,7 @@ static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
                pxa_dma->sg_cpu[i].ddadr =
                        pxa_dma->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc);
 
-               dev_vdbg(pcdev->dev, "DMA: desc.%08x->@phys=0x%08x, len=%d\n",
+               dev_vdbg(pcdev->soc_host.dev, "DMA: desc.%08x->@phys=0x%08x, len=%d\n",
                         pxa_dma->sg_dma + i * sizeof(struct pxa_dma_desc),
                         sg_dma_address(sg) + offset, xfer_len);
                offset = 0;
@@ -488,7 +487,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
                ret = pxa_init_dma_channel(pcdev, buf, dma, 0, CIBR0, size_y,
                                           &sg, &next_ofs);
                if (ret) {
-                       dev_err(pcdev->dev,
+                       dev_err(pcdev->soc_host.dev,
                                "DMA initialization for Y/RGB failed\n");
                        goto fail;
                }
@@ -498,7 +497,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
                        ret = pxa_init_dma_channel(pcdev, buf, dma, 1, CIBR1,
                                                   size_u, &sg, &next_ofs);
                if (ret) {
-                       dev_err(pcdev->dev,
+                       dev_err(pcdev->soc_host.dev,
                                "DMA initialization for U failed\n");
                        goto fail_u;
                }
@@ -508,7 +507,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
                        ret = pxa_init_dma_channel(pcdev, buf, dma, 2, CIBR2,
                                                   size_v, &sg, &next_ofs);
                if (ret) {
-                       dev_err(pcdev->dev,
+                       dev_err(pcdev->soc_host.dev,
                                "DMA initialization for V failed\n");
                        goto fail_v;
                }
@@ -522,10 +521,10 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
        return 0;
 
 fail_v:
-       dma_free_coherent(pcdev->dev, buf->dmas[1].sg_size,
+       dma_free_coherent(pcdev->soc_host.dev, buf->dmas[1].sg_size,
                          buf->dmas[1].sg_cpu, buf->dmas[1].sg_dma);
 fail_u:
-       dma_free_coherent(pcdev->dev, buf->dmas[0].sg_size,
+       dma_free_coherent(pcdev->soc_host.dev, buf->dmas[0].sg_size,
                          buf->dmas[0].sg_cpu, buf->dmas[0].sg_dma);
 fail:
        free_buffer(vq, buf);
@@ -549,7 +548,7 @@ static void pxa_dma_start_channels(struct pxa_camera_dev *pcdev)
        active = pcdev->active;
 
        for (i = 0; i < pcdev->channels; i++) {
-               dev_dbg(pcdev->dev, "%s (channel=%d) ddadr=%08x\n", __func__,
+               dev_dbg(pcdev->soc_host.dev, "%s (channel=%d) ddadr=%08x\n", __func__,
                        i, active->dmas[i].sg_dma);
                DDADR(pcdev->dma_chans[i]) = active->dmas[i].sg_dma;
                DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
@@ -561,7 +560,7 @@ static void pxa_dma_stop_channels(struct pxa_camera_dev *pcdev)
        int i;
 
        for (i = 0; i < pcdev->channels; i++) {
-               dev_dbg(pcdev->dev, "%s (channel=%d)\n", __func__, i);
+               dev_dbg(pcdev->soc_host.dev, "%s (channel=%d)\n", __func__, i);
                DCSR(pcdev->dma_chans[i]) = 0;
        }
 }
@@ -597,7 +596,7 @@ static void pxa_camera_start_capture(struct pxa_camera_dev *pcdev)
 {
        unsigned long cicr0, cifr;
 
-       dev_dbg(pcdev->dev, "%s\n", __func__);
+       dev_dbg(pcdev->soc_host.dev, "%s\n", __func__);
        /* Reset the FIFOs */
        cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F;
        __raw_writel(cifr, pcdev->base + CIFR);
@@ -617,7 +616,7 @@ static void pxa_camera_stop_capture(struct pxa_camera_dev *pcdev)
        __raw_writel(cicr0, pcdev->base + CICR0);
 
        pcdev->active = NULL;
-       dev_dbg(pcdev->dev, "%s\n", __func__);
+       dev_dbg(pcdev->soc_host.dev, "%s\n", __func__);
 }
 
 static void pxa_videobuf_queue(struct videobuf_queue *vq,
@@ -686,7 +685,7 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,
        do_gettimeofday(&vb->ts);
        vb->field_count++;
        wake_up(&vb->done);
-       dev_dbg(pcdev->dev, "%s dequeud buffer (vb=0x%p)\n", __func__, vb);
+       dev_dbg(pcdev->soc_host.dev, "%s dequeud buffer (vb=0x%p)\n", __func__, vb);
 
        if (list_empty(&pcdev->capture)) {
                pxa_camera_stop_capture(pcdev);
@@ -722,7 +721,7 @@ static void pxa_camera_check_link_miss(struct pxa_camera_dev *pcdev)
        for (i = 0; i < pcdev->channels; i++)
                if (DDADR(pcdev->dma_chans[i]) != DDADR_STOP)
                        is_dma_stopped = 0;
-       dev_dbg(pcdev->dev, "%s : top queued buffer=%p, dma_stopped=%d\n",
+       dev_dbg(pcdev->soc_host.dev, "%s : top queued buffer=%p, dma_stopped=%d\n",
                __func__, pcdev->active, is_dma_stopped);
        if (pcdev->active && is_dma_stopped)
                pxa_camera_start_capture(pcdev);
@@ -747,12 +746,12 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
                overrun |= CISR_IFO_1 | CISR_IFO_2;
 
        if (status & DCSR_BUSERR) {
-               dev_err(pcdev->dev, "DMA Bus Error IRQ!\n");
+               dev_err(pcdev->soc_host.dev, "DMA Bus Error IRQ!\n");
                goto out;
        }
 
        if (!(status & (DCSR_ENDINTR | DCSR_STARTINTR))) {
-               dev_err(pcdev->dev, "Unknown DMA IRQ source, "
+               dev_err(pcdev->soc_host.dev, "Unknown DMA IRQ source, "
                        "status: 0x%08x\n", status);
                goto out;
        }
@@ -776,7 +775,7 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
        buf = container_of(vb, struct pxa_buffer, vb);
        WARN_ON(buf->inwork || list_empty(&vb->queue));
 
-       dev_dbg(pcdev->dev, "%s channel=%d %s%s(vb=0x%p) dma.desc=%x\n",
+       dev_dbg(pcdev->soc_host.dev, "%s channel=%d %s%s(vb=0x%p) dma.desc=%x\n",
                __func__, channel, status & DCSR_STARTINTR ? "SOF " : "",
                status & DCSR_ENDINTR ? "EOF " : "", vb, DDADR(channel));
 
@@ -787,7 +786,7 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
                 */
                if (camera_status & overrun &&
                    !list_is_last(pcdev->capture.next, &pcdev->capture)) {
-                       dev_dbg(pcdev->dev, "FIFO overrun! CISR: %x\n",
+                       dev_dbg(pcdev->soc_host.dev, "FIFO overrun! CISR: %x\n",
                                camera_status);
                        pxa_camera_stop_capture(pcdev);
                        pxa_camera_start_capture(pcdev);
@@ -854,7 +853,7 @@ static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev)
        /* mclk <= ciclk / 4 (27.4.2) */
        if (mclk > lcdclk / 4) {
                mclk = lcdclk / 4;
-               dev_warn(pcdev->dev, "Limiting master clock to %lu\n", mclk);
+               dev_warn(pcdev->soc_host.dev, "Limiting master clock to %lu\n", mclk);
        }
 
        /* We verify mclk != 0, so if anyone breaks it, here comes their Oops */
@@ -864,7 +863,7 @@ static u32 mclk_get_divisor(struct pxa_camera_dev *pcdev)
        if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
                pcdev->mclk = lcdclk / (2 * (div + 1));
 
-       dev_dbg(pcdev->dev, "LCD clock %luHz, target freq %luHz, "
+       dev_dbg(pcdev->soc_host.dev, "LCD clock %luHz, target freq %luHz, "
                "divisor %u\n", lcdclk, mclk, div);
 
        return div;
@@ -884,12 +883,12 @@ static void pxa_camera_activate(struct pxa_camera_dev *pcdev)
        struct pxacamera_platform_data *pdata = pcdev->pdata;
        u32 cicr4 = 0;
 
-       dev_dbg(pcdev->dev, "Registered platform device at %p data %p\n",
+       dev_dbg(pcdev->soc_host.dev, "Registered platform device at %p data %p\n",
                pcdev, pdata);
 
        if (pdata && pdata->init) {
-               dev_dbg(pcdev->dev, "%s: Init gpios\n", __func__);
-               pdata->init(pcdev->dev);
+               dev_dbg(pcdev->soc_host.dev, "%s: Init gpios\n", __func__);
+               pdata->init(pcdev->soc_host.dev);
        }
 
        /* disable all interrupts */
@@ -931,7 +930,7 @@ static irqreturn_t pxa_camera_irq(int irq, void *data)
        struct videobuf_buffer *vb;
 
        status = __raw_readl(pcdev->base + CISR);
-       dev_dbg(pcdev->dev, "Camera interrupt status 0x%lx\n", status);
+       dev_dbg(pcdev->soc_host.dev, "Camera interrupt status 0x%lx\n", status);
 
        if (!status)
                return IRQ_NONE;
@@ -1259,7 +1258,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
                        xlate->cam_fmt = icd->formats + idx;
                        xlate->buswidth = buswidth;
                        xlate++;
-                       dev_dbg(&ici->dev, "Providing format %s using %s\n",
+                       dev_dbg(ici->dev, "Providing format %s using %s\n",
                                pxa_camera_formats[0].name,
                                icd->formats[idx].name);
                }
@@ -1274,7 +1273,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
                        xlate->cam_fmt = icd->formats + idx;
                        xlate->buswidth = buswidth;
                        xlate++;
-                       dev_dbg(&ici->dev, "Providing format %s packed\n",
+                       dev_dbg(ici->dev, "Providing format %s packed\n",
                                icd->formats[idx].name);
                }
                break;
@@ -1286,7 +1285,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
                        xlate->cam_fmt = icd->formats + idx;
                        xlate->buswidth = icd->formats[idx].depth;
                        xlate++;
-                       dev_dbg(&ici->dev,
+                       dev_dbg(ici->dev,
                                "Providing format %s in pass-through mode\n",
                                icd->formats[idx].name);
                }
@@ -1315,11 +1314,11 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd,
        icd->sense = NULL;
 
        if (ret < 0) {
-               dev_warn(&ici->dev, "Failed to crop to %ux%u@%u:%u\n",
+               dev_warn(ici->dev, "Failed to crop to %ux%u@%u:%u\n",
                         rect->width, rect->height, rect->left, rect->top);
        } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
                if (sense.pixel_clock > sense.pixel_clock_max) {
-                       dev_err(&ici->dev,
+                       dev_err(ici->dev,
                                "pixel clock %lu set by the camera too high!",
                                sense.pixel_clock);
                        return -EIO;
@@ -1347,7 +1346,7 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
        if (!xlate) {
-               dev_warn(&ici->dev, "Format %x not found\n", pix->pixelformat);
+               dev_warn(ici->dev, "Format %x not found\n", pix->pixelformat);
                return -EINVAL;
        }
 
@@ -1363,11 +1362,11 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
        icd->sense = NULL;
 
        if (ret < 0) {
-               dev_warn(&ici->dev, "Failed to configure for format %x\n",
+               dev_warn(ici->dev, "Failed to configure for format %x\n",
                         pix->pixelformat);
        } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) {
                if (sense.pixel_clock > sense.pixel_clock_max) {
-                       dev_err(&ici->dev,
+                       dev_err(ici->dev,
                                "pixel clock %lu set by the camera too high!",
                                sense.pixel_clock);
                        return -EIO;
@@ -1395,7 +1394,7 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
        if (!xlate) {
-               dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+               dev_warn(ici->dev, "Format %x not found\n", pixfmt);
                return -EINVAL;
        }
 
@@ -1552,13 +1551,7 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
        .set_bus_param  = pxa_camera_set_bus_param,
 };
 
-/* Should be allocated dynamically too, but we have only one. */
-static struct soc_camera_host pxa_soc_camera_host = {
-       .drv_name               = PXA_CAM_DRV_NAME,
-       .ops                    = &pxa_soc_camera_host_ops,
-};
-
-static int pxa_camera_probe(struct platform_device *pdev)
+static int __devinit pxa_camera_probe(struct platform_device *pdev)
 {
        struct pxa_camera_dev *pcdev;
        struct resource *res;
@@ -1586,7 +1579,6 @@ static int pxa_camera_probe(struct platform_device *pdev)
                goto exit_kfree;
        }
 
-       dev_set_drvdata(&pdev->dev, pcdev);
        pcdev->res = res;
 
        pcdev->pdata = pdev->dev.platform_data;
@@ -1607,7 +1599,6 @@ static int pxa_camera_probe(struct platform_device *pdev)
                pcdev->mclk = 20000000;
        }
 
-       pcdev->dev = &pdev->dev;
        pcdev->mclk_divisor = mclk_get_divisor(pcdev);
 
        INIT_LIST_HEAD(&pcdev->capture);
@@ -1616,13 +1607,13 @@ static int pxa_camera_probe(struct platform_device *pdev)
        /*
         * Request the regions.
         */
-       if (!request_mem_region(res->start, res->end - res->start + 1,
+       if (!request_mem_region(res->start, resource_size(res),
                                PXA_CAM_DRV_NAME)) {
                err = -EBUSY;
                goto exit_clk;
        }
 
-       base = ioremap(res->start, res->end - res->start + 1);
+       base = ioremap(res->start, resource_size(res));
        if (!base) {
                err = -ENOMEM;
                goto exit_release;
@@ -1634,29 +1625,29 @@ static int pxa_camera_probe(struct platform_device *pdev)
        err = pxa_request_dma("CI_Y", DMA_PRIO_HIGH,
                              pxa_camera_dma_irq_y, pcdev);
        if (err < 0) {
-               dev_err(pcdev->dev, "Can't request DMA for Y\n");
+               dev_err(&pdev->dev, "Can't request DMA for Y\n");
                goto exit_iounmap;
        }
        pcdev->dma_chans[0] = err;
-       dev_dbg(pcdev->dev, "got DMA channel %d\n", pcdev->dma_chans[0]);
+       dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_chans[0]);
 
        err = pxa_request_dma("CI_U", DMA_PRIO_HIGH,
                              pxa_camera_dma_irq_u, pcdev);
        if (err < 0) {
-               dev_err(pcdev->dev, "Can't request DMA for U\n");
+               dev_err(&pdev->dev, "Can't request DMA for U\n");
                goto exit_free_dma_y;
        }
        pcdev->dma_chans[1] = err;
-       dev_dbg(pcdev->dev, "got DMA channel (U) %d\n", pcdev->dma_chans[1]);
+       dev_dbg(&pdev->dev, "got DMA channel (U) %d\n", pcdev->dma_chans[1]);
 
        err = pxa_request_dma("CI_V", DMA_PRIO_HIGH,
                              pxa_camera_dma_irq_v, pcdev);
        if (err < 0) {
-               dev_err(pcdev->dev, "Can't request DMA for V\n");
+               dev_err(&pdev->dev, "Can't request DMA for V\n");
                goto exit_free_dma_u;
        }
        pcdev->dma_chans[2] = err;
-       dev_dbg(pcdev->dev, "got DMA channel (V) %d\n", pcdev->dma_chans[2]);
+       dev_dbg(&pdev->dev, "got DMA channel (V) %d\n", pcdev->dma_chans[2]);
 
        DRCMR(68) = pcdev->dma_chans[0] | DRCMR_MAPVLD;
        DRCMR(69) = pcdev->dma_chans[1] | DRCMR_MAPVLD;
@@ -1666,14 +1657,17 @@ static int pxa_camera_probe(struct platform_device *pdev)
        err = request_irq(pcdev->irq, pxa_camera_irq, 0, PXA_CAM_DRV_NAME,
                          pcdev);
        if (err) {
-               dev_err(pcdev->dev, "Camera interrupt register failed \n");
+               dev_err(&pdev->dev, "Camera interrupt register failed \n");
                goto exit_free_dma;
        }
 
-       pxa_soc_camera_host.priv        = pcdev;
-       pxa_soc_camera_host.dev.parent  = &pdev->dev;
-       pxa_soc_camera_host.nr          = pdev->id;
-       err = soc_camera_host_register(&pxa_soc_camera_host);
+       pcdev->soc_host.drv_name        = PXA_CAM_DRV_NAME;
+       pcdev->soc_host.ops             = &pxa_soc_camera_host_ops;
+       pcdev->soc_host.priv            = pcdev;
+       pcdev->soc_host.dev             = &pdev->dev;
+       pcdev->soc_host.nr              = pdev->id;
+
+       err = soc_camera_host_register(&pcdev->soc_host);
        if (err)
                goto exit_free_irq;
 
@@ -1690,7 +1684,7 @@ exit_free_dma_y:
 exit_iounmap:
        iounmap(base);
 exit_release:
-       release_mem_region(res->start, res->end - res->start + 1);
+       release_mem_region(res->start, resource_size(res));
 exit_clk:
        clk_put(pcdev->clk);
 exit_kfree:
@@ -1701,7 +1695,9 @@ exit:
 
 static int __devexit pxa_camera_remove(struct platform_device *pdev)
 {
-       struct pxa_camera_dev *pcdev = platform_get_drvdata(pdev);
+       struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+       struct pxa_camera_dev *pcdev = container_of(soc_host,
+                                       struct pxa_camera_dev, soc_host);
        struct resource *res;
 
        clk_put(pcdev->clk);
@@ -1711,12 +1707,12 @@ static int __devexit pxa_camera_remove(struct platform_device *pdev)
        pxa_free_dma(pcdev->dma_chans[2]);
        free_irq(pcdev->irq, pcdev);
 
-       soc_camera_host_unregister(&pxa_soc_camera_host);
+       soc_camera_host_unregister(soc_host);
 
        iounmap(pcdev->base);
 
        res = pcdev->res;
-       release_mem_region(res->start, res->end - res->start + 1);
+       release_mem_region(res->start, resource_size(res));
 
        kfree(pcdev);
 
@@ -1730,11 +1726,11 @@ static struct platform_driver pxa_camera_driver = {
                .name   = PXA_CAM_DRV_NAME,
        },
        .probe          = pxa_camera_probe,
-       .remove         = __exit_p(pxa_camera_remove),
+       .remove         = __devexit_p(pxa_camera_remove),
 };
 
 
-static int __devinit pxa_camera_init(void)
+static int __init pxa_camera_init(void)
 {
        return platform_driver_register(&pxa_camera_driver);
 }
index 30f4698be90a5a9555426b2732f7dfc268256fbb..6be845ccc7d7e7412f97b2e65c32e6cd3deb091e 100644 (file)
@@ -77,6 +77,8 @@
 #define MAX_CHANNELS           4
 #define S2255_MARKER_FRAME     0x2255DA4AL
 #define S2255_MARKER_RESPONSE  0x2255ACACL
+#define S2255_RESPONSE_SETMODE  0x01
+#define S2255_RESPONSE_FW       0x10
 #define S2255_USB_XFER_SIZE    (16 * 1024)
 #define MAX_CHANNELS           4
 #define MAX_PIPE_BUFFERS       1
 #define SCALE_4CIFS    1       /* 640x480(NTSC) or 704x576(PAL) */
 #define SCALE_2CIFS    2       /* 640x240(NTSC) or 704x288(PAL) */
 #define SCALE_1CIFS    3       /* 320x240(NTSC) or 352x288(PAL) */
+/* SCALE_4CIFSI is the 2 fields interpolated into one */
+#define SCALE_4CIFSI   4       /* 640x480(NTSC) or 704x576(PAL) high quality */
 
 #define COLOR_YUVPL    1       /* YUV planar */
 #define COLOR_YUVPK    2       /* YUV packed */
@@ -178,9 +182,6 @@ struct s2255_bufferi {
 
 struct s2255_dmaqueue {
        struct list_head        active;
-       /* thread for acquisition */
-       struct task_struct      *kthread;
-       int                     frame;
        struct s2255_dev        *dev;
        int                     channel;
 };
@@ -210,16 +211,11 @@ struct s2255_pipeinfo {
        u32 max_transfer_size;
        u32 cur_transfer_size;
        u8 *transfer_buffer;
-       u32 transfer_flags;;
        u32 state;
-       u32 prev_state;
-       u32 urb_size;
        void *stream_urb;
        void *dev;      /* back pointer to s2255_dev struct*/
        u32 err_count;
-       u32 buf_index;
        u32 idx;
-       u32 priority_set;
 };
 
 struct s2255_fmt; /*forward declaration */
@@ -239,13 +235,13 @@ struct s2255_dev {
        struct list_head        s2255_devlist;
        struct timer_list       timer;
        struct s2255_fw *fw_data;
-       int                     board_num;
-       int                     is_open;
        struct s2255_pipeinfo   pipes[MAX_PIPE_BUFFERS];
        struct s2255_bufferi            buffer[MAX_CHANNELS];
        struct s2255_mode       mode[MAX_CHANNELS];
        /* jpeg compression */
        struct v4l2_jpegcompression jc[MAX_CHANNELS];
+       /* capture parameters (for high quality mode full size) */
+       struct v4l2_captureparm cap_parm[MAX_CHANNELS];
        const struct s2255_fmt  *cur_fmt[MAX_CHANNELS];
        int                     cur_frame[MAX_CHANNELS];
        int                     last_frame[MAX_CHANNELS];
@@ -297,9 +293,10 @@ struct s2255_fh {
        int                     resources[MAX_CHANNELS];
 };
 
-#define CUR_USB_FWVER  774     /* current cypress EEPROM firmware version */
+/* current cypress EEPROM firmware version */
+#define S2255_CUR_USB_FWVER    ((3 << 8) | 6)
 #define S2255_MAJOR_VERSION    1
-#define S2255_MINOR_VERSION    13
+#define S2255_MINOR_VERSION    14
 #define S2255_RELEASE          0
 #define S2255_VERSION          KERNEL_VERSION(S2255_MAJOR_VERSION, \
                                               S2255_MINOR_VERSION, \
@@ -1027,9 +1024,16 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        fh->type = f->type;
        norm = norm_minw(fh->dev->vdev[fh->channel]);
        if (fh->width > norm_minw(fh->dev->vdev[fh->channel])) {
-               if (fh->height > norm_minh(fh->dev->vdev[fh->channel]))
-                       fh->mode.scale = SCALE_4CIFS;
-               else
+               if (fh->height > norm_minh(fh->dev->vdev[fh->channel])) {
+                       if (fh->dev->cap_parm[fh->channel].capturemode &
+                           V4L2_MODE_HIGHQUALITY) {
+                               fh->mode.scale = SCALE_4CIFSI;
+                               dprintk(2, "scale 4CIFSI\n");
+                       } else {
+                               fh->mode.scale = SCALE_4CIFS;
+                               dprintk(2, "scale 4CIFS\n");
+                       }
+               } else
                        fh->mode.scale = SCALE_2CIFS;
 
        } else {
@@ -1130,6 +1134,7 @@ static u32 get_transfer_size(struct s2255_mode *mode)
        if (mode->format == FORMAT_NTSC) {
                switch (mode->scale) {
                case SCALE_4CIFS:
+               case SCALE_4CIFSI:
                        linesPerFrame = NUM_LINES_4CIFS_NTSC * 2;
                        pixelsPerLine = LINE_SZ_4CIFS_NTSC;
                        break;
@@ -1147,6 +1152,7 @@ static u32 get_transfer_size(struct s2255_mode *mode)
        } else if (mode->format == FORMAT_PAL) {
                switch (mode->scale) {
                case SCALE_4CIFS:
+               case SCALE_4CIFSI:
                        linesPerFrame = NUM_LINES_4CIFS_PAL * 2;
                        pixelsPerLine = LINE_SZ_4CIFS_PAL;
                        break;
@@ -1502,6 +1508,33 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv,
        dprintk(2, "setting jpeg quality %d\n", jc->quality);
        return 0;
 }
+
+static int vidioc_g_parm(struct file *file, void *priv,
+                        struct v4l2_streamparm *sp)
+{
+       struct s2255_fh *fh = priv;
+       struct s2255_dev *dev = fh->dev;
+       if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+       sp->parm.capture.capturemode = dev->cap_parm[fh->channel].capturemode;
+       dprintk(2, "getting parm %d\n", sp->parm.capture.capturemode);
+       return 0;
+}
+
+static int vidioc_s_parm(struct file *file, void *priv,
+                        struct v4l2_streamparm *sp)
+{
+       struct s2255_fh *fh = priv;
+       struct s2255_dev *dev = fh->dev;
+
+       if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       dev->cap_parm[fh->channel].capturemode = sp->parm.capture.capturemode;
+       dprintk(2, "setting param capture mode %d\n",
+               sp->parm.capture.capturemode);
+       return 0;
+}
 static int s2255_open(struct file *file)
 {
        int minor = video_devdata(file)->minor;
@@ -1793,6 +1826,8 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
 #endif
        .vidioc_s_jpegcomp = vidioc_s_jpegcomp,
        .vidioc_g_jpegcomp = vidioc_g_jpegcomp,
+       .vidioc_s_parm = vidioc_s_parm,
+       .vidioc_g_parm = vidioc_g_parm,
 };
 
 static struct video_device template = {
@@ -1818,7 +1853,6 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
                INIT_LIST_HEAD(&dev->vidq[i].active);
                dev->vidq[i].dev = dev;
                dev->vidq[i].channel = i;
-               dev->vidq[i].kthread = NULL;
                /* register 4 video devices */
                dev->vdev[i] = video_device_alloc();
                memcpy(dev->vdev[i], &template, sizeof(struct video_device));
@@ -1839,7 +1873,9 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
                        return ret;
                }
        }
-       printk(KERN_INFO "Sensoray 2255 V4L driver\n");
+       printk(KERN_INFO "Sensoray 2255 V4L driver Revision: %d.%d\n",
+              S2255_MAJOR_VERSION,
+              S2255_MINOR_VERSION);
        return ret;
 }
 
@@ -1929,14 +1965,14 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
                                if (!(cc >= 0 && cc < MAX_CHANNELS))
                                        break;
                                switch (pdword[2]) {
-                               case 0x01:
+                               case S2255_RESPONSE_SETMODE:
                                        /* check if channel valid */
                                        /* set mode ready */
                                        dev->setmode_ready[cc] = 1;
                                        wake_up(&dev->wait_setmode[cc]);
                                        dprintk(5, "setmode ready %d\n", cc);
                                        break;
-                               case 0x10:
+                               case S2255_RESPONSE_FW:
 
                                        dev->chn_ready |= (1 << cc);
                                        if ((dev->chn_ready & 0x0f) != 0x0f)
@@ -2172,10 +2208,15 @@ static int s2255_board_init(struct s2255_dev *dev)
        /* query the firmware */
        fw_ver = s2255_get_fx2fw(dev);
 
-       printk(KERN_INFO "2255 usb firmware version %d \n", fw_ver);
-       if (fw_ver < CUR_USB_FWVER)
+       printk(KERN_INFO "2255 usb firmware version %d.%d\n",
+              (fw_ver >> 8) & 0xff,
+              fw_ver & 0xff);
+
+       if (fw_ver < S2255_CUR_USB_FWVER)
                dev_err(&dev->udev->dev,
-                       "usb firmware not up to date %d\n", fw_ver);
+                       "usb firmware not up to date %d.%d\n",
+                       (fw_ver >> 8) & 0xff,
+                       fw_ver & 0xff);
 
        for (j = 0; j < MAX_CHANNELS; j++) {
                dev->b_acquire[j] = 0;
@@ -2240,8 +2281,10 @@ static void read_pipe_completion(struct urb *purb)
                return;
        }
        status = purb->status;
-       if (status != 0) {
-               dprintk(2, "read_pipe_completion: err\n");
+       /* if shutting down, do not resubmit, exit immediately */
+       if (status == -ESHUTDOWN) {
+               dprintk(2, "read_pipe_completion: err shutdown\n");
+               pipe_info->err_count++;
                return;
        }
 
@@ -2250,9 +2293,13 @@ static void read_pipe_completion(struct urb *purb)
                return;
        }
 
-       s2255_read_video_callback(dev, pipe_info);
+       if (status == 0)
+               s2255_read_video_callback(dev, pipe_info);
+       else {
+               pipe_info->err_count++;
+               dprintk(1, "s2255drv: failed URB %d\n", status);
+       }
 
-       pipe_info->err_count = 0;
        pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint);
        /* reuse urb */
        usb_fill_bulk_urb(pipe_info->stream_urb, dev->udev,
@@ -2264,7 +2311,6 @@ static void read_pipe_completion(struct urb *purb)
        if (pipe_info->state != 0) {
                if (usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL)) {
                        dev_err(&dev->udev->dev, "error submitting urb\n");
-                       usb_free_urb(pipe_info->stream_urb);
                }
        } else {
                dprintk(2, "read pipe complete state 0\n");
@@ -2283,8 +2329,7 @@ static int s2255_start_readpipe(struct s2255_dev *dev)
 
        for (i = 0; i < MAX_PIPE_BUFFERS; i++) {
                pipe_info->state = 1;
-               pipe_info->buf_index = (u32) i;
-               pipe_info->priority_set = 0;
+               pipe_info->err_count = 0;
                pipe_info->stream_urb = usb_alloc_urb(0, GFP_KERNEL);
                if (!pipe_info->stream_urb) {
                        dev_err(&dev->udev->dev,
@@ -2298,7 +2343,6 @@ static int s2255_start_readpipe(struct s2255_dev *dev)
                                  pipe_info->cur_transfer_size,
                                  read_pipe_completion, pipe_info);
 
-               pipe_info->urb_size = sizeof(pipe_info->stream_urb);
                dprintk(4, "submitting URB %p\n", pipe_info->stream_urb);
                retval = usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL);
                if (retval) {
@@ -2403,8 +2447,6 @@ static void s2255_stop_readpipe(struct s2255_dev *dev)
                        if (pipe_info->state == 0)
                                continue;
                        pipe_info->state = 0;
-                       pipe_info->prev_state = 1;
-
                }
        }
 
@@ -2542,7 +2584,9 @@ static int s2255_probe(struct usb_interface *interface,
        s2255_probe_v4l(dev);
        usb_reset_device(dev->udev);
        /* load 2255 board specific */
-       s2255_board_init(dev);
+       retval = s2255_board_init(dev);
+       if (retval)
+               goto error;
 
        dprintk(4, "before probe done %p\n", dev);
        spin_lock_init(&dev->slock);
index 0ba68987bfce96c541788eddd94d3a1d2bd334b7..5bcce092e804dff85d5598f2c940b417c36aa5b4 100644 (file)
@@ -44,6 +44,7 @@ config VIDEO_SAA7134_DVB
        select DVB_LNBP21 if !DVB_FE_CUSTOMISE
        select DVB_ZL10353 if !DVB_FE_CUSTOMISE
        select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
+       select DVB_TDA10048 if !DVB_FE_CUSTOMISE
        select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
        select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
        ---help---
index 3dbaa19a6d00d7f3dbc81f7769681c91d5fff41e..604158a8c2352b092774e388ea442814fef9ebf8 100644 (file)
@@ -3,8 +3,7 @@ saa7134-objs := saa7134-cards.o saa7134-core.o saa7134-i2c.o    \
                saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o    \
                saa7134-video.o saa7134-input.o
 
-obj-$(CONFIG_VIDEO_SAA7134) +=  saa7134.o saa7134-empress.o \
-                               saa6752hs.o
+obj-$(CONFIG_VIDEO_SAA7134) +=  saa6752hs.o saa7134.o saa7134-empress.o
 
 obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o
 
index fdb19449d269df0396cd7802455916119265e09e..06861b782b9529f503ac26102eb17fc2ddd68908 100644 (file)
@@ -1669,6 +1669,39 @@ struct saa7134_board saa7134_boards[] = {
                        .amux = LINE1,
                },
        },
+       [SAA7134_BOARD_AVERMEDIA_CARDBUS_501] = {
+               /* Oldrich Jedlicka <oldium.pro@seznam.cz> */
+               .name           = "AVerMedia Cardbus TV/Radio (E501R)",
+               .audio_clock    = 0x187de7,
+               .tuner_type     = TUNER_ALPS_TSBE5_PAL,
+               .radio_type     = TUNER_TEA5767,
+               .tuner_addr     = 0x61,
+               .radio_addr     = 0x60,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .gpiomask       = 0x08000000,
+               .inputs         = { {
+                       .name = name_tv,
+                       .vmux = 1,
+                       .amux = TV,
+                       .tv   = 1,
+                       .gpio = 0x08000000,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 3,
+                       .amux = LINE1,
+                       .gpio = 0x08000000,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+                       .gpio = 0x08000000,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+                       .gpio = 0x00000000,
+               },
+       },
        [SAA7134_BOARD_CINERGY400_CARDBUS] = {
                .name           = "Terratec Cinergy 400 mobile",
                .audio_clock    = 0x187de7,
@@ -3331,13 +3364,15 @@ struct saa7134_board saa7134_boards[] = {
                },
        },
        [SAA7134_BOARD_HAUPPAUGE_HVR1110R3] = {
-               .name           = "Hauppauge WinTV-HVR1110r3",
+               .name           = "Hauppauge WinTV-HVR1110r3 DVB-T/Hybrid",
                .audio_clock    = 0x00187de7,
                .tuner_type     = TUNER_PHILIPS_TDA8290,
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tuner_config   = 3,
+               .mpeg           = SAA7134_MPEG_DVB,
+               .ts_type        = SAA7134_MPEG_TS_SERIAL,
                .gpiomask       = 0x0800100, /* GPIO 21 is an INPUT */
                .inputs         = {{
                        .name = name_tv,
@@ -4006,7 +4041,7 @@ struct saa7134_board saa7134_boards[] = {
        [SAA7134_BOARD_BEHOLD_505FM] = {
                /*       Beholder Intl. Ltd. 2008      */
                /*Dmitry Belimov <d.belimov@gmail.com> */
-               .name           = "Beholder BeholdTV 505 FM/RDS",
+               .name           = "Beholder BeholdTV 505 FM",
                .audio_clock    = 0x00200000,
                .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
                .radio_type     = UNSET,
@@ -4014,6 +4049,40 @@ struct saa7134_board saa7134_boards[] = {
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
                .gpiomask       = 0x00008000,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = LINE2,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+               .mute = {
+                       .name = name_mute,
+                       .amux = LINE1,
+               },
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_505RDS] = {
+               /*       Beholder Intl. Ltd. 2008      */
+               /*Dmitry Belimov <d.belimov@gmail.com> */
+               .name           = "Beholder BeholdTV 505 RDS",
+               .audio_clock    = 0x00200000,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .gpiomask       = 0x00008000,
                .inputs         = {{
                        .name = name_tv,
                        .vmux = 3,
@@ -4040,7 +4109,7 @@ struct saa7134_board saa7134_boards[] = {
        [SAA7134_BOARD_BEHOLD_507_9FM] = {
                /*       Beholder Intl. Ltd. 2008      */
                /*Dmitry Belimov <d.belimov@gmail.com> */
-               .name           = "Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM",
+               .name           = "Beholder BeholdTV 507 FM / BeholdTV 509 FM",
                .audio_clock    = 0x00187de7,
                .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
                .radio_type     = UNSET,
@@ -4067,6 +4136,66 @@ struct saa7134_board saa7134_boards[] = {
                        .amux = LINE2,
                },
        },
+       [SAA7134_BOARD_BEHOLD_507RDS_MK5] = {
+               /*       Beholder Intl. Ltd. 2008      */
+               /*Dmitry Belimov <d.belimov@gmail.com> */
+               .name           = "Beholder BeholdTV 507 RDS",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .gpiomask       = 0x00008000,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+                       .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_507RDS_MK3] = {
+               /*       Beholder Intl. Ltd. 2008      */
+               /*Dmitry Belimov <d.belimov@gmail.com> */
+               .name           = "Beholder BeholdTV 507 RDS",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .gpiomask       = 0x00008000,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+                       .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
        [SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM] = {
                /*       Beholder Intl. Ltd. 2008      */
                /*Dmitry Belimov <d.belimov@gmail.com> */
@@ -4101,15 +4230,211 @@ struct saa7134_board saa7134_boards[] = {
                        .gpio = 0x000A8000,
                },
        },
-       [SAA7134_BOARD_BEHOLD_607_9FM] = {
+       [SAA7134_BOARD_BEHOLD_607FM_MK3] = {
+               /* Andrey Melnikoff <temnota@kmv.ru> */
+               .name           = "Beholder BeholdTV 607 FM",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_609FM_MK3] = {
+               /* Andrey Melnikoff <temnota@kmv.ru> */
+               .name           = "Beholder BeholdTV 609 FM",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_607FM_MK5] = {
+               /* Andrey Melnikoff <temnota@kmv.ru> */
+               .name           = "Beholder BeholdTV 607 FM",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_609FM_MK5] = {
                /* Andrey Melnikoff <temnota@kmv.ru> */
-               .name           = "Beholder BeholdTV 607 / BeholdTV 609",
+               .name           = "Beholder BeholdTV 609 FM",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_607RDS_MK3] = {
+               /* Andrey Melnikoff <temnota@kmv.ru> */
+               .name           = "Beholder BeholdTV 607 RDS",
                .audio_clock    = 0x00187de7,
                .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
                .tda9887_conf   = TDA9887_PRESENT,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_609RDS_MK3] = {
+               /* Andrey Melnikoff <temnota@kmv.ru> */
+               .name           = "Beholder BeholdTV 609 RDS",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_607RDS_MK5] = {
+               /* Andrey Melnikoff <temnota@kmv.ru> */
+               .name           = "Beholder BeholdTV 607 RDS",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .inputs         = {{
+                       .name = name_tv,
+                       .vmux = 3,
+                       .amux = TV,
+                       .tv   = 1,
+               }, {
+                       .name = name_comp1,
+                       .vmux = 1,
+                       .amux = LINE1,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+               },
+       },
+       [SAA7134_BOARD_BEHOLD_609RDS_MK5] = {
+               /* Andrey Melnikoff <temnota@kmv.ru> */
+               .name           = "Beholder BeholdTV 609 RDS",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
                .inputs         = {{
                        .name = name_tv,
                        .vmux = 3,
@@ -4133,6 +4458,7 @@ struct saa7134_board saa7134_boards[] = {
                /* Igor Kuznetsov <igk@igk.ru> */
                /* Andrey Melnikoff <temnota@kmv.ru> */
                /* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+               /* Alexey Osipov <lion-simba@pridelands.ru> */
                .name           = "Beholder BeholdTV M6",
                .audio_clock    = 0x00187de7,
                .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
@@ -4207,10 +4533,10 @@ struct saa7134_board saa7134_boards[] = {
                /* Igor Kuznetsov <igk@igk.ru> */
                /* Andrey Melnikoff <temnota@kmv.ru> */
                /* Beholder Intl. Ltd. Dmitry Belimov <d.belimov@gmail.com> */
+               /* Alexey Osipov <lion-simba@pridelands.ru> */
                .name           = "Beholder BeholdTV M6 Extra",
                .audio_clock    = 0x00187de7,
-               /* FIXME: Must be PHILIPS_FM1216ME_MK5*/
-               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3, /* FIXME to MK5 */
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
@@ -4465,7 +4791,6 @@ struct saa7134_board saa7134_boards[] = {
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               .mpeg           = SAA7134_MPEG_DVB,
                .inputs = {{
                        .name   = name_tv,
                        .vmux   = 3,
@@ -4753,6 +5078,44 @@ struct saa7134_board saa7134_boards[] = {
                        .gpio = 0x01,
                },
        },
+       [SAA7134_BOARD_AVERMEDIA_STUDIO_507UA] = {
+               /* Andy Shevchenko <andy@smile.org.ua> */
+               .name           = "Avermedia AVerTV Studio 507UA",
+               .audio_clock    = 0x00187de7,
+               .tuner_type     = TUNER_PHILIPS_FM1216ME_MK3, /* Should be MK5 */
+               .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 = 3,
+                       .amux = LINE1,
+                       .gpio = 0x00,
+               }, {
+                       .name = name_svideo,
+                       .vmux = 8,
+                       .amux = LINE1,
+                       .gpio = 0x00,
+               } },
+               .radio = {
+                       .name = name_radio,
+                       .amux = LINE2,
+                       .gpio = 0x01,
+               },
+               .mute  = {
+                       .name = name_mute,
+                       .amux = LINE1,
+                       .gpio = 0x00,
+               },
+       },
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -5027,6 +5390,13 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subdevice    = 0xd6ee,
                .driver_data  = SAA7134_BOARD_AVERMEDIA_CARDBUS,
        },{
+               /* AVerMedia CardBus */
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = 0x1461, /* Avermedia Technologies Inc */
+               .subdevice    = 0xb7e9,
+               .driver_data  = SAA7134_BOARD_AVERMEDIA_CARDBUS_501,
+       }, {
                /* TransGear 3000TV */
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
@@ -5440,6 +5810,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subdevice    = 0x9715,
                .driver_data  = SAA7134_BOARD_AVERMEDIA_STUDIO_507,
        },{
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
+               .subvendor    = 0x1461, /* Avermedia Technologies Inc */
+               .subdevice    = 0xa11b,
+               .driver_data  = SAA7134_BOARD_AVERMEDIA_STUDIO_507UA,
+       }, {
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
                .subvendor    = 0x1043,
@@ -5643,18 +6019,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = 0x0000,
                .subdevice    = 0x4090,
                .driver_data  = SAA7134_BOARD_BEHOLD_409,
-       },{
-               .vendor       = PCI_VENDOR_ID_PHILIPS,
-               .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
-               .subvendor    = 0x0000,
-               .subdevice    = 0x5051,
-               .driver_data  = SAA7134_BOARD_BEHOLD_505FM,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
                .subvendor    = 0x0000,
                .subdevice    = 0x505B,
-               .driver_data  = SAA7134_BOARD_BEHOLD_505FM,
+               .driver_data  = SAA7134_BOARD_BEHOLD_505RDS,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
@@ -5666,13 +6036,13 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
                .subvendor    = 0x0000,
                .subdevice    = 0x5071,
-               .driver_data  = SAA7134_BOARD_BEHOLD_507_9FM,
+               .driver_data  = SAA7134_BOARD_BEHOLD_507RDS_MK3,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
                .subvendor    = 0x0000,
                .subdevice    = 0x507B,
-               .driver_data  = SAA7134_BOARD_BEHOLD_507_9FM,
+               .driver_data  = SAA7134_BOARD_BEHOLD_507RDS_MK5,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -5696,49 +6066,49 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
                .subvendor    = 0x5ace,
                .subdevice    = 0x6070,
-               .driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+               .driver_data  = SAA7134_BOARD_BEHOLD_607FM_MK3,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
                .subvendor    = 0x5ace,
                .subdevice    = 0x6071,
-               .driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+               .driver_data  = SAA7134_BOARD_BEHOLD_607FM_MK5,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
                .subvendor    = 0x5ace,
                .subdevice    = 0x6072,
-               .driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+               .driver_data  = SAA7134_BOARD_BEHOLD_607RDS_MK3,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
                .subvendor    = 0x5ace,
                .subdevice    = 0x6073,
-               .driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+               .driver_data  = SAA7134_BOARD_BEHOLD_607RDS_MK5,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
                .subvendor    = 0x5ace,
                .subdevice    = 0x6090,
-               .driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+               .driver_data  = SAA7134_BOARD_BEHOLD_609FM_MK3,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
                .subvendor    = 0x5ace,
                .subdevice    = 0x6091,
-               .driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+               .driver_data  = SAA7134_BOARD_BEHOLD_609FM_MK5,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
                .subvendor    = 0x5ace,
                .subdevice    = 0x6092,
-               .driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+               .driver_data  = SAA7134_BOARD_BEHOLD_609RDS_MK3,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
                .subvendor    = 0x5ace,
                .subdevice    = 0x6093,
-               .driver_data  = SAA7134_BOARD_BEHOLD_607_9FM,
+               .driver_data  = SAA7134_BOARD_BEHOLD_609RDS_MK5,
        },{
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
@@ -5829,6 +6199,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
                .subvendor    = 0x1461, /* Avermedia Technologies Inc */
                .subdevice    = 0xf636,
                .driver_data  = SAA7134_BOARD_AVERMEDIA_M103,
+       }, {
+               .vendor       = PCI_VENDOR_ID_PHILIPS,
+               .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+               .subvendor    = 0x1461, /* Avermedia Technologies Inc */
+               .subdevice    = 0xf736,
+               .driver_data  = SAA7134_BOARD_AVERMEDIA_M103,
        }, {
                .vendor       = PCI_VENDOR_ID_PHILIPS,
                .device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
@@ -6114,7 +6490,6 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_VIDEOMATE_DVBT_300:
        case SAA7134_BOARD_VIDEOMATE_DVBT_200:
        case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
-       case SAA7134_BOARD_VIDEOMATE_T750:
        case SAA7134_BOARD_MANLI_MTV001:
        case SAA7134_BOARD_MANLI_MTV002:
        case SAA7134_BOARD_BEHOLD_409FM:
@@ -6142,7 +6517,10 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_BEHOLD_407FM:
        case SAA7134_BOARD_BEHOLD_409:
        case SAA7134_BOARD_BEHOLD_505FM:
+       case SAA7134_BOARD_BEHOLD_505RDS:
        case SAA7134_BOARD_BEHOLD_507_9FM:
+       case SAA7134_BOARD_BEHOLD_507RDS_MK3:
+       case SAA7134_BOARD_BEHOLD_507RDS_MK5:
        case SAA7134_BOARD_GENIUS_TVGO_A11MCE:
        case SAA7134_BOARD_REAL_ANGEL_220:
        case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
@@ -6196,6 +6574,16 @@ int saa7134_board_init1(struct saa7134_dev *dev)
                saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff);
                msleep(10);
                break;
+       case SAA7134_BOARD_AVERMEDIA_CARDBUS_501:
+               /* power-down tuner chip */
+               saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x08400000, 0x08400000);
+               saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08400000, 0);
+               msleep(10);
+               saa_andorl(SAA7134_GPIO_GPMODE0 >> 2,   0x08400000, 0x08400000);
+               saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08400000, 0x08400000);
+               msleep(10);
+               dev->has_remote = SAA7134_REMOTE_I2C;
+               break;
        case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
                saa7134_set_gpio(dev, 23, 0);
                msleep(10);
@@ -6253,7 +6641,14 @@ int saa7134_board_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_UPMOST_PURPLE_TV:
        case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS:
        case SAA7134_BOARD_HAUPPAUGE_HVR1110:
-       case SAA7134_BOARD_BEHOLD_607_9FM:
+       case SAA7134_BOARD_BEHOLD_607FM_MK3:
+       case SAA7134_BOARD_BEHOLD_607FM_MK5:
+       case SAA7134_BOARD_BEHOLD_609FM_MK3:
+       case SAA7134_BOARD_BEHOLD_609FM_MK5:
+       case SAA7134_BOARD_BEHOLD_607RDS_MK3:
+       case SAA7134_BOARD_BEHOLD_607RDS_MK5:
+       case SAA7134_BOARD_BEHOLD_609RDS_MK3:
+       case SAA7134_BOARD_BEHOLD_609RDS_MK5:
        case SAA7134_BOARD_BEHOLD_M6:
        case SAA7134_BOARD_BEHOLD_M63:
        case SAA7134_BOARD_BEHOLD_M6_EXTRA:
@@ -6635,6 +7030,7 @@ int saa7134_board_init2(struct saa7134_dev *dev)
 
        switch (dev->board) {
        case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
+       case SAA7134_BOARD_AVERMEDIA_CARDBUS_501:
        {
                struct v4l2_priv_tun_config tea5767_cfg;
                struct tea5767_ctrl ctl;
index 2def6fec814bb31adaf6e2e32d476b13bdeb6107..94a023a14bbc7109843cd7ebae941204d9659604 100644 (file)
@@ -331,6 +331,10 @@ void saa7134_buffer_next(struct saa7134_dev *dev,
                dprintk("buffer_next %p\n",NULL);
                saa7134_set_dmabits(dev);
                del_timer(&q->timeout);
+
+               if (card_has_mpeg(dev))
+                       if (dev->ts_started)
+                               saa7134_ts_stop(dev);
        }
 }
 
@@ -416,6 +420,19 @@ int saa7134_set_dmabits(struct saa7134_dev *dev)
                ctrl |= SAA7134_MAIN_CTRL_TE5;
                irq  |= SAA7134_IRQ1_INTE_RA2_1 |
                        SAA7134_IRQ1_INTE_RA2_0;
+
+               /* dma: setup channel 5 (= TS) */
+
+               saa_writeb(SAA7134_TS_DMA0, (dev->ts.nr_packets - 1) & 0xff);
+               saa_writeb(SAA7134_TS_DMA1,
+                       ((dev->ts.nr_packets - 1) >> 8) & 0xff);
+               /* TSNOPIT=0, TSCOLAP=0 */
+               saa_writeb(SAA7134_TS_DMA2,
+                       (((dev->ts.nr_packets - 1) >> 16) & 0x3f) | 0x00);
+               saa_writel(SAA7134_RS_PITCH(5), TS_PACKET_SIZE);
+               saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_16 |
+                                                 SAA7134_RS_CONTROL_ME |
+                                                 (dev->ts.pt_ts.dma >> 12));
        }
 
        /* set task conditions + field handling */
@@ -775,7 +792,6 @@ static struct video_device *vdev_init(struct saa7134_dev *dev,
        if (NULL == vfd)
                return NULL;
        *vfd = *template;
-       vfd->minor   = -1;
        vfd->v4l2_dev  = &dev->v4l2_dev;
        vfd->release = video_device_release;
        vfd->debug   = video_debug;
index 4eff1ca8593cd9398fd15ce06d2e0c02ddf71d09..31930f26ffc7d5963aab8d24c7b3a70c918a62e3 100644 (file)
@@ -48,6 +48,7 @@
 #include "isl6405.h"
 #include "lnbp21.h"
 #include "tuner-simple.h"
+#include "tda10048.h"
 #include "tda18271.h"
 #include "lgdt3305.h"
 #include "tda8290.h"
@@ -978,6 +979,18 @@ static struct lgdt3305_config hcw_lgdt3305_config = {
        .vsb_if_khz         = 3250,
 };
 
+static struct tda10048_config hcw_tda10048_config = {
+       .demod_address    = 0x10 >> 1,
+       .output_mode      = TDA10048_SERIAL_OUTPUT,
+       .fwbulkwritelen   = TDA10048_BULKWRITE_200,
+       .inversion        = TDA10048_INVERSION_ON,
+       .dtv6_if_freq_khz = TDA10048_IF_3300,
+       .dtv7_if_freq_khz = TDA10048_IF_3500,
+       .dtv8_if_freq_khz = TDA10048_IF_4000,
+       .clk_freq_khz     = TDA10048_CLK_16000,
+       .disable_gate_access = 1,
+};
+
 static struct tda18271_std_map hauppauge_tda18271_std_map = {
        .atsc_6   = { .if_freq = 3250, .agc_mode = 3, .std = 4,
                      .if_lvl = 1, .rfagc_top = 0x58, },
@@ -1106,6 +1119,19 @@ static int dvb_init(struct saa7134_dev *dev)
                                         &tda827x_cfg_2) < 0)
                        goto dettach_frontend;
                break;
+       case SAA7134_BOARD_HAUPPAUGE_HVR1110R3:
+               fe0->dvb.frontend = dvb_attach(tda10048_attach,
+                                              &hcw_tda10048_config,
+                                              &dev->i2c_adap);
+               if (fe0->dvb.frontend != NULL) {
+                       dvb_attach(tda829x_attach, fe0->dvb.frontend,
+                                  &dev->i2c_adap, 0x4b,
+                                  &tda829x_no_probe);
+                       dvb_attach(tda18271_attach, fe0->dvb.frontend,
+                                  0x60, &dev->i2c_adap,
+                                  &hcw_tda18271_config);
+               }
+               break;
        case SAA7134_BOARD_PHILIPS_TIGER:
                if (configure_tda827x_fe(dev, &philips_tiger_config,
                                         &tda827x_cfg_0) < 0)
index 9db3472667e52d311f1aab49bd003efb21cac30a..add1757f89303851afa45f49d5c6975641efde9b 100644 (file)
@@ -255,6 +255,16 @@ static int empress_s_fmt_vid_cap(struct file *file, void *priv,
        return 0;
 }
 
+static int empress_try_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct saa7134_dev *dev = file->private_data;
+
+       f->fmt.pix.pixelformat  = V4L2_PIX_FMT_MPEG;
+       f->fmt.pix.sizeimage    = TS_PACKET_SIZE * dev->ts.nr_packets;
+
+       return 0;
+}
 
 static int empress_reqbufs(struct file *file, void *priv,
                                        struct v4l2_requestbuffers *p)
@@ -450,6 +460,7 @@ static const struct v4l2_file_operations ts_fops =
 static const struct v4l2_ioctl_ops ts_ioctl_ops = {
        .vidioc_querycap                = empress_querycap,
        .vidioc_enum_fmt_vid_cap        = empress_enum_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap         = empress_try_fmt_vid_cap,
        .vidioc_s_fmt_vid_cap           = empress_s_fmt_vid_cap,
        .vidioc_g_fmt_vid_cap           = empress_g_fmt_vid_cap,
        .vidioc_reqbufs                 = empress_reqbufs,
@@ -491,11 +502,8 @@ static void empress_signal_update(struct work_struct *work)
 
        if (dev->nosignal) {
                dprintk("no video signal\n");
-               ts_reset_encoder(dev);
        } else {
                dprintk("video signal acquired\n");
-               if (atomic_read(&dev->empress_users))
-                       ts_init_encoder(dev);
        }
 }
 
index f3e285aa2fb4ee66ea8a8e8365f0995816b9fd53..8096dace5f6c77d9b2eafde934300aea74a05f50 100644 (file)
@@ -259,7 +259,7 @@ static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap,
                                /* workaround for a saa7134 i2c bug
                                 * needed to talk to the mt352 demux
                                 * thanks to pinnacle for the hint */
-                               int quirk = 0xfd;
+                               int quirk = 0xfe;
                                d1printk(" [%02x quirk]",quirk);
                                i2c_send_byte(dev,START,quirk);
                                i2c_recv_byte(dev);
@@ -321,33 +321,6 @@ static u32 functionality(struct i2c_adapter *adap)
        return I2C_FUNC_SMBUS_EMUL;
 }
 
-static int attach_inform(struct i2c_client *client)
-{
-       struct saa7134_dev *dev = client->adapter->algo_data;
-
-       d1printk( "%s i2c attach [addr=0x%x,client=%s]\n",
-               client->driver->driver.name, client->addr, client->name);
-
-       /* Am I an i2c remote control? */
-
-       switch (client->addr) {
-               case 0x7a:
-               case 0x47:
-               case 0x71:
-               case 0x2d:
-               case 0x30:
-               {
-                       struct IR_i2c *ir = i2c_get_clientdata(client);
-                       d1printk("%s i2c IR detected (%s).\n",
-                                client->driver->driver.name, ir->phys);
-                       saa7134_set_i2c_ir(dev,ir);
-                       break;
-               }
-       }
-
-       return 0;
-}
-
 static struct i2c_algorithm saa7134_algo = {
        .master_xfer   = saa7134_i2c_xfer,
        .functionality = functionality,
@@ -358,7 +331,6 @@ static struct i2c_adapter saa7134_adap_template = {
        .name          = "saa7134",
        .id            = I2C_HW_SAA7134,
        .algo          = &saa7134_algo,
-       .client_register = attach_inform,
 };
 
 static struct i2c_client saa7134_client_template = {
@@ -433,6 +405,9 @@ int saa7134_i2c_register(struct saa7134_dev *dev)
        saa7134_i2c_eeprom(dev,dev->eedata,sizeof(dev->eedata));
        if (i2c_scan)
                do_i2c_scan(dev->name,&dev->i2c_client);
+
+       /* Instantiate the IR receiver device, if present */
+       saa7134_probe_i2c_ir(dev);
        return 0;
 }
 
index 8a106d36e7232c4bce0c38aef1071526cdf93ae1..6e219c2db8419013ab3ced30470ad1c19431974a 100644 (file)
@@ -60,7 +60,7 @@ MODULE_PARM_DESC(disable_other_ir, "disable full codes of "
 #define dprintk(fmt, arg...)   if (ir_debug) \
        printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
 #define i2cdprintk(fmt, arg...)    if (ir_debug) \
-       printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
+       printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg)
 
 /* Helper functions for RC5 and NEC decoding at GPIO16 or GPIO18 */
 static int saa7134_rc5_irq(struct saa7134_dev *dev);
@@ -134,10 +134,10 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key,
        int gpio;
 
        /* <dev> is needed to access GPIO. Used by the saa_readl macro. */
-       struct saa7134_dev *dev = ir->c.adapter->algo_data;
+       struct saa7134_dev *dev = ir->c->adapter->algo_data;
        if (dev == NULL) {
                dprintk("get_key_msi_tvanywhere_plus: "
-                       "gir->c.adapter->algo_data is NULL!\n");
+                       "gir->c->adapter->algo_data is NULL!\n");
                return -EIO;
        }
 
@@ -156,7 +156,7 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key,
 
        /* GPIO says there is a button press. Get it. */
 
-       if (1 != i2c_master_recv(&ir->c, &b, 1)) {
+       if (1 != i2c_master_recv(ir->c, &b, 1)) {
                i2cdprintk("read error\n");
                return -EIO;
        }
@@ -179,7 +179,7 @@ static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        unsigned char b;
 
        /* poll IR chip */
-       if (1 != i2c_master_recv(&ir->c,&b,1)) {
+       if (1 != i2c_master_recv(ir->c, &b, 1)) {
                i2cdprintk("read error\n");
                return -EIO;
        }
@@ -202,7 +202,7 @@ 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))
+       if (5 != i2c_master_recv(ir->c, buf, 5))
                return -EIO;
 
        cod4    = buf[4];
@@ -224,7 +224,7 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        unsigned char data[12];
        u32 gpio;
 
-       struct saa7134_dev *dev = ir->c.adapter->algo_data;
+       struct saa7134_dev *dev = ir->c->adapter->algo_data;
 
        /* rising SAA7134_GPIO_GPRESCAN reads the status */
        saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
@@ -235,9 +235,9 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
        if (0x400000 & ~gpio)
                return 0; /* No button press */
 
-       ir->c.addr = 0x5a >> 1;
+       ir->c->addr = 0x5a >> 1;
 
-       if (12 != i2c_master_recv(&ir->c, data, 12)) {
+       if (12 != i2c_master_recv(ir->c, data, 12)) {
                i2cdprintk("read error\n");
                return -EIO;
        }
@@ -267,7 +267,7 @@ static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
        unsigned int start = 0,parity = 0,code = 0;
 
        /* poll IR chip */
-       if (4 != i2c_master_recv(&ir->c, b, 4)) {
+       if (4 != i2c_master_recv(ir->c, b, 4)) {
                i2cdprintk("read error\n");
                return -EIO;
        }
@@ -447,6 +447,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
        case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
        case SAA7134_BOARD_AVERMEDIA_STUDIO_507:
+       case SAA7134_BOARD_AVERMEDIA_STUDIO_507UA:
        case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
        case SAA7134_BOARD_AVERMEDIA_M102:
        case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS:
@@ -506,7 +507,10 @@ int saa7134_input_init1(struct saa7134_dev *dev)
        case SAA7134_BOARD_BEHOLD_407FM:
        case SAA7134_BOARD_BEHOLD_409:
        case SAA7134_BOARD_BEHOLD_505FM:
+       case SAA7134_BOARD_BEHOLD_505RDS:
        case SAA7134_BOARD_BEHOLD_507_9FM:
+       case SAA7134_BOARD_BEHOLD_507RDS_MK3:
+       case SAA7134_BOARD_BEHOLD_507RDS_MK5:
                ir_codes     = ir_codes_manli;
                mask_keycode = 0x003f00;
                mask_keyup   = 0x004000;
@@ -678,55 +682,101 @@ void saa7134_input_fini(struct saa7134_dev *dev)
        dev->remote = NULL;
 }
 
-void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
+void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
 {
+       struct i2c_board_info info;
+       struct IR_i2c_init_data init_data;
+       const unsigned short addr_list[] = {
+               0x7a, 0x47, 0x71, 0x2d,
+               I2C_CLIENT_END
+       };
+
+       struct i2c_msg msg_msi = {
+               .addr = 0x50,
+               .flags = I2C_M_RD,
+               .len = 0,
+               .buf = NULL,
+       };
+
+       int rc;
+
        if (disable_ir) {
-               dprintk("Found supported i2c remote, but IR has been disabled\n");
-               ir->get_key=NULL;
+               dprintk("IR has been disabled, not probing for i2c remote\n");
                return;
        }
 
+       memset(&info, 0, sizeof(struct i2c_board_info));
+       memset(&init_data, 0, sizeof(struct IR_i2c_init_data));
+       strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+
        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");
+               init_data.name = "Pinnacle PCTV";
                if (pinnacle_remote == 0) {
-                       ir->get_key   = get_key_pinnacle_color;
-                       ir->ir_codes = ir_codes_pinnacle_color;
+                       init_data.get_key = get_key_pinnacle_color;
+                       init_data.ir_codes = ir_codes_pinnacle_color;
                } else {
-                       ir->get_key   = get_key_pinnacle_grey;
-                       ir->ir_codes = ir_codes_pinnacle_grey;
+                       init_data.get_key = get_key_pinnacle_grey;
+                       init_data.ir_codes = ir_codes_pinnacle_grey;
                }
                break;
        case SAA7134_BOARD_UPMOST_PURPLE_TV:
-               snprintf(ir->c.name, sizeof(ir->c.name), "Purple TV");
-               ir->get_key   = get_key_purpletv;
-               ir->ir_codes  = ir_codes_purpletv;
+               init_data.name = "Purple TV";
+               init_data.get_key = get_key_purpletv;
+               init_data.ir_codes = ir_codes_purpletv;
                break;
        case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS:
-               snprintf(ir->c.name, sizeof(ir->c.name), "MSI TV@nywhere Plus");
-               ir->get_key  = get_key_msi_tvanywhere_plus;
-               ir->ir_codes = ir_codes_msi_tvanywhere_plus;
+               init_data.name = "MSI TV@nywhere Plus";
+               init_data.get_key = get_key_msi_tvanywhere_plus;
+               init_data.ir_codes = ir_codes_msi_tvanywhere_plus;
+               info.addr = 0x30;
+               /* MSI TV@nywhere Plus controller doesn't seem to
+                  respond to probes unless we read something from
+                  an existing device. Weird...
+                  REVISIT: might no longer be needed */
+               rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1);
+               dprintk(KERN_DEBUG "probe 0x%02x @ %s: %s\n",
+                       msg_msi.addr, dev->i2c_adap.name,
+                       (1 == rc) ? "yes" : "no");
                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;
-       case SAA7134_BOARD_BEHOLD_607_9FM:
+               init_data.name = "HVR 1110";
+               init_data.get_key = get_key_hvr1110;
+               init_data.ir_codes = ir_codes_hauppauge_new;
+               break;
+       case SAA7134_BOARD_BEHOLD_607FM_MK3:
+       case SAA7134_BOARD_BEHOLD_607FM_MK5:
+       case SAA7134_BOARD_BEHOLD_609FM_MK3:
+       case SAA7134_BOARD_BEHOLD_609FM_MK5:
+       case SAA7134_BOARD_BEHOLD_607RDS_MK3:
+       case SAA7134_BOARD_BEHOLD_607RDS_MK5:
+       case SAA7134_BOARD_BEHOLD_609RDS_MK3:
+       case SAA7134_BOARD_BEHOLD_609RDS_MK5:
        case SAA7134_BOARD_BEHOLD_M6:
        case SAA7134_BOARD_BEHOLD_M63:
        case SAA7134_BOARD_BEHOLD_M6_EXTRA:
        case SAA7134_BOARD_BEHOLD_H6:
-               snprintf(ir->c.name, sizeof(ir->c.name), "BeholdTV");
-               ir->get_key   = get_key_beholdm6xx;
-               ir->ir_codes  = ir_codes_behold;
+               init_data.name = "BeholdTV";
+               init_data.get_key = get_key_beholdm6xx;
+               init_data.ir_codes = ir_codes_behold;
                break;
-       default:
-               dprintk("Shouldn't get here: Unknown board %x for I2C IR?\n",dev->board);
+       case SAA7134_BOARD_AVERMEDIA_CARDBUS_501:
+       case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+               info.addr = 0x40;
                break;
        }
 
+       if (init_data.name)
+               info.platform_data = &init_data;
+       /* No need to probe if address is known */
+       if (info.addr) {
+               i2c_new_device(&dev->i2c_adap, &info);
+               return;
+       }
+
+       /* Address not known, fallback to probing */
+       i2c_new_probed_device(&dev->i2c_adap, &info, addr_list);
 }
 
 static int saa7134_rc5_irq(struct saa7134_dev *dev)
index cc8b923afbc077c37cee7708a4518c2b91968f09..3fa652279ac091bcbc464766ea42da38982bae2e 100644 (file)
@@ -65,35 +65,10 @@ static int buffer_activate(struct saa7134_dev *dev,
        /* start DMA */
        saa7134_set_dmabits(dev);
 
-       mod_timer(&dev->ts_q.timeout, jiffies+BUFFER_TIMEOUT);
-
-       if (dev->ts_state == SAA7134_TS_BUFF_DONE) {
-               /* Clear TS cache */
-               dev->buff_cnt = 0;
-               saa_writeb(SAA7134_TS_SERIAL1, 0x00);
-               saa_writeb(SAA7134_TS_SERIAL1, 0x03);
-               saa_writeb(SAA7134_TS_SERIAL1, 0x00);
-               saa_writeb(SAA7134_TS_SERIAL1, 0x01);
-
-               /* TS clock non-inverted */
-               saa_writeb(SAA7134_TS_SERIAL1, 0x00);
-
-               /* Start TS stream */
-               switch (saa7134_boards[dev->board].ts_type) {
-               case SAA7134_MPEG_TS_PARALLEL:
-                       saa_writeb(SAA7134_TS_SERIAL0, 0x40);
-                       saa_writeb(SAA7134_TS_PARALLEL, 0xec);
-                       break;
-               case SAA7134_MPEG_TS_SERIAL:
-                       saa_writeb(SAA7134_TS_SERIAL0, 0xd8);
-                       saa_writeb(SAA7134_TS_PARALLEL, 0x6c);
-                       saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 0xbc);
-                       saa_writeb(SAA7134_TS_SERIAL1, 0x02);
-                       break;
-               }
+       mod_timer(&dev->ts_q.timeout, jiffies+TS_BUFFER_TIMEOUT);
 
-               dev->ts_state = SAA7134_TS_STARTED;
-       }
+       if (!dev->ts_started)
+               saa7134_ts_start(dev);
 
        return 0;
 }
@@ -104,7 +79,6 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
        struct saa7134_dev *dev = q->priv_data;
        struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
        unsigned int lines, llength, size;
-       u32 control;
        int err;
 
        dprintk("buffer_prepare [%p,%s]\n",buf,v4l2_field_names[field]);
@@ -121,8 +95,11 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
        }
 
        if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+
                struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 
+               dprintk("buffer_prepare: needs_init\n");
+
                buf->vb.width  = llength;
                buf->vb.height = lines;
                buf->vb.size   = size;
@@ -139,23 +116,6 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
                        goto oops;
        }
 
-       dev->buff_cnt++;
-
-       if (dev->buff_cnt == dev->ts.nr_bufs) {
-               dev->ts_state = SAA7134_TS_BUFF_DONE;
-               /* dma: setup channel 5 (= TS) */
-               control = SAA7134_RS_CONTROL_BURST_16 |
-                       SAA7134_RS_CONTROL_ME |
-                       (buf->pt->dma >> 12);
-
-               saa_writeb(SAA7134_TS_DMA0, (lines - 1) & 0xff);
-               saa_writeb(SAA7134_TS_DMA1, ((lines - 1) >> 8) & 0xff);
-               /* TSNOPIT=0, TSCOLAP=0 */
-               saa_writeb(SAA7134_TS_DMA2, (((lines - 1) >> 16) & 0x3f) | 0x00);
-               saa_writel(SAA7134_RS_PITCH(5), TS_PACKET_SIZE);
-               saa_writel(SAA7134_RS_CONTROL(5), control);
-       }
-
        buf->vb.state = VIDEOBUF_PREPARED;
        buf->activate = buffer_activate;
        buf->vb.field = field;
@@ -175,8 +135,7 @@ buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
        if (0 == *count)
                *count = dev->ts.nr_bufs;
        *count = saa7134_buffer_count(*size,*count);
-       dev->buff_cnt = 0;
-       dev->ts_state = SAA7134_TS_STOPPED;
+
        return 0;
 }
 
@@ -193,11 +152,9 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
        struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
        struct saa7134_dev *dev = q->priv_data;
 
-       if (dev->ts_state == SAA7134_TS_STARTED) {
-               /* Stop TS transport */
-               saa_writeb(SAA7134_TS_PARALLEL, 0x6c);
-               dev->ts_state = SAA7134_TS_STOPPED;
-       }
+       if (dev->ts_started)
+               saa7134_ts_stop(dev);
+
        saa7134_dma_free(q,buf);
 }
 
@@ -214,7 +171,7 @@ EXPORT_SYMBOL_GPL(saa7134_ts_qops);
 
 static unsigned int tsbufs = 8;
 module_param(tsbufs, int, 0444);
-MODULE_PARM_DESC(tsbufs,"number of ts buffers, range 2-32");
+MODULE_PARM_DESC(tsbufs, "number of ts buffers for read/write IO, range 2-32");
 
 static unsigned int ts_nr_packets = 64;
 module_param(ts_nr_packets, int, 0444);
@@ -256,6 +213,7 @@ int saa7134_ts_init1(struct saa7134_dev *dev)
        dev->ts_q.timeout.data     = (unsigned long)(&dev->ts_q);
        dev->ts_q.dev              = dev;
        dev->ts_q.need_two         = 1;
+       dev->ts_started            = 0;
        saa7134_pgtable_alloc(dev->pci,&dev->ts.pt_ts);
 
        /* init TS hw */
@@ -264,13 +222,67 @@ int saa7134_ts_init1(struct saa7134_dev *dev)
        return 0;
 }
 
+/* Function for stop TS */
+int saa7134_ts_stop(struct saa7134_dev *dev)
+{
+       dprintk("TS stop\n");
+
+       BUG_ON(!dev->ts_started);
+
+       /* Stop TS stream */
+       switch (saa7134_boards[dev->board].ts_type) {
+       case SAA7134_MPEG_TS_PARALLEL:
+               saa_writeb(SAA7134_TS_PARALLEL, 0x6c);
+               dev->ts_started = 0;
+               break;
+       case SAA7134_MPEG_TS_SERIAL:
+               saa_writeb(SAA7134_TS_SERIAL0, 0x40);
+               dev->ts_started = 0;
+               break;
+       }
+       return 0;
+}
+
+/* Function for start TS */
+int saa7134_ts_start(struct saa7134_dev *dev)
+{
+       dprintk("TS start\n");
+
+       BUG_ON(dev->ts_started);
+
+       saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+       saa_writeb(SAA7134_TS_SERIAL1, 0x03);
+       saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+       saa_writeb(SAA7134_TS_SERIAL1, 0x01);
+
+       /* TS clock non-inverted */
+       saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+
+       /* Start TS stream */
+       switch (saa7134_boards[dev->board].ts_type) {
+       case SAA7134_MPEG_TS_PARALLEL:
+               saa_writeb(SAA7134_TS_SERIAL0, 0x40);
+               saa_writeb(SAA7134_TS_PARALLEL, 0xec);
+               break;
+       case SAA7134_MPEG_TS_SERIAL:
+               saa_writeb(SAA7134_TS_SERIAL0, 0xd8);
+               saa_writeb(SAA7134_TS_PARALLEL, 0x6c);
+               saa_writeb(SAA7134_TS_PARALLEL_SERIAL, 0xbc);
+               saa_writeb(SAA7134_TS_SERIAL1, 0x02);
+               break;
+       }
+
+       dev->ts_started = 1;
+
+       return 0;
+}
+
 int saa7134_ts_fini(struct saa7134_dev *dev)
 {
        saa7134_pgtable_free(dev->pci,&dev->ts.pt_ts);
        return 0;
 }
 
-
 void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status)
 {
        enum v4l2_field field;
index 493cad941460e0fc32725332d907e19959c474e6..e305c1674cee2415432519b2b6caf28062411cd0 100644 (file)
@@ -1057,6 +1057,7 @@ static int buffer_prepare(struct videobuf_queue *q,
                buf->vb.field  = field;
                buf->fmt       = fh->fmt;
                buf->pt        = &fh->pt_cap;
+               dev->video_q.curr = NULL;
 
                err = videobuf_iolock(q,&buf->vb,&dev->ovbuf);
                if (err)
@@ -1423,11 +1424,13 @@ video_poll(struct file *file, struct poll_table_struct *wait)
 {
        struct saa7134_fh *fh = file->private_data;
        struct videobuf_buffer *buf = NULL;
+       unsigned int rc = 0;
 
        if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)
                return videobuf_poll_stream(file, &fh->vbi, wait);
 
        if (res_check(fh,RESOURCE_VIDEO)) {
+               mutex_lock(&fh->cap.vb_lock);
                if (!list_empty(&fh->cap.stream))
                        buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream);
        } else {
@@ -1446,13 +1449,14 @@ video_poll(struct file *file, struct poll_table_struct *wait)
        }
 
        if (!buf)
-               return POLLERR;
+               goto err;
 
        poll_wait(file, &buf->done, wait);
        if (buf->state == VIDEOBUF_DONE ||
            buf->state == VIDEOBUF_ERROR)
-               return POLLIN|POLLRDNORM;
-       return 0;
+               rc = POLLIN|POLLRDNORM;
+       mutex_unlock(&fh->cap.vb_lock);
+       return rc;
 
 err:
        mutex_unlock(&fh->cap.vb_lock);
index 0cbaf90d48745ead75f6c08149729fdf81ad39e0..82268848f26a4cc8817e17f7a6c5a4281a6952d4 100644 (file)
@@ -252,7 +252,7 @@ struct saa7134_format {
 #define SAA7134_BOARD_BEHOLD_505FM     126
 #define SAA7134_BOARD_BEHOLD_507_9FM   127
 #define SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM 128
-#define SAA7134_BOARD_BEHOLD_607_9FM   129
+#define SAA7134_BOARD_BEHOLD_607FM_MK3 129
 #define SAA7134_BOARD_BEHOLD_M6                130
 #define SAA7134_BOARD_TWINHAN_DTV_DVB_3056 131
 #define SAA7134_BOARD_GENIUS_TVGO_A11MCE   132
@@ -280,6 +280,18 @@ struct saa7134_format {
 #define SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS 154
 #define SAA7134_BOARD_HAUPPAUGE_HVR1120     155
 #define SAA7134_BOARD_HAUPPAUGE_HVR1110R3   156
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_507UA 157
+#define SAA7134_BOARD_AVERMEDIA_CARDBUS_501 158
+#define SAA7134_BOARD_BEHOLD_505RDS         159
+#define SAA7134_BOARD_BEHOLD_507RDS_MK3     160
+#define SAA7134_BOARD_BEHOLD_507RDS_MK5     161
+#define SAA7134_BOARD_BEHOLD_607FM_MK5      162
+#define SAA7134_BOARD_BEHOLD_609FM_MK3      163
+#define SAA7134_BOARD_BEHOLD_609FM_MK5      164
+#define SAA7134_BOARD_BEHOLD_607RDS_MK3     165
+#define SAA7134_BOARD_BEHOLD_607RDS_MK5     166
+#define SAA7134_BOARD_BEHOLD_609RDS_MK3     167
+#define SAA7134_BOARD_BEHOLD_609RDS_MK5     168
 
 #define SAA7134_MAXBOARDS 32
 #define SAA7134_INPUT_MAX 8
@@ -364,6 +376,7 @@ struct saa7134_board {
 #define INTERLACE_OFF          2
 
 #define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds */
+#define TS_BUFFER_TIMEOUT  msecs_to_jiffies(1000)  /* 1 second */
 
 struct saa7134_dev;
 struct saa7134_dma;
@@ -480,12 +493,6 @@ struct saa7134_mpeg_ops {
        void                       (*signal_change)(struct saa7134_dev *dev);
 };
 
-enum saa7134_ts_status {
-       SAA7134_TS_STOPPED,
-       SAA7134_TS_BUFF_DONE,
-       SAA7134_TS_STARTED,
-};
-
 /* global device status */
 struct saa7134_dev {
        struct list_head           devlist;
@@ -580,8 +587,7 @@ struct saa7134_dev {
        /* SAA7134_MPEG_* */
        struct saa7134_ts          ts;
        struct saa7134_dmaqueue    ts_q;
-       enum saa7134_ts_status     ts_state;
-       unsigned int               buff_cnt;
+       int                        ts_started;
        struct saa7134_mpeg_ops    *mops;
 
        /* SAA7134_MPEG_EMPRESS only */
@@ -739,6 +745,9 @@ void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops);
 
 int saa7134_ts_init_hw(struct saa7134_dev *dev);
 
+int saa7134_ts_start(struct saa7134_dev *dev);
+int saa7134_ts_stop(struct saa7134_dev *dev);
+
 /* ----------------------------------------------------------- */
 /* saa7134-vbi.c                                               */
 
@@ -786,7 +795,7 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status);
 int  saa7134_input_init1(struct saa7134_dev *dev);
 void saa7134_input_fini(struct saa7134_dev *dev);
 void saa7134_input_irq(struct saa7134_dev *dev);
-void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir);
+void saa7134_probe_i2c_ir(struct saa7134_dev *dev);
 void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir);
 void saa7134_ir_stop(struct saa7134_dev *dev);
 
index 5990ab38a1249146a8ebdff9b2b1c8be02b58a8e..c8f05297d0f0680acccc7513231a5e561c57b3db 100644 (file)
@@ -38,7 +38,7 @@ static const char version[] = "0.24";
 static int flickerless;
 static int video_nr = -1;
 
-static struct usb_device_id device_table [] = {
+static struct usb_device_id device_table[] = {
        { USB_DEVICE(0x03e8, 0x0004) },/* Endpoints/Aox SE401 */
        { USB_DEVICE(0x0471, 0x030b) },/* Philips PCVC665K */
        { USB_DEVICE(0x047d, 0x5001) },/* Kensington 67014 */
@@ -53,7 +53,8 @@ MODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>");
 MODULE_DESCRIPTION("SE401 USB Camera Driver");
 MODULE_LICENSE("GPL");
 module_param(flickerless, int, 0);
-MODULE_PARM_DESC(flickerless, "Net frequency to adjust exposure time to (0/50/60)");
+MODULE_PARM_DESC(flickerless,
+               "Net frequency to adjust exposure time to (0/50/60)");
 module_param(video_nr, int, 0);
 
 static struct usb_driver se401_driver;
@@ -78,8 +79,8 @@ static void *rvmalloc(unsigned long size)
        adr = (unsigned long) mem;
        while (size > 0) {
                SetPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
+               adr +=  PAGE_SIZE;
+               size -=  PAGE_SIZE;
        }
 
        return mem;
@@ -95,8 +96,8 @@ static void rvfree(void *mem, unsigned long size)
        adr = (unsigned long) mem;
        while ((long) size > 0) {
                ClearPageReserved(vmalloc_to_page((void *)adr));
-               adr += PAGE_SIZE;
-               size -= PAGE_SIZE;
+               adr +=  PAGE_SIZE;
+               size -=  PAGE_SIZE;
        }
        vfree(mem);
 }
@@ -112,7 +113,7 @@ static void rvfree(void *mem, unsigned long size)
 static int se401_sndctrl(int set, struct usb_se401 *se401, unsigned short req,
                         unsigned short value, unsigned char *cp, int size)
 {
-       return usb_control_msg (
+       return usb_control_msg(
                se401->dev,
                set ? usb_sndctrlpipe(se401->dev, 0) : usb_rcvctrlpipe(se401->dev, 0),
                req,
@@ -132,7 +133,7 @@ static int se401_set_feature(struct usb_se401 *se401, unsigned short selector,
           and the param in index, but in the logs of the windows driver they do
           this the other way around...
         */
-       return usb_control_msg (
+       return usb_control_msg(
                se401->dev,
                usb_sndctrlpipe(se401->dev, 0),
                SE401_REQ_SET_EXT_FEATURE,
@@ -152,7 +153,7 @@ static unsigned short se401_get_feature(struct usb_se401 *se401,
           wrong here to....
         */
        unsigned char cp[2];
-       usb_control_msg (
+       usb_control_msg(
                se401->dev,
                usb_rcvctrlpipe(se401->dev, 0),
                SE401_REQ_GET_EXT_FEATURE,
@@ -175,46 +176,51 @@ static unsigned short se401_get_feature(struct usb_se401 *se401,
 
 static int se401_send_pict(struct usb_se401 *se401)
 {
-       se401_set_feature(se401, HV7131_REG_TITL, se401->expose_l);/* integration time low */
-       se401_set_feature(se401, HV7131_REG_TITM, se401->expose_m);/* integration time mid */
-       se401_set_feature(se401, HV7131_REG_TITU, se401->expose_h);/* integration time mid */
-       se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);/* reset level value */
-       se401_set_feature(se401, HV7131_REG_ARCG, se401->rgain);/* red color gain */
-       se401_set_feature(se401, HV7131_REG_AGCG, se401->ggain);/* green color gain */
-       se401_set_feature(se401, HV7131_REG_ABCG, se401->bgain);/* blue color gain */
+       /* integration time low */
+       se401_set_feature(se401, HV7131_REG_TITL, se401->expose_l);
+       /* integration time mid */
+       se401_set_feature(se401, HV7131_REG_TITM, se401->expose_m);
+       /* integration time mid */
+       se401_set_feature(se401, HV7131_REG_TITU, se401->expose_h);
+       /* reset level value */
+       se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);
+       /* red color gain */
+       se401_set_feature(se401, HV7131_REG_ARCG, se401->rgain);
+       /* green color gain */
+       se401_set_feature(se401, HV7131_REG_AGCG, se401->ggain);
+       /* blue color gain */
+       se401_set_feature(se401, HV7131_REG_ABCG, se401->bgain);
 
        return 0;
 }
 
 static void se401_set_exposure(struct usb_se401 *se401, int brightness)
 {
-       int integration=brightness<<5;
-
-       if (flickerless==50) {
-               integration=integration-integration%106667;
-       }
-       if (flickerless==60) {
-               integration=integration-integration%88889;
-       }
-       se401->brightness=integration>>5;
-       se401->expose_h=(integration>>16)&0xff;
-       se401->expose_m=(integration>>8)&0xff;
-       se401->expose_l=integration&0xff;
+       int integration = brightness << 5;
+
+       if (flickerless == 50)
+               integration = integration-integration % 106667;
+       if (flickerless == 60)
+               integration = integration-integration % 88889;
+       se401->brightness = integration >> 5;
+       se401->expose_h = (integration >> 16) & 0xff;
+       se401->expose_m = (integration >> 8) & 0xff;
+       se401->expose_l = integration & 0xff;
 }
 
 static int se401_get_pict(struct usb_se401 *se401, struct video_picture *p)
 {
-       p->brightness=se401->brightness;
-       if (se401->enhance) {
-               p->whiteness=32768;
-       } else {
-               p->whiteness=0;
-       }
-       p->colour=65535;
-       p->contrast=65535;
-       p->hue=se401->rgain<<10;
-       p->palette=se401->palette;
-       p->depth=3; /* rgb24 */
+       p->brightness = se401->brightness;
+       if (se401->enhance)
+               p->whiteness = 32768;
+       else
+               p->whiteness = 0;
+
+       p->colour = 65535;
+       p->contrast = 65535;
+       p->hue = se401->rgain << 10;
+       p->palette = se401->palette;
+       p->depth = 3; /* rgb24 */
        return 0;
 }
 
@@ -223,20 +229,19 @@ static int se401_set_pict(struct usb_se401 *se401, struct video_picture *p)
 {
        if (p->palette != VIDEO_PALETTE_RGB24)
                return 1;
-       se401->palette=p->palette;
-       if (p->hue!=se401->hue) {
-               se401->rgain= p->hue>>10;
-               se401->bgain= 0x40-(p->hue>>10);
-               se401->hue=p->hue;
+       se401->palette = p->palette;
+       if (p->hue != se401->hue) {
+               se401->rgain =  p->hue >> 10;
+               se401->bgain =  0x40-(p->hue >> 10);
+               se401->hue = p->hue;
        }
-       if (p->brightness!=se401->brightness) {
+       if (p->brightness != se401->brightness)
                se401_set_exposure(se401, p->brightness);
-       }
-       if (p->whiteness>=32768) {
-               se401->enhance=1;
-       } else {
-               se401->enhance=0;
-       }
+
+       if (p->whiteness >= 32768)
+               se401->enhance = 1;
+       else
+               se401->enhance = 0;
        se401_send_pict(se401);
        se401_send_pict(se401);
        return 0;
@@ -249,7 +254,7 @@ static int se401_set_pict(struct usb_se401 *se401, struct video_picture *p)
 static void se401_auto_resetlevel(struct usb_se401 *se401)
 {
        unsigned int ahrc, alrc;
-       int oldreset=se401->resetlevel;
+       int oldreset = se401->resetlevel;
 
        /* For some reason this normally read-only register doesn't get reset
           to zero after reading them just once...
@@ -258,24 +263,24 @@ static void se401_auto_resetlevel(struct usb_se401 *se401)
        se401_get_feature(se401, HV7131_REG_HIREFNOL);
        se401_get_feature(se401, HV7131_REG_LOREFNOH);
        se401_get_feature(se401, HV7131_REG_LOREFNOL);
-       ahrc=256*se401_get_feature(se401, HV7131_REG_HIREFNOH) +
+       ahrc = 256*se401_get_feature(se401, HV7131_REG_HIREFNOH) +
            se401_get_feature(se401, HV7131_REG_HIREFNOL);
-       alrc=256*se401_get_feature(se401, HV7131_REG_LOREFNOH) +
+       alrc = 256*se401_get_feature(se401, HV7131_REG_LOREFNOH) +
            se401_get_feature(se401, HV7131_REG_LOREFNOL);
 
        /* Not an exact science, but it seems to work pretty well... */
        if (alrc > 10) {
-               while (alrc>=10 && se401->resetlevel < 63) {
+               while (alrc >= 10 && se401->resetlevel < 63) {
                        se401->resetlevel++;
-                       alrc /=2;
+                       alrc /= 2;
                }
        } else if (ahrc > 20) {
-               while (ahrc>=20 && se401->resetlevel > 0) {
+               while (ahrc >= 20 && se401->resetlevel > 0) {
                        se401->resetlevel--;
-                       ahrc /=2;
+                       ahrc /= 2;
                }
        }
-       if (se401->resetlevel!=oldreset)
+       if (se401->resetlevel != oldreset)
                se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);
 
        return;
@@ -300,21 +305,22 @@ static void se401_button_irq(struct urb *urb)
        case -ENOENT:
        case -ESHUTDOWN:
                /* this urb is terminated, clean up */
-               dbg("%s - urb shutting down with status: %d", __func__, urb->status);
+               dbg("%s - urb shutting down with status: %d",
+                                                       __func__, urb->status);
                return;
        default:
-               dbg("%s - nonzero urb status received: %d", __func__, urb->status);
+               dbg("%s - nonzero urb status received: %d",
+                                                       __func__, urb->status);
                goto exit;
        }
 
-       if (urb->actual_length >=2) {
+       if (urb->actual_length  >= 2)
                if (se401->button)
-                       se401->buttonpressed=1;
-       }
+                       se401->buttonpressed = 1;
 exit:
-       status = usb_submit_urb (urb, GFP_ATOMIC);
+       status = usb_submit_urb(urb, GFP_ATOMIC);
        if (status)
-               err ("%s - usb_submit_urb failed with result %d",
+               err("%s - usb_submit_urb failed with result %d",
                     __func__, status);
 }
 
@@ -336,55 +342,52 @@ static void se401_video_irq(struct urb *urb)
           keeps sending them forever...
         */
        if (length && !urb->status) {
-               se401->nullpackets=0;
-               switch(se401->scratch[se401->scratch_next].state) {
-                       case BUFFER_READY:
-                       case BUFFER_BUSY: {
-                               se401->dropped++;
-                               break;
-                       }
-                       case BUFFER_UNUSED: {
-                               memcpy(se401->scratch[se401->scratch_next].data, (unsigned char *)urb->transfer_buffer, length);
-                               se401->scratch[se401->scratch_next].state=BUFFER_READY;
-                               se401->scratch[se401->scratch_next].offset=se401->bayeroffset;
-                               se401->scratch[se401->scratch_next].length=length;
-                               if (waitqueue_active(&se401->wq)) {
-                                       wake_up_interruptible(&se401->wq);
-                               }
-                               se401->scratch_overflow=0;
-                               se401->scratch_next++;
-                               if (se401->scratch_next>=SE401_NUMSCRATCH)
-                                       se401->scratch_next=0;
-                               break;
-                       }
-               }
-               se401->bayeroffset+=length;
-               if (se401->bayeroffset>=se401->cheight*se401->cwidth) {
-                       se401->bayeroffset=0;
+               se401->nullpackets = 0;
+               switch (se401->scratch[se401->scratch_next].state) {
+               case BUFFER_READY:
+               case BUFFER_BUSY:
+                       se401->dropped++;
+                       break;
+               case BUFFER_UNUSED:
+                       memcpy(se401->scratch[se401->scratch_next].data,
+                               (unsigned char *)urb->transfer_buffer, length);
+                       se401->scratch[se401->scratch_next].state
+                                                       = BUFFER_READY;
+                       se401->scratch[se401->scratch_next].offset
+                                                       = se401->bayeroffset;
+                       se401->scratch[se401->scratch_next].length = length;
+                       if (waitqueue_active(&se401->wq))
+                               wake_up_interruptible(&se401->wq);
+                       se401->scratch_overflow = 0;
+                       se401->scratch_next++;
+                       if (se401->scratch_next >= SE401_NUMSCRATCH)
+                               se401->scratch_next = 0;
+                       break;
                }
+               se401->bayeroffset += length;
+               if (se401->bayeroffset >= se401->cheight * se401->cwidth)
+                       se401->bayeroffset = 0;
        } else {
                se401->nullpackets++;
-               if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
-                       if (waitqueue_active(&se401->wq)) {
+               if (se401->nullpackets > SE401_MAX_NULLPACKETS)
+                       if (waitqueue_active(&se401->wq))
                                wake_up_interruptible(&se401->wq);
-                       }
-               }
        }
 
        /* Resubmit urb for new data */
-       urb->status=0;
-       urb->dev=se401->dev;
-       if(usb_submit_urb(urb, GFP_KERNEL))
+       urb->status = 0;
+       urb->dev = se401->dev;
+       if (usb_submit_urb(urb, GFP_KERNEL))
                dev_info(&urb->dev->dev, "urb burned down\n");
        return;
 }
 
 static void se401_send_size(struct usb_se401 *se401, int width, int height)
 {
-       int i=0;
-       int mode=0x03; /* No compression */
-       int sendheight=height;
-       int sendwidth=width;
+       int i = 0;
+       int mode = 0x03; /* No compression */
+       int sendheight = height;
+       int sendwidth = width;
 
        /* JangGu compression can only be used with the camera supported sizes,
           but bayer seems to work with any size that fits on the sensor.
@@ -392,18 +395,21 @@ static void se401_send_size(struct usb_se401 *se401, int width, int height)
           4 or 16 times subcapturing, if not we use uncompressed bayer data
           but this will result in cutouts of the maximum size....
         */
-       while (i<se401->sizes && !(se401->width[i]==width && se401->height[i]==height))
+       while (i < se401->sizes && !(se401->width[i] == width &&
+                                               se401->height[i] == height))
                i++;
-       while (i<se401->sizes) {
-               if (se401->width[i]==width*2 && se401->height[i]==height*2) {
-                       sendheight=se401->height[i];
-                       sendwidth=se401->width[i];
-                       mode=0x40;
+       while (i < se401->sizes) {
+               if (se401->width[i] == width * 2 &&
+                               se401->height[i] == height * 2) {
+                       sendheight = se401->height[i];
+                       sendwidth = se401->width[i];
+                       mode = 0x40;
                }
-               if (se401->width[i]==width*4 && se401->height[i]==height*4) {
-                       sendheight=se401->height[i];
-                       sendwidth=se401->width[i];
-                       mode=0x42;
+               if (se401->width[i] == width * 4 &&
+                               se401->height[i] == height * 4) {
+                       sendheight = se401->height[i];
+                       sendwidth = se401->width[i];
+                       mode = 0x42;
                }
                i++;
        }
@@ -412,13 +418,10 @@ static void se401_send_size(struct usb_se401 *se401, int width, int height)
        se401_sndctrl(1, se401, SE401_REQ_SET_HEIGHT, sendheight, NULL, 0);
        se401_set_feature(se401, SE401_OPERATINGMODE, mode);
 
-       if (mode==0x03) {
-               se401->format=FMT_BAYER;
-       } else {
-               se401->format=FMT_JANGGU;
-       }
-
-       return;
+       if (mode == 0x03)
+               se401->format = FMT_BAYER;
+       else
+               se401->format = FMT_JANGGU;
 }
 
 /*
@@ -429,29 +432,31 @@ static void se401_send_size(struct usb_se401 *se401, int width, int height)
 static int se401_start_stream(struct usb_se401 *se401)
 {
        struct urb *urb;
-       int err=0, i;
-       se401->streaming=1;
+       int err = 0, i;
+       se401->streaming = 1;
 
        se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
        se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
 
        /* Set picture settings */
-       se401_set_feature(se401, HV7131_REG_MODE_B, 0x05);/*windowed + pix intg */
+       /* windowed + pix intg */
+       se401_set_feature(se401, HV7131_REG_MODE_B, 0x05);
        se401_send_pict(se401);
 
        se401_send_size(se401, se401->cwidth, se401->cheight);
 
-       se401_sndctrl(1, se401, SE401_REQ_START_CONTINUOUS_CAPTURE, 0, NULL, 0);
+       se401_sndctrl(1, se401, SE401_REQ_START_CONTINUOUS_CAPTURE,
+                                                               0, NULL, 0);
 
        /* Do some memory allocation */
-       for (i=0; i<SE401_NUMFRAMES; i++) {
-               se401->frame[i].data=se401->fbuf + i * se401->maxframesize;
-               se401->frame[i].curpix=0;
+       for (i = 0; i < SE401_NUMFRAMES; i++) {
+               se401->frame[i].data = se401->fbuf + i * se401->maxframesize;
+               se401->frame[i].curpix = 0;
        }
-       for (i=0; i<SE401_NUMSBUF; i++) {
-               se401->sbuf[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
+       for (i = 0; i < SE401_NUMSBUF; i++) {
+               se401->sbuf[i].data = kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
                if (!se401->sbuf[i].data) {
-                       for(i = i - 1; i >= 0; i--) {
+                       for (i = i - 1; i >= 0; i--) {
                                kfree(se401->sbuf[i].data);
                                se401->sbuf[i].data = NULL;
                        }
@@ -459,26 +464,26 @@ static int se401_start_stream(struct usb_se401 *se401)
                }
        }
 
-       se401->bayeroffset=0;
-       se401->scratch_next=0;
-       se401->scratch_use=0;
-       se401->scratch_overflow=0;
-       for (i=0; i<SE401_NUMSCRATCH; i++) {
-               se401->scratch[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
+       se401->bayeroffset = 0;
+       se401->scratch_next = 0;
+       se401->scratch_use = 0;
+       se401->scratch_overflow = 0;
+       for (i = 0; i < SE401_NUMSCRATCH; i++) {
+               se401->scratch[i].data = kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
                if (!se401->scratch[i].data) {
-                       for(i = i - 1; i >= 0; i--) {
+                       for (i = i - 1; i >= 0; i--) {
                                kfree(se401->scratch[i].data);
                                se401->scratch[i].data = NULL;
                        }
                        goto nomem_sbuf;
                }
-               se401->scratch[i].state=BUFFER_UNUSED;
+               se401->scratch[i].state = BUFFER_UNUSED;
        }
 
-       for (i=0; i<SE401_NUMSBUF; i++) {
-               urb=usb_alloc_urb(0, GFP_KERNEL);
-               if(!urb) {
-                       for(i = i - 1; i >= 0; i--) {
+       for (i = 0; i < SE401_NUMSBUF; i++) {
+               urb = usb_alloc_urb(0, GFP_KERNEL);
+               if (!urb) {
+                       for (i = i - 1; i >= 0; i--) {
                                usb_kill_urb(se401->urb[i]);
                                usb_free_urb(se401->urb[i]);
                                se401->urb[i] = NULL;
@@ -492,24 +497,24 @@ static int se401_start_stream(struct usb_se401 *se401)
                        se401_video_irq,
                        se401);
 
-               se401->urb[i]=urb;
+               se401->urb[i] = urb;
 
-               err=usb_submit_urb(se401->urb[i], GFP_KERNEL);
-               if(err)
+               err = usb_submit_urb(se401->urb[i], GFP_KERNEL);
+               if (err)
                        err("urb burned down");
        }
 
-       se401->framecount=0;
+       se401->framecount = 0;
 
        return 0;
 
  nomem_scratch:
-       for (i=0; i<SE401_NUMSCRATCH; i++) {
+       for (i = 0; i < SE401_NUMSCRATCH; i++) {
                kfree(se401->scratch[i].data);
                se401->scratch[i].data = NULL;
        }
  nomem_sbuf:
-       for (i=0; i<SE401_NUMSBUF; i++) {
+       for (i = 0; i < SE401_NUMSBUF; i++) {
                kfree(se401->sbuf[i].data);
                se401->sbuf[i].data = NULL;
        }
@@ -523,22 +528,23 @@ static int se401_stop_stream(struct usb_se401 *se401)
        if (!se401->streaming || !se401->dev)
                return 1;
 
-       se401->streaming=0;
+       se401->streaming = 0;
 
        se401_sndctrl(1, se401, SE401_REQ_STOP_CONTINUOUS_CAPTURE, 0, NULL, 0);
 
        se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0);
        se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0);
 
-       for (i=0; i<SE401_NUMSBUF; i++) if (se401->urb[i]) {
-               usb_kill_urb(se401->urb[i]);
-               usb_free_urb(se401->urb[i]);
-               se401->urb[i]=NULL;
-               kfree(se401->sbuf[i].data);
-       }
-       for (i=0; i<SE401_NUMSCRATCH; i++) {
+       for (i = 0; i < SE401_NUMSBUF; i++)
+               if (se401->urb[i]) {
+                       usb_kill_urb(se401->urb[i]);
+                       usb_free_urb(se401->urb[i]);
+                       se401->urb[i] = NULL;
+                       kfree(se401->sbuf[i].data);
+               }
+       for (i = 0; i < SE401_NUMSCRATCH; i++) {
                kfree(se401->scratch[i].data);
-               se401->scratch[i].data=NULL;
+               se401->scratch[i].data = NULL;
        }
 
        return 0;
@@ -546,9 +552,9 @@ static int se401_stop_stream(struct usb_se401 *se401)
 
 static int se401_set_size(struct usb_se401 *se401, int width, int height)
 {
-       int wasstreaming=se401->streaming;
+       int wasstreaming = se401->streaming;
        /* Check to see if we need to change */
-       if (se401->cwidth==width && se401->cheight==height)
+       if (se401->cwidth == width && se401->cheight == height)
                return 0;
 
        /* Check for a valid mode */
@@ -556,16 +562,16 @@ static int se401_set_size(struct usb_se401 *se401, int width, int height)
                return 1;
        if ((width & 1) || (height & 1))
                return 1;
-       if (width>se401->width[se401->sizes-1])
+       if (width > se401->width[se401->sizes-1])
                return 1;
-       if (height>se401->height[se401->sizes-1])
+       if (height > se401->height[se401->sizes-1])
                return 1;
 
        /* Stop a current stream and start it again at the new size */
        if (wasstreaming)
                se401_stop_stream(se401);
-       se401->cwidth=width;
-       se401->cheight=height;
+       se401->cwidth = width;
+       se401->cheight = height;
        if (wasstreaming)
                se401_start_stream(se401);
        return 0;
@@ -586,68 +592,68 @@ static int se401_set_size(struct usb_se401 *se401, int width, int height)
 static inline void enhance_picture(unsigned char *frame, int len)
 {
        while (len--) {
-               *frame=(((*frame^255)*(*frame^255))/255)^255;
+               *frame = (((*frame^255)*(*frame^255))/255)^255;
                frame++;
        }
 }
 
 static inline void decode_JangGu_integrate(struct usb_se401 *se401, int data)
 {
-       struct se401_frame *frame=&se401->frame[se401->curframe];
-       int linelength=se401->cwidth*3;
+       struct se401_frame *frame = &se401->frame[se401->curframe];
+       int linelength = se401->cwidth * 3;
 
        if (frame->curlinepix >= linelength) {
-               frame->curlinepix=0;
-               frame->curline+=linelength;
+               frame->curlinepix = 0;
+               frame->curline += linelength;
        }
 
        /* First three are absolute, all others relative.
         * Format is rgb from right to left (mirrorred image),
         * we flip it to get bgr from left to right. */
-       if (frame->curlinepix < 3) {
-               *(frame->curline-frame->curlinepix)=1+data*4;
-       } else {
-               *(frame->curline-frame->curlinepix)=
-                   *(frame->curline-frame->curlinepix+3)+data*4;
-       }
+       if (frame->curlinepix < 3)
+               *(frame->curline-frame->curlinepix) = 1 + data * 4;
+       else
+               *(frame->curline-frame->curlinepix) =
+                   *(frame->curline-frame->curlinepix + 3) + data * 4;
        frame->curlinepix++;
 }
 
-static inline void decode_JangGu_vlc (struct usb_se401 *se401, unsigned char *data, int bit_exp, int packetlength)
+static inline void decode_JangGu_vlc(struct usb_se401 *se401,
+                       unsigned char *data, int bit_exp, int packetlength)
 {
-       int pos=0;
-       int vlc_cod=0;
-       int vlc_size=0;
-       int vlc_data=0;
+       int pos = 0;
+       int vlc_cod = 0;
+       int vlc_size = 0;
+       int vlc_data = 0;
        int bit_cur;
        int bit;
-       data+=4;
+       data += 4;
        while (pos < packetlength) {
-               bit_cur=8;
+               bit_cur = 8;
                while (bit_cur && bit_exp) {
-                       bit=((*data)>>(bit_cur-1))&1;
+                       bit = ((*data) >> (bit_cur-1))&1;
                        if (!vlc_cod) {
                                if (bit) {
                                        vlc_size++;
                                } else {
-                                       if (!vlc_size) {
+                                       if (!vlc_size)
                                                decode_JangGu_integrate(se401, 0);
-                                       else {
-                                               vlc_cod=2;
-                                               vlc_data=0;
+                                       else {
+                                               vlc_cod = 2;
+                                               vlc_data = 0;
                                        }
                                }
                        } else {
-                               if (vlc_cod==2) {
+                               if (vlc_cod == 2) {
                                        if (!bit)
-                                               vlc_data =  -(1<<vlc_size) + 1;
+                                               vlc_data =  -(1 << vlc_size) + 1;
                                        vlc_cod--;
                                }
                                vlc_size--;
-                               vlc_data+=bit<<vlc_size;
+                               vlc_data += bit << vlc_size;
                                if (!vlc_size) {
                                        decode_JangGu_integrate(se401, vlc_data);
-                                       vlc_cod=0;
+                                       vlc_cod = 0;
                                }
                        }
                        bit_cur--;
@@ -658,186 +664,188 @@ static inline void decode_JangGu_vlc (struct usb_se401 *se401, unsigned char *da
        }
 }
 
-static inline void decode_JangGu (struct usb_se401 *se401, struct se401_scratch *buffer)
+static inline void decode_JangGu(struct usb_se401 *se401,
+                                               struct se401_scratch *buffer)
 {
-       unsigned char *data=buffer->data;
-       int len=buffer->length;
-       int bit_exp=0, pix_exp=0, frameinfo=0, packetlength=0, size;
-       int datapos=0;
+       unsigned char *data = buffer->data;
+       int len = buffer->length;
+       int bit_exp = 0, pix_exp = 0, frameinfo = 0, packetlength = 0, size;
+       int datapos = 0;
 
        /* New image? */
        if (!se401->frame[se401->curframe].curpix) {
-               se401->frame[se401->curframe].curlinepix=0;
-               se401->frame[se401->curframe].curline=
+               se401->frame[se401->curframe].curlinepix = 0;
+               se401->frame[se401->curframe].curline =
                    se401->frame[se401->curframe].data+
-                   se401->cwidth*3-1;
-               if (se401->frame[se401->curframe].grabstate==FRAME_READY)
-                       se401->frame[se401->curframe].grabstate=FRAME_GRABBING;
-               se401->vlcdatapos=0;
+                   se401->cwidth * 3 - 1;
+               if (se401->frame[se401->curframe].grabstate == FRAME_READY)
+                       se401->frame[se401->curframe].grabstate = FRAME_GRABBING;
+               se401->vlcdatapos = 0;
        }
        while (datapos < len) {
-               size=1024-se401->vlcdatapos;
+               size = 1024 - se401->vlcdatapos;
                if (size+datapos > len)
-                       size=len-datapos;
+                       size = len-datapos;
                memcpy(se401->vlcdata+se401->vlcdatapos, data+datapos, size);
-               se401->vlcdatapos+=size;
-               packetlength=0;
+               se401->vlcdatapos += size;
+               packetlength = 0;
                if (se401->vlcdatapos >= 4) {
-                       bit_exp=se401->vlcdata[3]+(se401->vlcdata[2]<<8);
-                       pix_exp=se401->vlcdata[1]+((se401->vlcdata[0]&0x3f)<<8);
-                       frameinfo=se401->vlcdata[0]&0xc0;
-                       packetlength=((bit_exp+47)>>4)<<1;
+                       bit_exp = se401->vlcdata[3] + (se401->vlcdata[2] << 8);
+                       pix_exp = se401->vlcdata[1] +
+                                       ((se401->vlcdata[0] & 0x3f) << 8);
+                       frameinfo = se401->vlcdata[0] & 0xc0;
+                       packetlength = ((bit_exp + 47) >> 4) << 1;
                        if (packetlength > 1024) {
-                               se401->vlcdatapos=0;
-                               datapos=len;
-                               packetlength=0;
+                               se401->vlcdatapos = 0;
+                               datapos = len;
+                               packetlength = 0;
                                se401->error++;
-                               se401->frame[se401->curframe].curpix=0;
+                               se401->frame[se401->curframe].curpix = 0;
                        }
                }
                if (packetlength && se401->vlcdatapos >= packetlength) {
-                       decode_JangGu_vlc(se401, se401->vlcdata, bit_exp, packetlength);
-                       se401->frame[se401->curframe].curpix+=pix_exp*3;
-                       datapos+=size-(se401->vlcdatapos-packetlength);
-                       se401->vlcdatapos=0;
-                       if (se401->frame[se401->curframe].curpix>=se401->cwidth*se401->cheight*3) {
-                               if (se401->frame[se401->curframe].curpix==se401->cwidth*se401->cheight*3) {
-                                       if (se401->frame[se401->curframe].grabstate==FRAME_GRABBING) {
-                                               se401->frame[se401->curframe].grabstate=FRAME_DONE;
+                       decode_JangGu_vlc(se401, se401->vlcdata, bit_exp,
+                                                               packetlength);
+                       se401->frame[se401->curframe].curpix += pix_exp * 3;
+                       datapos += size-(se401->vlcdatapos-packetlength);
+                       se401->vlcdatapos = 0;
+                       if (se401->frame[se401->curframe].curpix >= se401->cwidth * se401->cheight * 3) {
+                               if (se401->frame[se401->curframe].curpix == se401->cwidth * se401->cheight * 3) {
+                                       if (se401->frame[se401->curframe].grabstate == FRAME_GRABBING) {
+                                               se401->frame[se401->curframe].grabstate = FRAME_DONE;
                                                se401->framecount++;
                                                se401->readcount++;
                                        }
-                                       if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) {
-                                               se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1);
-                                       }
-                               } else {
+                                       if (se401->frame[(se401->curframe + 1) & (SE401_NUMFRAMES - 1)].grabstate == FRAME_READY)
+                                               se401->curframe = (se401->curframe + 1) & (SE401_NUMFRAMES - 1);
+                               } else
                                        se401->error++;
-                               }
-                               se401->frame[se401->curframe].curpix=0;
-                               datapos=len;
+                               se401->frame[se401->curframe].curpix = 0;
+                               datapos = len;
                        }
-               } else {
-                       datapos+=size;
-               }
+               } else
+                       datapos += size;
        }
 }
 
-static inline void decode_bayer (struct usb_se401 *se401, struct se401_scratch *buffer)
+static inline void decode_bayer(struct usb_se401 *se401,
+                                               struct se401_scratch *buffer)
 {
-       unsigned char *data=buffer->data;
-       int len=buffer->length;
-       int offset=buffer->offset;
-       int datasize=se401->cwidth*se401->cheight;
-       struct se401_frame *frame=&se401->frame[se401->curframe];
+       unsigned char *data = buffer->data;
+       int len = buffer->length;
+       int offset = buffer->offset;
+       int datasize = se401->cwidth * se401->cheight;
+       struct se401_frame *frame = &se401->frame[se401->curframe];
+       unsigned char *framedata = frame->data, *curline, *nextline;
+       int width = se401->cwidth;
+       int blineoffset = 0, bline;
+       int linelength = width * 3, i;
 
-       unsigned char *framedata=frame->data, *curline, *nextline;
-       int width=se401->cwidth;
-       int blineoffset=0, bline;
-       int linelength=width*3, i;
 
+       if (frame->curpix == 0) {
+               if (frame->grabstate == FRAME_READY)
+                       frame->grabstate = FRAME_GRABBING;
 
-       if (frame->curpix==0) {
-               if (frame->grabstate==FRAME_READY) {
-                       frame->grabstate=FRAME_GRABBING;
-               }
-               frame->curline=framedata+linelength;
-               frame->curlinepix=0;
+               frame->curline = framedata + linelength;
+               frame->curlinepix = 0;
        }
 
-       if (offset!=frame->curpix) {
+       if (offset != frame->curpix) {
                /* Regard frame as lost :( */
-               frame->curpix=0;
+               frame->curpix = 0;
                se401->error++;
                return;
        }
 
        /* Check if we have to much data */
-       if (frame->curpix+len > datasize) {
-               len=datasize-frame->curpix;
-       }
-       if (se401->cheight%4)
-               blineoffset=1;
-       bline=frame->curpix/se401->cwidth+blineoffset;
-
-       curline=frame->curline;
-       nextline=curline+linelength;
-       if (nextline >= framedata+datasize*3)
-               nextline=curline;
+       if (frame->curpix + len > datasize)
+               len = datasize-frame->curpix;
+
+       if (se401->cheight % 4)
+               blineoffset = 1;
+       bline = frame->curpix / se401->cwidth+blineoffset;
+
+       curline = frame->curline;
+       nextline = curline + linelength;
+       if (nextline >= framedata+datasize * 3)
+               nextline = curline;
        while (len) {
-               if (frame->curlinepix>=width) {
-                       frame->curlinepix-=width;
-                       bline=frame->curpix/width+blineoffset;
-                       curline+=linelength*2;
-                       nextline+=linelength*2;
-                       if (curline >= framedata+datasize*3) {
+               if (frame->curlinepix >= width) {
+                       frame->curlinepix -= width;
+                       bline = frame->curpix / width + blineoffset;
+                       curline += linelength*2;
+                       nextline += linelength*2;
+                       if (curline >= framedata+datasize * 3) {
                                frame->curlinepix++;
-                               curline-=3;
-                               nextline-=3;
+                               curline -= 3;
+                               nextline -= 3;
                                len--;
                                data++;
                                frame->curpix++;
                        }
                        if (nextline >= framedata+datasize*3)
-                               nextline=curline;
+                               nextline = curline;
                }
-               if ((bline&1)) {
-                       if ((frame->curlinepix&1)) {
-                               *(curline+2)=*data;
-                               *(curline-1)=*data;
-                               *(nextline+2)=*data;
-                               *(nextline-1)=*data;
+               if (bline & 1) {
+                       if (frame->curlinepix & 1) {
+                               *(curline + 2) = *data;
+                               *(curline - 1) = *data;
+                               *(nextline + 2) = *data;
+                               *(nextline - 1) = *data;
                        } else {
-                               *(curline+1)=
-                                       (*(curline+1)+*data)/2;
-                               *(curline-2)=
-                                       (*(curline-2)+*data)/2;
-                               *(nextline+1)=*data;
-                               *(nextline-2)=*data;
+                               *(curline + 1) =
+                                       (*(curline + 1) + *data) / 2;
+                               *(curline-2) =
+                                       (*(curline - 2) + *data) / 2;
+                               *(nextline + 1) = *data;
+                               *(nextline - 2) = *data;
                        }
                } else {
-                       if ((frame->curlinepix&1)) {
-                               *(curline+1)=
-                                       (*(curline+1)+*data)/2;
-                               *(curline-2)=
-                                       (*(curline-2)+*data)/2;
-                               *(nextline+1)=*data;
-                               *(nextline-2)=*data;
+                       if (frame->curlinepix & 1) {
+                               *(curline + 1) =
+                                       (*(curline + 1) + *data) / 2;
+                               *(curline - 2) =
+                                       (*(curline - 2) + *data) / 2;
+                               *(nextline + 1) = *data;
+                               *(nextline - 2) = *data;
                        } else {
-                               *curline=*data;
-                               *(curline-3)=*data;
-                               *nextline=*data;
-                               *(nextline-3)=*data;
+                               *curline = *data;
+                               *(curline - 3) = *data;
+                               *nextline = *data;
+                               *(nextline - 3) = *data;
                        }
                }
                frame->curlinepix++;
-               curline-=3;
-               nextline-=3;
+               curline -= 3;
+               nextline -= 3;
                len--;
                data++;
                frame->curpix++;
        }
-       frame->curline=curline;
+       frame->curline = curline;
 
-       if (frame->curpix>=datasize) {
+       if (frame->curpix >= datasize) {
                /* Fix the top line */
-               framedata+=linelength;
-               for (i=0; i<linelength; i++) {
+               framedata += linelength;
+               for (i = 0; i < linelength; i++) {
                        framedata--;
-                       *framedata=*(framedata+linelength);
+                       *framedata = *(framedata + linelength);
                }
                /* Fix the left side (green is already present) */
-               for (i=0; i<se401->cheight; i++) {
-                       *framedata=*(framedata+3);
-                       *(framedata+1)=*(framedata+4);
-                       *(framedata+2)=*(framedata+5);
-                       framedata+=linelength;
+               for (i = 0; i < se401->cheight; i++) {
+                       *framedata = *(framedata + 3);
+                       *(framedata + 1) = *(framedata + 4);
+                       *(framedata + 2) = *(framedata + 5);
+                       framedata += linelength;
                }
-               frame->curpix=0;
-               frame->grabstate=FRAME_DONE;
+               frame->curpix = 0;
+               frame->grabstate = FRAME_DONE;
                se401->framecount++;
                se401->readcount++;
-               if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) {
-                       se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1);
+               if (se401->frame[(se401->curframe + 1) &
+                   (SE401_NUMFRAMES - 1)].grabstate == FRAME_READY) {
+                       se401->curframe = (se401->curframe+1) &
+                                                       (SE401_NUMFRAMES-1);
                }
        }
 }
@@ -845,72 +853,76 @@ static inline void decode_bayer (struct usb_se401 *se401, struct se401_scratch *
 static int se401_newframe(struct usb_se401 *se401, int framenr)
 {
        DECLARE_WAITQUEUE(wait, current);
-       int errors=0;
+       int errors = 0;
 
        while (se401->streaming &&
-           (se401->frame[framenr].grabstate==FRAME_READY ||
-            se401->frame[framenr].grabstate==FRAME_GRABBING) ) {
-               if(!se401->frame[framenr].curpix) {
+           (se401->frame[framenr].grabstate == FRAME_READY ||
+            se401->frame[framenr].grabstate == FRAME_GRABBING)) {
+               if (!se401->frame[framenr].curpix)
                        errors++;
-               }
+
                wait_interruptible(
-                   se401->scratch[se401->scratch_use].state!=BUFFER_READY,
-                   &se401->wq,
-                   &wait
-               );
+                   se401->scratch[se401->scratch_use].state != BUFFER_READY,
+                                                   &se401->wq, &wait);
                if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
-                       se401->nullpackets=0;
+                       se401->nullpackets = 0;
                        dev_info(&se401->dev->dev,
-                                "too many null length packets, restarting capture\n");
+                        "too many null length packets, restarting capture\n");
                        se401_stop_stream(se401);
                        se401_start_stream(se401);
                } else {
-                       if (se401->scratch[se401->scratch_use].state!=BUFFER_READY) {
-                               se401->frame[framenr].grabstate=FRAME_ERROR;
+                       if (se401->scratch[se401->scratch_use].state !=
+                                                               BUFFER_READY) {
+                               se401->frame[framenr].grabstate = FRAME_ERROR;
                                return -EIO;
                        }
-                       se401->scratch[se401->scratch_use].state=BUFFER_BUSY;
-                       if (se401->format==FMT_JANGGU) {
-                               decode_JangGu(se401, &se401->scratch[se401->scratch_use]);
-                       } else {
-                               decode_bayer(se401, &se401->scratch[se401->scratch_use]);
-                       }
-                       se401->scratch[se401->scratch_use].state=BUFFER_UNUSED;
+                       se401->scratch[se401->scratch_use].state = BUFFER_BUSY;
+                       if (se401->format == FMT_JANGGU)
+                               decode_JangGu(se401,
+                                       &se401->scratch[se401->scratch_use]);
+                       else
+                               decode_bayer(se401,
+                                       &se401->scratch[se401->scratch_use]);
+
+                       se401->scratch[se401->scratch_use].state =
+                                                       BUFFER_UNUSED;
                        se401->scratch_use++;
-                       if (se401->scratch_use>=SE401_NUMSCRATCH)
-                               se401->scratch_use=0;
+                       if (se401->scratch_use >= SE401_NUMSCRATCH)
+                               se401->scratch_use = 0;
                        if (errors > SE401_MAX_ERRORS) {
-                               errors=0;
+                               errors = 0;
                                dev_info(&se401->dev->dev,
-                                        "too many errors, restarting capture\n");
+                                     "too many errors, restarting capture\n");
                                se401_stop_stream(se401);
                                se401_start_stream(se401);
                        }
                }
        }
 
-       if (se401->frame[framenr].grabstate==FRAME_DONE)
+       if (se401->frame[framenr].grabstate == FRAME_DONE)
                if (se401->enhance)
-                       enhance_picture(se401->frame[framenr].data, se401->cheight*se401->cwidth*3);
+                       enhance_picture(se401->frame[framenr].data,
+                                       se401->cheight * se401->cwidth * 3);
        return 0;
 }
 
-static void usb_se401_remove_disconnected (struct usb_se401 *se401)
+static void usb_se401_remove_disconnected(struct usb_se401 *se401)
 {
        int i;
 
        se401->dev = NULL;
 
-       for (i=0; i<SE401_NUMSBUF; i++)
+       for (i = 0; i < SE401_NUMSBUF; i++)
                if (se401->urb[i]) {
                        usb_kill_urb(se401->urb[i]);
                        usb_free_urb(se401->urb[i]);
                        se401->urb[i] = NULL;
                        kfree(se401->sbuf[i].data);
                }
-       for (i=0; i<SE401_NUMSCRATCH; i++) {
+
+       for (i = 0; i < SE401_NUMSCRATCH; i++)
                kfree(se401->scratch[i].data);
-       }
+
        if (se401->inturb) {
                usb_kill_urb(se401->inturb);
                usb_free_urb(se401->inturb);
@@ -965,11 +977,11 @@ static int se401_close(struct file *file)
                dev_info(&se401->dev->dev, "device unregistered\n");
                usb_se401_remove_disconnected(se401);
        } else {
-               for (i=0; i<SE401_NUMFRAMES; i++)
-                       se401->frame[i].grabstate=FRAME_UNUSED;
+               for (i = 0; i < SE401_NUMFRAMES; i++)
+                       se401->frame[i].grabstate = FRAME_UNUSED;
                if (se401->streaming)
                        se401_stop_stream(se401);
-               se401->user=0;
+               se401->user = 0;
        }
        file->private_data = NULL;
        return 0;
@@ -1065,7 +1077,7 @@ static long se401_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                memset(vm, 0, sizeof(*vm));
                vm->size = SE401_NUMFRAMES * se401->maxframesize;
                vm->frames = SE401_NUMFRAMES;
-               for (i=0; i<SE401_NUMFRAMES; i++)
+               for (i = 0; i < SE401_NUMFRAMES; i++)
                        vm->offsets[i] = se401->maxframesize * i;
                return 0;
        }
@@ -1083,16 +1095,16 @@ static long se401_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                /* Is this according to the v4l spec??? */
                if (se401_set_size(se401, vm->width, vm->height))
                        return -EINVAL;
-               se401->frame[vm->frame].grabstate=FRAME_READY;
+               se401->frame[vm->frame].grabstate = FRAME_READY;
 
                if (!se401->streaming)
                        se401_start_stream(se401);
 
                /* Set the picture properties */
-               if (se401->framecount==0)
+               if (se401->framecount == 0)
                        se401_send_pict(se401);
                /* Calibrate the reset level after a few frames. */
-               if (se401->framecount%20==1)
+               if (se401->framecount % 20 == 1)
                        se401_auto_resetlevel(se401);
 
                return 0;
@@ -1100,13 +1112,13 @@ static long se401_do_ioctl(struct file *file, unsigned int cmd, void *arg)
        case VIDIOCSYNC:
        {
                int *frame = arg;
-               int ret=0;
+               int ret = 0;
 
-               if(*frame <0 || *frame >= SE401_NUMFRAMES)
+               if (*frame < 0 || *frame >= SE401_NUMFRAMES)
                        return -EINVAL;
 
-               ret=se401_newframe(se401, *frame);
-               se401->frame[*frame].grabstate=FRAME_UNUSED;
+               ret = se401_newframe(se401, *frame);
+               se401->frame[*frame].grabstate = FRAME_UNUSED;
                return ret;
        }
        case VIDIOCGFBUF:
@@ -1147,36 +1159,36 @@ static long se401_ioctl(struct file *file,
 static ssize_t se401_read(struct file *file, char __user *buf,
                     size_t count, loff_t *ppos)
 {
-       int realcount=count, ret=0;
+       int realcount = count, ret = 0;
        struct video_device *dev = file->private_data;
        struct usb_se401 *se401 = (struct usb_se401 *)dev;
 
 
-       if (se401->dev == NULL)
+       if (se401->dev ==  NULL)
                return -EIO;
        if (realcount > se401->cwidth*se401->cheight*3)
-               realcount=se401->cwidth*se401->cheight*3;
+               realcount = se401->cwidth*se401->cheight*3;
 
        /* Shouldn't happen: */
-       if (se401->frame[0].grabstate==FRAME_GRABBING)
+       if (se401->frame[0].grabstate == FRAME_GRABBING)
                return -EBUSY;
-       se401->frame[0].grabstate=FRAME_READY;
-       se401->frame[1].grabstate=FRAME_UNUSED;
-       se401->curframe=0;
+       se401->frame[0].grabstate = FRAME_READY;
+       se401->frame[1].grabstate = FRAME_UNUSED;
+       se401->curframe = 0;
 
        if (!se401->streaming)
                se401_start_stream(se401);
 
        /* Set the picture properties */
-       if (se401->framecount==0)
+       if (se401->framecount == 0)
                se401_send_pict(se401);
        /* Calibrate the reset level after a few frames. */
-       if (se401->framecount%20==1)
+       if (se401->framecount%20 == 1)
                se401_auto_resetlevel(se401);
 
-       ret=se401_newframe(se401, 0);
+       ret = se401_newframe(se401, 0);
 
-       se401->frame[0].grabstate=FRAME_UNUSED;
+       se401->frame[0].grabstate = FRAME_UNUSED;
        if (ret)
                return ret;
        if (copy_to_user(buf, se401->frame[0].data, realcount))
@@ -1195,11 +1207,12 @@ static int se401_mmap(struct file *file, struct vm_area_struct *vma)
 
        mutex_lock(&se401->lock);
 
-       if (se401->dev == NULL) {
+       if (se401->dev ==  NULL) {
                mutex_unlock(&se401->lock);
                return -EIO;
        }
-       if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
+       if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1)
+                                                       & ~(PAGE_SIZE - 1))) {
                mutex_unlock(&se401->lock);
                return -EINVAL;
        }
@@ -1210,10 +1223,10 @@ static int se401_mmap(struct file *file, struct vm_area_struct *vma)
                        mutex_unlock(&se401->lock);
                        return -EAGAIN;
                }
-               start += PAGE_SIZE;
-               pos += PAGE_SIZE;
+               start +=  PAGE_SIZE;
+               pos +=  PAGE_SIZE;
                if (size > PAGE_SIZE)
-                       size -= PAGE_SIZE;
+                       size -=  PAGE_SIZE;
                else
                        size = 0;
        }
@@ -1223,7 +1236,7 @@ static int se401_mmap(struct file *file, struct vm_area_struct *vma)
 }
 
 static const struct v4l2_file_operations se401_fops = {
-       .owner        THIS_MODULE,
+       .owner  =       THIS_MODULE,
        .open =         se401_open,
        .release =      se401_close,
        .read =         se401_read,
@@ -1241,71 +1254,76 @@ static struct video_device se401_template = {
 /***************************/
 static int se401_init(struct usb_se401 *se401, int button)
 {
-       int i=0, rc;
+       int i = 0, rc;
        unsigned char cp[0x40];
        char temp[200];
+       int slen;
 
        /* led on */
        se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
 
        /* get camera descriptor */
-       rc=se401_sndctrl(0, se401, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0, cp, sizeof(cp));
-       if (cp[1]!=0x41) {
+       rc = se401_sndctrl(0, se401, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0,
+                                                       cp, sizeof(cp));
+       if (cp[1] != 0x41) {
                err("Wrong descriptor type");
                return 1;
        }
-       sprintf (temp, "ExtraFeatures: %d", cp[3]);
+       slen = snprintf(temp, 200, "ExtraFeatures: %d", cp[3]);
 
-       se401->sizes=cp[4]+cp[5]*256;
-       se401->width=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
+       se401->sizes = cp[4] + cp[5] * 256;
+       se401->width = kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
        if (!se401->width)
                return 1;
-       se401->height=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
+       se401->height = kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
        if (!se401->height) {
                kfree(se401->width);
                return 1;
        }
-       for (i=0; i<se401->sizes; i++) {
-                   se401->width[i]=cp[6+i*4+0]+cp[6+i*4+1]*256;
-                   se401->height[i]=cp[6+i*4+2]+cp[6+i*4+3]*256;
+       for (i = 0; i < se401->sizes; i++) {
+               se401->width[i] = cp[6 + i * 4 + 0] + cp[6 + i*4 + 1] * 256;
+               se401->height[i] = cp[6 + i * 4 + 2] + cp[6 + i * 4 + 3] * 256;
        }
-       sprintf (temp, "%s Sizes:", temp);
-       for (i=0; i<se401->sizes; i++) {
-               sprintf(temp, "%s %dx%d", temp, se401->width[i], se401->height[i]);
+       slen += snprintf(temp + slen, 200 - slen, " Sizes:");
+       for (i = 0; i < se401->sizes; i++) {
+               slen +=  snprintf(temp + slen, 200 - slen,
+                       " %dx%d", se401->width[i], se401->height[i]);
        }
        dev_info(&se401->dev->dev, "%s\n", temp);
-       se401->maxframesize=se401->width[se401->sizes-1]*se401->height[se401->sizes-1]*3;
+       se401->maxframesize = se401->width[se401->sizes-1] *
+                                       se401->height[se401->sizes - 1] * 3;
 
-       rc=se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp));
-       se401->cwidth=cp[0]+cp[1]*256;
-       rc=se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp));
-       se401->cheight=cp[0]+cp[1]*256;
+       rc = se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp));
+       se401->cwidth = cp[0]+cp[1]*256;
+       rc = se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp));
+       se401->cheight = cp[0]+cp[1]*256;
 
        if (!(cp[2] & SE401_FORMAT_BAYER)) {
                err("Bayer format not supported!");
                return 1;
        }
        /* set output mode (BAYER) */
-       se401_sndctrl(1, se401, SE401_REQ_SET_OUTPUT_MODE, SE401_FORMAT_BAYER, NULL, 0);
+       se401_sndctrl(1, se401, SE401_REQ_SET_OUTPUT_MODE,
+                                               SE401_FORMAT_BAYER, NULL, 0);
 
-       rc=se401_sndctrl(0, se401, SE401_REQ_GET_BRT, 0, cp, sizeof(cp));
-       se401->brightness=cp[0]+cp[1]*256;
+       rc = se401_sndctrl(0, se401, SE401_REQ_GET_BRT, 0, cp, sizeof(cp));
+       se401->brightness = cp[0]+cp[1]*256;
        /* some default values */
-       se401->resetlevel=0x2d;
-       se401->rgain=0x20;
-       se401->ggain=0x20;
-       se401->bgain=0x20;
+       se401->resetlevel = 0x2d;
+       se401->rgain = 0x20;
+       se401->ggain = 0x20;
+       se401->bgain = 0x20;
        se401_set_exposure(se401, 20000);
-       se401->palette=VIDEO_PALETTE_RGB24;
-       se401->enhance=1;
-       se401->dropped=0;
-       se401->error=0;
-       se401->framecount=0;
-       se401->readcount=0;
+       se401->palette = VIDEO_PALETTE_RGB24;
+       se401->enhance = 1;
+       se401->dropped = 0;
+       se401->error = 0;
+       se401->framecount = 0;
+       se401->readcount = 0;
 
        /* Start interrupt transfers for snapshot button */
        if (button) {
-               se401->inturb=usb_alloc_urb(0, GFP_KERNEL);
+               se401->inturb = usb_alloc_urb(0, GFP_KERNEL);
                if (!se401->inturb) {
                        dev_info(&se401->dev->dev,
                                 "Allocation of inturb failed\n");
@@ -1323,7 +1341,7 @@ static int se401_init(struct usb_se401 *se401, int button)
                        return 1;
                }
        } else
-               se401->inturb=NULL;
+               se401->inturb = NULL;
 
        /* Flash the led */
        se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
@@ -1340,8 +1358,8 @@ static int se401_probe(struct usb_interface *intf,
        struct usb_device *dev = interface_to_usbdev(intf);
        struct usb_interface_descriptor *interface;
        struct usb_se401 *se401;
-       char *camera_name=NULL;
-       int button=1;
+       char *camera_name = NULL;
+       int button = 1;
 
        /* We don't handle multi-config cameras */
        if (dev->descriptor.bNumConfigurations != 1)
@@ -1350,22 +1368,22 @@ static int se401_probe(struct usb_interface *intf,
        interface = &intf->cur_altsetting->desc;
 
        /* Is it an se401? */
-       if (le16_to_cpu(dev->descriptor.idVendor) == 0x03e8 &&
-           le16_to_cpu(dev->descriptor.idProduct) == 0x0004) {
-               camera_name="Endpoints/Aox SE401";
-       } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x0471 &&
-           le16_to_cpu(dev->descriptor.idProduct) == 0x030b) {
-               camera_name="Philips PCVC665K";
-       } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
-           le16_to_cpu(dev->descriptor.idProduct) == 0x5001) {
-               camera_name="Kensington VideoCAM 67014";
-       } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
-           le16_to_cpu(dev->descriptor.idProduct) == 0x5002) {
-               camera_name="Kensington VideoCAM 6701(5/7)";
-       } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
-           le16_to_cpu(dev->descriptor.idProduct) == 0x5003) {
-               camera_name="Kensington VideoCAM 67016";
-               button=0;
+       if (le16_to_cpu(dev->descriptor.idVendor) ==  0x03e8 &&
+           le16_to_cpu(dev->descriptor.idProduct) ==  0x0004) {
+               camera_name = "Endpoints/Aox SE401";
+       } else if (le16_to_cpu(dev->descriptor.idVendor) ==  0x0471 &&
+           le16_to_cpu(dev->descriptor.idProduct) ==  0x030b) {
+               camera_name = "Philips PCVC665K";
+       } else if (le16_to_cpu(dev->descriptor.idVendor) ==  0x047d &&
+           le16_to_cpu(dev->descriptor.idProduct) ==  0x5001) {
+               camera_name = "Kensington VideoCAM 67014";
+       } else if (le16_to_cpu(dev->descriptor.idVendor) ==  0x047d &&
+           le16_to_cpu(dev->descriptor.idProduct) ==  0x5002) {
+               camera_name = "Kensington VideoCAM 6701(5/7)";
+       } else if (le16_to_cpu(dev->descriptor.idVendor) ==  0x047d &&
+           le16_to_cpu(dev->descriptor.idProduct) ==  0x5003) {
+               camera_name = "Kensington VideoCAM 67016";
+               button = 0;
        } else
                return -ENODEV;
 
@@ -1378,7 +1396,8 @@ static int se401_probe(struct usb_interface *intf,
        /* We found one */
        dev_info(&intf->dev, "SE401 camera found: %s\n", camera_name);
 
-       if ((se401 = kzalloc(sizeof(*se401), GFP_KERNEL)) == NULL) {
+       se401 = kzalloc(sizeof(*se401), GFP_KERNEL);
+       if (se401 ==  NULL) {
                err("couldn't kmalloc se401 struct");
                return -ENOMEM;
        }
@@ -1396,12 +1415,14 @@ static int se401_probe(struct usb_interface *intf,
        }
 
        memcpy(&se401->vdev, &se401_template, sizeof(se401_template));
-       memcpy(se401->vdev.name, se401->camera_name, strlen(se401->camera_name));
+       memcpy(se401->vdev.name, se401->camera_name,
+                                       strlen(se401->camera_name));
        init_waitqueue_head(&se401->wq);
        mutex_init(&se401->lock);
        wmb();
 
-       if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
+       if (video_register_device(&se401->vdev,
+                                       VFL_TYPE_GRABBER, video_nr) < 0) {
                kfree(se401);
                err("video_register_device failed");
                return -EIO;
@@ -1409,20 +1430,20 @@ static int se401_probe(struct usb_interface *intf,
        dev_info(&intf->dev, "registered new video device: video%d\n",
                 se401->vdev.num);
 
-       usb_set_intfdata (intf, se401);
+       usb_set_intfdata(intf, se401);
        return 0;
 }
 
 static void se401_disconnect(struct usb_interface *intf)
 {
-       struct usb_se401 *se401 = usb_get_intfdata (intf);
+       struct usb_se401 *se401 = usb_get_intfdata(intf);
 
-       usb_set_intfdata (intf, NULL);
+       usb_set_intfdata(intf, NULL);
        if (se401) {
                video_unregister_device(&se401->vdev);
-               if (!se401->user){
+               if (!se401->user)
                        usb_se401_remove_disconnected(se401);
-               else {
+               else {
                        se401->frame[0].grabstate = FRAME_ERROR;
                        se401->frame[0].grabstate = FRAME_ERROR;
 
@@ -1435,10 +1456,10 @@ static void se401_disconnect(struct usb_interface *intf)
 }
 
 static struct usb_driver se401_driver = {
-       .name           = "se401",
-       .id_table       = device_table,
-       .probe          = se401_probe,
-       .disconnect     = se401_disconnect,
+       .name            =  "se401",
+       .id_table        =  device_table,
+       .probe           =  se401_probe,
+       .disconnect      =  se401_disconnect,
 };
 
 
@@ -1451,9 +1472,10 @@ static struct usb_driver se401_driver = {
 
 static int __init usb_se401_init(void)
 {
-       printk(KERN_INFO "SE401 usb camera driver version %s registering\n", version);
+       printk(KERN_INFO "SE401 usb camera driver version %s registering\n",
+                                                               version);
        if (flickerless)
-               if (flickerless!=50 && flickerless!=60) {
+               if (flickerless != 50 && flickerless != 60) {
                        printk(KERN_ERR "Invallid flickerless value, use 0, 50 or 60.\n");
                        return -1;
        }
index 2ce685db5d8b2eaa91021d7668b669cf59f1e74e..bf7d2e9765b0dee82c8ecb88c68e0cf6c29ed095 100644 (file)
@@ -2,7 +2,7 @@
 #ifndef __LINUX_se401_H
 #define __LINUX_se401_H
 
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 
 #ifdef se401_DEBUG
 #  define PDEBUG(level, fmt, args...) \
-if (debug >= level) info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args)
+if (debug >= level) \
+       info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args)
 #else
-#  define PDEBUG(level, fmt, args...) do {} while(0)
+#  define PDEBUG(level, fmt, args...) do {} while (0)
 #endif
 
 /* An almost drop-in replacement for sleep_on_interruptible */
index b5e37a530c62a9cad5ac1401d78639c31577d62f..d369e8409ab8bfcd9bb677d189a36b0d7d8068e4 100644 (file)
@@ -81,7 +81,6 @@ struct sh_mobile_ceu_buffer {
 };
 
 struct sh_mobile_ceu_dev {
-       struct device *dev;
        struct soc_camera_host ici;
        struct soc_camera_device *icd;
 
@@ -617,7 +616,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
                        xlate->cam_fmt = icd->formats + idx;
                        xlate->buswidth = icd->formats[idx].depth;
                        xlate++;
-                       dev_dbg(&ici->dev, "Providing format %s using %s\n",
+                       dev_dbg(ici->dev, "Providing format %s using %s\n",
                                sh_mobile_ceu_formats[k].name,
                                icd->formats[idx].name);
                }
@@ -630,7 +629,7 @@ add_single_format:
                        xlate->cam_fmt = icd->formats + idx;
                        xlate->buswidth = icd->formats[idx].depth;
                        xlate++;
-                       dev_dbg(&ici->dev,
+                       dev_dbg(ici->dev,
                                "Providing format %s in pass-through mode\n",
                                icd->formats[idx].name);
                }
@@ -657,7 +656,7 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
        if (!xlate) {
-               dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+               dev_warn(ici->dev, "Format %x not found\n", pixfmt);
                return -EINVAL;
        }
 
@@ -684,7 +683,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
 
        xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
        if (!xlate) {
-               dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+               dev_warn(ici->dev, "Format %x not found\n", pixfmt);
                return -EINVAL;
        }
 
@@ -782,7 +781,7 @@ static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q,
 
        videobuf_queue_dma_contig_init(q,
                                       &sh_mobile_ceu_videobuf_ops,
-                                      &ici->dev, &pcdev->lock,
+                                      ici->dev, &pcdev->lock,
                                       V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                       pcdev->is_interlaced ?
                                       V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE,
@@ -829,7 +828,6 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
                goto exit;
        }
 
-       platform_set_drvdata(pdev, pcdev);
        INIT_LIST_HEAD(&pcdev->capture);
        spin_lock_init(&pcdev->lock);
 
@@ -840,7 +838,7 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
                goto exit_kfree;
        }
 
-       base = ioremap_nocache(res->start, res->end - res->start + 1);
+       base = ioremap_nocache(res->start, resource_size(res));
        if (!base) {
                err = -ENXIO;
                dev_err(&pdev->dev, "Unable to ioremap CEU registers.\n");
@@ -850,13 +848,12 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
        pcdev->irq = irq;
        pcdev->base = base;
        pcdev->video_limit = 0; /* only enabled if second resource exists */
-       pcdev->dev = &pdev->dev;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        if (res) {
                err = dma_declare_coherent_memory(&pdev->dev, res->start,
                                                  res->start,
-                                                 (res->end - res->start) + 1,
+                                                 resource_size(res),
                                                  DMA_MEMORY_MAP |
                                                  DMA_MEMORY_EXCLUSIVE);
                if (!err) {
@@ -865,7 +862,7 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
                        goto exit_iounmap;
                }
 
-               pcdev->video_limit = (res->end - res->start) + 1;
+               pcdev->video_limit = resource_size(res);
        }
 
        /* request irq */
@@ -885,7 +882,7 @@ static int sh_mobile_ceu_probe(struct platform_device *pdev)
        }
 
        pcdev->ici.priv = pcdev;
-       pcdev->ici.dev.parent = &pdev->dev;
+       pcdev->ici.dev = &pdev->dev;
        pcdev->ici.nr = pdev->id;
        pcdev->ici.drv_name = dev_name(&pdev->dev);
        pcdev->ici.ops = &sh_mobile_ceu_host_ops;
@@ -913,9 +910,11 @@ exit:
 
 static int sh_mobile_ceu_remove(struct platform_device *pdev)
 {
-       struct sh_mobile_ceu_dev *pcdev = platform_get_drvdata(pdev);
+       struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+       struct sh_mobile_ceu_dev *pcdev = container_of(soc_host,
+                                       struct sh_mobile_ceu_dev, ici);
 
-       soc_camera_host_unregister(&pcdev->ici);
+       soc_camera_host_unregister(soc_host);
        clk_put(pcdev->clk);
        free_irq(pcdev->irq, pcdev);
        if (platform_get_resource(pdev, IORESOURCE_MEM, 1))
index 0e890cc233776d85c3cba061299761e9402e7047..16f595d4337abfb76b3c08d98bad1ced20cf0b9d 100644 (file)
  * published by the Free Software Foundation.
  */
 
-#include <linux/module.h>
-#include <linux/init.h>
 #include <linux/device.h>
-#include <linux/list.h>
 #include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
 #include <linux/mutex.h>
+#include <linux/platform_device.h>
 #include <linux/vmalloc.h>
 
+#include <media/soc_camera.h>
 #include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
 #include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
 #include <media/videobuf-core.h>
-#include <media/soc_camera.h>
 
 /* Default to VGA resolution */
 #define DEFAULT_WIDTH  640
@@ -279,7 +281,7 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf,
                return ret;
        } else if (!icd->current_fmt ||
                   icd->current_fmt->fourcc != pix->pixelformat) {
-               dev_err(&ici->dev,
+               dev_err(ici->dev,
                        "Host driver hasn't set up current format correctly!\n");
                return -EINVAL;
        }
@@ -794,7 +796,7 @@ static void scan_add_host(struct soc_camera_host *ici)
 
        list_for_each_entry(icd, &devices, list) {
                if (icd->iface == ici->nr) {
-                       icd->dev.parent = &ici->dev;
+                       icd->dev.parent = ici->dev;
                        device_register_link(icd);
                }
        }
@@ -818,7 +820,7 @@ static int scan_add_device(struct soc_camera_device *icd)
        list_for_each_entry(ici, &hosts, list) {
                if (icd->iface == ici->nr) {
                        ret = 1;
-                       icd->dev.parent = &ici->dev;
+                       icd->dev.parent = ici->dev;
                        break;
                }
        }
@@ -952,7 +954,6 @@ static void dummy_release(struct device *dev)
 
 int soc_camera_host_register(struct soc_camera_host *ici)
 {
-       int ret;
        struct soc_camera_host *ix;
 
        if (!ici || !ici->ops ||
@@ -965,12 +966,10 @@ int soc_camera_host_register(struct soc_camera_host *ici)
            !ici->ops->reqbufs ||
            !ici->ops->add ||
            !ici->ops->remove ||
-           !ici->ops->poll)
+           !ici->ops->poll ||
+           !ici->dev)
                return -EINVAL;
 
-       /* Number might be equal to the platform device ID */
-       dev_set_name(&ici->dev, "camera_host%d", ici->nr);
-
        mutex_lock(&list_lock);
        list_for_each_entry(ix, &hosts, list) {
                if (ix->nr == ici->nr) {
@@ -979,26 +978,14 @@ int soc_camera_host_register(struct soc_camera_host *ici)
                }
        }
 
+       dev_set_drvdata(ici->dev, ici);
+
        list_add_tail(&ici->list, &hosts);
        mutex_unlock(&list_lock);
 
-       ici->dev.release = dummy_release;
-
-       ret = device_register(&ici->dev);
-
-       if (ret)
-               goto edevr;
-
        scan_add_host(ici);
 
        return 0;
-
-edevr:
-       mutex_lock(&list_lock);
-       list_del(&ici->list);
-       mutex_unlock(&list_lock);
-
-       return ret;
 }
 EXPORT_SYMBOL(soc_camera_host_register);
 
@@ -1012,7 +999,7 @@ void soc_camera_host_unregister(struct soc_camera_host *ici)
        list_del(&ici->list);
 
        list_for_each_entry(icd, &devices, list) {
-               if (icd->dev.parent == &ici->dev) {
+               if (icd->dev.parent == ici->dev) {
                        device_unregister(&icd->dev);
                        /* Not before device_unregister(), .remove
                         * needs parent to call ici->ops->remove() */
@@ -1023,7 +1010,7 @@ void soc_camera_host_unregister(struct soc_camera_host *ici)
 
        mutex_unlock(&list_lock);
 
-       device_unregister(&ici->dev);
+       dev_set_drvdata(ici->dev, NULL);
 }
 EXPORT_SYMBOL(soc_camera_host_unregister);
 
@@ -1130,7 +1117,7 @@ int soc_camera_video_start(struct soc_camera_device *icd)
        vdev = video_device_alloc();
        if (!vdev)
                goto evidallocd;
-       dev_dbg(&ici->dev, "Allocated video_device %p\n", vdev);
+       dev_dbg(ici->dev, "Allocated video_device %p\n", vdev);
 
        strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
 
@@ -1174,6 +1161,57 @@ void soc_camera_video_stop(struct soc_camera_device *icd)
 }
 EXPORT_SYMBOL(soc_camera_video_stop);
 
+static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
+{
+       struct soc_camera_link *icl = pdev->dev.platform_data;
+       struct i2c_adapter *adap;
+       struct i2c_client *client;
+
+       if (!icl)
+               return -EINVAL;
+
+       adap = i2c_get_adapter(icl->i2c_adapter_id);
+       if (!adap) {
+               dev_warn(&pdev->dev, "Cannot get adapter #%d. No driver?\n",
+                        icl->i2c_adapter_id);
+               /* -ENODEV and -ENXIO do not produce an error on probe()... */
+               return -ENOENT;
+       }
+
+       icl->board_info->platform_data = icl;
+       client = i2c_new_device(adap, icl->board_info);
+       if (!client) {
+               i2c_put_adapter(adap);
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(pdev, client);
+
+       return 0;
+}
+
+static int __devexit soc_camera_pdrv_remove(struct platform_device *pdev)
+{
+       struct i2c_client *client = platform_get_drvdata(pdev);
+
+       if (!client)
+               return -ENODEV;
+
+       i2c_unregister_device(client);
+       i2c_put_adapter(client->adapter);
+
+       return 0;
+}
+
+static struct platform_driver __refdata soc_camera_pdrv = {
+       .probe  = soc_camera_pdrv_probe,
+       .remove = __devexit_p(soc_camera_pdrv_remove),
+       .driver = {
+               .name = "soc-camera-pdrv",
+               .owner = THIS_MODULE,
+       },
+};
+
 static int __init soc_camera_init(void)
 {
        int ret = bus_register(&soc_camera_bus_type);
@@ -1183,8 +1221,14 @@ static int __init soc_camera_init(void)
        if (ret)
                goto edrvr;
 
+       ret = platform_driver_register(&soc_camera_pdrv);
+       if (ret)
+               goto epdr;
+
        return 0;
 
+epdr:
+       driver_unregister(&ic_drv);
 edrvr:
        bus_unregister(&soc_camera_bus_type);
        return ret;
@@ -1192,6 +1236,7 @@ edrvr:
 
 static void __exit soc_camera_exit(void)
 {
+       platform_driver_unregister(&soc_camera_pdrv);
        driver_unregister(&ic_drv);
        bus_unregister(&soc_camera_bus_type);
 }
@@ -1202,3 +1247,4 @@ module_exit(soc_camera_exit);
 MODULE_DESCRIPTION("Image capture bus driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:soc-camera-pdrv");
index 1a6d39cbd6f31b79ad91071f1d9a2802a91042a3..2e59370472788712ba3e08ae62dd2b5f2b62f2e0 100644 (file)
@@ -1137,7 +1137,7 @@ static int stk_vidioc_querybuf(struct file *filp,
        struct stk_camera *dev = priv;
        struct stk_sio_buffer *sbuf;
 
-       if (buf->index < 0 || buf->index >= dev->n_sbufs)
+       if (buf->index >= dev->n_sbufs)
                return -EINVAL;
        sbuf = dev->sio_bufs + buf->index;
        *buf = sbuf->v4lbuf;
@@ -1154,7 +1154,7 @@ static int stk_vidioc_qbuf(struct file *filp,
        if (buf->memory != V4L2_MEMORY_MMAP)
                return -EINVAL;
 
-       if (buf->index < 0 || buf->index >= dev->n_sbufs)
+       if (buf->index >= dev->n_sbufs)
                return -EINVAL;
        sbuf = dev->sio_bufs + buf->index;
        if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED)
index 005f8a46803148873f6e1dfba22a6bc36c8fcc6b..80f1cee23fa5a70bba5f3afd44faa1be21c3d3b6 100644 (file)
  * loudness - set between 0 and 15 for varying degrees of loudness effect
  *
  * maxvol   - set maximium volume to +20db (1), default is 0db(0)
- *
- *
- *  Revision: 0.7 - maxvol module parm to set maximium volume 0db or +20db
- *                             store if muted so we can return it
- *                             change balance only if flaged to
- *  Revision: 0.6 - added tone controls
- *  Revision: 0.5 - Fixed odd balance problem
- *  Revision: 0.4 - added muting
- *  Revision: 0.3 - Fixed silly reversed volume controls.  :)
- *  Revision: 0.2 - Cleaned up #defines
- *                     fixed volume control
- *          Added I2C_DRIVERID_TDA7432
- *                     added loudness insmod control
- *  Revision: 0.1 - initial version
  */
 
 #include <linux/module.h>
index d4a9ed45764b066c0b47c0c3bdd81fe52ac9734e..1585839bd0bd3d352270a6f1f2caa039a1a00bff 100644 (file)
@@ -141,7 +141,6 @@ static const struct v4l2_subdev_ops tea6415c_ops = {
        .video = &tea6415c_video_ops,
 };
 
-/* this function is called by i2c_probe */
 static int tea6415c_probe(struct i2c_client *client,
                          const struct i2c_device_id *id)
 {
index ced6eadf347a6d2090104ef340936a3cf6cad51b..0446524d354304bb1f6ceab3dc1def63db89c98c 100644 (file)
@@ -112,7 +112,6 @@ static const struct v4l2_subdev_ops tea6420_ops = {
        .audio = &tea6420_audio_ops,
 };
 
-/* this function is called by i2c_probe */
 static int tea6420_probe(struct i2c_client *client,
                          const struct i2c_device_id *id)
 {
diff --git a/drivers/media/video/ths7303.c b/drivers/media/video/ths7303.c
new file mode 100644 (file)
index 0000000..21781f8
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * ths7303- THS7303 Video Amplifier driver
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ctype.h>
+#include <linux/i2c.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-chip-ident.h>
+
+MODULE_DESCRIPTION("TI THS7303 video amplifier driver");
+MODULE_AUTHOR("Chaithrika U S");
+MODULE_LICENSE("GPL");
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level 0-1");
+
+/* following function is used to set ths7303 */
+static int ths7303_setvalue(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+       int err = 0;
+       u8 val;
+       struct i2c_client *client;
+
+       client = v4l2_get_subdevdata(sd);
+
+       if (std & (V4L2_STD_ALL & ~V4L2_STD_SECAM)) {
+               val = 0x02;
+               v4l2_dbg(1, debug, sd, "setting value for SDTV format\n");
+       } else {
+               val = 0x00;
+               v4l2_dbg(1, debug, sd, "disabling all channels\n");
+       }
+
+       err |= i2c_smbus_write_byte_data(client, 0x01, val);
+       err |= i2c_smbus_write_byte_data(client, 0x02, val);
+       err |= i2c_smbus_write_byte_data(client, 0x03, val);
+
+       if (err)
+               v4l2_err(sd, "write failed\n");
+
+       return err;
+}
+
+static int ths7303_s_std_output(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+       return ths7303_setvalue(sd, norm);
+}
+
+static int ths7303_g_chip_ident(struct v4l2_subdev *sd,
+                               struct v4l2_dbg_chip_ident *chip)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_THS7303, 0);
+}
+
+static const struct v4l2_subdev_video_ops ths7303_video_ops = {
+       .s_std_output   = ths7303_s_std_output,
+};
+
+static const struct v4l2_subdev_core_ops ths7303_core_ops = {
+       .g_chip_ident = ths7303_g_chip_ident,
+};
+
+static const struct v4l2_subdev_ops ths7303_ops = {
+       .core   = &ths7303_core_ops,
+       .video  = &ths7303_video_ops,
+};
+
+static int ths7303_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct v4l2_subdev *sd;
+       v4l2_std_id std_id = V4L2_STD_NTSC;
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -ENODEV;
+
+       v4l_info(client, "chip found @ 0x%x (%s)\n",
+                       client->addr << 1, client->adapter->name);
+
+       sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+       if (sd == NULL)
+               return -ENOMEM;
+
+       v4l2_i2c_subdev_init(sd, client, &ths7303_ops);
+
+       return ths7303_setvalue(sd, std_id);
+}
+
+static int ths7303_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       v4l2_device_unregister_subdev(sd);
+       kfree(sd);
+
+       return 0;
+}
+
+static const struct i2c_device_id ths7303_id[] = {
+       {"ths7303", 0},
+       {},
+};
+
+MODULE_DEVICE_TABLE(i2c, ths7303_id);
+
+static struct i2c_driver ths7303_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "ths7303",
+       },
+       .probe          = ths7303_probe,
+       .remove         = ths7303_remove,
+       .id_table       = ths7303_id,
+};
+
+static int __init ths7303_init(void)
+{
+       return i2c_add_driver(&ths7303_driver);
+}
+
+static void __exit ths7303_exit(void)
+{
+       i2c_del_driver(&ths7303_driver);
+}
+
+module_init(ths7303_init);
+module_exit(ths7303_exit);
+
index 78c377a399cb893d1517b4ea6f4a48a6c04d8f19..537594211a90e1ccb6fa49b74e188b642ae0c6ae 100644 (file)
@@ -309,32 +309,6 @@ static void set_freq(struct i2c_client *c, unsigned long freq)
        }
 }
 
-static void tuner_i2c_address_check(struct tuner *t)
-{
-       if ((t->type == UNSET || t->type == TUNER_ABSENT) ||
-           ((t->i2c->addr < 0x64) || (t->i2c->addr > 0x6f)))
-               return;
-
-       /* We already know that the XC5000 can only be located at
-        * i2c address 0x61, 0x62, 0x63 or 0x64 */
-       if ((t->type == TUNER_XC5000) &&
-           ((t->i2c->addr <= 0x64)) && (t->i2c->addr >= 0x61))
-               return;
-
-       tuner_warn("====================== WARNING! ======================\n");
-       tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n");
-       tuner_warn("will soon be dropped. This message indicates that your\n");
-       tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n",
-                  t->name, t->i2c->addr);
-       tuner_warn("To ensure continued support for your device, please\n");
-       tuner_warn("send a copy of this message, along with full dmesg\n");
-       tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n");
-       tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");
-       tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",
-                  t->i2c->adapter->name, t->i2c->addr, t->type, t->name);
-       tuner_warn("====================== WARNING! ======================\n");
-}
-
 static struct xc5000_config xc5000_cfg;
 
 static void set_type(struct i2c_client *c, unsigned int type,
@@ -438,18 +412,12 @@ static void set_type(struct i2c_client *c, unsigned int type,
                break;
        case TUNER_XC5000:
        {
-               struct dvb_tuner_ops *xc_tuner_ops;
-
                xc5000_cfg.i2c_address    = t->i2c->addr;
                /* if_khz will be set when the digital dvb_attach() occurs */
                xc5000_cfg.if_khz         = 0;
                if (!dvb_attach(xc5000_attach,
                                &t->fe, t->i2c->adapter, &xc5000_cfg))
                        goto attach_failed;
-
-               xc_tuner_ops = &t->fe.ops.tuner_ops;
-               if (xc_tuner_ops->init)
-                       xc_tuner_ops->init(&t->fe);
                break;
        }
        default:
@@ -490,7 +458,6 @@ static void set_type(struct i2c_client *c, unsigned int type,
        tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
                  c->adapter->name, c->driver->driver.name, c->addr << 1, type,
                  t->mode_mask);
-       tuner_i2c_address_check(t);
        return;
 
 attach_failed:
index e24a38c7fa46320dac823bcb2778846db2f3e210..ac02808106c145120fbb49c72eecc85d5a54ac9c 100644 (file)
@@ -184,7 +184,7 @@ hauppauge_tuner[] =
        { TUNER_ABSENT,                 "Silicon TDA8275C1 8290 FM"},
        { TUNER_ABSENT,                 "Thompson DTT757"},
        /* 80-89 */
-       { TUNER_PHILIPS_FM1216ME_MK3,   "Philips FQ1216LME MK3"},
+       { TUNER_PHILIPS_FQ1216LME_MK3,  "Philips FQ1216LME MK3"},
        { TUNER_LG_PAL_NEW_TAPC,        "LG TAPC G701D"},
        { TUNER_LG_NTSC_NEW_TAPC,       "LG TAPC H791F"},
        { TUNER_LG_PAL_NEW_TAPC,        "TCL 2002MB 3"},
@@ -210,7 +210,7 @@ hauppauge_tuner[] =
        { TUNER_TEA5767,                "Philips TEA5768HL FM Radio"},
        { TUNER_ABSENT,                 "Panasonic ENV57H12D5"},
        { TUNER_PHILIPS_FM1236_MK3,     "TCL MFNM05-4"},
-       { TUNER_ABSENT,                 "TCL MNM05-4"},
+       { TUNER_PHILIPS_FM1236_MK3,     "TCL MNM05-4"},
        { TUNER_PHILIPS_FM1216ME_MK3,   "TCL MPE05-2"},
        { TUNER_ABSENT,                 "TCL MQNM05-4"},
        { TUNER_ABSENT,                 "LG TAPC-W701D"},
@@ -229,7 +229,7 @@ hauppauge_tuner[] =
        { TUNER_ABSENT,                 "Samsung THPD5222FG30A"},
        /* 120-129 */
        { TUNER_XC2028,                 "Xceive XC3028"},
-       { TUNER_ABSENT,                 "Philips FQ1216LME MK5"},
+       { TUNER_PHILIPS_FQ1216LME_MK3,  "Philips FQ1216LME MK5"},
        { TUNER_ABSENT,                 "Philips FQD1216LME"},
        { TUNER_ABSENT,                 "Conexant CX24118A"},
        { TUNER_ABSENT,                 "TCL DMF11WIP"},
index 4262e60b8116a3df1fb161ae49fa44bc0c3ae037..3750f7fadb121466918d32c46017f3f795050ba9 100644 (file)
@@ -692,7 +692,7 @@ static int ioctl_s_routing(struct v4l2_int_device *s,
                        break;  /* Input detected */
        }
 
-       if ((current_std == STD_INVALID) || (try_count <= 0))
+       if ((current_std == STD_INVALID) || (try_count < 0))
                return -EINVAL;
 
        decoder->current_std = current_std;
index a399476439920f78d320c376c72153995381ae0f..aa5065ea09eda99cabe0cf6041c4c3498b38e8c8 100644 (file)
@@ -875,10 +875,12 @@ static int tw9910_probe(struct i2c_client *client,
        const struct tw9910_scale_ctrl *scale;
        int                             i, ret;
 
-       info = client->dev.platform_data;
-       if (!info)
+       if (!client->dev.platform_data)
                return -EINVAL;
 
+       info = container_of(client->dev.platform_data,
+                           struct tw9910_video_info, link);
+
        if (!i2c_check_functionality(to_i2c_adapter(client->dev.parent),
                                     I2C_FUNC_SMBUS_BYTE_DATA)) {
                dev_err(&client->dev,
index 900ec2129ca16a283ec351ec3efd4f1ee9827144..31d57f2d09e1ba5d39be1e6296eff2414c994e7b 100644 (file)
@@ -240,7 +240,7 @@ static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev
        input_dev->dev.parent = &dev->dev;
 
        input_dev->evbit[0] = BIT_MASK(EV_KEY);
-       input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
+       input_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA);
 
        error = input_register_device(cam->input);
        if (error) {
@@ -263,7 +263,7 @@ static void konicawc_unregister_input(struct konicawc *cam)
 static void konicawc_report_buttonstat(struct konicawc *cam)
 {
        if (cam->input) {
-               input_report_key(cam->input, BTN_0, cam->buttonsts);
+               input_report_key(cam->input, KEY_CAMERA, cam->buttonsts);
                input_sync(cam->input);
        }
 }
index fd112f0b9d35e7082b113c37ca549c59d547c546..803d3e4e29a20316ccbe14d9c4aa0f5cb6961099 100644 (file)
@@ -103,7 +103,7 @@ static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
        input_dev->dev.parent = &dev->dev;
 
        input_dev->evbit[0] = BIT_MASK(EV_KEY);
-       input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
+       input_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA);
 
        error = input_register_device(cam->input);
        if (error) {
@@ -126,7 +126,7 @@ static void qcm_unregister_input(struct qcm *cam)
 static void qcm_report_buttonstat(struct qcm *cam)
 {
        if (cam->input) {
-               input_report_key(cam->input, BTN_0, cam->button_sts);
+               input_report_key(cam->input, KEY_CAMERA, cam->button_sts);
                input_sync(cam->input);
        }
 }
index 8bc03b9e1315b2a517df95392b2cd76b97b08bcd..6ba16abeebdd61af7c03e310a7e6b0b0441056b1 100644 (file)
@@ -390,10 +390,9 @@ int usbvision_scratch_alloc(struct usb_usbvision *usbvision)
 
 void usbvision_scratch_free(struct usb_usbvision *usbvision)
 {
-       if (usbvision->scratch != NULL) {
-               vfree(usbvision->scratch);
-               usbvision->scratch = NULL;
-       }
+       vfree(usbvision->scratch);
+       usbvision->scratch = NULL;
+
 }
 
 /*
@@ -506,10 +505,9 @@ int usbvision_decompress_alloc(struct usb_usbvision *usbvision)
  */
 void usbvision_decompress_free(struct usb_usbvision *usbvision)
 {
-       if (usbvision->IntraFrameBuffer != NULL) {
-               vfree(usbvision->IntraFrameBuffer);
-               usbvision->IntraFrameBuffer = NULL;
-       }
+       vfree(usbvision->IntraFrameBuffer);
+       usbvision->IntraFrameBuffer = NULL;
+
 }
 
 /************************************************************
index d7056a5b7f9b1bc9a463d70282cd8be47dcabc8d..90b58914f98472644e289c97ce02297490c920d2 100644 (file)
@@ -541,7 +541,7 @@ static int vidioc_enum_input (struct file *file, void *priv,
        struct usb_usbvision *usbvision = video_drvdata(file);
        int chan;
 
-       if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) )
+       if (vi->index >= usbvision->video_inputs)
                return -EINVAL;
        if (usbvision->have_tuner) {
                chan = vi->index;
@@ -1794,7 +1794,7 @@ static struct usb_driver usbvision_driver = {
        .name           = "usbvision",
        .id_table       = usbvision_table,
        .probe          = usbvision_probe,
-       .disconnect     = usbvision_disconnect
+       .disconnect     = __devexit_p(usbvision_disconnect),
 };
 
 /*
index 0d7e38d6ff6a416ed6905b9bb66d6b3f6f2dd2f6..36a6ba92df2700710746db302c152dc61ea14842 100644 (file)
@@ -1372,21 +1372,19 @@ end:
 }
 
 /*
- * Prune an entity of its bogus controls. This currently includes processing
- * unit auto controls for which no corresponding manual control is available.
- * Such auto controls make little sense if any, and are known to crash at
- * least the SiGma Micro webcam.
+ * Prune an entity of its bogus controls using a blacklist. Bogus controls
+ * are currently the ones that crash the camera or unconditionally return an
+ * error when queried.
  */
 static void
-uvc_ctrl_prune_entity(struct uvc_entity *entity)
+uvc_ctrl_prune_entity(struct uvc_device *dev, struct uvc_entity *entity)
 {
        static const struct {
-               u8 idx_manual;
-               u8 idx_auto;
+               struct usb_device_id id;
+               u8 index;
        } blacklist[] = {
-               { 2, 11 }, /* Hue */
-               { 6, 12 }, /* White Balance Temperature */
-               { 7, 13 }, /* White Balance Component */
+               { { USB_DEVICE(0x1c4f, 0x3000) }, 6 }, /* WB Temperature */
+               { { USB_DEVICE(0x5986, 0x0241) }, 2 }, /* Hue */
        };
 
        u8 *controls;
@@ -1400,19 +1398,17 @@ uvc_ctrl_prune_entity(struct uvc_entity *entity)
        size = entity->processing.bControlSize;
 
        for (i = 0; i < ARRAY_SIZE(blacklist); ++i) {
-               if (blacklist[i].idx_auto >= 8 * size ||
-                   blacklist[i].idx_manual >= 8 * size)
+               if (!usb_match_id(dev->intf, &blacklist[i].id))
                        continue;
 
-               if (!uvc_test_bit(controls, blacklist[i].idx_auto) ||
-                    uvc_test_bit(controls, blacklist[i].idx_manual))
+               if (blacklist[i].index >= 8 * size ||
+                   !uvc_test_bit(controls, blacklist[i].index))
                        continue;
 
-               uvc_trace(UVC_TRACE_CONTROL, "Auto control %u/%u has no "
-                       "matching manual control, removing it.\n", entity->id,
-                       blacklist[i].idx_auto);
+               uvc_trace(UVC_TRACE_CONTROL, "%u/%u control is black listed, "
+                       "removing it.\n", entity->id, blacklist[i].index);
 
-               uvc_clear_bit(controls, blacklist[i].idx_auto);
+               uvc_clear_bit(controls, blacklist[i].index);
        }
 }
 
@@ -1442,8 +1438,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
                        bControlSize = entity->camera.bControlSize;
                }
 
-               if (dev->quirks & UVC_QUIRK_PRUNE_CONTROLS)
-                       uvc_ctrl_prune_entity(entity);
+               uvc_ctrl_prune_entity(dev, entity);
 
                for (i = 0; i < bControlSize; ++i)
                        ncontrols += hweight8(bmControls[i]);
index 507dc85646b2312256d7096aff7ea0e536caba3f..89927b7aec28dce2dcd9131b7e36339de826436d 100644 (file)
@@ -289,10 +289,8 @@ static int uvc_parse_format(struct uvc_device *dev,
        struct uvc_format_desc *fmtdesc;
        struct uvc_frame *frame;
        const unsigned char *start = buffer;
-       unsigned char *_buffer;
        unsigned int interval;
        unsigned int i, n;
-       int _buflen;
        __u8 ftype;
 
        format->type = buffer[2];
@@ -303,7 +301,7 @@ static int uvc_parse_format(struct uvc_device *dev,
        case VS_FORMAT_FRAME_BASED:
                n = buffer[2] == VS_FORMAT_UNCOMPRESSED ? 27 : 28;
                if (buflen < n) {
-                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                               "interface %d FORMAT error\n",
                               dev->udev->devnum,
                               alts->desc.bInterfaceNumber);
@@ -338,7 +336,7 @@ static int uvc_parse_format(struct uvc_device *dev,
 
        case VS_FORMAT_MJPEG:
                if (buflen < 11) {
-                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                               "interface %d FORMAT error\n",
                               dev->udev->devnum,
                               alts->desc.bInterfaceNumber);
@@ -354,7 +352,7 @@ static int uvc_parse_format(struct uvc_device *dev,
 
        case VS_FORMAT_DV:
                if (buflen < 9) {
-                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                               "interface %d FORMAT error\n",
                               dev->udev->devnum,
                               alts->desc.bInterfaceNumber);
@@ -372,7 +370,7 @@ static int uvc_parse_format(struct uvc_device *dev,
                        strlcpy(format->name, "HD-DV", sizeof format->name);
                        break;
                default:
-                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                               "interface %d: unknown DV format %u\n",
                               dev->udev->devnum,
                               alts->desc.bInterfaceNumber, buffer[8]);
@@ -401,7 +399,7 @@ static int uvc_parse_format(struct uvc_device *dev,
        case VS_FORMAT_STREAM_BASED:
                /* Not supported yet. */
        default:
-               uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+               uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                       "interface %d unsupported format %u\n",
                       dev->udev->devnum, alts->desc.bInterfaceNumber,
                       buffer[2]);
@@ -413,20 +411,11 @@ static int uvc_parse_format(struct uvc_device *dev,
        buflen -= buffer[0];
        buffer += buffer[0];
 
-       /* Count the number of frame descriptors to test the bFrameIndex
-        * field when parsing the descriptors. We can't rely on the
-        * bNumFrameDescriptors field as some cameras don't initialize it
-        * properly.
-        */
-       for (_buflen = buflen, _buffer = buffer;
-            _buflen > 2 && _buffer[2] == ftype;
-            _buflen -= _buffer[0], _buffer += _buffer[0])
-               format->nframes++;
-
        /* Parse the frame descriptors. Only uncompressed, MJPEG and frame
         * based formats have frame descriptors.
         */
        while (buflen > 2 && buffer[2] == ftype) {
+               frame = &format->frame[format->nframes];
                if (ftype != VS_FRAME_FRAME_BASED)
                        n = buflen > 25 ? buffer[25] : 0;
                else
@@ -435,22 +424,12 @@ static int uvc_parse_format(struct uvc_device *dev,
                n = n ? n : 3;
 
                if (buflen < 26 + 4*n) {
-                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                               "interface %d FRAME error\n", dev->udev->devnum,
                               alts->desc.bInterfaceNumber);
                        return -EINVAL;
                }
 
-               if (buffer[3] - 1 >= format->nframes) {
-                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
-                              "interface %d frame index %u out of range\n",
-                              dev->udev->devnum, alts->desc.bInterfaceNumber,
-                              buffer[3]);
-                       return -EINVAL;
-               }
-
-               frame = &format->frame[buffer[3] - 1];
-
                frame->bFrameIndex = buffer[3];
                frame->bmCapabilities = buffer[4];
                frame->wWidth = get_unaligned_le16(&buffer[5]);
@@ -507,6 +486,7 @@ static int uvc_parse_format(struct uvc_device *dev,
                        10000000/frame->dwDefaultFrameInterval,
                        (100000000/frame->dwDefaultFrameInterval)%10);
 
+               format->nframes++;
                buflen -= buffer[0];
                buffer += buffer[0];
        }
@@ -518,7 +498,7 @@ static int uvc_parse_format(struct uvc_device *dev,
 
        if (buflen > 2 && buffer[2] == VS_COLORFORMAT) {
                if (buflen < 6) {
-                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"
+                       uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
                               "interface %d COLORFORMAT error\n",
                               dev->udev->devnum,
                               alts->desc.bInterfaceNumber);
@@ -664,7 +644,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
        _buflen = buflen;
 
        /* Count the format and frame descriptors. */
-       while (_buflen > 2) {
+       while (_buflen > 2 && _buffer[1] == CS_INTERFACE) {
                switch (_buffer[2]) {
                case VS_FORMAT_UNCOMPRESSED:
                case VS_FORMAT_MJPEG:
@@ -729,7 +709,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
        streaming->nformats = nformats;
 
        /* Parse the format descriptors. */
-       while (buflen > 2) {
+       while (buflen > 2 && buffer[1] == CS_INTERFACE) {
                switch (buffer[2]) {
                case VS_FORMAT_UNCOMPRESSED:
                case VS_FORMAT_MJPEG:
@@ -1316,7 +1296,7 @@ static int uvc_scan_chain_forward(struct uvc_video_device *video,
                        continue;
 
                if (forward->extension.bNrInPins != 1) {
-                       uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has"
+                       uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has "
                                "more than 1 input pin.\n", entity->id);
                        return -1;
                }
@@ -1614,6 +1594,7 @@ static int uvc_probe(struct usb_interface *intf,
        INIT_LIST_HEAD(&dev->entities);
        INIT_LIST_HEAD(&dev->streaming);
        kref_init(&dev->kref);
+       atomic_set(&dev->users, 0);
 
        dev->udev = usb_get_dev(udev);
        dev->intf = usb_get_intf(intf);
@@ -1927,7 +1908,7 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_STREAM_NO_FID },
-       /* Lenovo Thinkpad SL500 */
+       /* Lenovo Thinkpad SL400/SL500 */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
          .idVendor             = 0x17ef,
@@ -1936,6 +1917,15 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_STREAM_NO_FID },
+       /* Aveo Technology USB 2.0 Camera */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x1871,
+         .idProduct            = 0x0306,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_PROBE_EXTRAFIELDS },
        /* Ecamm Pico iMage */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_INT_INFO,
@@ -1945,6 +1935,15 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_PROBE_EXTRAFIELDS },
+       /* FSC WebCam V30S */
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                               | USB_DEVICE_ID_MATCH_INT_INFO,
+         .idVendor             = 0x18ec,
+         .idProduct            = 0x3288,
+         .bInterfaceClass      = USB_CLASS_VIDEO,
+         .bInterfaceSubClass   = 1,
+         .bInterfaceProtocol   = 0,
+         .driver_info          = UVC_QUIRK_PROBE_MINMAX },
        /* Bodelin ProScopeHR */
        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
                                | USB_DEVICE_ID_MATCH_DEV_HI
@@ -1965,8 +1964,7 @@ static struct usb_device_id uvc_ids[] = {
          .bInterfaceSubClass   = 1,
          .bInterfaceProtocol   = 0,
          .driver_info          = UVC_QUIRK_PROBE_MINMAX
-                               | UVC_QUIRK_IGNORE_SELECTOR_UNIT
-                               | UVC_QUIRK_PRUNE_CONTROLS },
+                               | UVC_QUIRK_IGNORE_SELECTOR_UNIT },
        /* Generic USB Video Class */
        { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
        {}
index 0155752e4a5aea54140c55044a266df1099b8575..f854698c40618a4a5225209f1060933f1aafb430 100644 (file)
@@ -172,6 +172,20 @@ int uvc_free_buffers(struct uvc_video_queue *queue)
        return 0;
 }
 
+/*
+ * Check if buffers have been allocated.
+ */
+int uvc_queue_allocated(struct uvc_video_queue *queue)
+{
+       int allocated;
+
+       mutex_lock(&queue->mutex);
+       allocated = queue->count != 0;
+       mutex_unlock(&queue->mutex);
+
+       return allocated;
+}
+
 static void __uvc_query_buffer(struct uvc_buffer *buf,
                struct v4l2_buffer *v4l2_buf)
 {
index 21d87124986b57336afc53debe4315ce17d618a2..f152a9903862abe4780eebe67ba282f2bf6d9eac 100644 (file)
@@ -194,7 +194,7 @@ int uvc_status_init(struct uvc_device *dev)
                dev->status, UVC_MAX_STATUS_SIZE, uvc_status_complete,
                dev, interval);
 
-       return usb_submit_urb(dev->int_urb, GFP_KERNEL);
+       return 0;
 }
 
 void uvc_status_cleanup(struct uvc_device *dev)
@@ -205,15 +205,30 @@ void uvc_status_cleanup(struct uvc_device *dev)
        uvc_input_cleanup(dev);
 }
 
-int uvc_status_suspend(struct uvc_device *dev)
+int uvc_status_start(struct uvc_device *dev)
+{
+       if (dev->int_urb == NULL)
+               return 0;
+
+       return usb_submit_urb(dev->int_urb, GFP_KERNEL);
+}
+
+void uvc_status_stop(struct uvc_device *dev)
 {
        usb_kill_urb(dev->int_urb);
+}
+
+int uvc_status_suspend(struct uvc_device *dev)
+{
+       if (atomic_read(&dev->users))
+               usb_kill_urb(dev->int_urb);
+
        return 0;
 }
 
 int uvc_status_resume(struct uvc_device *dev)
 {
-       if (dev->int_urb == NULL)
+       if (dev->int_urb == NULL || atomic_read(&dev->users) == 0)
                return 0;
 
        return usb_submit_urb(dev->int_urb, GFP_NOIO);
index 2a80caa54fb42638d6808e8819a0fbb7c351e0aa..5e77cad29690112bb734486a62e8b766f0eebb6e 100644 (file)
@@ -46,6 +46,8 @@ static int uvc_v4l2_query_menu(struct uvc_video_device *video,
        struct uvc_menu_info *menu_info;
        struct uvc_control_mapping *mapping;
        struct uvc_control *ctrl;
+       u32 index = query_menu->index;
+       u32 id = query_menu->id;
 
        ctrl = uvc_find_control(video, query_menu->id, &mapping);
        if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU)
@@ -54,6 +56,10 @@ static int uvc_v4l2_query_menu(struct uvc_video_device *video,
        if (query_menu->index >= mapping->menu_count)
                return -EINVAL;
 
+       memset(query_menu, 0, sizeof(*query_menu));
+       query_menu->id = id;
+       query_menu->index = index;
+
        menu_info = &mapping->menu_info[query_menu->index];
        strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name);
        return 0;
@@ -245,7 +251,7 @@ static int uvc_v4l2_set_format(struct uvc_video_device *video,
        if (fmt->type != video->streaming->type)
                return -EINVAL;
 
-       if (uvc_queue_streaming(&video->queue))
+       if (uvc_queue_allocated(&video->queue))
                return -EBUSY;
 
        ret = uvc_v4l2_try_format(video, fmt, &probe, &format, &frame);
@@ -433,6 +439,15 @@ static int uvc_v4l2_open(struct file *file)
                goto done;
        }
 
+       if (atomic_inc_return(&video->dev->users) == 1) {
+               if ((ret = uvc_status_start(video->dev)) < 0) {
+                       usb_autopm_put_interface(video->dev->intf);
+                       atomic_dec(&video->dev->users);
+                       kfree(handle);
+                       goto done;
+               }
+       }
+
        handle->device = video;
        handle->state = UVC_HANDLE_PASSIVE;
        file->private_data = handle;
@@ -467,6 +482,9 @@ static int uvc_v4l2_release(struct file *file)
        kfree(handle);
        file->private_data = NULL;
 
+       if (atomic_dec_return(&video->dev->users) == 0)
+               uvc_status_stop(video->dev);
+
        usb_autopm_put_interface(video->dev->intf);
        kref_put(&video->dev->kref, uvc_delete);
        return 0;
@@ -512,7 +530,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                memset(&xctrl, 0, sizeof xctrl);
                xctrl.id = ctrl->id;
 
-               uvc_ctrl_begin(video);
+              ret = uvc_ctrl_begin(video);
+              if (ret < 0)
+                       return ret;
+
                ret = uvc_ctrl_get(video, &xctrl);
                uvc_ctrl_rollback(video);
                if (ret >= 0)
@@ -529,7 +550,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                xctrl.id = ctrl->id;
                xctrl.value = ctrl->value;
 
-               uvc_ctrl_begin(video);
+              ret = uvc_ctrl_begin(video);
+              if (ret < 0)
+                       return ret;
+
                ret = uvc_ctrl_set(video, &xctrl);
                if (ret < 0) {
                        uvc_ctrl_rollback(video);
@@ -548,7 +572,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                struct v4l2_ext_control *ctrl = ctrls->controls;
                unsigned int i;
 
-               uvc_ctrl_begin(video);
+              ret = uvc_ctrl_begin(video);
+              if (ret < 0)
+                       return ret;
+
                for (i = 0; i < ctrls->count; ++ctrl, ++i) {
                        ret = uvc_ctrl_get(video, ctrl);
                        if (ret < 0) {
@@ -648,7 +675,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
        case VIDIOC_S_INPUT:
        {
-               u8 input = *(u32 *)arg + 1;
+               u32 input = *(u32 *)arg + 1;
 
                if ((ret = uvc_acquire_privileges(handle)) < 0)
                        return ret;
@@ -660,7 +687,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
                        break;
                }
 
-               if (input > video->selector->selector.bNrInPins)
+               if (input == 0 || input > video->selector->selector.bNrInPins)
                        return -EINVAL;
 
                return uvc_query_ctrl(video->dev, SET_CUR, video->selector->id,
index 6ce974d7362f2d2c442f6d7174693eb1419b9f37..01b633c734803ac3d4cf3b42a690cbedc51dc96f 100644 (file)
@@ -65,7 +65,8 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video,
        struct uvc_streaming_control *ctrl)
 {
        struct uvc_format *format;
-       struct uvc_frame *frame;
+       struct uvc_frame *frame = NULL;
+       unsigned int i;
 
        if (ctrl->bFormatIndex <= 0 ||
            ctrl->bFormatIndex > video->streaming->nformats)
@@ -73,11 +74,15 @@ static void uvc_fixup_video_ctrl(struct uvc_video_device *video,
 
        format = &video->streaming->format[ctrl->bFormatIndex - 1];
 
-       if (ctrl->bFrameIndex <= 0 ||
-           ctrl->bFrameIndex > format->nframes)
-               return;
+       for (i = 0; i < format->nframes; ++i) {
+               if (format->frame[i].bFrameIndex == ctrl->bFrameIndex) {
+                       frame = &format->frame[i];
+                       break;
+               }
+       }
 
-       frame = &format->frame[ctrl->bFrameIndex - 1];
+       if (frame == NULL)
+               return;
 
        if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) ||
             (ctrl->dwMaxVideoFrameSize == 0 &&
@@ -1089,7 +1094,7 @@ int uvc_video_init(struct uvc_video_device *video)
        /* Zero bFrameIndex might be correct. Stream-based formats (including
         * MPEG-2 TS and DV) do not support frames but have a dummy frame
         * descriptor with bFrameIndex set to zero. If the default frame
-        * descriptor is not found, use the first avalable frame.
+        * descriptor is not found, use the first available frame.
         */
        for (i = format->nframes; i > 0; --i) {
                frame = &format->frame[i-1];
index e5014e668f9979307996d507d034cdc3fb793e94..3c78d3c1e4c0f7482122d7ddff4ea2c0411fea2e 100644 (file)
@@ -313,7 +313,6 @@ struct uvc_xu_control {
 #define UVC_QUIRK_BUILTIN_ISIGHT       0x00000008
 #define UVC_QUIRK_STREAM_NO_FID                0x00000010
 #define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020
-#define UVC_QUIRK_PRUNE_CONTROLS       0x00000040
 #define UVC_QUIRK_FIX_BANDWIDTH                0x00000080
 
 /* Format flags */
@@ -634,6 +633,7 @@ struct uvc_device {
        enum uvc_device_state state;
        struct kref kref;
        struct list_head list;
+       atomic_t users;
 
        /* Video control interface */
        __u16 uvc_version;
@@ -747,6 +747,7 @@ extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
                struct uvc_buffer *buf);
 extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
                struct file *file, poll_table *wait);
+extern int uvc_queue_allocated(struct uvc_video_queue *queue);
 static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
 {
        return queue->flags & UVC_QUEUE_STREAMING;
@@ -770,6 +771,8 @@ extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
 /* Status */
 extern int uvc_status_init(struct uvc_device *dev);
 extern void uvc_status_cleanup(struct uvc_device *dev);
+extern int uvc_status_start(struct uvc_device *dev);
+extern void uvc_status_stop(struct uvc_device *dev);
 extern int uvc_status_suspend(struct uvc_device *dev);
 extern int uvc_status_resume(struct uvc_device *dev);
 
index f576ef66b8078a79f42dfd9667d498a61118338f..f96475626da78949079318fe4372edf0ae7dd37e 100644 (file)
@@ -746,6 +746,7 @@ void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
                const struct v4l2_subdev_ops *ops)
 {
        v4l2_subdev_init(sd, ops);
+       sd->flags |= V4L2_SUBDEV_FL_IS_I2C;
        /* the owner is the same as the i2c_client's driver owner */
        sd->owner = client->driver->driver.owner;
        /* i2c_client and v4l2_subdev point to one another */
@@ -897,8 +898,7 @@ const unsigned short *v4l2_i2c_tuner_addrs(enum v4l2_i2c_tuner_type type)
        };
        static const unsigned short tv_addrs[] = {
                0x42, 0x43, 0x4a, 0x4b,         /* tda8290 */
-               0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
-               0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+               0x60, 0x61, 0x62, 0x63, 0x64,
                I2C_CLIENT_END
        };
 
index 94aa485ade52efb9b87a01871366b8363a39143b..0d06e7cbd5b3187aee89bbcfb14410c69ffb013b 100644 (file)
@@ -49,6 +49,22 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
 }
 EXPORT_SYMBOL_GPL(v4l2_device_register);
 
+int v4l2_device_set_name(struct v4l2_device *v4l2_dev, const char *basename,
+                                               atomic_t *instance)
+{
+       int num = atomic_inc_return(instance) - 1;
+       int len = strlen(basename);
+
+       if (basename[len - 1] >= '0' && basename[len - 1] <= '9')
+               snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
+                               "%s-%d", basename, num);
+       else
+               snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
+                               "%s%d", basename, num);
+       return num;
+}
+EXPORT_SYMBOL_GPL(v4l2_device_set_name);
+
 void v4l2_device_disconnect(struct v4l2_device *v4l2_dev)
 {
        if (v4l2_dev->dev) {
@@ -67,8 +83,21 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
        v4l2_device_disconnect(v4l2_dev);
 
        /* Unregister subdevs */
-       list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list)
+       list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list) {
                v4l2_device_unregister_subdev(sd);
+#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
+               if (sd->flags & V4L2_SUBDEV_FL_IS_I2C) {
+                       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+                       /* We need to unregister the i2c client explicitly.
+                          We cannot rely on i2c_del_adapter to always
+                          unregister clients for us, since if the i2c bus
+                          is a platform bus, then it is never deleted. */
+                       if (client)
+                               i2c_unregister_device(client);
+               }
+#endif
+       }
 }
 EXPORT_SYMBOL_GPL(v4l2_device_unregister);
 
index b7b05842cf281bda10b27572df02ff9301fb823d..f1ccf98c0a6f071d287a066a2902c4783b3675fd 100644 (file)
@@ -118,6 +118,7 @@ void videobuf_queue_core_init(struct videobuf_queue *q,
                         void *priv,
                         struct videobuf_qtype_ops *int_ops)
 {
+       BUG_ON(!q);
        memset(q, 0, sizeof(*q));
        q->irqlock   = irqlock;
        q->dev       = dev;
@@ -439,6 +440,7 @@ int videobuf_reqbufs(struct videobuf_queue *q,
        }
 
        req->count = retval;
+       retval = 0;
 
  done:
        mutex_unlock(&q->vb_lock);
@@ -454,7 +456,7 @@ int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
                dprintk(1, "querybuf: Wrong type.\n");
                goto done;
        }
-       if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME)) {
+       if (unlikely(b->index >= VIDEO_MAX_FRAME)) {
                dprintk(1, "querybuf: index out of range.\n");
                goto done;
        }
@@ -495,7 +497,7 @@ int videobuf_qbuf(struct videobuf_queue *q,
                dprintk(1, "qbuf: Wrong type.\n");
                goto done;
        }
-       if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) {
+       if (b->index >= VIDEO_MAX_FRAME) {
                dprintk(1, "qbuf: index out of range.\n");
                goto done;
        }
index 6109fb5f34e2bb9b54ae7a1a289c8144c9ea86f3..d09ce83a9429af98060b7d3dd27e21923f2431ea 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mm.h>
+#include <linux/pagemap.h>
 #include <linux/dma-mapping.h>
 #include <media/videobuf-dma-contig.h>
 
@@ -25,6 +26,7 @@ struct videobuf_dma_contig_memory {
        void *vaddr;
        dma_addr_t dma_handle;
        unsigned long size;
+       int is_userptr;
 };
 
 #define MAGIC_DC_MEM 0x0733ac61
@@ -108,6 +110,82 @@ static struct vm_operations_struct videobuf_vm_ops = {
        .close    = videobuf_vm_close,
 };
 
+/**
+ * videobuf_dma_contig_user_put() - reset pointer to user space buffer
+ * @mem: per-buffer private videobuf-dma-contig data
+ *
+ * This function resets the user space pointer
+ */
+static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem)
+{
+       mem->is_userptr = 0;
+       mem->dma_handle = 0;
+       mem->size = 0;
+}
+
+/**
+ * videobuf_dma_contig_user_get() - setup user space memory pointer
+ * @mem: per-buffer private videobuf-dma-contig data
+ * @vb: video buffer to map
+ *
+ * This function validates and sets up a pointer to user space memory.
+ * Only physically contiguous pfn-mapped memory is accepted.
+ *
+ * Returns 0 if successful.
+ */
+static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
+                                       struct videobuf_buffer *vb)
+{
+       struct mm_struct *mm = current->mm;
+       struct vm_area_struct *vma;
+       unsigned long prev_pfn, this_pfn;
+       unsigned long pages_done, user_address;
+       int ret;
+
+       mem->size = PAGE_ALIGN(vb->size);
+       mem->is_userptr = 0;
+       ret = -EINVAL;
+
+       down_read(&mm->mmap_sem);
+
+       vma = find_vma(mm, vb->baddr);
+       if (!vma)
+               goto out_up;
+
+       if ((vb->baddr + mem->size) > vma->vm_end)
+               goto out_up;
+
+       pages_done = 0;
+       prev_pfn = 0; /* kill warning */
+       user_address = vb->baddr;
+
+       while (pages_done < (mem->size >> PAGE_SHIFT)) {
+               ret = follow_pfn(vma, user_address, &this_pfn);
+               if (ret)
+                       break;
+
+               if (pages_done == 0)
+                       mem->dma_handle = this_pfn << PAGE_SHIFT;
+               else if (this_pfn != (prev_pfn + 1))
+                       ret = -EFAULT;
+
+               if (ret)
+                       break;
+
+               prev_pfn = this_pfn;
+               user_address += PAGE_SIZE;
+               pages_done++;
+       }
+
+       if (!ret)
+               mem->is_userptr = 1;
+
+ out_up:
+       up_read(&current->mm->mmap_sem);
+
+       return ret;
+}
+
 static void *__videobuf_alloc(size_t size)
 {
        struct videobuf_dma_contig_memory *mem;
@@ -154,12 +232,11 @@ static int __videobuf_iolock(struct videobuf_queue *q,
        case V4L2_MEMORY_USERPTR:
                dev_dbg(q->dev, "%s memory method USERPTR\n", __func__);
 
-               /* The only USERPTR currently supported is the one needed for
-                  read() method.
-                */
+               /* handle pointer from user space */
                if (vb->baddr)
-                       return -EINVAL;
+                       return videobuf_dma_contig_user_get(mem, vb);
 
+               /* allocate memory for the read() method */
                mem->size = PAGE_ALIGN(vb->size);
                mem->vaddr = dma_alloc_coherent(q->dev, mem->size,
                                                &mem->dma_handle, GFP_KERNEL);
@@ -182,19 +259,6 @@ static int __videobuf_iolock(struct videobuf_queue *q,
        return 0;
 }
 
-static int __videobuf_sync(struct videobuf_queue *q,
-                          struct videobuf_buffer *buf)
-{
-       struct videobuf_dma_contig_memory *mem = buf->priv;
-
-       BUG_ON(!mem);
-       MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
-
-       dma_sync_single_for_cpu(q->dev, mem->dma_handle, mem->size,
-                               DMA_FROM_DEVICE);
-       return 0;
-}
-
 static int __videobuf_mmap_free(struct videobuf_queue *q)
 {
        unsigned int i;
@@ -356,7 +420,6 @@ static struct videobuf_qtype_ops qops = {
 
        .alloc        = __videobuf_alloc,
        .iolock       = __videobuf_iolock,
-       .sync         = __videobuf_sync,
        .mmap_free    = __videobuf_mmap_free,
        .mmap_mapper  = __videobuf_mmap_mapper,
        .video_copy_to_user = __videobuf_copy_to_user,
@@ -400,7 +463,7 @@ void videobuf_dma_contig_free(struct videobuf_queue *q,
           So, it should free memory only if the memory were allocated for
           read() operation.
         */
-       if ((buf->memory != V4L2_MEMORY_USERPTR) || buf->baddr)
+       if (buf->memory != V4L2_MEMORY_USERPTR)
                return;
 
        if (!mem)
@@ -408,6 +471,13 @@ void videobuf_dma_contig_free(struct videobuf_queue *q,
 
        MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
 
+       /* handle user space pointer case */
+       if (buf->baddr) {
+               videobuf_dma_contig_user_put(mem);
+               return;
+       }
+
+       /* read() method */
        dma_free_coherent(q->dev, mem->size, mem->vaddr, mem->dma_handle);
        mem->vaddr = NULL;
 }
index da1790e57a86c87b03c530deb58435cab036b80d..a8dd22ace3fbb270b938ba815b617ba815a98fae 100644 (file)
@@ -58,9 +58,10 @@ videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages)
        struct page *pg;
        int i;
 
-       sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL);
+       sglist = vmalloc(nr_pages * sizeof(*sglist));
        if (NULL == sglist)
                return NULL;
+       memset(sglist, 0, nr_pages * sizeof(*sglist));
        sg_init_table(sglist, nr_pages);
        for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {
                pg = vmalloc_to_page(virt);
@@ -72,7 +73,7 @@ videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages)
        return sglist;
 
  err:
-       kfree(sglist);
+       vfree(sglist);
        return NULL;
 }
 
@@ -84,7 +85,7 @@ videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset)
 
        if (NULL == pages[0])
                return NULL;
-       sglist = kmalloc(nr_pages * sizeof(*sglist), GFP_KERNEL);
+       sglist = vmalloc(nr_pages * sizeof(*sglist));
        if (NULL == sglist)
                return NULL;
        sg_init_table(sglist, nr_pages);
@@ -104,12 +105,12 @@ videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset)
 
  nopage:
        dprintk(2,"sgl: oops - no page\n");
-       kfree(sglist);
+       vfree(sglist);
        return NULL;
 
  highmem:
        dprintk(2,"sgl: oops - highmem page\n");
-       kfree(sglist);
+       vfree(sglist);
        return NULL;
 }
 
@@ -230,7 +231,7 @@ int videobuf_dma_map(struct videobuf_queue* q, struct videobuf_dmabuf *dma)
                                                (dma->vmalloc,dma->nr_pages);
        }
        if (dma->bus_addr) {
-               dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL);
+               dma->sglist = vmalloc(sizeof(*dma->sglist));
                if (NULL != dma->sglist) {
                        dma->sglen  = 1;
                        sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK;
@@ -248,10 +249,10 @@ int videobuf_dma_map(struct videobuf_queue* q, struct videobuf_dmabuf *dma)
                if (0 == dma->sglen) {
                        printk(KERN_WARNING
                               "%s: videobuf_map_sg failed\n",__func__);
-                       kfree(dma->sglist);
+                       vfree(dma->sglist);
                        dma->sglist = NULL;
                        dma->sglen = 0;
-                       return -EIO;
+                       return -ENOMEM;
                }
        }
        return 0;
@@ -274,7 +275,7 @@ int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
 
        dma_unmap_sg(q->dev, dma->sglist, dma->nr_pages, dma->direction);
 
-       kfree(dma->sglist);
+       vfree(dma->sglist);
        dma->sglist = NULL;
        dma->sglen = 0;
        return 0;
index 43e0998adb534bb857fdc88ada51117c914ab411..97b082fe44736423bf2a2240abc962cfdb90f999 100644 (file)
@@ -868,9 +868,9 @@ static void vino_sync_buffer(struct vino_framebuffer *fb)
        dprintk("vino_sync_buffer():\n");
 
        for (i = 0; i < fb->desc_table.page_count; i++)
-               dma_sync_single(NULL,
-                               fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i],
-                               PAGE_SIZE, DMA_FROM_DEVICE);
+               dma_sync_single_for_cpu(NULL,
+                                       fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i],
+                                       PAGE_SIZE, DMA_FROM_DEVICE);
 }
 
 /* Framebuffer fifo functions (need to be locked externally) */
index ea6c577b0eb3131f7366e5b163ed317de4dad623..03dc2f3cf84af17d33530a3a6b6cc941764dbdd2 100644 (file)
@@ -1022,7 +1022,7 @@ zr36057_init (struct zoran *zr)
        zr->vbuf_bytesperline = 0;
 
        /* Avoid nonsense settings from user for default input/norm */
-       if (default_norm < 0 && default_norm > 2)
+       if (default_norm < 0 || default_norm > 2)
                default_norm = 0;
        if (default_norm == 0) {
                zr->norm = V4L2_STD_PAL;
@@ -1477,7 +1477,7 @@ static struct pci_driver zoran_driver = {
        .name = "zr36067",
        .id_table = zr36067_pci_tbl,
        .probe = zoran_probe,
-       .remove = zoran_remove,
+       .remove = __devexit_p(zoran_remove),
 };
 
 static int __init zoran_init(void)
index ac169c9eb18d04e958ff1b6bc406f5513efbf471..fc976f42f4328d70bbccb9a65a1d4bd0b5173cf5 100644 (file)
@@ -882,9 +882,11 @@ static void zr364xx_disconnect(struct usb_interface *intf)
                video_unregister_device(cam->vdev);
        cam->vdev = NULL;
        kfree(cam->buffer);
-       if (cam->framebuf)
-               vfree(cam->framebuf);
+       cam->buffer = NULL;
+       vfree(cam->framebuf);
+       cam->framebuf = NULL;
        kfree(cam);
+       cam = NULL;
 }
 
 
index 386da1566fccb41f76a6828e3e5de2dde965ccfb..cb73051e43db8ca04e1eabbdafd65af4966f47ef 100644 (file)
@@ -35,7 +35,7 @@ struct pasic3_data {
  */
 void pasic3_write_register(struct device *dev, u32 reg, u8 val)
 {
-       struct pasic3_data *asic = dev->driver_data;
+       struct pasic3_data *asic = dev_get_drvdata(dev);
        int bus_shift = asic->bus_shift;
        void __iomem *addr = asic->mapping + (REG_ADDR << bus_shift);
        void __iomem *data = asic->mapping + (REG_DATA << bus_shift);
@@ -50,7 +50,7 @@ EXPORT_SYMBOL(pasic3_write_register); /* for leds-pasic3 */
  */
 u8 pasic3_read_register(struct device *dev, u32 reg)
 {
-       struct pasic3_data *asic = dev->driver_data;
+       struct pasic3_data *asic = dev_get_drvdata(dev);
        int bus_shift = asic->bus_shift;
        void __iomem *addr = asic->mapping + (REG_ADDR << bus_shift);
        void __iomem *data = asic->mapping + (REG_DATA << bus_shift);
index 11a6248cc1c1dd0af3a57ace1ec228ccdb3ed257..082c197ab9b861f3071f4dac1677bbcfb512dca4 100644 (file)
@@ -618,7 +618,7 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
 
                pdev->dev.parent = pcf->dev;
                pdev->dev.platform_data = &pdata->reg_init_data[i];
-               pdev->dev.driver_data = pcf;
+               dev_set_drvdata(&pdev->dev, pcf);
                pcf->regulator_pdev[i] = pdev;
 
                platform_device_add(pdev);
index cf30d06a0104a6ab4f6295a7abf2a8ad85700a9a..7c21bf7915696253b75064b3146a89bdf5a9c905 100644 (file)
@@ -265,7 +265,7 @@ static int wm8400_init(struct wm8400 *wm8400,
 
        mutex_init(&wm8400->io_lock);
 
-       wm8400->dev->driver_data = wm8400;
+       dev_set_drvdata(wm8400->dev, wm8400);
 
        /* Check that this is actually a WM8400 */
        ret = wm8400->read_dev(wm8400->io_data, WM8400_RESET_ID, 1, &reg);
index 0207dd59090d195b4d0d21027e511cf484e14121..b5346b4db91a2021d43c470b09bd53fbdc7a4170 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/kernel.h>
+#include <linux/kmemcheck.h>
 #include <linux/ctype.h>
 #include <linux/delay.h>
 #include <linux/idr.h>
@@ -891,6 +892,7 @@ struct c2port_device *c2port_device_register(char *name,
                return ERR_PTR(-EINVAL);
 
        c2dev = kmalloc(sizeof(struct c2port_device), GFP_KERNEL);
+       kmemcheck_annotate_bitfield(c2dev, flags);
        if (unlikely(!c2dev))
                return ERR_PTR(-ENOMEM);
 
index 89fec052f3b45ee7bf774028349d634c700200fc..9118613af3210b1f0d52c8ad9ac73ba7f5793992 100644 (file)
@@ -48,6 +48,20 @@ config EEPROM_LEGACY
          This driver can also be built as a module.  If so, the module
          will be called eeprom.
 
+config EEPROM_MAX6875
+       tristate "Maxim MAX6874/5 power supply supervisor"
+       depends on I2C && EXPERIMENTAL
+       help
+         If you say yes here you get read-only support for the user EEPROM of
+         the Maxim MAX6874/5 EEPROM-programmable, quad power-supply
+         sequencer/supervisor.
+
+         All other features of this chip should be accessed via i2c-dev.
+
+         This driver can also be built as a module.  If so, the module
+         will be called max6875.
+
+
 config EEPROM_93CX6
        tristate "EEPROM 93CX6 support"
        help
index 539dd8f881281f96f3c88c5cf16e2ca3045508c1..df3d68ffa9d18f20506cff8fd9b719d2a6cb8f22 100644 (file)
@@ -1,4 +1,5 @@
 obj-$(CONFIG_EEPROM_AT24)      += at24.o
 obj-$(CONFIG_EEPROM_AT25)      += at25.o
 obj-$(CONFIG_EEPROM_LEGACY)    += eeprom.o
+obj-$(CONFIG_EEPROM_MAX6875)   += max6875.o
 obj-$(CONFIG_EEPROM_93CX6)     += eeprom_93cx6.o
similarity index 99%
rename from drivers/i2c/chips/max6875.c
rename to drivers/misc/eeprom/max6875.c
index 033d9d81ec8ae0381f3139f541254d3345b8cae8..3c0c58eed34778a22b6d052dbb665584e8b55147 100644 (file)
@@ -3,7 +3,7 @@
 
     Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com>
 
-    Based on i2c/chips/eeprom.c
+    Based on eeprom.c
 
     The MAX6875 has a bank of registers and two banks of EEPROM.
     Address ranges are defined as follows:
index bbefe77c67a93dd4f88ae2c5e139f2405986eb2c..3ce2920e2bf3fb4f37b0223ec2fa7f23bb23a0e0 100644 (file)
@@ -302,7 +302,7 @@ static int gru_init_tables(unsigned long gru_base_paddr, void *gru_base_vaddr)
                pnode = uv_node_to_pnode(nid);
                if (bid < 0 || gru_base[bid])
                        continue;
-               page = alloc_pages_node(nid, GFP_KERNEL, order);
+               page = alloc_pages_exact_node(nid, GFP_KERNEL, order);
                if (!page)
                        goto fail;
                gru_base[bid] = page_address(page);
index 9172fcdee4e2f468e7780c965d8ffbf257cb75d8..c76677afda1b50591b855759fa711253d99458ee 100644 (file)
@@ -232,7 +232,7 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name,
        mq->mmr_blade = uv_cpu_to_blade_id(cpu);
 
        nid = cpu_to_node(cpu);
-       page = alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
+       page = alloc_pages_exact_node(nid, GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
                                pg_order);
        if (page == NULL) {
                dev_err(xpc_part, "xpc_create_gru_mq_uv() failed to alloc %d "
index 01f282cd0989d7123b0cb1b74477cded1571919d..3b6383168c6916cf57c41015d8a10c22dee0d015 100644 (file)
@@ -2206,7 +2206,7 @@ config SKGE_DEBUG
        depends on SKGE && DEBUG_FS
        help
         This option adds the ability to dump driver state for debugging.
-        The file debugfs/skge/ethX displays the state of the internal
+        The file /sys/kernel/debug/skge/ethX displays the state of the internal
         transmit and receive rings.
 
         If unsure, say N.
@@ -2232,7 +2232,7 @@ config SKY2_DEBUG
        depends on SKY2 && DEBUG_FS
        help
         This option adds the ability to dump driver state for debugging.
-        The file debugfs/sky2/ethX displays the state of the internal
+        The file /sys/kernel/debug/sky2/ethX displays the state of the internal
         transmit and receive rings.
 
         If unsure, say N.
index 30900b30d532e9dedf2b040a672d47d0921e6203..2b38f39924a67df3e6cd1ce657ac949535f18d1a 100644 (file)
@@ -1648,7 +1648,7 @@ static int ps3_gelic_driver_probe(struct ps3_system_bus_device *dev)
                result = -ENOMEM;
                goto fail_alloc_card;
        }
-       ps3_system_bus_set_driver_data(dev, card);
+       ps3_system_bus_set_drvdata(dev, card);
        card->dev = dev;
 
        /* get internal vlan info */
@@ -1749,7 +1749,7 @@ fail_alloc_irq:
                                               bus_id(card),
                                               0, 0);
 fail_status_indicator:
-       ps3_system_bus_set_driver_data(dev, NULL);
+       ps3_system_bus_set_drvdata(dev, NULL);
        kfree(netdev_card(netdev)->unalign);
        free_netdev(netdev);
 fail_alloc_card:
@@ -1766,7 +1766,7 @@ fail_open:
 
 static int ps3_gelic_driver_remove(struct ps3_system_bus_device *dev)
 {
-       struct gelic_card *card = ps3_system_bus_get_driver_data(dev);
+       struct gelic_card *card = ps3_system_bus_get_drvdata(dev);
        struct net_device *netdev0;
        pr_debug("%s: called\n", __func__);
 
@@ -1803,7 +1803,7 @@ static int ps3_gelic_driver_remove(struct ps3_system_bus_device *dev)
        kfree(netdev_card(netdev0)->unalign);
        free_netdev(netdev0);
 
-       ps3_system_bus_set_driver_data(dev, NULL);
+       ps3_system_bus_set_drvdata(dev, NULL);
 
        ps3_dma_region_free(dev->d_region);
 
index 811d3517fce0c99895b4738df64a60d934f86fcf..11a0ba47b67782d920f3bf5cb36d3e24d4874b63 100644 (file)
@@ -1366,6 +1366,7 @@ static const struct file_operations tun_fops = {
 static struct miscdevice tun_miscdev = {
        .minor = TUN_MINOR,
        .name = "tun",
+       .devnode = "net/tun",
        .fops = &tun_fops,
 };
 
index 1fe5da4cf0a02d918942e0f19f7a36aaf9ef1264..60330f313f2781ea65630a484564ef7750011487 100644 (file)
@@ -432,7 +432,7 @@ struct i2400m {
        unsigned ready:1;               /* all probing steps done */
        unsigned rx_reorder:1;          /* RX reorder is enabled */
        u8 trace_msg_from_user;         /* echo rx msgs to 'trace' pipe */
-                                       /* typed u8 so debugfs/u8 can tweak */
+                                       /* typed u8 so /sys/kernel/debug/u8 can tweak */
        enum i2400m_system_state state;
        wait_queue_head_t state_wq;     /* Woken up when on state updates */
 
index 509b6f94f73b94930ad95f90441e6b4002223ee9..daf0c83527d88cd0f6e64ff29e26ef7c5387fe4b 100644 (file)
@@ -28,11 +28,10 @@ config ATH5K_DEBUG
          Say Y, if and you will get debug options for ath5k.
          To use this, you need to mount debugfs:
 
-         mkdir /debug/
-         mount -t debugfs debug /debug/
+         mount -t debugfs debug /sys/kernel/debug
 
          You will get access to files under:
-         /debug/ath5k/phy0/
+         /sys/kernel/debug/ath5k/phy0/
 
          To enable debug, pass the debug level to the debug module
          parameter. For example:
index d860fc375752d928b3d51e2ec7e6cca1fdd416d8..ab6a2d518af0ff07f0cd1ff1aec21f777208a644 100644 (file)
@@ -72,7 +72,7 @@ rdrf
        location that is to be read.  This parameter must be specified in
        hexadecimal (its possible to preceed preceding the number with a "0x").
 
-       Path: /debugfs/libertas_wireless/ethX/registers/
+       Path: /sys/kernel/debug/libertas_wireless/ethX/registers/
 
        Usage:
                echo "0xa123" > rdmac ; cat rdmac
@@ -95,7 +95,7 @@ wrrf
 sleepparams
        This command is used to set the sleepclock configurations
 
-       Path: /debugfs/libertas_wireless/ethX/
+       Path: /sys/kernel/debug/libertas_wireless/ethX/
 
        Usage:
                cat sleepparams: reads the current sleepclock configuration
@@ -115,7 +115,7 @@ subscribed_events
        The subscribed_events directory contains the interface for the
        subscribed events API.
 
-       Path: /debugfs/libertas_wireless/ethX/subscribed_events/
+       Path: /sys/kernel/debug/libertas_wireless/ethX/subscribed_events/
 
        Each event is represented by a filename. Each filename consists of the
        following three fields:
@@ -165,7 +165,7 @@ subscribed_events
 extscan
        This command is used to do a specific scan.
 
-       Path: /debugfs/libertas_wireless/ethX/
+       Path: /sys/kernel/debug/libertas_wireless/ethX/
 
        Usage: echo "SSID" > extscan
 
@@ -179,7 +179,7 @@ getscantable
        Display the current contents of the driver scan table (ie. get the
        scan results).
 
-       Path: /debugfs/libertas_wireless/ethX/
+       Path: /sys/kernel/debug/libertas_wireless/ethX/
 
        Usage:
                cat getscantable
@@ -188,7 +188,7 @@ setuserscan
        Initiate a customized scan and retrieve the results
 
 
-       Path: /debugfs/libertas_wireless/ethX/
+       Path: /sys/kernel/debug/libertas_wireless/ethX/
 
     Usage:
        echo "[ARGS]" > setuserscan
index f8c2898d82b05b305e69c566e52e8291b5118348..06a46d7b3d6c2460aecd793d2827033c7c0348f6 100644 (file)
@@ -43,8 +43,8 @@ struct if_spi_card {
        struct lbs_private              *priv;
        struct libertas_spi_platform_data *pdata;
 
-       char                            helper_fw_name[FIRMWARE_NAME_MAX];
-       char                            main_fw_name[FIRMWARE_NAME_MAX];
+       char                            helper_fw_name[IF_SPI_FW_NAME_MAX];
+       char                            main_fw_name[IF_SPI_FW_NAME_MAX];
 
        /* The card ID and card revision, as reported by the hardware. */
        u16                             card_id;
@@ -1019,9 +1019,9 @@ static int if_spi_calculate_fw_names(u16 card_id,
                lbs_pr_err("Unsupported chip_id: 0x%02x\n", card_id);
                return -EAFNOSUPPORT;
        }
-       snprintf(helper_fw, FIRMWARE_NAME_MAX, "libertas/gspi%d_hlp.bin",
+       snprintf(helper_fw, IF_SPI_FW_NAME_MAX, "libertas/gspi%d_hlp.bin",
                 chip_id_to_device_name[i].name);
-       snprintf(main_fw, FIRMWARE_NAME_MAX, "libertas/gspi%d.bin",
+       snprintf(main_fw, IF_SPI_FW_NAME_MAX, "libertas/gspi%d.bin",
                 chip_id_to_device_name[i].name);
        return 0;
 }
index 2103869cc5b06dc8940eb2a3c8c00cd89af6c8a5..f87eec410848fb023416170c0241a84938949f55 100644 (file)
@@ -22,6 +22,9 @@
 #define IF_SPI_CMD_BUF_SIZE 2400
 
 /***************** Firmware *****************/
+
+#define IF_SPI_FW_NAME_MAX 30
+
 struct chip_ident {
        u16 chip_id;
        u16 name;
index d649caebf08a1e93ffd9a136f7682340fe380f33..1844c5adf6e9fb1ad3807f5346174a75654a71c8 100644 (file)
@@ -61,11 +61,9 @@ static ssize_t if_usb_firmware_set(struct device *dev,
 {
        struct lbs_private *priv = to_net_dev(dev)->ml_priv;
        struct if_usb_card *cardp = priv->card;
-       char fwname[FIRMWARE_NAME_MAX];
        int ret;
 
-       sscanf(buf, "%29s", fwname); /* FIRMWARE_NAME_MAX - 1 = 29 */
-       ret = if_usb_prog_firmware(cardp, fwname, BOOT_CMD_UPDATE_FW);
+       ret = if_usb_prog_firmware(cardp, buf, BOOT_CMD_UPDATE_FW);
        if (ret == 0)
                return count;
 
@@ -88,11 +86,9 @@ static ssize_t if_usb_boot2_set(struct device *dev,
 {
        struct lbs_private *priv = to_net_dev(dev)->ml_priv;
        struct if_usb_card *cardp = priv->card;
-       char fwname[FIRMWARE_NAME_MAX];
        int ret;
 
-       sscanf(buf, "%29s", fwname); /* FIRMWARE_NAME_MAX - 1 = 29 */
-       ret = if_usb_prog_firmware(cardp, fwname, BOOT_CMD_UPDATE_BOOT2);
+       ret = if_usb_prog_firmware(cardp, buf, BOOT_CMD_UPDATE_BOOT2);
        if (ret == 0)
                return count;
 
index f673253879024d18b90557be62b145feb7e99ec7..8d88daeed0c6e51c7b73046468a6e8a2606de77d 100644 (file)
@@ -1212,7 +1212,7 @@ static int __devinit netfront_probe(struct xenbus_device *dev,
        }
 
        info = netdev_priv(netdev);
-       dev->dev.driver_data = info;
+       dev_set_drvdata(&dev->dev, info);
 
        err = register_netdev(info->netdev);
        if (err) {
@@ -1233,7 +1233,7 @@ static int __devinit netfront_probe(struct xenbus_device *dev,
 
  fail:
        free_netdev(netdev);
-       dev->dev.driver_data = NULL;
+       dev_set_drvdata(&dev->dev, NULL);
        return err;
 }
 
@@ -1275,7 +1275,7 @@ static void xennet_disconnect_backend(struct netfront_info *info)
  */
 static int netfront_resume(struct xenbus_device *dev)
 {
-       struct netfront_info *info = dev->dev.driver_data;
+       struct netfront_info *info = dev_get_drvdata(&dev->dev);
 
        dev_dbg(&dev->dev, "%s\n", dev->nodename);
 
@@ -1600,7 +1600,7 @@ static int xennet_connect(struct net_device *dev)
 static void backend_changed(struct xenbus_device *dev,
                            enum xenbus_state backend_state)
 {
-       struct netfront_info *np = dev->dev.driver_data;
+       struct netfront_info *np = dev_get_drvdata(&dev->dev);
        struct net_device *netdev = np->netdev;
 
        dev_dbg(&dev->dev, "%s\n", xenbus_strstate(backend_state));
@@ -1774,7 +1774,7 @@ static struct xenbus_device_id netfront_ids[] = {
 
 static int __devexit xennet_remove(struct xenbus_device *dev)
 {
-       struct netfront_info *info = dev->dev.driver_data;
+       struct netfront_info *info = dev_get_drvdata(&dev->dev);
 
        dev_dbg(&dev->dev, "%s\n", dev->nodename);
 
index f415fdd9a88599296a9c5195854c25192b8fbc0b..5b89f404e668876f53da1f0278523763e3512e16 100644 (file)
@@ -373,7 +373,7 @@ static int __init eisa_probe(struct parisc_device *dev)
        if (result >= 0) {
                /* FIXME : Don't enumerate the bus twice. */
                eisa_dev.root.dev = &dev->dev;
-               dev->dev.driver_data = &eisa_dev.root;
+               dev_set_drvdata(&dev->dev, &eisa_dev.root);
                eisa_dev.root.bus_base_addr = 0;
                eisa_dev.root.res = &eisa_dev.hba.io_space;
                eisa_dev.root.slots = result;
index e5999c4cedc81d64aad819f25a9d38a78de06f78..d46dd57450acd151d4d97a7d7016e54cedab1f54 100644 (file)
@@ -2010,7 +2010,7 @@ void __init sba_init(void)
 void * sba_get_iommu(struct parisc_device *pci_hba)
 {
        struct parisc_device *sba_dev = parisc_parent(pci_hba);
-       struct sba_device *sba = sba_dev->dev.driver_data;
+       struct sba_device *sba = dev_get_drvdata(&sba_dev->dev);
        char t = sba_dev->id.hw_type;
        int iocnum = (pci_hba->hw_path >> 3);   /* rope # */
 
@@ -2031,7 +2031,7 @@ void * sba_get_iommu(struct parisc_device *pci_hba)
 void sba_directed_lmmio(struct parisc_device *pci_hba, struct resource *r)
 {
        struct parisc_device *sba_dev = parisc_parent(pci_hba);
-       struct sba_device *sba = sba_dev->dev.driver_data;
+       struct sba_device *sba = dev_get_drvdata(&sba_dev->dev);
        char t = sba_dev->id.hw_type;
        int i;
        int rope = (pci_hba->hw_path & (ROPES_PER_IOC-1));  /* rope # */
@@ -2073,7 +2073,7 @@ void sba_directed_lmmio(struct parisc_device *pci_hba, struct resource *r)
 void sba_distributed_lmmio(struct parisc_device *pci_hba, struct resource *r )
 {
        struct parisc_device *sba_dev = parisc_parent(pci_hba);
-       struct sba_device *sba = sba_dev->dev.driver_data;
+       struct sba_device *sba = dev_get_drvdata(&sba_dev->dev);
        char t = sba_dev->id.hw_type;
        int base, size;
        int rope = (pci_hba->hw_path & (ROPES_PER_IOC-1));  /* rope # */
index ea31a452b153e55e8ce378000e02ee952a5e8991..5d6de380e42ba87526cdfa2b87f658431223be86 100644 (file)
@@ -376,14 +376,14 @@ static int __devinit parport_init_chip(struct parisc_device *dev)
                        /* PARPORT_IRQ_NONE */ PARPORT_DMA_NONE, NULL);
        if (p)
                parport_count++;
-       dev->dev.driver_data = p;
+       dev_set_drvdata(&dev->dev, p);
 
        return 0;
 }
 
 static int __devexit parport_remove_chip(struct parisc_device *dev)
 {
-       struct parport *p = dev->dev.driver_data;
+       struct parport *p = dev_get_drvdata(&dev->dev);
        if (p) {
                struct parport_gsc_private *priv = p->private_data;
                struct parport_operations *ops = p->ops;
index 1a91bf9687af969c69f26c8e67fca08747c0d426..07bbb9b3b93fe1a46ba4e15dcd4d309d31b54ba9 100644 (file)
 #include <asm/setup.h>
 #include "pci.h"
 
+const char *pci_power_names[] = {
+       "error", "D0", "D1", "D2", "D3hot", "D3cold", "unknown",
+};
+EXPORT_SYMBOL_GPL(pci_power_names);
+
 unsigned int pci_pm_d3_delay = PCI_PM_D3_WAIT;
 
 #ifdef CONFIG_PCI_DOMAINS
index e39982503863e4a1539d4f1f968a9dbf47bc3242..13ffdc35ea0eb2573f47d81953871ef61ffc8b48 100644 (file)
@@ -275,7 +275,7 @@ static void pcie_device_init(struct pci_dev *parent, struct pcie_device *dev,
        memset(device, 0, sizeof(struct device));
        device->bus = &pcie_port_bus_type;
        device->driver = NULL;
-       device->driver_data = NULL;
+       dev_set_drvdata(device, NULL);
        device->release = release_pcie_device;  /* callback to free pcie dev */
        dev_set_name(device, "%s:pcie%02x",
                 pci_name(parent), get_descriptor_id(port_type, service_type));
index 47cab31ff6e49c0780692ead159cf81fb4113c58..304ff6d5cf3b2ec13850a253bc908481027cd844 100644 (file)
@@ -394,7 +394,7 @@ static int pcmcia_device_probe(struct device * dev)
        p_drv = to_pcmcia_drv(dev->driver);
        s = p_dev->socket;
 
-       /* The PCMCIA code passes the match data in via dev->driver_data
+       /* The PCMCIA code passes the match data in via dev_set_drvdata(dev)
         * which is an ugly hack. Once the driver probe is called it may
         * and often will overwrite the match data so we must save it first
         *
@@ -404,7 +404,7 @@ static int pcmcia_device_probe(struct device * dev)
         * call which will then check whether there are two
         * pseudo devices, and if not, add the second one.
         */
-       did = p_dev->dev.driver_data;
+       did = dev_get_drvdata(&p_dev->dev);
 
        ds_dev_dbg(1, dev, "trying to bind to %s\n", p_drv->drv.name);
 
@@ -499,7 +499,7 @@ static int pcmcia_device_remove(struct device * dev)
         * pseudo multi-function card, we need to unbind
         * all devices
         */
-       did = p_dev->dev.driver_data;
+       did = dev_get_drvdata(&p_dev->dev);
        if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) &&
            (p_dev->socket->device_count != 0) &&
            (p_dev->device_no == 0))
@@ -828,7 +828,6 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
 {
        struct pcmcia_socket *s = dev->socket;
        const struct firmware *fw;
-       char path[FIRMWARE_NAME_MAX];
        int ret = -ENOMEM;
        int no_funcs;
        int old_funcs;
@@ -839,16 +838,7 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
 
        ds_dev_dbg(1, &dev->dev, "trying to load CIS file %s\n", filename);
 
-       if (strlen(filename) > (FIRMWARE_NAME_MAX - 1)) {
-               dev_printk(KERN_WARNING, &dev->dev,
-                          "pcmcia: CIS filename is too long [%s]\n",
-                          filename);
-               return -EINVAL;
-       }
-
-       snprintf(path, sizeof(path), "%s", filename);
-
-       if (request_firmware(&fw, path, &dev->dev) == 0) {
+       if (request_firmware(&fw, filename, &dev->dev) == 0) {
                if (fw->size >= CISTPL_MAX_CIS_SIZE) {
                        ret = -EINVAL;
                        dev_printk(KERN_ERR, &dev->dev,
@@ -988,7 +978,7 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev,
                        return 0;
        }
 
-       dev->dev.driver_data = (void *) did;
+       dev_set_drvdata(&dev->dev, did);
 
        return 1;
 }
index 1703b20cad5d215ae1a2295329d87a2b253380f1..6095f8daecd7f1eb31fc1a3bc14626ad0df33db5 100644 (file)
@@ -915,12 +915,9 @@ static int ds_ioctl(struct inode * inode, struct file * file,
                err = -EPERM;
                goto free_out;
        } else {
-               static int printed = 0;
-               if (!printed) {
-                       printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
-                       printk(KERN_WARNING "MTD handling any more.\n");
-                       printed++;
-               }
+                       printk_once(KERN_WARNING
+                               "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
+                       printk_once(KERN_WARNING "MTD handling any more.\n");
        }
        err = -EINVAL;
        goto free_out;
index f17513dd9d4ba4a340effd9cb63f5fa6e1a04eeb..88cb74088611be6258013f53a9ec28c0a1c86d09 100644 (file)
@@ -706,7 +706,7 @@ static void ps3_sys_manager_work(struct ps3_system_bus_device *dev)
        ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN);
 }
 
-static int ps3_sys_manager_probe(struct ps3_system_bus_device *dev)
+static int __devinit ps3_sys_manager_probe(struct ps3_system_bus_device *dev)
 {
        int result;
        struct ps3_sys_manager_ops ops;
index 235e87fcb49f5c5ab5979c2dc2fd6eeaa4b5feef..e82d8c9c6cda6a6c098ce2c7bd685d30515fcb5b 100644 (file)
@@ -80,12 +80,12 @@ static const struct avset_video_mode {
        {     0, }, /* auto */
        {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I,       A_N,  720,  480},
        {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P,       A_N,  720,  480},
-       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ,  A_N, 1280,  720},
+       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ,  A_W, 1280,  720},
        {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080},
        {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080},
        {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I,       A_N,  720,  576},
        {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P,       A_N,  720,  576},
-       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ,  A_N, 1280,  720},
+       {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ,  A_W, 1280,  720},
        {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080},
        {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080},
        {  RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA,       A_W, 1280,  768},
@@ -937,7 +937,7 @@ int ps3av_audio_mute(int mute)
 
 EXPORT_SYMBOL_GPL(ps3av_audio_mute);
 
-static int ps3av_probe(struct ps3_system_bus_device *dev)
+static int __devinit ps3av_probe(struct ps3_system_bus_device *dev)
 {
        int res;
        int id;
@@ -1048,7 +1048,7 @@ static struct ps3_vuart_port_driver ps3av_driver = {
        .shutdown = ps3av_shutdown,
 };
 
-static int ps3av_module_init(void)
+static int __init ps3av_module_init(void)
 {
        int error;
 
index 716596e8e5b0acdc26d92d607af85516897f932d..f555fedd5073270a7624995e09417b1e41119663 100644 (file)
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
+
 #include <asm/ps3av.h>
-#include <asm/ps3fb.h>
 #include <asm/ps3.h>
+#include <asm/ps3gpu.h>
 
 #include "vuart.h"
 
index 442bb98a2821c5a34519b08e452bfb9ffa1bf629..e5b84db0aa037d97bd6df4fb0ee234b3a49ce5ab 100644 (file)
@@ -5,8 +5,7 @@
  *                 Carsten Otte <Cotte@de.ibm.com>
  *                 Martin Schwidefsky <schwidefsky@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
- *
+ * Copyright IBM Corp. 1999, 2009
  */
 
 #define KMSG_COMPONENT "dasd"
@@ -61,6 +60,7 @@ static int dasd_flush_block_queue(struct dasd_block *);
 static void dasd_device_tasklet(struct dasd_device *);
 static void dasd_block_tasklet(struct dasd_block *);
 static void do_kick_device(struct work_struct *);
+static void do_restore_device(struct work_struct *);
 static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *);
 static void dasd_device_timeout(unsigned long);
 static void dasd_block_timeout(unsigned long);
@@ -109,6 +109,7 @@ struct dasd_device *dasd_alloc_device(void)
        device->timer.function = dasd_device_timeout;
        device->timer.data = (unsigned long) device;
        INIT_WORK(&device->kick_work, do_kick_device);
+       INIT_WORK(&device->restore_device, do_restore_device);
        device->state = DASD_STATE_NEW;
        device->target = DASD_STATE_NEW;
 
@@ -511,6 +512,25 @@ void dasd_kick_device(struct dasd_device *device)
        schedule_work(&device->kick_work);
 }
 
+/*
+ * dasd_restore_device will schedule a call do do_restore_device to the kernel
+ * event daemon.
+ */
+static void do_restore_device(struct work_struct *work)
+{
+       struct dasd_device *device = container_of(work, struct dasd_device,
+                                                 restore_device);
+       device->cdev->drv->restore(device->cdev);
+       dasd_put_device(device);
+}
+
+void dasd_restore_device(struct dasd_device *device)
+{
+       dasd_get_device(device);
+       /* queue call to dasd_restore_device to the kernel event daemon. */
+       schedule_work(&device->restore_device);
+}
+
 /*
  * Set the target state for a device and starts the state change.
  */
@@ -908,6 +928,12 @@ int dasd_start_IO(struct dasd_ccw_req *cqr)
                DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
                              "start_IO: -EIO device gone, retry");
                break;
+       case -EINVAL:
+               /* most likely caused in power management context */
+               DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
+                             "start_IO: -EINVAL device currently "
+                             "not accessible");
+               break;
        default:
                /* internal error 11 - unknown rc */
                snprintf(errorstring, ERRORLENGTH, "11 %d", rc);
@@ -2400,6 +2426,12 @@ int dasd_generic_notify(struct ccw_device *cdev, int event)
        case CIO_OPER:
                /* FIXME: add a sanity check. */
                device->stopped &= ~DASD_STOPPED_DC_WAIT;
+               if (device->stopped & DASD_UNRESUMED_PM) {
+                       device->stopped &= ~DASD_UNRESUMED_PM;
+                       dasd_restore_device(device);
+                       ret = 1;
+                       break;
+               }
                dasd_schedule_device_bh(device);
                if (device->block)
                        dasd_schedule_block_bh(device->block);
@@ -2410,6 +2442,79 @@ int dasd_generic_notify(struct ccw_device *cdev, int event)
        return ret;
 }
 
+int dasd_generic_pm_freeze(struct ccw_device *cdev)
+{
+       struct dasd_ccw_req *cqr, *n;
+       int rc;
+       struct list_head freeze_queue;
+       struct dasd_device *device = dasd_device_from_cdev(cdev);
+
+       if (IS_ERR(device))
+               return PTR_ERR(device);
+       /* disallow new I/O  */
+       device->stopped |= DASD_STOPPED_PM;
+       /* clear active requests */
+       INIT_LIST_HEAD(&freeze_queue);
+       spin_lock_irq(get_ccwdev_lock(cdev));
+       rc = 0;
+       list_for_each_entry_safe(cqr, n, &device->ccw_queue, devlist) {
+               /* Check status and move request to flush_queue */
+               if (cqr->status == DASD_CQR_IN_IO) {
+                       rc = device->discipline->term_IO(cqr);
+                       if (rc) {
+                               /* unable to terminate requeust */
+                               dev_err(&device->cdev->dev,
+                                       "Unable to terminate request %p "
+                                       "on suspend\n", cqr);
+                               spin_unlock_irq(get_ccwdev_lock(cdev));
+                               dasd_put_device(device);
+                               return rc;
+                       }
+               }
+               list_move_tail(&cqr->devlist, &freeze_queue);
+       }
+
+       spin_unlock_irq(get_ccwdev_lock(cdev));
+
+       list_for_each_entry_safe(cqr, n, &freeze_queue, devlist) {
+               wait_event(dasd_flush_wq,
+                          (cqr->status != DASD_CQR_CLEAR_PENDING));
+               if (cqr->status == DASD_CQR_CLEARED)
+                       cqr->status = DASD_CQR_QUEUED;
+       }
+       /* move freeze_queue to start of the ccw_queue */
+       spin_lock_irq(get_ccwdev_lock(cdev));
+       list_splice_tail(&freeze_queue, &device->ccw_queue);
+       spin_unlock_irq(get_ccwdev_lock(cdev));
+
+       if (device->discipline->freeze)
+               rc = device->discipline->freeze(device);
+
+       dasd_put_device(device);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(dasd_generic_pm_freeze);
+
+int dasd_generic_restore_device(struct ccw_device *cdev)
+{
+       struct dasd_device *device = dasd_device_from_cdev(cdev);
+       int rc = 0;
+
+       if (IS_ERR(device))
+               return PTR_ERR(device);
+
+       dasd_schedule_device_bh(device);
+       if (device->block)
+               dasd_schedule_block_bh(device->block);
+
+       if (device->discipline->restore)
+               rc = device->discipline->restore(device);
+
+       dasd_put_device(device);
+       return rc;
+}
+EXPORT_SYMBOL_GPL(dasd_generic_restore_device);
+
 static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,
                                                   void *rdc_buffer,
                                                   int rdc_buffer_size,
index e77666c8e6c01af8df79963215c686112b8a2a42..4cac5b54f26a6fff837c17983d4fe79a05811af5 100644 (file)
@@ -1098,6 +1098,7 @@ dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid)
        spin_unlock(&dasd_devmap_lock);
        return 0;
 }
+EXPORT_SYMBOL_GPL(dasd_get_uid);
 
 /*
  * Register the given device unique identifier into devmap struct.
index cf0cfdba1244bb95891955820f6e873b24bdb6c7..1c28ec3e4ccb63bb554563c292173d19faa2efa6 100644 (file)
@@ -5,10 +5,9 @@
  *                 Carsten Otte <Cotte@de.ibm.com>
  *                 Martin Schwidefsky <schwidefsky@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+ * Copyright IBM Corp. 1999, 2009
  * EMC Symmetrix ioctl Copyright EMC Corporation, 2008
  * Author.........: Nigel Hislop <hislop_nigel@emc.com>
- *
  */
 
 #define KMSG_COMPONENT "dasd"
@@ -104,17 +103,6 @@ dasd_eckd_set_online(struct ccw_device *cdev)
        return dasd_generic_set_online(cdev, &dasd_eckd_discipline);
 }
 
-static struct ccw_driver dasd_eckd_driver = {
-       .name        = "dasd-eckd",
-       .owner       = THIS_MODULE,
-       .ids         = dasd_eckd_ids,
-       .probe       = dasd_eckd_probe,
-       .remove      = dasd_generic_remove,
-       .set_offline = dasd_generic_set_offline,
-       .set_online  = dasd_eckd_set_online,
-       .notify      = dasd_generic_notify,
-};
-
 static const int sizes_trk0[] = { 28, 148, 84 };
 #define LABEL_SIZE 140
 
@@ -3236,6 +3224,98 @@ static void dasd_eckd_dump_sense(struct dasd_device *device,
                dasd_eckd_dump_sense_ccw(device, req, irb);
 }
 
+int dasd_eckd_pm_freeze(struct dasd_device *device)
+{
+       /*
+        * the device should be disconnected from our LCU structure
+        * on restore we will reconnect it and reread LCU specific
+        * information like PAV support that might have changed
+        */
+       dasd_alias_remove_device(device);
+       dasd_alias_disconnect_device_from_lcu(device);
+
+       return 0;
+}
+
+int dasd_eckd_restore_device(struct dasd_device *device)
+{
+       struct dasd_eckd_private *private;
+       int is_known, rc;
+       struct dasd_uid temp_uid;
+
+       /* allow new IO again */
+       device->stopped &= ~DASD_STOPPED_PM;
+
+       private = (struct dasd_eckd_private *) device->private;
+
+       /* Read Configuration Data */
+       rc = dasd_eckd_read_conf(device);
+       if (rc)
+               goto out_err;
+
+       /* Generate device unique id and register in devmap */
+       rc = dasd_eckd_generate_uid(device, &private->uid);
+       dasd_get_uid(device->cdev, &temp_uid);
+       if (memcmp(&private->uid, &temp_uid, sizeof(struct dasd_uid)) != 0)
+               dev_err(&device->cdev->dev, "The UID of the DASD has changed\n");
+       if (rc)
+               goto out_err;
+       dasd_set_uid(device->cdev, &private->uid);
+
+       /* register lcu with alias handling, enable PAV if this is a new lcu */
+       is_known = dasd_alias_make_device_known_to_lcu(device);
+       if (is_known < 0)
+               return is_known;
+       if (!is_known) {
+               /* new lcu found */
+               rc = dasd_eckd_validate_server(device); /* will switch pav on */
+               if (rc)
+                       goto out_err;
+       }
+
+       /* Read Feature Codes */
+       rc = dasd_eckd_read_features(device);
+       if (rc)
+               goto out_err;
+
+       /* Read Device Characteristics */
+       memset(&private->rdc_data, 0, sizeof(private->rdc_data));
+       rc = dasd_generic_read_dev_chars(device, "ECKD",
+                                        &private->rdc_data, 64);
+       if (rc) {
+               DBF_EVENT(DBF_WARNING,
+                         "Read device characteristics failed, rc=%d for "
+                         "device: %s", rc, dev_name(&device->cdev->dev));
+               goto out_err;
+       }
+
+       /* add device to alias management */
+       dasd_alias_add_device(device);
+
+       return 0;
+
+out_err:
+       /*
+        * if the resume failed for the DASD we put it in
+        * an UNRESUMED stop state
+        */
+       device->stopped |= DASD_UNRESUMED_PM;
+       return 0;
+}
+
+static struct ccw_driver dasd_eckd_driver = {
+       .name        = "dasd-eckd",
+       .owner       = THIS_MODULE,
+       .ids         = dasd_eckd_ids,
+       .probe       = dasd_eckd_probe,
+       .remove      = dasd_generic_remove,
+       .set_offline = dasd_generic_set_offline,
+       .set_online  = dasd_eckd_set_online,
+       .notify      = dasd_generic_notify,
+       .freeze      = dasd_generic_pm_freeze,
+       .thaw        = dasd_generic_restore_device,
+       .restore     = dasd_generic_restore_device,
+};
 
 /*
  * max_blocks is dependent on the amount of storage that is available
@@ -3274,6 +3354,8 @@ static struct dasd_discipline dasd_eckd_discipline = {
        .dump_sense_dbf = dasd_eckd_dump_sense_dbf,
        .fill_info = dasd_eckd_fill_info,
        .ioctl = dasd_eckd_ioctl,
+       .freeze = dasd_eckd_pm_freeze,
+       .restore = dasd_eckd_restore_device,
 };
 
 static int __init
index 597c6ffdb9f2308258a292a0b584f440f9c0ec6a..e21ee735f92673c4df91fb91a4c788f0b1d97b46 100644 (file)
@@ -2,8 +2,7 @@
  * File...........: linux/drivers/s390/block/dasd_fba.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
- *
+ * Copyright IBM Corp. 1999, 2009
  */
 
 #define KMSG_COMPONENT "dasd"
@@ -75,6 +74,9 @@ static struct ccw_driver dasd_fba_driver = {
        .set_offline = dasd_generic_set_offline,
        .set_online  = dasd_fba_set_online,
        .notify      = dasd_generic_notify,
+       .freeze      = dasd_generic_pm_freeze,
+       .thaw        = dasd_generic_restore_device,
+       .restore     = dasd_generic_restore_device,
 };
 
 static void
index f97ceb795078ee9c1cb0df2bba09c0755575dc9f..fd63b2f2bda9baeaefb4e0edefb2bd2407c4c913 100644 (file)
@@ -4,8 +4,7 @@
  *                 Horst Hummel <Horst.Hummel@de.ibm.com>
  *                 Martin Schwidefsky <schwidefsky@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
- *
+ * Copyright IBM Corp. 1999, 2009
  */
 
 #ifndef DASD_INT_H
@@ -295,6 +294,10 @@ struct dasd_discipline {
        int (*fill_geometry) (struct dasd_block *, struct hd_geometry *);
        int (*fill_info) (struct dasd_device *, struct dasd_information2_t *);
        int (*ioctl) (struct dasd_block *, unsigned int, void __user *);
+
+       /* suspend/resume functions */
+       int (*freeze) (struct dasd_device *);
+       int (*restore) (struct dasd_device *);
 };
 
 extern struct dasd_discipline *dasd_diag_discipline_pointer;
@@ -367,6 +370,7 @@ struct dasd_device {
        atomic_t tasklet_scheduled;
         struct tasklet_struct tasklet;
        struct work_struct kick_work;
+       struct work_struct restore_device;
        struct timer_list timer;
 
        debug_info_t *debug_area;
@@ -410,6 +414,8 @@ struct dasd_block {
 #define DASD_STOPPED_PENDING 4         /* long busy */
 #define DASD_STOPPED_DC_WAIT 8         /* disconnected, wait */
 #define DASD_STOPPED_SU      16        /* summary unit check handling */
+#define DASD_STOPPED_PM      32        /* pm state transition */
+#define DASD_UNRESUMED_PM    64        /* pm resume failed state */
 
 /* per device flags */
 #define DASD_FLAG_OFFLINE      3       /* device is in offline processing */
@@ -556,6 +562,7 @@ void dasd_free_block(struct dasd_block *);
 void dasd_enable_device(struct dasd_device *);
 void dasd_set_target_state(struct dasd_device *, int);
 void dasd_kick_device(struct dasd_device *);
+void dasd_restore_device(struct dasd_device *);
 
 void dasd_add_request_head(struct dasd_ccw_req *);
 void dasd_add_request_tail(struct dasd_ccw_req *);
@@ -578,6 +585,8 @@ int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *);
 int dasd_generic_set_offline (struct ccw_device *cdev);
 int dasd_generic_notify(struct ccw_device *, int);
 void dasd_generic_handle_state_change(struct dasd_device *);
+int dasd_generic_pm_freeze(struct ccw_device *);
+int dasd_generic_restore_device(struct ccw_device *);
 
 int dasd_generic_read_dev_chars(struct dasd_device *, char *, void *, int);
 char *dasd_get_sense(struct irb *);
index b21caf177e370ef929f637c0f289b96a0db713db..016f9e9d259186e14351168b682b168fb25ab58b 100644 (file)
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/blkdev.h>
-#include <asm/extmem.h>
-#include <asm/io.h>
 #include <linux/completion.h>
 #include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <asm/extmem.h>
+#include <asm/io.h>
 
 #define DCSSBLK_NAME "dcssblk"
 #define DCSSBLK_MINORS_PER_DISK 1
@@ -939,12 +940,95 @@ dcssblk_check_params(void)
        }
 }
 
+/*
+ * Suspend / Resume
+ */
+static int dcssblk_freeze(struct device *dev)
+{
+       struct dcssblk_dev_info *dev_info;
+       int rc = 0;
+
+       list_for_each_entry(dev_info, &dcssblk_devices, lh) {
+               switch (dev_info->segment_type) {
+                       case SEG_TYPE_SR:
+                       case SEG_TYPE_ER:
+                       case SEG_TYPE_SC:
+                               if (!dev_info->is_shared)
+                                       rc = -EINVAL;
+                               break;
+                       default:
+                               rc = -EINVAL;
+                               break;
+               }
+               if (rc)
+                       break;
+       }
+       if (rc)
+               pr_err("Suspend failed because device %s is writeable.\n",
+                      dev_info->segment_name);
+       return rc;
+}
+
+static int dcssblk_restore(struct device *dev)
+{
+       struct dcssblk_dev_info *dev_info;
+       struct segment_info *entry;
+       unsigned long start, end;
+       int rc = 0;
+
+       list_for_each_entry(dev_info, &dcssblk_devices, lh) {
+               list_for_each_entry(entry, &dev_info->seg_list, lh) {
+                       segment_unload(entry->segment_name);
+                       rc = segment_load(entry->segment_name, SEGMENT_SHARED,
+                                         &start, &end);
+                       if (rc < 0) {
+// TODO in_use check ?
+                               segment_warning(rc, entry->segment_name);
+                               goto out_panic;
+                       }
+                       if (start != entry->start || end != entry->end) {
+                               pr_err("Mismatch of start / end address after "
+                                      "resuming device %s\n",
+                                      entry->segment_name);
+                               goto out_panic;
+                       }
+               }
+       }
+       return 0;
+out_panic:
+       panic("fatal dcssblk resume error\n");
+}
+
+static int dcssblk_thaw(struct device *dev)
+{
+       return 0;
+}
+
+static struct dev_pm_ops dcssblk_pm_ops = {
+       .freeze         = dcssblk_freeze,
+       .thaw           = dcssblk_thaw,
+       .restore        = dcssblk_restore,
+};
+
+static struct platform_driver dcssblk_pdrv = {
+       .driver = {
+               .name   = "dcssblk",
+               .owner  = THIS_MODULE,
+               .pm     = &dcssblk_pm_ops,
+       },
+};
+
+static struct platform_device *dcssblk_pdev;
+
+
 /*
  * The init/exit functions.
  */
 static void __exit
 dcssblk_exit(void)
 {
+       platform_device_unregister(dcssblk_pdev);
+       platform_driver_unregister(&dcssblk_pdrv);
        root_device_unregister(dcssblk_root_dev);
        unregister_blkdev(dcssblk_major, DCSSBLK_NAME);
 }
@@ -954,30 +1038,44 @@ dcssblk_init(void)
 {
        int rc;
 
-       dcssblk_root_dev = root_device_register("dcssblk");
-       if (IS_ERR(dcssblk_root_dev))
-               return PTR_ERR(dcssblk_root_dev);
-       rc = device_create_file(dcssblk_root_dev, &dev_attr_add);
-       if (rc) {
-               root_device_unregister(dcssblk_root_dev);
+       rc = platform_driver_register(&dcssblk_pdrv);
+       if (rc)
                return rc;
+
+       dcssblk_pdev = platform_device_register_simple("dcssblk", -1, NULL,
+                                                       0);
+       if (IS_ERR(dcssblk_pdev)) {
+               rc = PTR_ERR(dcssblk_pdev);
+               goto out_pdrv;
        }
-       rc = device_create_file(dcssblk_root_dev, &dev_attr_remove);
-       if (rc) {
-               root_device_unregister(dcssblk_root_dev);
-               return rc;
+
+       dcssblk_root_dev = root_device_register("dcssblk");
+       if (IS_ERR(dcssblk_root_dev)) {
+               rc = PTR_ERR(dcssblk_root_dev);
+               goto out_pdev;
        }
+       rc = device_create_file(dcssblk_root_dev, &dev_attr_add);
+       if (rc)
+               goto out_root;
+       rc = device_create_file(dcssblk_root_dev, &dev_attr_remove);
+       if (rc)
+               goto out_root;
        rc = register_blkdev(0, DCSSBLK_NAME);
-       if (rc < 0) {
-               root_device_unregister(dcssblk_root_dev);
-               return rc;
-       }
+       if (rc < 0)
+               goto out_root;
        dcssblk_major = rc;
        init_rwsem(&dcssblk_devices_sem);
 
        dcssblk_check_params();
-
        return 0;
+
+out_root:
+       root_device_unregister(dcssblk_root_dev);
+out_pdev:
+       platform_device_unregister(dcssblk_pdev);
+out_pdrv:
+       platform_driver_unregister(&dcssblk_pdrv);
+       return rc;
 }
 
 module_init(dcssblk_init);
index 0ae0c83ef87903e9121b76e14ae372dd2e40b8d1..2e9e1ecd6d82b2d1f03181d4237d04ff37dedab6 100644 (file)
 #include <linux/hdreg.h>  /* HDIO_GETGEO */
 #include <linux/sysdev.h>
 #include <linux/bio.h>
+#include <linux/suspend.h>
+#include <linux/platform_device.h>
 #include <asm/uaccess.h>
+#include <asm/checksum.h>
 
 #define XPRAM_NAME     "xpram"
 #define XPRAM_DEVS     1       /* one partition */
@@ -48,6 +51,7 @@
 typedef struct {
        unsigned int    size;           /* size of xpram segment in pages */
        unsigned int    offset;         /* start page of xpram segment */
+       unsigned int    csum;           /* partition checksum for suspend */
 } xpram_device_t;
 
 static xpram_device_t xpram_devices[XPRAM_MAX_DEVS];
@@ -138,7 +142,7 @@ static long xpram_page_out (unsigned long page_addr, unsigned int xpage_index)
 /*
  * Check if xpram is available.
  */
-static int __init xpram_present(void)
+static int xpram_present(void)
 {
        unsigned long mem_page;
        int rc;
@@ -154,7 +158,7 @@ static int __init xpram_present(void)
 /*
  * Return index of the last available xpram page.
  */
-static unsigned long __init xpram_highest_page_index(void)
+static unsigned long xpram_highest_page_index(void)
 {
        unsigned int page_index, add_bit;
        unsigned long mem_page;
@@ -382,6 +386,106 @@ out:
        return rc;
 }
 
+/*
+ * Save checksums for all partitions.
+ */
+static int xpram_save_checksums(void)
+{
+       unsigned long mem_page;
+       int rc, i;
+
+       rc = 0;
+       mem_page = (unsigned long) __get_free_page(GFP_KERNEL);
+       if (!mem_page)
+               return -ENOMEM;
+       for (i = 0; i < xpram_devs; i++) {
+               rc = xpram_page_in(mem_page, xpram_devices[i].offset);
+               if (rc)
+                       goto fail;
+               xpram_devices[i].csum = csum_partial((const void *) mem_page,
+                                                    PAGE_SIZE, 0);
+       }
+fail:
+       free_page(mem_page);
+       return rc ? -ENXIO : 0;
+}
+
+/*
+ * Verify checksums for all partitions.
+ */
+static int xpram_validate_checksums(void)
+{
+       unsigned long mem_page;
+       unsigned int csum;
+       int rc, i;
+
+       rc = 0;
+       mem_page = (unsigned long) __get_free_page(GFP_KERNEL);
+       if (!mem_page)
+               return -ENOMEM;
+       for (i = 0; i < xpram_devs; i++) {
+               rc = xpram_page_in(mem_page, xpram_devices[i].offset);
+               if (rc)
+                       goto fail;
+               csum = csum_partial((const void *) mem_page, PAGE_SIZE, 0);
+               if (xpram_devices[i].csum != csum) {
+                       rc = -EINVAL;
+                       goto fail;
+               }
+       }
+fail:
+       free_page(mem_page);
+       return rc ? -ENXIO : 0;
+}
+
+/*
+ * Resume failed: Print error message and call panic.
+ */
+static void xpram_resume_error(const char *message)
+{
+       pr_err("Resume error: %s\n", message);
+       panic("xpram resume error\n");
+}
+
+/*
+ * Check if xpram setup changed between suspend and resume.
+ */
+static int xpram_restore(struct device *dev)
+{
+       if (!xpram_pages)
+               return 0;
+       if (xpram_present() != 0)
+               xpram_resume_error("xpram disappeared");
+       if (xpram_pages != xpram_highest_page_index() + 1)
+               xpram_resume_error("Size of xpram changed");
+       if (xpram_validate_checksums())
+               xpram_resume_error("Data of xpram changed");
+       return 0;
+}
+
+/*
+ * Save necessary state in suspend.
+ */
+static int xpram_freeze(struct device *dev)
+{
+       return xpram_save_checksums();
+}
+
+static struct dev_pm_ops xpram_pm_ops = {
+       .freeze         = xpram_freeze,
+       .restore        = xpram_restore,
+};
+
+static struct platform_driver xpram_pdrv = {
+       .driver = {
+               .name   = XPRAM_NAME,
+               .owner  = THIS_MODULE,
+               .pm     = &xpram_pm_ops,
+       },
+};
+
+static struct platform_device *xpram_pdev;
+
 /*
  * Finally, the init/exit functions.
  */
@@ -394,6 +498,8 @@ static void __exit xpram_exit(void)
                put_disk(xpram_disks[i]);
        }
        unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME);
+       platform_device_unregister(xpram_pdev);
+       platform_driver_unregister(&xpram_pdrv);
 }
 
 static int __init xpram_init(void)
@@ -411,7 +517,24 @@ static int __init xpram_init(void)
        rc = xpram_setup_sizes(xpram_pages);
        if (rc)
                return rc;
-       return xpram_setup_blkdev();
+       rc = platform_driver_register(&xpram_pdrv);
+       if (rc)
+               return rc;
+       xpram_pdev = platform_device_register_simple(XPRAM_NAME, -1, NULL, 0);
+       if (IS_ERR(xpram_pdev)) {
+               rc = PTR_ERR(xpram_pdev);
+               goto fail_platform_driver_unregister;
+       }
+       rc = xpram_setup_blkdev();
+       if (rc)
+               goto fail_platform_device_unregister;
+       return 0;
+
+fail_platform_device_unregister:
+       platform_device_unregister(xpram_pdev);
+fail_platform_driver_unregister:
+       platform_driver_unregister(&xpram_pdrv);
+       return rc;
 }
 
 module_init(xpram_init);
index 9ab06e0dad408abdc2b5f66b33b559ec8ec23000..04dc734805c61418353e2b68802a6621121c3317 100644 (file)
@@ -1,14 +1,12 @@
 /*
- *  drivers/s390/char/con3215.c
- *    3215 line mode terminal driver.
+ * 3215 line mode terminal driver.
  *
- *  S390 version
- *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ * Copyright IBM Corp. 1999, 2009
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
  *
- *  Updated:
- *   Aug-2000: Added tab support
- *            Dan Morrison, IBM Corporation (dmorriso@cse.buffalo.edu)
+ * Updated:
+ *  Aug-2000: Added tab support
+ *           Dan Morrison, IBM Corporation <dmorriso@cse.buffalo.edu>
  */
 
 #include <linux/module.h>
@@ -56,6 +54,7 @@
 #define RAW3215_CLOSING            32        /* set while in close process */
 #define RAW3215_TIMER_RUNS  64       /* set if the output delay timer is on */
 #define RAW3215_FLUSHING    128              /* set to flush buffer (no delay) */
+#define RAW3215_FROZEN     256       /* set if 3215 is frozen for suspend */
 
 #define TAB_STOP_SIZE      8         /* tab stop size */
 
@@ -111,8 +110,8 @@ static struct tty_driver *tty3215_driver;
 /*
  * Get a request structure from the free list
  */
-static inline struct raw3215_req *
-raw3215_alloc_req(void) {
+static inline struct raw3215_req *raw3215_alloc_req(void)
+{
        struct raw3215_req *req;
        unsigned long flags;
 
@@ -126,8 +125,8 @@ raw3215_alloc_req(void) {
 /*
  * Put a request structure back to the free list
  */
-static inline void
-raw3215_free_req(struct raw3215_req *req) {
+static inline void raw3215_free_req(struct raw3215_req *req)
+{
        unsigned long flags;
 
        if (req->type == RAW3215_FREE)
@@ -145,8 +144,7 @@ raw3215_free_req(struct raw3215_req *req) {
  * because a 3215 terminal won't accept a new read before the old one is
  * completed.
  */
-static void
-raw3215_mk_read_req(struct raw3215_info *raw)
+static void raw3215_mk_read_req(struct raw3215_info *raw)
 {
        struct raw3215_req *req;
        struct ccw1 *ccw;
@@ -174,8 +172,7 @@ raw3215_mk_read_req(struct raw3215_info *raw)
  * buffer to the 3215 device. If a queued write exists it is replaced by
  * the new, probably lengthened request.
  */
-static void
-raw3215_mk_write_req(struct raw3215_info *raw)
+static void raw3215_mk_write_req(struct raw3215_info *raw)
 {
        struct raw3215_req *req;
        struct ccw1 *ccw;
@@ -251,8 +248,7 @@ raw3215_mk_write_req(struct raw3215_info *raw)
 /*
  * Start a read or a write request
  */
-static void
-raw3215_start_io(struct raw3215_info *raw)
+static void raw3215_start_io(struct raw3215_info *raw)
 {
        struct raw3215_req *req;
        int res;
@@ -290,8 +286,7 @@ raw3215_start_io(struct raw3215_info *raw)
 /*
  * Function to start a delayed output after RAW3215_TIMEOUT seconds
  */
-static void
-raw3215_timeout(unsigned long __data)
+static void raw3215_timeout(unsigned long __data)
 {
        struct raw3215_info *raw = (struct raw3215_info *) __data;
        unsigned long flags;
@@ -300,8 +295,10 @@ raw3215_timeout(unsigned long __data)
        if (raw->flags & RAW3215_TIMER_RUNS) {
                del_timer(&raw->timer);
                raw->flags &= ~RAW3215_TIMER_RUNS;
-               raw3215_mk_write_req(raw);
-               raw3215_start_io(raw);
+               if (!(raw->flags & RAW3215_FROZEN)) {
+                       raw3215_mk_write_req(raw);
+                       raw3215_start_io(raw);
+               }
        }
        spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
 }
@@ -312,10 +309,9 @@ raw3215_timeout(unsigned long __data)
  * amount of data is bigger than RAW3215_MIN_WRITE. If a write is not
  * done immediately a timer is started with a delay of RAW3215_TIMEOUT.
  */
-static inline void
-raw3215_try_io(struct raw3215_info *raw)
+static inline void raw3215_try_io(struct raw3215_info *raw)
 {
-       if (!(raw->flags & RAW3215_ACTIVE))
+       if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FROZEN))
                return;
        if (raw->queued_read != NULL)
                raw3215_start_io(raw);
@@ -359,8 +355,8 @@ static void raw3215_next_io(struct raw3215_info *raw)
 /*
  * Interrupt routine, called from common io layer
  */
-static void
-raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
+static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
+                       struct irb *irb)
 {
        struct raw3215_info *raw;
        struct raw3215_req *req;
@@ -368,7 +364,7 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
        int cstat, dstat;
        int count;
 
-       raw = cdev->dev.driver_data;
+       raw = dev_get_drvdata(&cdev->dev);
        req = (struct raw3215_req *) intparm;
        cstat = irb->scsw.cmd.cstat;
        dstat = irb->scsw.cmd.dstat;
@@ -458,15 +454,41 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
        return;
 }
 
+/*
+ * Drop the oldest line from the output buffer.
+ */
+static void raw3215_drop_line(struct raw3215_info *raw)
+{
+       int ix;
+       char ch;
+
+       BUG_ON(raw->written != 0);
+       ix = (raw->head - raw->count) & (RAW3215_BUFFER_SIZE - 1);
+       while (raw->count > 0) {
+               ch = raw->buffer[ix];
+               ix = (ix + 1) & (RAW3215_BUFFER_SIZE - 1);
+               raw->count--;
+               if (ch == 0x15)
+                       break;
+       }
+       raw->head = ix;
+}
+
 /*
  * Wait until length bytes are available int the output buffer.
  * Has to be called with the s390irq lock held. Can be called
  * disabled.
  */
-static void
-raw3215_make_room(struct raw3215_info *raw, unsigned int length)
+static void raw3215_make_room(struct raw3215_info *raw, unsigned int length)
 {
        while (RAW3215_BUFFER_SIZE - raw->count < length) {
+               /* While console is frozen for suspend we have no other
+                * choice but to drop message from the buffer to make
+                * room for even more messages. */
+               if (raw->flags & RAW3215_FROZEN) {
+                       raw3215_drop_line(raw);
+                       continue;
+               }
                /* there might be a request pending */
                raw->flags |= RAW3215_FLUSHING;
                raw3215_mk_write_req(raw);
@@ -488,8 +510,8 @@ raw3215_make_room(struct raw3215_info *raw, unsigned int length)
 /*
  * String write routine for 3215 devices
  */
-static void
-raw3215_write(struct raw3215_info *raw, const char *str, unsigned int length)
+static void raw3215_write(struct raw3215_info *raw, const char *str,
+                         unsigned int length)
 {
        unsigned long flags;
        int c, count;
@@ -529,8 +551,7 @@ raw3215_write(struct raw3215_info *raw, const char *str, unsigned int length)
 /*
  * Put character routine for 3215 devices
  */
-static void
-raw3215_putchar(struct raw3215_info *raw, unsigned char ch)
+static void raw3215_putchar(struct raw3215_info *raw, unsigned char ch)
 {
        unsigned long flags;
        unsigned int length, i;
@@ -566,8 +587,7 @@ raw3215_putchar(struct raw3215_info *raw, unsigned char ch)
  * Flush routine, it simply sets the flush flag and tries to start
  * pending IO.
  */
-static void
-raw3215_flush_buffer(struct raw3215_info *raw)
+static void raw3215_flush_buffer(struct raw3215_info *raw)
 {
        unsigned long flags;
 
@@ -583,8 +603,7 @@ raw3215_flush_buffer(struct raw3215_info *raw)
 /*
  * Fire up a 3215 device.
  */
-static int
-raw3215_startup(struct raw3215_info *raw)
+static int raw3215_startup(struct raw3215_info *raw)
 {
        unsigned long flags;
 
@@ -602,8 +621,7 @@ raw3215_startup(struct raw3215_info *raw)
 /*
  * Shutdown a 3215 device.
  */
-static void
-raw3215_shutdown(struct raw3215_info *raw)
+static void raw3215_shutdown(struct raw3215_info *raw)
 {
        DECLARE_WAITQUEUE(wait, current);
        unsigned long flags;
@@ -628,14 +646,13 @@ raw3215_shutdown(struct raw3215_info *raw)
        spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
 }
 
-static int
-raw3215_probe (struct ccw_device *cdev)
+static int raw3215_probe (struct ccw_device *cdev)
 {
        struct raw3215_info *raw;
        int line;
 
        /* Console is special. */
-       if (raw3215[0] && (cdev->dev.driver_data == raw3215[0]))
+       if (raw3215[0] && (raw3215[0] == dev_get_drvdata(&cdev->dev)))
                return 0;
        raw = kmalloc(sizeof(struct raw3215_info) +
                      RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA);
@@ -669,44 +686,41 @@ raw3215_probe (struct ccw_device *cdev)
        }
        init_waitqueue_head(&raw->empty_wait);
 
-       cdev->dev.driver_data = raw;
+       dev_set_drvdata(&cdev->dev, raw);
        cdev->handler = raw3215_irq;
 
        return 0;
 }
 
-static void
-raw3215_remove (struct ccw_device *cdev)
+static void raw3215_remove (struct ccw_device *cdev)
 {
        struct raw3215_info *raw;
 
        ccw_device_set_offline(cdev);
-       raw = cdev->dev.driver_data;
+       raw = dev_get_drvdata(&cdev->dev);
        if (raw) {
-               cdev->dev.driver_data = NULL;
+               dev_set_drvdata(&cdev->dev, NULL);
                kfree(raw->buffer);
                kfree(raw);
        }
 }
 
-static int
-raw3215_set_online (struct ccw_device *cdev)
+static int raw3215_set_online (struct ccw_device *cdev)
 {
        struct raw3215_info *raw;
 
-       raw = cdev->dev.driver_data;
+       raw = dev_get_drvdata(&cdev->dev);
        if (!raw)
                return -ENODEV;
 
        return raw3215_startup(raw);
 }
 
-static int
-raw3215_set_offline (struct ccw_device *cdev)
+static int raw3215_set_offline (struct ccw_device *cdev)
 {
        struct raw3215_info *raw;
 
-       raw = cdev->dev.driver_data;
+       raw = dev_get_drvdata(&cdev->dev);
        if (!raw)
                return -ENODEV;
 
@@ -715,6 +729,36 @@ raw3215_set_offline (struct ccw_device *cdev)
        return 0;
 }
 
+static int raw3215_pm_stop(struct ccw_device *cdev)
+{
+       struct raw3215_info *raw;
+       unsigned long flags;
+
+       /* Empty the output buffer, then prevent new I/O. */
+       raw = cdev->dev.driver_data;
+       spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
+       raw3215_make_room(raw, RAW3215_BUFFER_SIZE);
+       raw->flags |= RAW3215_FROZEN;
+       spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
+       return 0;
+}
+
+static int raw3215_pm_start(struct ccw_device *cdev)
+{
+       struct raw3215_info *raw;
+       unsigned long flags;
+
+       /* Allow I/O again and flush output buffer. */
+       raw = cdev->dev.driver_data;
+       spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
+       raw->flags &= ~RAW3215_FROZEN;
+       raw->flags |= RAW3215_FLUSHING;
+       raw3215_try_io(raw);
+       raw->flags &= ~RAW3215_FLUSHING;
+       spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
+       return 0;
+}
+
 static struct ccw_device_id raw3215_id[] = {
        { CCW_DEVICE(0x3215, 0) },
        { /* end of list */ },
@@ -728,14 +772,17 @@ static struct ccw_driver raw3215_ccw_driver = {
        .remove         = &raw3215_remove,
        .set_online     = &raw3215_set_online,
        .set_offline    = &raw3215_set_offline,
+       .freeze         = &raw3215_pm_stop,
+       .thaw           = &raw3215_pm_start,
+       .restore        = &raw3215_pm_start,
 };
 
 #ifdef CONFIG_TN3215_CONSOLE
 /*
  * Write a string to the 3215 console
  */
-static void
-con3215_write(struct console *co, const char *str, unsigned int count)
+static void con3215_write(struct console *co, const char *str,
+                         unsigned int count)
 {
        struct raw3215_info *raw;
        int i;
@@ -768,13 +815,17 @@ static struct tty_driver *con3215_device(struct console *c, int *index)
  * panic() calls con3215_flush through a panic_notifier
  * before the system enters a disabled, endless loop.
  */
-static void
-con3215_flush(void)
+static void con3215_flush(void)
 {
        struct raw3215_info *raw;
        unsigned long flags;
 
        raw = raw3215[0];  /* console 3215 is the first one */
+       if (raw->flags & RAW3215_FROZEN)
+               /* The console is still frozen for suspend. */
+               if (ccw_device_force_console())
+                       /* Forcing didn't work, no panic message .. */
+                       return;
        spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
        raw3215_make_room(raw, RAW3215_BUFFER_SIZE);
        spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
@@ -811,8 +862,7 @@ static struct console con3215 = {
  * 3215 console initialization code called from console_init().
  * NOTE: This is called before kmalloc is available.
  */
-static int __init
-con3215_init(void)
+static int __init con3215_init(void)
 {
        struct ccw_device *cdev;
        struct raw3215_info *raw;
@@ -848,7 +898,7 @@ con3215_init(void)
        raw->buffer = (char *) alloc_bootmem_low(RAW3215_BUFFER_SIZE);
        raw->inbuf = (char *) alloc_bootmem_low(RAW3215_INBUF_SIZE);
        raw->cdev = cdev;
-       cdev->dev.driver_data = raw;
+       dev_set_drvdata(&cdev->dev, raw);
        cdev->handler = raw3215_irq;
 
        raw->flags |= RAW3215_FIXED;
@@ -875,8 +925,7 @@ console_initcall(con3215_init);
  *
  * This routine is called whenever a 3215 tty is opened.
  */
-static int
-tty3215_open(struct tty_struct *tty, struct file * filp)
+static int tty3215_open(struct tty_struct *tty, struct file * filp)
 {
        struct raw3215_info *raw;
        int retval, line;
@@ -909,8 +958,7 @@ tty3215_open(struct tty_struct *tty, struct file * filp)
  * This routine is called when the 3215 tty is closed. We wait
  * for the remaining request to be completed. Then we clean up.
  */
-static void
-tty3215_close(struct tty_struct *tty, struct file * filp)
+static void tty3215_close(struct tty_struct *tty, struct file * filp)
 {
        struct raw3215_info *raw;
 
@@ -927,8 +975,7 @@ tty3215_close(struct tty_struct *tty, struct file * filp)
 /*
  * Returns the amount of free space in the output buffer.
  */
-static int
-tty3215_write_room(struct tty_struct *tty)
+static int tty3215_write_room(struct tty_struct *tty)
 {
        struct raw3215_info *raw;
 
@@ -944,9 +991,8 @@ tty3215_write_room(struct tty_struct *tty)
 /*
  * String write routine for 3215 ttys
  */
-static int
-tty3215_write(struct tty_struct * tty,
-             const unsigned char *buf, int count)
+static int tty3215_write(struct tty_struct * tty,
+                        const unsigned char *buf, int count)
 {
        struct raw3215_info *raw;
 
@@ -960,8 +1006,7 @@ tty3215_write(struct tty_struct * tty,
 /*
  * Put character routine for 3215 ttys
  */
-static int
-tty3215_put_char(struct tty_struct *tty, unsigned char ch)
+static int tty3215_put_char(struct tty_struct *tty, unsigned char ch)
 {
        struct raw3215_info *raw;
 
@@ -972,16 +1017,14 @@ tty3215_put_char(struct tty_struct *tty, unsigned char ch)
        return 1;
 }
 
-static void
-tty3215_flush_chars(struct tty_struct *tty)
+static void tty3215_flush_chars(struct tty_struct *tty)
 {
 }
 
 /*
  * Returns the number of characters in the output buffer
  */
-static int
-tty3215_chars_in_buffer(struct tty_struct *tty)
+static int tty3215_chars_in_buffer(struct tty_struct *tty)
 {
        struct raw3215_info *raw;
 
@@ -989,8 +1032,7 @@ tty3215_chars_in_buffer(struct tty_struct *tty)
        return raw->count;
 }
 
-static void
-tty3215_flush_buffer(struct tty_struct *tty)
+static void tty3215_flush_buffer(struct tty_struct *tty)
 {
        struct raw3215_info *raw;
 
@@ -1002,9 +1044,8 @@ tty3215_flush_buffer(struct tty_struct *tty)
 /*
  * Currently we don't have any io controls for 3215 ttys
  */
-static int
-tty3215_ioctl(struct tty_struct *tty, struct file * file,
-             unsigned int cmd, unsigned long arg)
+static int tty3215_ioctl(struct tty_struct *tty, struct file * file,
+                        unsigned int cmd, unsigned long arg)
 {
        if (tty->flags & (1 << TTY_IO_ERROR))
                return -EIO;
@@ -1019,8 +1060,7 @@ tty3215_ioctl(struct tty_struct *tty, struct file * file,
 /*
  * Disable reading from a 3215 tty
  */
-static void
-tty3215_throttle(struct tty_struct * tty)
+static void tty3215_throttle(struct tty_struct * tty)
 {
        struct raw3215_info *raw;
 
@@ -1031,8 +1071,7 @@ tty3215_throttle(struct tty_struct * tty)
 /*
  * Enable reading from a 3215 tty
  */
-static void
-tty3215_unthrottle(struct tty_struct * tty)
+static void tty3215_unthrottle(struct tty_struct * tty)
 {
        struct raw3215_info *raw;
        unsigned long flags;
@@ -1049,8 +1088,7 @@ tty3215_unthrottle(struct tty_struct * tty)
 /*
  * Disable writing to a 3215 tty
  */
-static void
-tty3215_stop(struct tty_struct *tty)
+static void tty3215_stop(struct tty_struct *tty)
 {
        struct raw3215_info *raw;
 
@@ -1061,8 +1099,7 @@ tty3215_stop(struct tty_struct *tty)
 /*
  * Enable writing to a 3215 tty
  */
-static void
-tty3215_start(struct tty_struct *tty)
+static void tty3215_start(struct tty_struct *tty)
 {
        struct raw3215_info *raw;
        unsigned long flags;
@@ -1096,8 +1133,7 @@ static const struct tty_operations tty3215_ops = {
  * 3215 tty registration code called from tty_init().
  * Most kernel services (incl. kmalloc) are available at this poimt.
  */
-static int __init
-tty3215_init(void)
+static int __init tty3215_init(void)
 {
        struct tty_driver *driver;
        int ret;
@@ -1142,8 +1178,7 @@ tty3215_init(void)
        return 0;
 }
 
-static void __exit
-tty3215_exit(void)
+static void __exit tty3215_exit(void)
 {
        tty_unregister_driver(tty3215_driver);
        put_tty_driver(tty3215_driver);
index ed5396dae58eef0edc2eb6f451419737c0b5dfd7..44d02e371c04b89f1d089ecc1b0e3f2881610919 100644 (file)
@@ -1,11 +1,10 @@
 /*
- *  drivers/s390/char/con3270.c
- *    IBM/3270 Driver - console view.
+ * IBM/3270 Driver - console view.
  *
- *  Author(s):
- *    Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
- *    Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com>
- *     -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s):
+ *   Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
+ *   Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *     Copyright IBM Corp. 2003, 2009
  */
 
 #include <linux/bootmem.h>
@@ -530,6 +529,7 @@ con3270_flush(void)
        cp = condev;
        if (!cp->view.dev)
                return;
+       raw3270_pm_unfreeze(&cp->view);
        spin_lock_irqsave(&cp->view.lock, flags);
        con3270_wait_write(cp);
        cp->nr_up = 0;
index 40759c33477d1d38bca2400f034affbf24e3efcc..097d3846a828df50ccd45cc4a063a430695d5959 100644 (file)
@@ -1,11 +1,10 @@
 /*
- *  drivers/s390/char/fs3270.c
- *    IBM/3270 Driver - fullscreen driver.
+ * IBM/3270 Driver - fullscreen driver.
  *
- *  Author(s):
- *    Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
- *    Rewritten for 2.5/2.6 by Martin Schwidefsky <schwidefsky@de.ibm.com>
- *     -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s):
+ *   Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
+ *   Rewritten for 2.5/2.6 by Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *     Copyright IBM Corp. 2003, 2009
  */
 
 #include <linux/bootmem.h>
@@ -399,6 +398,11 @@ fs3270_free_view(struct raw3270_view *view)
 static void
 fs3270_release(struct raw3270_view *view)
 {
+       struct fs3270 *fp;
+
+       fp = (struct fs3270 *) view;
+       if (fp->fs_pid)
+               kill_pid(fp->fs_pid, SIGHUP, 1);
 }
 
 /* View to a 3270 device. Can be console, tty or fullscreen. */
index 97e63cf469443ab594e231a288b856c0cc5d9562..75a8831eebbc78dbf7b5bdd60903c2d9e1226355 100644 (file)
@@ -1,10 +1,9 @@
 /*
- * drivers/s390/char/monreader.c
- *
  * Character device driver for reading z/VM *MONITOR service records.
  *
- *   Copyright IBM Corp. 2004, 2008
- *   Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
+ * Copyright IBM Corp. 2004, 2009
+ *
+ * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com>
  */
 
 #define KMSG_COMPONENT "monreader"
@@ -22,6 +21,7 @@
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/poll.h>
+#include <linux/device.h>
 #include <net/iucv/iucv.h>
 #include <asm/uaccess.h>
 #include <asm/ebcdic.h>
@@ -78,6 +78,7 @@ static u8 user_data_sever[16] = {
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 };
 
+static struct device *monreader_device;
 
 /******************************************************************************
  *                             helper functions                               *
@@ -319,11 +320,12 @@ static int mon_open(struct inode *inode, struct file *filp)
                goto out_path;
        }
        filp->private_data = monpriv;
+       monreader_device->driver_data = monpriv;
        unlock_kernel();
        return nonseekable_open(inode, filp);
 
 out_path:
-       kfree(monpriv->path);
+       iucv_path_free(monpriv->path);
 out_priv:
        mon_free_mem(monpriv);
 out_use:
@@ -341,10 +343,13 @@ static int mon_close(struct inode *inode, struct file *filp)
        /*
         * Close IUCV connection and unregister
         */
-       rc = iucv_path_sever(monpriv->path, user_data_sever);
-       if (rc)
-               pr_warning("Disconnecting the z/VM *MONITOR system service "
-                          "failed with rc=%i\n", rc);
+       if (monpriv->path) {
+               rc = iucv_path_sever(monpriv->path, user_data_sever);
+               if (rc)
+                       pr_warning("Disconnecting the z/VM *MONITOR system "
+                                  "service failed with rc=%i\n", rc);
+               iucv_path_free(monpriv->path);
+       }
 
        atomic_set(&monpriv->iucv_severed, 0);
        atomic_set(&monpriv->iucv_connected, 0);
@@ -452,6 +457,94 @@ static struct miscdevice mon_dev = {
        .minor      = MISC_DYNAMIC_MINOR,
 };
 
+
+/******************************************************************************
+ *                             suspend / resume                              *
+ *****************************************************************************/
+static int monreader_freeze(struct device *dev)
+{
+       struct mon_private *monpriv = dev->driver_data;
+       int rc;
+
+       if (!monpriv)
+               return 0;
+       if (monpriv->path) {
+               rc = iucv_path_sever(monpriv->path, user_data_sever);
+               if (rc)
+                       pr_warning("Disconnecting the z/VM *MONITOR system "
+                                  "service failed with rc=%i\n", rc);
+               iucv_path_free(monpriv->path);
+       }
+       atomic_set(&monpriv->iucv_severed, 0);
+       atomic_set(&monpriv->iucv_connected, 0);
+       atomic_set(&monpriv->read_ready, 0);
+       atomic_set(&monpriv->msglim_count, 0);
+       monpriv->write_index  = 0;
+       monpriv->read_index   = 0;
+       monpriv->path = NULL;
+       return 0;
+}
+
+static int monreader_thaw(struct device *dev)
+{
+       struct mon_private *monpriv = dev->driver_data;
+       int rc;
+
+       if (!monpriv)
+               return 0;
+       rc = -ENOMEM;
+       monpriv->path = iucv_path_alloc(MON_MSGLIM, IUCV_IPRMDATA, GFP_KERNEL);
+       if (!monpriv->path)
+               goto out;
+       rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler,
+                              MON_SERVICE, NULL, user_data_connect, monpriv);
+       if (rc) {
+               pr_err("Connecting to the z/VM *MONITOR system service "
+                      "failed with rc=%i\n", rc);
+               goto out_path;
+       }
+       wait_event(mon_conn_wait_queue,
+                  atomic_read(&monpriv->iucv_connected) ||
+                  atomic_read(&monpriv->iucv_severed));
+       if (atomic_read(&monpriv->iucv_severed))
+               goto out_path;
+       return 0;
+out_path:
+       rc = -EIO;
+       iucv_path_free(monpriv->path);
+       monpriv->path = NULL;
+out:
+       atomic_set(&monpriv->iucv_severed, 1);
+       return rc;
+}
+
+static int monreader_restore(struct device *dev)
+{
+       int rc;
+
+       segment_unload(mon_dcss_name);
+       rc = segment_load(mon_dcss_name, SEGMENT_SHARED,
+                         &mon_dcss_start, &mon_dcss_end);
+       if (rc < 0) {
+               segment_warning(rc, mon_dcss_name);
+               panic("fatal monreader resume error: no monitor dcss\n");
+       }
+       return monreader_thaw(dev);
+}
+
+static struct dev_pm_ops monreader_pm_ops = {
+       .freeze  = monreader_freeze,
+       .thaw    = monreader_thaw,
+       .restore = monreader_restore,
+};
+
+static struct device_driver monreader_driver = {
+       .name = "monreader",
+       .bus  = &iucv_bus,
+       .pm   = &monreader_pm_ops,
+};
+
+
 /******************************************************************************
  *                              module init/exit                              *
  *****************************************************************************/
@@ -475,16 +568,33 @@ static int __init mon_init(void)
                return rc;
        }
 
+       rc = driver_register(&monreader_driver);
+       if (rc)
+               goto out_iucv;
+       monreader_device = kzalloc(sizeof(struct device), GFP_KERNEL);
+       if (!monreader_device)
+               goto out_driver;
+       dev_set_name(monreader_device, "monreader-dev");
+       monreader_device->bus = &iucv_bus;
+       monreader_device->parent = iucv_root;
+       monreader_device->driver = &monreader_driver;
+       monreader_device->release = (void (*)(struct device *))kfree;
+       rc = device_register(monreader_device);
+       if (rc) {
+               kfree(monreader_device);
+               goto out_driver;
+       }
+
        rc = segment_type(mon_dcss_name);
        if (rc < 0) {
                segment_warning(rc, mon_dcss_name);
-               goto out_iucv;
+               goto out_device;
        }
        if (rc != SEG_TYPE_SC) {
                pr_err("The specified *MONITOR DCSS %s does not have the "
                       "required type SC\n", mon_dcss_name);
                rc = -EINVAL;
-               goto out_iucv;
+               goto out_device;
        }
 
        rc = segment_load(mon_dcss_name, SEGMENT_SHARED,
@@ -492,7 +602,7 @@ static int __init mon_init(void)
        if (rc < 0) {
                segment_warning(rc, mon_dcss_name);
                rc = -EINVAL;
-               goto out_iucv;
+               goto out_device;
        }
        dcss_mkname(mon_dcss_name, &user_data_connect[8]);
 
@@ -503,6 +613,10 @@ static int __init mon_init(void)
 
 out:
        segment_unload(mon_dcss_name);
+out_device:
+       device_unregister(monreader_device);
+out_driver:
+       driver_unregister(&monreader_driver);
 out_iucv:
        iucv_unregister(&monreader_iucv_handler, 1);
        return rc;
@@ -512,6 +626,8 @@ static void __exit mon_exit(void)
 {
        segment_unload(mon_dcss_name);
        WARN_ON(misc_deregister(&mon_dev) != 0);
+       device_unregister(monreader_device);
+       driver_unregister(&monreader_driver);
        iucv_unregister(&monreader_iucv_handler, 1);
        return;
 }
index c7d7483bab9ae010fef8e225d3138242aa9a00c7..66fb8eba93f43bfe16d03784dbc21eac52b78f78 100644 (file)
@@ -1,9 +1,7 @@
 /*
- * drivers/s390/char/monwriter.c
- *
  * Character device driver for writing z/VM *MONITOR service records.
  *
- * Copyright (C) IBM Corp. 2006
+ * Copyright IBM Corp. 2006, 2009
  *
  * Author(s): Melissa Howland <Melissa.Howland@us.ibm.com>
  */
@@ -22,6 +20,7 @@
 #include <linux/ctype.h>
 #include <linux/poll.h>
 #include <linux/mutex.h>
+#include <linux/platform_device.h>
 #include <asm/uaccess.h>
 #include <asm/ebcdic.h>
 #include <asm/io.h>
@@ -40,7 +39,10 @@ struct mon_buf {
        char *data;
 };
 
+static LIST_HEAD(mon_priv_list);
+
 struct mon_private {
+       struct list_head priv_list;
        struct list_head list;
        struct monwrite_hdr hdr;
        size_t hdr_to_read;
@@ -188,6 +190,7 @@ static int monwrite_open(struct inode *inode, struct file *filp)
        monpriv->hdr_to_read = sizeof(monpriv->hdr);
        mutex_init(&monpriv->thread_mutex);
        filp->private_data = monpriv;
+       list_add_tail(&monpriv->priv_list, &mon_priv_list);
        unlock_kernel();
        return nonseekable_open(inode, filp);
 }
@@ -206,6 +209,7 @@ static int monwrite_close(struct inode *inode, struct file *filp)
                kfree(entry->data);
                kfree(entry);
        }
+       list_del(&monpriv->priv_list);
        kfree(monpriv);
        return 0;
 }
@@ -280,21 +284,103 @@ static struct miscdevice mon_dev = {
        .minor  = MISC_DYNAMIC_MINOR,
 };
 
+/*
+ * suspend/resume
+ */
+
+static int monwriter_freeze(struct device *dev)
+{
+       struct mon_private *monpriv;
+       struct mon_buf *monbuf;
+
+       list_for_each_entry(monpriv, &mon_priv_list, priv_list) {
+               list_for_each_entry(monbuf, &monpriv->list, list) {
+                       if (monbuf->hdr.mon_function != MONWRITE_GEN_EVENT)
+                               monwrite_diag(&monbuf->hdr, monbuf->data,
+                                             APPLDATA_STOP_REC);
+               }
+       }
+       return 0;
+}
+
+static int monwriter_restore(struct device *dev)
+{
+       struct mon_private *monpriv;
+       struct mon_buf *monbuf;
+
+       list_for_each_entry(monpriv, &mon_priv_list, priv_list) {
+               list_for_each_entry(monbuf, &monpriv->list, list) {
+                       if (monbuf->hdr.mon_function == MONWRITE_START_INTERVAL)
+                               monwrite_diag(&monbuf->hdr, monbuf->data,
+                                             APPLDATA_START_INTERVAL_REC);
+                       if (monbuf->hdr.mon_function == MONWRITE_START_CONFIG)
+                               monwrite_diag(&monbuf->hdr, monbuf->data,
+                                             APPLDATA_START_CONFIG_REC);
+               }
+       }
+       return 0;
+}
+
+static int monwriter_thaw(struct device *dev)
+{
+       return monwriter_restore(dev);
+}
+
+static struct dev_pm_ops monwriter_pm_ops = {
+       .freeze         = monwriter_freeze,
+       .thaw           = monwriter_thaw,
+       .restore        = monwriter_restore,
+};
+
+static struct platform_driver monwriter_pdrv = {
+       .driver = {
+               .name   = "monwriter",
+               .owner  = THIS_MODULE,
+               .pm     = &monwriter_pm_ops,
+       },
+};
+
+static struct platform_device *monwriter_pdev;
+
 /*
  * module init/exit
  */
 
 static int __init mon_init(void)
 {
-       if (MACHINE_IS_VM)
-               return misc_register(&mon_dev);
-       else
+       int rc;
+
+       if (!MACHINE_IS_VM)
                return -ENODEV;
+
+       rc = platform_driver_register(&monwriter_pdrv);
+       if (rc)
+               return rc;
+
+       monwriter_pdev = platform_device_register_simple("monwriter", -1, NULL,
+                                                       0);
+       if (IS_ERR(monwriter_pdev)) {
+               rc = PTR_ERR(monwriter_pdev);
+               goto out_driver;
+       }
+
+       rc = misc_register(&mon_dev);
+       if (rc)
+               goto out_device;
+       return 0;
+
+out_device:
+       platform_device_unregister(monwriter_pdev);
+out_driver:
+       platform_driver_unregister(&monwriter_pdrv);
+       return rc;
 }
 
 static void __exit mon_exit(void)
 {
        WARN_ON(misc_deregister(&mon_dev) != 0);
+       platform_device_unregister(monwriter_pdev);
+       platform_driver_unregister(&monwriter_pdrv);
 }
 
 module_init(mon_init);
index 0b15cf107ec97d9162506d1acc23d678416692a3..acab7b2dfe8ab2a23174487dda6658a1c7d2ac5d 100644 (file)
@@ -1,11 +1,10 @@
 /*
- *  drivers/s390/char/raw3270.c
- *    IBM/3270 Driver - core functions.
+ * IBM/3270 Driver - core functions.
  *
- *  Author(s):
- *    Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
- *    Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com>
- *     -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s):
+ *   Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
+ *   Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *     Copyright IBM Corp. 2003, 2009
  */
 
 #include <linux/bootmem.h>
@@ -61,6 +60,7 @@ struct raw3270 {
 #define RAW3270_FLAGS_ATTN     2       /* Device sent an ATTN interrupt */
 #define RAW3270_FLAGS_READY    4       /* Device is useable by views */
 #define RAW3270_FLAGS_CONSOLE  8       /* Device is the console. */
+#define RAW3270_FLAGS_FROZEN   16      /* set if 3270 is frozen for suspend */
 
 /* Semaphore to protect global data of raw3270 (devices, views, etc). */
 static DEFINE_MUTEX(raw3270_mutex);
@@ -306,7 +306,8 @@ raw3270_start(struct raw3270_view *view, struct raw3270_request *rq)
 
        spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags);
        rp = view->dev;
-       if (!rp || rp->view != view)
+       if (!rp || rp->view != view ||
+           test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
                rc = -EACCES;
        else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
                rc = -ENODEV;
@@ -323,7 +324,8 @@ raw3270_start_locked(struct raw3270_view *view, struct raw3270_request *rq)
        int rc;
 
        rp = view->dev;
-       if (!rp || rp->view != view)
+       if (!rp || rp->view != view ||
+           test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
                rc = -EACCES;
        else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
                rc = -ENODEV;
@@ -355,7 +357,7 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
        struct raw3270_request *rq;
        int rc;
 
-       rp = (struct raw3270 *) cdev->dev.driver_data;
+       rp = dev_get_drvdata(&cdev->dev);
        if (!rp)
                return;
        rq = (struct raw3270_request *) intparm;
@@ -764,7 +766,8 @@ raw3270_reset(struct raw3270_view *view)
        int rc;
 
        rp = view->dev;
-       if (!rp || rp->view != view)
+       if (!rp || rp->view != view ||
+           test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
                rc = -EACCES;
        else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
                rc = -ENODEV;
@@ -828,7 +831,7 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
        if (rp->minor == -1)
                return -EUSERS;
        rp->cdev = cdev;
-       cdev->dev.driver_data = rp;
+       dev_set_drvdata(&cdev->dev, rp);
        cdev->handler = raw3270_irq;
        return 0;
 }
@@ -922,6 +925,8 @@ raw3270_activate_view(struct raw3270_view *view)
                rc = 0;
        else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
                rc = -ENODEV;
+       else if (test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
+               rc = -EACCES;
        else {
                oldview = NULL;
                if (rp->view) {
@@ -969,7 +974,8 @@ raw3270_deactivate_view(struct raw3270_view *view)
                list_del_init(&view->list);
                list_add_tail(&view->list, &rp->view_list);
                /* Try to activate another view. */
-               if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
+               if (test_bit(RAW3270_FLAGS_READY, &rp->flags) &&
+                   !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) {
                        list_for_each_entry(view, &rp->view_list, list) {
                                rp->view = view;
                                if (view->fn->activate(view) == 0)
@@ -1068,7 +1074,8 @@ raw3270_del_view(struct raw3270_view *view)
                rp->view = NULL;
        }
        list_del_init(&view->list);
-       if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
+       if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags) &&
+           !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) {
                /* Try to activate another view. */
                list_for_each_entry(nv, &rp->view_list, list) {
                        if (nv->fn->activate(nv) == 0) {
@@ -1105,7 +1112,7 @@ raw3270_delete_device(struct raw3270 *rp)
        /* Disconnect from ccw_device. */
        cdev = rp->cdev;
        rp->cdev = NULL;
-       cdev->dev.driver_data = NULL;
+       dev_set_drvdata(&cdev->dev, NULL);
        cdev->handler = NULL;
 
        /* Put ccw_device structure. */
@@ -1129,7 +1136,7 @@ static ssize_t
 raw3270_model_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        return snprintf(buf, PAGE_SIZE, "%i\n",
-                       ((struct raw3270 *) dev->driver_data)->model);
+                       ((struct raw3270 *) dev_get_drvdata(dev))->model);
 }
 static DEVICE_ATTR(model, 0444, raw3270_model_show, NULL);
 
@@ -1137,7 +1144,7 @@ static ssize_t
 raw3270_rows_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        return snprintf(buf, PAGE_SIZE, "%i\n",
-                       ((struct raw3270 *) dev->driver_data)->rows);
+                       ((struct raw3270 *) dev_get_drvdata(dev))->rows);
 }
 static DEVICE_ATTR(rows, 0444, raw3270_rows_show, NULL);
 
@@ -1145,7 +1152,7 @@ static ssize_t
 raw3270_columns_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        return snprintf(buf, PAGE_SIZE, "%i\n",
-                       ((struct raw3270 *) dev->driver_data)->cols);
+                       ((struct raw3270 *) dev_get_drvdata(dev))->cols);
 }
 static DEVICE_ATTR(columns, 0444, raw3270_columns_show, NULL);
 
@@ -1282,7 +1289,7 @@ raw3270_remove (struct ccw_device *cdev)
        struct raw3270_view *v;
        struct raw3270_notifier *np;
 
-       rp = cdev->dev.driver_data;
+       rp = dev_get_drvdata(&cdev->dev);
        /*
         * _remove is the opposite of _probe; it's probe that
         * should set up rp.  raw3270_remove gets entered for
@@ -1330,13 +1337,65 @@ raw3270_set_offline (struct ccw_device *cdev)
 {
        struct raw3270 *rp;
 
-       rp = cdev->dev.driver_data;
+       rp = dev_get_drvdata(&cdev->dev);
        if (test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags))
                return -EBUSY;
        raw3270_remove(cdev);
        return 0;
 }
 
+static int raw3270_pm_stop(struct ccw_device *cdev)
+{
+       struct raw3270 *rp;
+       struct raw3270_view *view;
+       unsigned long flags;
+
+       rp = cdev->dev.driver_data;
+       if (!rp)
+               return 0;
+       spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
+       if (rp->view)
+               rp->view->fn->deactivate(rp->view);
+       if (!test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags)) {
+               /*
+                * Release tty and fullscreen for all non-console
+                * devices.
+                */
+               list_for_each_entry(view, &rp->view_list, list) {
+                       if (view->fn->release)
+                               view->fn->release(view);
+               }
+       }
+       set_bit(RAW3270_FLAGS_FROZEN, &rp->flags);
+       spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
+       return 0;
+}
+
+static int raw3270_pm_start(struct ccw_device *cdev)
+{
+       struct raw3270 *rp;
+       unsigned long flags;
+
+       rp = cdev->dev.driver_data;
+       if (!rp)
+               return 0;
+       spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
+       clear_bit(RAW3270_FLAGS_FROZEN, &rp->flags);
+       if (rp->view)
+               rp->view->fn->activate(rp->view);
+       spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
+       return 0;
+}
+
+void raw3270_pm_unfreeze(struct raw3270_view *view)
+{
+       struct raw3270 *rp;
+
+       rp = view->dev;
+       if (rp && test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
+               ccw_device_force_console();
+}
+
 static struct ccw_device_id raw3270_id[] = {
        { CCW_DEVICE(0x3270, 0) },
        { CCW_DEVICE(0x3271, 0) },
@@ -1360,6 +1419,9 @@ static struct ccw_driver raw3270_ccw_driver = {
        .remove         = &raw3270_remove,
        .set_online     = &raw3270_set_online,
        .set_offline    = &raw3270_set_offline,
+       .freeze         = &raw3270_pm_stop,
+       .thaw           = &raw3270_pm_start,
+       .restore        = &raw3270_pm_start,
 };
 
 static int
index 90beaa80a78229d94368e3e170274158bf2a9f55..ed34eb2199cc3ea4165f095c5c2533866df34d26 100644 (file)
@@ -1,11 +1,10 @@
 /*
- *  drivers/s390/char/raw3270.h
- *    IBM/3270 Driver
+ * IBM/3270 Driver
  *
- *  Author(s):
- *    Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
- *    Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com>
- *     -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s):
+ *   Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
+ *   Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *     Copyright IBM Corp. 2003, 2009
  */
 
 #include <asm/idals.h>
@@ -195,6 +194,7 @@ void raw3270_wait_cons_dev(struct raw3270 *);
 /* Notifier for device addition/removal */
 int raw3270_register_notifier(void (*notifier)(int, int));
 void raw3270_unregister_notifier(void (*notifier)(int, int));
+void raw3270_pm_unfreeze(struct raw3270_view *);
 
 /*
  * Little memory allocator for string objects. 
index 4377e93a43d7f97b7087ed5164967743337fc8a5..a983f50867881643f06ad0b2364fc5b9cbf2bb04 100644 (file)
@@ -1,11 +1,10 @@
 /*
- *  drivers/s390/char/sclp.c
- *     core function to access sclp interface
+ * core function to access sclp interface
  *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
- *              Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Copyright IBM Corp. 1999, 2009
+ *
+ * Author(s): Martin Peschke <mpeschke@de.ibm.com>
+ *           Martin Schwidefsky <schwidefsky@de.ibm.com>
  */
 
 #include <linux/module.h>
@@ -16,6 +15,9 @@
 #include <linux/reboot.h>
 #include <linux/jiffies.h>
 #include <linux/init.h>
+#include <linux/suspend.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
 #include <asm/types.h>
 #include <asm/s390_ext.h>
 
@@ -47,6 +49,16 @@ static struct sclp_req sclp_init_req;
 static char sclp_read_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
 static char sclp_init_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
 
+/* Suspend request */
+static DECLARE_COMPLETION(sclp_request_queue_flushed);
+
+static void sclp_suspend_req_cb(struct sclp_req *req, void *data)
+{
+       complete(&sclp_request_queue_flushed);
+}
+
+static struct sclp_req sclp_suspend_req;
+
 /* Timer for request retries. */
 static struct timer_list sclp_request_timer;
 
@@ -84,6 +96,12 @@ static volatile enum sclp_mask_state_t {
        sclp_mask_state_initializing
 } sclp_mask_state = sclp_mask_state_idle;
 
+/* Internal state: is the driver suspended? */
+static enum sclp_suspend_state_t {
+       sclp_suspend_state_running,
+       sclp_suspend_state_suspended,
+} sclp_suspend_state = sclp_suspend_state_running;
+
 /* Maximum retry counts */
 #define SCLP_INIT_RETRY                3
 #define SCLP_MASK_RETRY                3
@@ -211,6 +229,8 @@ sclp_process_queue(void)
        del_timer(&sclp_request_timer);
        while (!list_empty(&sclp_req_queue)) {
                req = list_entry(sclp_req_queue.next, struct sclp_req, list);
+               if (!req->sccb)
+                       goto do_post;
                rc = __sclp_start_request(req);
                if (rc == 0)
                        break;
@@ -222,6 +242,7 @@ sclp_process_queue(void)
                                                 sclp_request_timeout, 0);
                        break;
                }
+do_post:
                /* Post-processing for aborted request */
                list_del(&req->list);
                if (req->callback) {
@@ -233,6 +254,19 @@ sclp_process_queue(void)
        spin_unlock_irqrestore(&sclp_lock, flags);
 }
 
+static int __sclp_can_add_request(struct sclp_req *req)
+{
+       if (req == &sclp_suspend_req || req == &sclp_init_req)
+               return 1;
+       if (sclp_suspend_state != sclp_suspend_state_running)
+               return 0;
+       if (sclp_init_state != sclp_init_state_initialized)
+               return 0;
+       if (sclp_activation_state != sclp_activation_state_active)
+               return 0;
+       return 1;
+}
+
 /* Queue a new request. Return zero on success, non-zero otherwise. */
 int
 sclp_add_request(struct sclp_req *req)
@@ -241,9 +275,7 @@ sclp_add_request(struct sclp_req *req)
        int rc;
 
        spin_lock_irqsave(&sclp_lock, flags);
-       if ((sclp_init_state != sclp_init_state_initialized ||
-            sclp_activation_state != sclp_activation_state_active) &&
-           req != &sclp_init_req) {
+       if (!__sclp_can_add_request(req)) {
                spin_unlock_irqrestore(&sclp_lock, flags);
                return -EIO;
        }
@@ -254,10 +286,16 @@ sclp_add_request(struct sclp_req *req)
        /* Start if request is first in list */
        if (sclp_running_state == sclp_running_state_idle &&
            req->list.prev == &sclp_req_queue) {
+               if (!req->sccb) {
+                       list_del(&req->list);
+                       rc = -ENODATA;
+                       goto out;
+               }
                rc = __sclp_start_request(req);
                if (rc)
                        list_del(&req->list);
        }
+out:
        spin_unlock_irqrestore(&sclp_lock, flags);
        return rc;
 }
@@ -560,6 +598,7 @@ sclp_register(struct sclp_register *reg)
        /* Trigger initial state change callback */
        reg->sclp_receive_mask = 0;
        reg->sclp_send_mask = 0;
+       reg->pm_event_posted = 0;
        list_add(&reg->list, &sclp_reg_list);
        spin_unlock_irqrestore(&sclp_lock, flags);
        rc = sclp_init_mask(1);
@@ -880,20 +919,134 @@ static struct notifier_block sclp_reboot_notifier = {
        .notifier_call = sclp_reboot_event
 };
 
+/*
+ * Suspend/resume SCLP notifier implementation
+ */
+
+static void sclp_pm_event(enum sclp_pm_event sclp_pm_event, int rollback)
+{
+       struct sclp_register *reg;
+       unsigned long flags;
+
+       if (!rollback) {
+               spin_lock_irqsave(&sclp_lock, flags);
+               list_for_each_entry(reg, &sclp_reg_list, list)
+                       reg->pm_event_posted = 0;
+               spin_unlock_irqrestore(&sclp_lock, flags);
+       }
+       do {
+               spin_lock_irqsave(&sclp_lock, flags);
+               list_for_each_entry(reg, &sclp_reg_list, list) {
+                       if (rollback && reg->pm_event_posted)
+                               goto found;
+                       if (!rollback && !reg->pm_event_posted)
+                               goto found;
+               }
+               spin_unlock_irqrestore(&sclp_lock, flags);
+               return;
+found:
+               spin_unlock_irqrestore(&sclp_lock, flags);
+               if (reg->pm_event_fn)
+                       reg->pm_event_fn(reg, sclp_pm_event);
+               reg->pm_event_posted = rollback ? 0 : 1;
+       } while (1);
+}
+
+/*
+ * Susend/resume callbacks for platform device
+ */
+
+static int sclp_freeze(struct device *dev)
+{
+       unsigned long flags;
+       int rc;
+
+       sclp_pm_event(SCLP_PM_EVENT_FREEZE, 0);
+
+       spin_lock_irqsave(&sclp_lock, flags);
+       sclp_suspend_state = sclp_suspend_state_suspended;
+       spin_unlock_irqrestore(&sclp_lock, flags);
+
+       /* Init supend data */
+       memset(&sclp_suspend_req, 0, sizeof(sclp_suspend_req));
+       sclp_suspend_req.callback = sclp_suspend_req_cb;
+       sclp_suspend_req.status = SCLP_REQ_FILLED;
+       init_completion(&sclp_request_queue_flushed);
+
+       rc = sclp_add_request(&sclp_suspend_req);
+       if (rc == 0)
+               wait_for_completion(&sclp_request_queue_flushed);
+       else if (rc != -ENODATA)
+               goto fail_thaw;
+
+       rc = sclp_deactivate();
+       if (rc)
+               goto fail_thaw;
+       return 0;
+
+fail_thaw:
+       spin_lock_irqsave(&sclp_lock, flags);
+       sclp_suspend_state = sclp_suspend_state_running;
+       spin_unlock_irqrestore(&sclp_lock, flags);
+       sclp_pm_event(SCLP_PM_EVENT_THAW, 1);
+       return rc;
+}
+
+static int sclp_undo_suspend(enum sclp_pm_event event)
+{
+       unsigned long flags;
+       int rc;
+
+       rc = sclp_reactivate();
+       if (rc)
+               return rc;
+
+       spin_lock_irqsave(&sclp_lock, flags);
+       sclp_suspend_state = sclp_suspend_state_running;
+       spin_unlock_irqrestore(&sclp_lock, flags);
+
+       sclp_pm_event(event, 0);
+       return 0;
+}
+
+static int sclp_thaw(struct device *dev)
+{
+       return sclp_undo_suspend(SCLP_PM_EVENT_THAW);
+}
+
+static int sclp_restore(struct device *dev)
+{
+       return sclp_undo_suspend(SCLP_PM_EVENT_RESTORE);
+}
+
+static struct dev_pm_ops sclp_pm_ops = {
+       .freeze         = sclp_freeze,
+       .thaw           = sclp_thaw,
+       .restore        = sclp_restore,
+};
+
+static struct platform_driver sclp_pdrv = {
+       .driver = {
+               .name   = "sclp",
+               .owner  = THIS_MODULE,
+               .pm     = &sclp_pm_ops,
+       },
+};
+
+static struct platform_device *sclp_pdev;
+
 /* Initialize SCLP driver. Return zero if driver is operational, non-zero
  * otherwise. */
 static int
 sclp_init(void)
 {
        unsigned long flags;
-       int rc;
+       int rc = 0;
 
        spin_lock_irqsave(&sclp_lock, flags);
        /* Check for previous or running initialization */
-       if (sclp_init_state != sclp_init_state_uninitialized) {
-               spin_unlock_irqrestore(&sclp_lock, flags);
-               return 0;
-       }
+       if (sclp_init_state != sclp_init_state_uninitialized)
+               goto fail_unlock;
        sclp_init_state = sclp_init_state_initializing;
        /* Set up variables */
        INIT_LIST_HEAD(&sclp_req_queue);
@@ -904,27 +1057,17 @@ sclp_init(void)
        spin_unlock_irqrestore(&sclp_lock, flags);
        rc = sclp_check_interface();
        spin_lock_irqsave(&sclp_lock, flags);
-       if (rc) {
-               sclp_init_state = sclp_init_state_uninitialized;
-               spin_unlock_irqrestore(&sclp_lock, flags);
-               return rc;
-       }
+       if (rc)
+               goto fail_init_state_uninitialized;
        /* Register reboot handler */
        rc = register_reboot_notifier(&sclp_reboot_notifier);
-       if (rc) {
-               sclp_init_state = sclp_init_state_uninitialized;
-               spin_unlock_irqrestore(&sclp_lock, flags);
-               return rc;
-       }
+       if (rc)
+               goto fail_init_state_uninitialized;
        /* Register interrupt handler */
        rc = register_early_external_interrupt(0x2401, sclp_interrupt_handler,
                                               &ext_int_info_hwc);
-       if (rc) {
-               unregister_reboot_notifier(&sclp_reboot_notifier);
-               sclp_init_state = sclp_init_state_uninitialized;
-               spin_unlock_irqrestore(&sclp_lock, flags);
-               return rc;
-       }
+       if (rc)
+               goto fail_unregister_reboot_notifier;
        sclp_init_state = sclp_init_state_initialized;
        spin_unlock_irqrestore(&sclp_lock, flags);
        /* Enable service-signal external interruption - needs to happen with
@@ -932,11 +1075,56 @@ sclp_init(void)
        ctl_set_bit(0, 9);
        sclp_init_mask(1);
        return 0;
+
+fail_unregister_reboot_notifier:
+       unregister_reboot_notifier(&sclp_reboot_notifier);
+fail_init_state_uninitialized:
+       sclp_init_state = sclp_init_state_uninitialized;
+fail_unlock:
+       spin_unlock_irqrestore(&sclp_lock, flags);
+       return rc;
 }
 
+/*
+ * SCLP panic notifier: If we are suspended, we thaw SCLP in order to be able
+ * to print the panic message.
+ */
+static int sclp_panic_notify(struct notifier_block *self,
+                            unsigned long event, void *data)
+{
+       if (sclp_suspend_state == sclp_suspend_state_suspended)
+               sclp_undo_suspend(SCLP_PM_EVENT_THAW);
+       return NOTIFY_OK;
+}
+
+static struct notifier_block sclp_on_panic_nb = {
+       .notifier_call = sclp_panic_notify,
+       .priority = SCLP_PANIC_PRIO,
+};
+
 static __init int sclp_initcall(void)
 {
+       int rc;
+
+       rc = platform_driver_register(&sclp_pdrv);
+       if (rc)
+               return rc;
+       sclp_pdev = platform_device_register_simple("sclp", -1, NULL, 0);
+       rc = IS_ERR(sclp_pdev) ? PTR_ERR(sclp_pdev) : 0;
+       if (rc)
+               goto fail_platform_driver_unregister;
+       rc = atomic_notifier_chain_register(&panic_notifier_list,
+                                           &sclp_on_panic_nb);
+       if (rc)
+               goto fail_platform_device_unregister;
+
        return sclp_init();
+
+fail_platform_device_unregister:
+       platform_device_unregister(sclp_pdev);
+fail_platform_driver_unregister:
+       platform_driver_unregister(&sclp_pdrv);
+       return rc;
 }
 
 arch_initcall(sclp_initcall);
index bac80e856f97978d1c9354e7df7830fc2fa76691..60e7cb07095b6fa2c6e0b2908a6886c2cfc5c1c6 100644 (file)
@@ -1,10 +1,8 @@
 /*
- *  drivers/s390/char/sclp.h
+ * Copyright IBM Corp. 1999, 2009
  *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
- *              Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Author(s): Martin Peschke <mpeschke@de.ibm.com>
+ *           Martin Schwidefsky <schwidefsky@de.ibm.com>
  */
 
 #ifndef __SCLP_H__
@@ -17,7 +15,7 @@
 
 /* maximum number of pages concerning our own memory management */
 #define MAX_KMEM_PAGES (sizeof(unsigned long) << 3)
-#define MAX_CONSOLE_PAGES      4
+#define MAX_CONSOLE_PAGES      6
 
 #define EVTYP_OPCMD            0x01
 #define EVTYP_MSG              0x02
@@ -68,6 +66,15 @@ typedef unsigned int sclp_cmdw_t;
 
 #define GDS_KEY_SELFDEFTEXTMSG 0x31
 
+enum sclp_pm_event {
+       SCLP_PM_EVENT_FREEZE,
+       SCLP_PM_EVENT_THAW,
+       SCLP_PM_EVENT_RESTORE,
+};
+
+#define SCLP_PANIC_PRIO                1
+#define SCLP_PANIC_PRIO_CLIENT 0
+
 typedef u32 sccb_mask_t;       /* ATTENTION: assumes 32bit mask !!! */
 
 struct sccb_header {
@@ -134,6 +141,10 @@ struct sclp_register {
        void (*state_change_fn)(struct sclp_register *);
        /* called for events in cp_receive_mask/sclp_receive_mask */
        void (*receiver_fn)(struct evbuf_header *);
+       /* called for power management events */
+       void (*pm_event_fn)(struct sclp_register *, enum sclp_pm_event);
+       /* pm event posted flag */
+       int pm_event_posted;
 };
 
 /* externals from sclp.c */
index 77ab6e34a100b758bc3047888e78f1962a90146d..5cc11c636d38ad8e4fb640ef38afdbbb635095ee 100644 (file)
@@ -1,9 +1,8 @@
 /*
- *  drivers/s390/char/sclp_cmd.c
+ * Copyright IBM Corp. 2007, 2009
  *
- *    Copyright IBM Corp. 2007
- *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
- *              Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
+ * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>,
+ *           Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
  */
 
 #define KMSG_COMPONENT "sclp_cmd"
 #include <linux/completion.h>
 #include <linux/init.h>
 #include <linux/errno.h>
+#include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/mmzone.h>
 #include <linux/memory.h>
+#include <linux/platform_device.h>
 #include <asm/chpid.h>
 #include <asm/sclp.h>
 #include <asm/setup.h>
@@ -292,6 +293,7 @@ static DEFINE_MUTEX(sclp_mem_mutex);
 static LIST_HEAD(sclp_mem_list);
 static u8 sclp_max_storage_id;
 static unsigned long sclp_storage_ids[256 / BITS_PER_LONG];
+static int sclp_mem_state_changed;
 
 struct memory_increment {
        struct list_head list;
@@ -450,6 +452,8 @@ static int sclp_mem_notifier(struct notifier_block *nb,
                rc = -EINVAL;
                break;
        }
+       if (!rc)
+               sclp_mem_state_changed = 1;
        mutex_unlock(&sclp_mem_mutex);
        return rc ? NOTIFY_BAD : NOTIFY_OK;
 }
@@ -525,6 +529,14 @@ static void __init insert_increment(u16 rn, int standby, int assigned)
        list_add(&new_incr->list, prev);
 }
 
+static int sclp_mem_freeze(struct device *dev)
+{
+       if (!sclp_mem_state_changed)
+               return 0;
+       pr_err("Memory hotplug state changed, suspend refused.\n");
+       return -EPERM;
+}
+
 struct read_storage_sccb {
        struct sccb_header header;
        u16 max_id;
@@ -534,8 +546,20 @@ struct read_storage_sccb {
        u32 entries[0];
 } __packed;
 
+static struct dev_pm_ops sclp_mem_pm_ops = {
+       .freeze         = sclp_mem_freeze,
+};
+
+static struct platform_driver sclp_mem_pdrv = {
+       .driver = {
+               .name   = "sclp_mem",
+               .pm     = &sclp_mem_pm_ops,
+       },
+};
+
 static int __init sclp_detect_standby_memory(void)
 {
+       struct platform_device *sclp_pdev;
        struct read_storage_sccb *sccb;
        int i, id, assigned, rc;
 
@@ -588,7 +612,17 @@ static int __init sclp_detect_standby_memory(void)
        rc = register_memory_notifier(&sclp_mem_nb);
        if (rc)
                goto out;
+       rc = platform_driver_register(&sclp_mem_pdrv);
+       if (rc)
+               goto out;
+       sclp_pdev = platform_device_register_simple("sclp_mem", -1, NULL, 0);
+       rc = IS_ERR(sclp_pdev) ? PTR_ERR(sclp_pdev) : 0;
+       if (rc)
+               goto out_driver;
        sclp_add_standby_memory();
+       goto out;
+out_driver:
+       platform_driver_unregister(&sclp_mem_pdrv);
 out:
        free_page((unsigned long) sccb);
        return rc;
index 9a25c4bd14210ded21fffa666b53f653febced08..336811a77672c751f9a8ab3f74281dd52f068f38 100644 (file)
@@ -1,11 +1,9 @@
 /*
- *  drivers/s390/char/sclp_con.c
- *    SCLP line mode console driver
+ * SCLP line mode console driver
  *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
- *              Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Copyright IBM Corp. 1999, 2009
+ * Author(s): Martin Peschke <mpeschke@de.ibm.com>
+ *           Martin Schwidefsky <schwidefsky@de.ibm.com>
  */
 
 #include <linux/kmod.h>
@@ -32,13 +30,14 @@ static spinlock_t sclp_con_lock;
 static struct list_head sclp_con_pages;
 /* List of full struct sclp_buffer structures ready for output */
 static struct list_head sclp_con_outqueue;
-/* Counter how many buffers are emitted (max 1) and how many */
-/* are on the output queue. */
-static int sclp_con_buffer_count;
 /* Pointer to current console buffer */
 static struct sclp_buffer *sclp_conbuf;
 /* Timer for delayed output of console messages */
 static struct timer_list sclp_con_timer;
+/* Suspend mode flag */
+static int sclp_con_suspended;
+/* Flag that output queue is currently running */
+static int sclp_con_queue_running;
 
 /* Output format for console messages */
 static unsigned short sclp_con_columns;
@@ -53,42 +52,71 @@ sclp_conbuf_callback(struct sclp_buffer *buffer, int rc)
        do {
                page = sclp_unmake_buffer(buffer);
                spin_lock_irqsave(&sclp_con_lock, flags);
+
                /* Remove buffer from outqueue */
                list_del(&buffer->list);
-               sclp_con_buffer_count--;
                list_add_tail((struct list_head *) page, &sclp_con_pages);
+
                /* Check if there is a pending buffer on the out queue. */
                buffer = NULL;
                if (!list_empty(&sclp_con_outqueue))
-                       buffer = list_entry(sclp_con_outqueue.next,
-                                           struct sclp_buffer, list);
+                       buffer = list_first_entry(&sclp_con_outqueue,
+                                                 struct sclp_buffer, list);
+               if (!buffer || sclp_con_suspended) {
+                       sclp_con_queue_running = 0;
+                       spin_unlock_irqrestore(&sclp_con_lock, flags);
+                       break;
+               }
                spin_unlock_irqrestore(&sclp_con_lock, flags);
-       } while (buffer && sclp_emit_buffer(buffer, sclp_conbuf_callback));
+       } while (sclp_emit_buffer(buffer, sclp_conbuf_callback));
 }
 
-static void
-sclp_conbuf_emit(void)
+/*
+ * Finalize and emit first pending buffer.
+ */
+static void sclp_conbuf_emit(void)
 {
        struct sclp_buffer* buffer;
        unsigned long flags;
-       int count;
        int rc;
 
        spin_lock_irqsave(&sclp_con_lock, flags);
-       buffer = sclp_conbuf;
+       if (sclp_conbuf)
+               list_add_tail(&sclp_conbuf->list, &sclp_con_outqueue);
        sclp_conbuf = NULL;
-       if (buffer == NULL) {
-               spin_unlock_irqrestore(&sclp_con_lock, flags);
-               return;
-       }
-       list_add_tail(&buffer->list, &sclp_con_outqueue);
-       count = sclp_con_buffer_count++;
+       if (sclp_con_queue_running || sclp_con_suspended)
+               goto out_unlock;
+       if (list_empty(&sclp_con_outqueue))
+               goto out_unlock;
+       buffer = list_first_entry(&sclp_con_outqueue, struct sclp_buffer,
+                                 list);
+       sclp_con_queue_running = 1;
        spin_unlock_irqrestore(&sclp_con_lock, flags);
-       if (count)
-               return;
+
        rc = sclp_emit_buffer(buffer, sclp_conbuf_callback);
        if (rc)
                sclp_conbuf_callback(buffer, rc);
+       return;
+out_unlock:
+       spin_unlock_irqrestore(&sclp_con_lock, flags);
+}
+
+/*
+ * Wait until out queue is empty
+ */
+static void sclp_console_sync_queue(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sclp_con_lock, flags);
+       if (timer_pending(&sclp_con_timer))
+               del_timer_sync(&sclp_con_timer);
+       while (sclp_con_queue_running) {
+               spin_unlock_irqrestore(&sclp_con_lock, flags);
+               sclp_sync_wait();
+               spin_lock_irqsave(&sclp_con_lock, flags);
+       }
+       spin_unlock_irqrestore(&sclp_con_lock, flags);
 }
 
 /*
@@ -123,6 +151,8 @@ sclp_console_write(struct console *console, const char *message,
                /* make sure we have a console output buffer */
                if (sclp_conbuf == NULL) {
                        while (list_empty(&sclp_con_pages)) {
+                               if (sclp_con_suspended)
+                                       goto out;
                                spin_unlock_irqrestore(&sclp_con_lock, flags);
                                sclp_sync_wait();
                                spin_lock_irqsave(&sclp_con_lock, flags);
@@ -157,6 +187,7 @@ sclp_console_write(struct console *console, const char *message,
                sclp_con_timer.expires = jiffies + HZ/10;
                add_timer(&sclp_con_timer);
        }
+out:
        spin_unlock_irqrestore(&sclp_con_lock, flags);
 }
 
@@ -168,30 +199,43 @@ sclp_console_device(struct console *c, int *index)
 }
 
 /*
- * This routine is called from panic when the kernel
- * is going to give up. We have to make sure that all buffers
- * will be flushed to the SCLP.
+ * Make sure that all buffers will be flushed to the SCLP.
  */
 static void
 sclp_console_flush(void)
+{
+       sclp_conbuf_emit();
+       sclp_console_sync_queue();
+}
+
+/*
+ * Resume console: If there are cached messages, emit them.
+ */
+static void sclp_console_resume(void)
 {
        unsigned long flags;
 
+       spin_lock_irqsave(&sclp_con_lock, flags);
+       sclp_con_suspended = 0;
+       spin_unlock_irqrestore(&sclp_con_lock, flags);
        sclp_conbuf_emit();
+}
+
+/*
+ * Suspend console: Set suspend flag and flush console
+ */
+static void sclp_console_suspend(void)
+{
+       unsigned long flags;
+
        spin_lock_irqsave(&sclp_con_lock, flags);
-       if (timer_pending(&sclp_con_timer))
-               del_timer(&sclp_con_timer);
-       while (sclp_con_buffer_count > 0) {
-               spin_unlock_irqrestore(&sclp_con_lock, flags);
-               sclp_sync_wait();
-               spin_lock_irqsave(&sclp_con_lock, flags);
-       }
+       sclp_con_suspended = 1;
        spin_unlock_irqrestore(&sclp_con_lock, flags);
+       sclp_console_flush();
 }
 
-static int
-sclp_console_notify(struct notifier_block *self,
-                         unsigned long event, void *data)
+static int sclp_console_notify(struct notifier_block *self,
+                              unsigned long event, void *data)
 {
        sclp_console_flush();
        return NOTIFY_OK;
@@ -199,7 +243,7 @@ sclp_console_notify(struct notifier_block *self,
 
 static struct notifier_block on_panic_nb = {
        .notifier_call = sclp_console_notify,
-       .priority = 1,
+       .priority = SCLP_PANIC_PRIO_CLIENT,
 };
 
 static struct notifier_block on_reboot_nb = {
@@ -220,6 +264,22 @@ static struct console sclp_console =
        .index = 0 /* ttyS0 */
 };
 
+/*
+ * This function is called for SCLP suspend and resume events.
+ */
+void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event)
+{
+       switch (sclp_pm_event) {
+       case SCLP_PM_EVENT_FREEZE:
+               sclp_console_suspend();
+               break;
+       case SCLP_PM_EVENT_RESTORE:
+       case SCLP_PM_EVENT_THAW:
+               sclp_console_resume();
+               break;
+       }
+}
+
 /*
  * called by console_init() in drivers/char/tty_io.c at boot-time.
  */
@@ -243,7 +303,6 @@ sclp_console_init(void)
        }
        INIT_LIST_HEAD(&sclp_con_outqueue);
        spin_lock_init(&sclp_con_lock);
-       sclp_con_buffer_count = 0;
        sclp_conbuf = NULL;
        init_timer(&sclp_con_timer);
 
index 710af42603f80f7866b2d3be13e7ebaff14ce166..4be63be7344564a113e29a0051c79ac430b372a6 100644 (file)
@@ -1,11 +1,10 @@
 /*
- *  drivers/s390/char/sclp_rw.c
- *     driver: reading from and writing to system console on S/390 via SCLP
+ * driver: reading from and writing to system console on S/390 via SCLP
  *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
- *              Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Copyright IBM Corp. 1999, 2009
+ *
+ * Author(s): Martin Peschke <mpeschke@de.ibm.com>
+ *           Martin Schwidefsky <schwidefsky@de.ibm.com>
  */
 
 #include <linux/kmod.h>
  */
 #define MAX_SCCB_ROOM (PAGE_SIZE - sizeof(struct sclp_buffer))
 
+static void sclp_rw_pm_event(struct sclp_register *reg,
+                            enum sclp_pm_event sclp_pm_event)
+{
+       sclp_console_pm_event(sclp_pm_event);
+}
+
 /* Event type structure for write message and write priority message */
 static struct sclp_register sclp_rw_event = {
-       .send_mask = EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK
+       .send_mask = EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK,
+       .pm_event_fn = sclp_rw_pm_event,
 };
 
 /*
index 6aa7a6948bc91a29a6047b7d6f808a064cd0fcc4..85f491ea929c0da0df28ee54676949354f51b7b0 100644 (file)
@@ -1,11 +1,10 @@
 /*
- *  drivers/s390/char/sclp_rw.h
- *    interface to the SCLP-read/write driver
+ * interface to the SCLP-read/write driver
  *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
- *              Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Copyright IBM Corporation 1999, 2009
+ *
+ * Author(s): Martin Peschke <mpeschke@de.ibm.com>
+ *           Martin Schwidefsky <schwidefsky@de.ibm.com>
  */
 
 #ifndef __SCLP_RW_H__
@@ -93,4 +92,5 @@ void sclp_set_columns(struct sclp_buffer *, unsigned short);
 void sclp_set_htab(struct sclp_buffer *, unsigned short);
 int sclp_chars_in_buffer(struct sclp_buffer *);
 
+void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event);
 #endif /* __SCLP_RW_H__ */
index a839aa531d7c0f011cbe6e135ce3bac897333d7e..5518e24946aa7735c618699e6bf4e2762fcb3fa8 100644 (file)
@@ -1,10 +1,9 @@
 /*
- *  drivers/s390/char/sclp_vt220.c
- *    SCLP VT220 terminal driver.
+ * SCLP VT220 terminal driver.
  *
- *  S390 version
- *    Copyright IBM Corp. 2003,2008
- *    Author(s): Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
+ * Copyright IBM Corp. 2003, 2009
+ *
+ * Author(s): Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
  */
 
 #include <linux/module.h>
@@ -69,8 +68,11 @@ static struct list_head sclp_vt220_empty;
 /* List of pending requests */
 static struct list_head sclp_vt220_outqueue;
 
-/* Number of requests in outqueue */
-static int sclp_vt220_outqueue_count;
+/* Suspend mode flag */
+static int sclp_vt220_suspended;
+
+/* Flag that output queue is currently running */
+static int sclp_vt220_queue_running;
 
 /* Timer used for delaying write requests to merge subsequent messages into
  * a single buffer */
@@ -92,6 +94,8 @@ static int __initdata sclp_vt220_init_count;
 static int sclp_vt220_flush_later;
 
 static void sclp_vt220_receiver_fn(struct evbuf_header *evbuf);
+static void sclp_vt220_pm_event_fn(struct sclp_register *reg,
+                                  enum sclp_pm_event sclp_pm_event);
 static int __sclp_vt220_emit(struct sclp_vt220_request *request);
 static void sclp_vt220_emit_current(void);
 
@@ -100,7 +104,8 @@ static struct sclp_register sclp_vt220_register = {
        .send_mask              = EVTYP_VT220MSG_MASK,
        .receive_mask           = EVTYP_VT220MSG_MASK,
        .state_change_fn        = NULL,
-       .receiver_fn            = sclp_vt220_receiver_fn
+       .receiver_fn            = sclp_vt220_receiver_fn,
+       .pm_event_fn            = sclp_vt220_pm_event_fn,
 };
 
 
@@ -120,15 +125,19 @@ sclp_vt220_process_queue(struct sclp_vt220_request *request)
                spin_lock_irqsave(&sclp_vt220_lock, flags);
                /* Move request from outqueue to empty queue */
                list_del(&request->list);
-               sclp_vt220_outqueue_count--;
                list_add_tail((struct list_head *) page, &sclp_vt220_empty);
                /* Check if there is a pending buffer on the out queue. */
                request = NULL;
                if (!list_empty(&sclp_vt220_outqueue))
                        request = list_entry(sclp_vt220_outqueue.next,
                                             struct sclp_vt220_request, list);
+               if (!request || sclp_vt220_suspended) {
+                       sclp_vt220_queue_running = 0;
+                       spin_unlock_irqrestore(&sclp_vt220_lock, flags);
+                       break;
+               }
                spin_unlock_irqrestore(&sclp_vt220_lock, flags);
-       } while (request && __sclp_vt220_emit(request));
+       } while (__sclp_vt220_emit(request));
        if (request == NULL && sclp_vt220_flush_later)
                sclp_vt220_emit_current();
        /* Check if the tty needs a wake up call */
@@ -212,26 +221,7 @@ __sclp_vt220_emit(struct sclp_vt220_request *request)
 }
 
 /*
- * Queue and emit given request.
- */
-static void
-sclp_vt220_emit(struct sclp_vt220_request *request)
-{
-       unsigned long flags;
-       int count;
-
-       spin_lock_irqsave(&sclp_vt220_lock, flags);
-       list_add_tail(&request->list, &sclp_vt220_outqueue);
-       count = sclp_vt220_outqueue_count++;
-       spin_unlock_irqrestore(&sclp_vt220_lock, flags);
-       /* Emit only the first buffer immediately - callback takes care of
-        * the rest */
-       if (count == 0 && __sclp_vt220_emit(request))
-               sclp_vt220_process_queue(request);
-}
-
-/*
- * Queue and emit current request. Return zero on success, non-zero otherwise.
+ * Queue and emit current request.
  */
 static void
 sclp_vt220_emit_current(void)
@@ -241,22 +231,33 @@ sclp_vt220_emit_current(void)
        struct sclp_vt220_sccb *sccb;
 
        spin_lock_irqsave(&sclp_vt220_lock, flags);
-       request = NULL;
-       if (sclp_vt220_current_request != NULL) {
+       if (sclp_vt220_current_request) {
                sccb = (struct sclp_vt220_sccb *) 
                                sclp_vt220_current_request->sclp_req.sccb;
                /* Only emit buffers with content */
                if (sccb->header.length != sizeof(struct sclp_vt220_sccb)) {
-                       request = sclp_vt220_current_request;
+                       list_add_tail(&sclp_vt220_current_request->list,
+                                     &sclp_vt220_outqueue);
                        sclp_vt220_current_request = NULL;
                        if (timer_pending(&sclp_vt220_timer))
                                del_timer(&sclp_vt220_timer);
                }
                sclp_vt220_flush_later = 0;
        }
+       if (sclp_vt220_queue_running || sclp_vt220_suspended)
+               goto out_unlock;
+       if (list_empty(&sclp_vt220_outqueue))
+               goto out_unlock;
+       request = list_first_entry(&sclp_vt220_outqueue,
+                                  struct sclp_vt220_request, list);
+       sclp_vt220_queue_running = 1;
+       spin_unlock_irqrestore(&sclp_vt220_lock, flags);
+
+       if (__sclp_vt220_emit(request))
+               sclp_vt220_process_queue(request);
+       return;
+out_unlock:
        spin_unlock_irqrestore(&sclp_vt220_lock, flags);
-       if (request != NULL)
-               sclp_vt220_emit(request);
 }
 
 #define SCLP_NORMAL_WRITE      0x00
@@ -396,7 +397,7 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule,
                if (sclp_vt220_current_request == NULL) {
                        while (list_empty(&sclp_vt220_empty)) {
                                spin_unlock_irqrestore(&sclp_vt220_lock, flags);
-                               if (may_fail)
+                               if (may_fail || sclp_vt220_suspended)
                                        goto out;
                                else
                                        sclp_sync_wait();
@@ -531,7 +532,7 @@ sclp_vt220_put_char(struct tty_struct *tty, unsigned char ch)
 static void
 sclp_vt220_flush_chars(struct tty_struct *tty)
 {
-       if (sclp_vt220_outqueue_count == 0)
+       if (!sclp_vt220_queue_running)
                sclp_vt220_emit_current();
        else
                sclp_vt220_flush_later = 1;
@@ -635,7 +636,6 @@ static int __init __sclp_vt220_init(int num_pages)
        init_timer(&sclp_vt220_timer);
        sclp_vt220_current_request = NULL;
        sclp_vt220_buffered_chars = 0;
-       sclp_vt220_outqueue_count = 0;
        sclp_vt220_tty = NULL;
        sclp_vt220_flush_later = 0;
 
@@ -736,7 +736,7 @@ static void __sclp_vt220_flush_buffer(void)
        spin_lock_irqsave(&sclp_vt220_lock, flags);
        if (timer_pending(&sclp_vt220_timer))
                del_timer(&sclp_vt220_timer);
-       while (sclp_vt220_outqueue_count > 0) {
+       while (sclp_vt220_queue_running) {
                spin_unlock_irqrestore(&sclp_vt220_lock, flags);
                sclp_sync_wait();
                spin_lock_irqsave(&sclp_vt220_lock, flags);
@@ -744,6 +744,46 @@ static void __sclp_vt220_flush_buffer(void)
        spin_unlock_irqrestore(&sclp_vt220_lock, flags);
 }
 
+/*
+ * Resume console: If there are cached messages, emit them.
+ */
+static void sclp_vt220_resume(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sclp_vt220_lock, flags);
+       sclp_vt220_suspended = 0;
+       spin_unlock_irqrestore(&sclp_vt220_lock, flags);
+       sclp_vt220_emit_current();
+}
+
+/*
+ * Suspend console: Set suspend flag and flush console
+ */
+static void sclp_vt220_suspend(void)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sclp_vt220_lock, flags);
+       sclp_vt220_suspended = 1;
+       spin_unlock_irqrestore(&sclp_vt220_lock, flags);
+       __sclp_vt220_flush_buffer();
+}
+
+static void sclp_vt220_pm_event_fn(struct sclp_register *reg,
+                                  enum sclp_pm_event sclp_pm_event)
+{
+       switch (sclp_pm_event) {
+       case SCLP_PM_EVENT_FREEZE:
+               sclp_vt220_suspend();
+               break;
+       case SCLP_PM_EVENT_RESTORE:
+       case SCLP_PM_EVENT_THAW:
+               sclp_vt220_resume();
+               break;
+       }
+}
+
 static int
 sclp_vt220_notify(struct notifier_block *self,
                          unsigned long event, void *data)
index 5469e099597e6083e4b80dc2ae01407b258b3a08..a263337747012de55f87375292403fb149fd5cec 100644 (file)
@@ -3,7 +3,7 @@
  *    tape device driver for 3480/3490E/3590 tapes.
  *
  *  S390 and zSeries version
- *    Copyright IBM Corp. 2001,2006
+ *    Copyright IBM Corp. 2001, 2009
  *    Author(s): Carsten Otte <cotte@de.ibm.com>
  *              Tuan Ngo-Anh <ngoanh@de.ibm.com>
  *              Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -286,6 +286,7 @@ extern void tape_state_set(struct tape_device *, enum tape_state);
 
 extern int tape_generic_online(struct tape_device *, struct tape_discipline *);
 extern int tape_generic_offline(struct ccw_device *);
+extern int tape_generic_pm_suspend(struct ccw_device *);
 
 /* Externals from tape_devmap.c */
 extern int tape_generic_probe(struct ccw_device *);
index 2d00a383a475ca50fbc93a6b0fee0cc1df018c59..5a519fac37b7187505499ff33e95103da31a9e9a 100644 (file)
@@ -2,7 +2,7 @@
  *  drivers/s390/char/tape_34xx.c
  *    tape device discipline for 3480/3490 tapes.
  *
- *    Copyright (C) IBM Corp. 2001,2006
+ *    Copyright IBM Corp. 2001, 2009
  *    Author(s): Carsten Otte <cotte@de.ibm.com>
  *              Tuan Ngo-Anh <ngoanh@de.ibm.com>
  *              Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -1289,7 +1289,7 @@ static int
 tape_34xx_online(struct ccw_device *cdev)
 {
        return tape_generic_online(
-               cdev->dev.driver_data,
+               dev_get_drvdata(&cdev->dev),
                &tape_discipline_34xx
        );
 }
@@ -1302,6 +1302,7 @@ static struct ccw_driver tape_34xx_driver = {
        .remove = tape_generic_remove,
        .set_online = tape_34xx_online,
        .set_offline = tape_generic_offline,
+       .freeze = tape_generic_pm_suspend,
 };
 
 static int
index c453b2f3e9f4c6c46cf73a9be1397c9f10873c7c..418f72dd39b4d4836457edd8e87a9b6b25808566 100644 (file)
@@ -2,7 +2,7 @@
  *  drivers/s390/char/tape_3590.c
  *    tape device discipline for 3590 tapes.
  *
- *    Copyright IBM Corp. 2001,2006
+ *    Copyright IBM Corp. 2001, 2009
  *    Author(s): Stefan Bader <shbader@de.ibm.com>
  *              Michael Holzheu <holzheu@de.ibm.com>
  *              Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -1703,7 +1703,7 @@ static struct ccw_device_id tape_3590_ids[] = {
 static int
 tape_3590_online(struct ccw_device *cdev)
 {
-       return tape_generic_online(cdev->dev.driver_data,
+       return tape_generic_online(dev_get_drvdata(&cdev->dev),
                                   &tape_discipline_3590);
 }
 
@@ -1715,6 +1715,7 @@ static struct ccw_driver tape_3590_driver = {
        .remove = tape_generic_remove,
        .set_offline = tape_generic_offline,
        .set_online = tape_3590_online,
+       .freeze = tape_generic_pm_suspend,
 };
 
 /*
index 8a109f3b69c6480d3f3dbd1463a173ed9989f66d..595aa04cfd019699e09cd03b99e9774c7f99a100 100644 (file)
@@ -3,7 +3,7 @@
  *    basic function of the tape device driver
  *
  *  S390 and zSeries version
- *    Copyright IBM Corp. 2001,2006
+ *    Copyright IBM Corp. 2001, 2009
  *    Author(s): Carsten Otte <cotte@de.ibm.com>
  *              Michael Holzheu <holzheu@de.ibm.com>
  *              Tuan Ngo-Anh <ngoanh@de.ibm.com>
@@ -92,7 +92,7 @@ tape_medium_state_show(struct device *dev, struct device_attribute *attr, char *
 {
        struct tape_device *tdev;
 
-       tdev = (struct tape_device *) dev->driver_data;
+       tdev = dev_get_drvdata(dev);
        return scnprintf(buf, PAGE_SIZE, "%i\n", tdev->medium_state);
 }
 
@@ -104,7 +104,7 @@ tape_first_minor_show(struct device *dev, struct device_attribute *attr, char *b
 {
        struct tape_device *tdev;
 
-       tdev = (struct tape_device *) dev->driver_data;
+       tdev = dev_get_drvdata(dev);
        return scnprintf(buf, PAGE_SIZE, "%i\n", tdev->first_minor);
 }
 
@@ -116,7 +116,7 @@ tape_state_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct tape_device *tdev;
 
-       tdev = (struct tape_device *) dev->driver_data;
+       tdev = dev_get_drvdata(dev);
        return scnprintf(buf, PAGE_SIZE, "%s\n", (tdev->first_minor < 0) ?
                "OFFLINE" : tape_state_verbose[tdev->tape_state]);
 }
@@ -130,7 +130,7 @@ tape_operation_show(struct device *dev, struct device_attribute *attr, char *buf
        struct tape_device *tdev;
        ssize_t rc;
 
-       tdev = (struct tape_device *) dev->driver_data;
+       tdev = dev_get_drvdata(dev);
        if (tdev->first_minor < 0)
                return scnprintf(buf, PAGE_SIZE, "N/A\n");
 
@@ -156,7 +156,7 @@ tape_blocksize_show(struct device *dev, struct device_attribute *attr, char *buf
 {
        struct tape_device *tdev;
 
-       tdev = (struct tape_device *) dev->driver_data;
+       tdev = dev_get_drvdata(dev);
 
        return scnprintf(buf, PAGE_SIZE, "%i\n", tdev->char_data.block_size);
 }
@@ -379,6 +379,55 @@ tape_cleanup_device(struct tape_device *device)
        tape_med_state_set(device, MS_UNKNOWN);
 }
 
+/*
+ * Suspend device.
+ *
+ * Called by the common I/O layer if the drive should be suspended on user
+ * request. We refuse to suspend if the device is loaded or in use for the
+ * following reason:
+ * While the Linux guest is suspended, it might be logged off which causes
+ * devices to be detached. Tape devices are automatically rewound and unloaded
+ * during DETACH processing (unless the tape device was attached with the
+ * NOASSIGN or MULTIUSER option). After rewind/unload, there is no way to
+ * resume the original state of the tape device, since we would need to
+ * manually re-load the cartridge which was active at suspend time.
+ */
+int tape_generic_pm_suspend(struct ccw_device *cdev)
+{
+       struct tape_device *device;
+
+       device = cdev->dev.driver_data;
+       if (!device) {
+               return -ENODEV;
+       }
+
+       DBF_LH(3, "(%08x): tape_generic_pm_suspend(%p)\n",
+               device->cdev_id, device);
+
+       if (device->medium_state != MS_UNLOADED) {
+               pr_err("A cartridge is loaded in tape device %s, "
+                      "refusing to suspend\n", dev_name(&cdev->dev));
+               return -EBUSY;
+       }
+
+       spin_lock_irq(get_ccwdev_lock(device->cdev));
+       switch (device->tape_state) {
+               case TS_INIT:
+               case TS_NOT_OPER:
+               case TS_UNUSED:
+                       spin_unlock_irq(get_ccwdev_lock(device->cdev));
+                       break;
+               default:
+                       pr_err("Tape device %s is busy, refusing to "
+                              "suspend\n", dev_name(&cdev->dev));
+                       spin_unlock_irq(get_ccwdev_lock(device->cdev));
+                       return -EBUSY;
+       }
+
+       DBF_LH(3, "(%08x): Drive suspended.\n", device->cdev_id);
+       return 0;
+}
+
 /*
  * Set device offline.
  *
@@ -391,7 +440,7 @@ tape_generic_offline(struct ccw_device *cdev)
 {
        struct tape_device *device;
 
-       device = cdev->dev.driver_data;
+       device = dev_get_drvdata(&cdev->dev);
        if (!device) {
                return -ENODEV;
        }
@@ -534,7 +583,7 @@ tape_generic_probe(struct ccw_device *cdev)
                tape_put_device(device);
                return ret;
        }
-       cdev->dev.driver_data = device;
+       dev_set_drvdata(&cdev->dev, device);
        cdev->handler = __tape_do_irq;
        device->cdev = cdev;
        ccw_device_get_id(cdev, &dev_id);
@@ -573,7 +622,7 @@ tape_generic_remove(struct ccw_device *cdev)
 {
        struct tape_device *    device;
 
-       device = cdev->dev.driver_data;
+       device = dev_get_drvdata(&cdev->dev);
        if (!device) {
                return;
        }
@@ -613,9 +662,9 @@ tape_generic_remove(struct ccw_device *cdev)
                        tape_cleanup_device(device);
        }
 
-       if (cdev->dev.driver_data != NULL) {
+       if (!dev_get_drvdata(&cdev->dev)) {
                sysfs_remove_group(&cdev->dev.kobj, &tape_attr_group);
-               cdev->dev.driver_data = tape_put_device(cdev->dev.driver_data);
+               dev_set_drvdata(&cdev->dev, tape_put_device(dev_get_drvdata(&cdev->dev)));
        }
 }
 
@@ -1011,7 +1060,7 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
        struct tape_request *request;
        int rc;
 
-       device = (struct tape_device *) cdev->dev.driver_data;
+       device = dev_get_drvdata(&cdev->dev);
        if (device == NULL) {
                return;
        }
@@ -1273,6 +1322,7 @@ EXPORT_SYMBOL(tape_generic_remove);
 EXPORT_SYMBOL(tape_generic_probe);
 EXPORT_SYMBOL(tape_generic_online);
 EXPORT_SYMBOL(tape_generic_offline);
+EXPORT_SYMBOL(tape_generic_pm_suspend);
 EXPORT_SYMBOL(tape_put_device);
 EXPORT_SYMBOL(tape_get_device_reference);
 EXPORT_SYMBOL(tape_state_verbose);
index d8a2289fcb699c8f501d510340b90bf43051a03f..411cfa3c77196261c126b79356563505b8bb901e 100644 (file)
@@ -3,7 +3,7 @@
  *     character device driver for reading z/VM system service records
  *
  *
- *     Copyright 2004 IBM Corporation
+ *     Copyright IBM Corp. 2004, 2009
  *     character device driver for reading z/VM system service records,
  *     Version 1.0
  *     Author(s): Xenia Tkatschow <xenia@us.ibm.com>
@@ -504,7 +504,7 @@ static ssize_t vmlogrdr_autopurge_store(struct device * dev,
                                        struct device_attribute *attr,
                                        const char * buf, size_t count)
 {
-       struct vmlogrdr_priv_t *priv = dev->driver_data;
+       struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev);
        ssize_t ret = count;
 
        switch (buf[0]) {
@@ -525,7 +525,7 @@ static ssize_t vmlogrdr_autopurge_show(struct device *dev,
                                       struct device_attribute *attr,
                                       char *buf)
 {
-       struct vmlogrdr_priv_t *priv = dev->driver_data;
+       struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev);
        return sprintf(buf, "%u\n", priv->autopurge);
 }
 
@@ -541,7 +541,7 @@ static ssize_t vmlogrdr_purge_store(struct device * dev,
 
        char cp_command[80];
        char cp_response[80];
-       struct vmlogrdr_priv_t *priv = dev->driver_data;
+       struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev);
 
        if (buf[0] != '1')
                return -EINVAL;
@@ -578,7 +578,7 @@ static ssize_t vmlogrdr_autorecording_store(struct device *dev,
                                            struct device_attribute *attr,
                                            const char *buf, size_t count)
 {
-       struct vmlogrdr_priv_t *priv = dev->driver_data;
+       struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev);
        ssize_t ret = count;
 
        switch (buf[0]) {
@@ -599,7 +599,7 @@ static ssize_t vmlogrdr_autorecording_show(struct device *dev,
                                           struct device_attribute *attr,
                                           char *buf)
 {
-       struct vmlogrdr_priv_t *priv = dev->driver_data;
+       struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev);
        return sprintf(buf, "%u\n", priv->autorecording);
 }
 
@@ -612,7 +612,7 @@ static ssize_t vmlogrdr_recording_store(struct device * dev,
                                        struct device_attribute *attr,
                                        const char * buf, size_t count)
 {
-       struct vmlogrdr_priv_t *priv = dev->driver_data;
+       struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev);
        ssize_t ret;
 
        switch (buf[0]) {
@@ -660,6 +660,29 @@ static struct attribute *vmlogrdr_attrs[] = {
        NULL,
 };
 
+static int vmlogrdr_pm_prepare(struct device *dev)
+{
+       int rc;
+       struct vmlogrdr_priv_t *priv = dev->driver_data;
+
+       rc = 0;
+       if (priv) {
+               spin_lock_bh(&priv->priv_lock);
+               if (priv->dev_in_use)
+                       rc = -EBUSY;
+               spin_unlock_bh(&priv->priv_lock);
+       }
+       if (rc)
+               pr_err("vmlogrdr: device %s is busy. Refuse to suspend.\n",
+                      dev_name(dev));
+       return rc;
+}
+
+
+static struct dev_pm_ops vmlogrdr_pm_ops = {
+       .prepare = vmlogrdr_pm_prepare,
+};
+
 static struct attribute_group vmlogrdr_attr_group = {
        .attrs = vmlogrdr_attrs,
 };
@@ -668,6 +691,7 @@ static struct class *vmlogrdr_class;
 static struct device_driver vmlogrdr_driver = {
        .name = "vmlogrdr",
        .bus  = &iucv_bus,
+       .pm = &vmlogrdr_pm_ops,
 };
 
 
@@ -729,6 +753,7 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv)
                dev->bus = &iucv_bus;
                dev->parent = iucv_root;
                dev->driver = &vmlogrdr_driver;
+               dev->driver_data = priv;
                /*
                 * The release function could be called after the
                 * module has been unloaded. It's _only_ task is to
index 5dcef81fc9d927a0bf5672a0f979e564dac32953..7d9e67cb64714494043bf62449632a27780fa0be 100644 (file)
@@ -2,7 +2,7 @@
  * Linux driver for System z and s390 unit record devices
  * (z/VM virtual punch, reader, printer)
  *
- * Copyright IBM Corp. 2001, 2007
+ * Copyright IBM Corp. 2001, 2009
  * Authors: Malcolm Beattie <beattiem@uk.ibm.com>
  *         Michael Holzheu <holzheu@de.ibm.com>
  *         Frank Munzert <munzert@de.ibm.com>
@@ -60,6 +60,7 @@ static int ur_probe(struct ccw_device *cdev);
 static void ur_remove(struct ccw_device *cdev);
 static int ur_set_online(struct ccw_device *cdev);
 static int ur_set_offline(struct ccw_device *cdev);
+static int ur_pm_suspend(struct ccw_device *cdev);
 
 static struct ccw_driver ur_driver = {
        .name           = "vmur",
@@ -69,6 +70,7 @@ static struct ccw_driver ur_driver = {
        .remove         = ur_remove,
        .set_online     = ur_set_online,
        .set_offline    = ur_set_offline,
+       .freeze         = ur_pm_suspend,
 };
 
 static DEFINE_MUTEX(vmur_mutex);
@@ -78,11 +80,11 @@ static DEFINE_MUTEX(vmur_mutex);
  *
  * Each ur device (urd) contains a reference to its corresponding ccw device
  * (cdev) using the urd->cdev pointer. Each ccw device has a reference to the
- * ur device using the cdev->dev.driver_data pointer.
+ * ur device using dev_get_drvdata(&cdev->dev) pointer.
  *
  * urd references:
  * - ur_probe gets a urd reference, ur_remove drops the reference
- *   (cdev->dev.driver_data)
+ *   dev_get_drvdata(&cdev->dev)
  * - ur_open gets a urd reference, ur_relase drops the reference
  *   (urf->urd)
  *
@@ -90,7 +92,7 @@ static DEFINE_MUTEX(vmur_mutex);
  * - urdev_alloc get a cdev reference (urd->cdev)
  * - urdev_free drops the cdev reference (urd->cdev)
  *
- * Setting and clearing of cdev->dev.driver_data is protected by the ccwdev lock
+ * Setting and clearing of dev_get_drvdata(&cdev->dev) is protected by the ccwdev lock
  */
 static struct urdev *urdev_alloc(struct ccw_device *cdev)
 {
@@ -129,7 +131,7 @@ static struct urdev *urdev_get_from_cdev(struct ccw_device *cdev)
        unsigned long flags;
 
        spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
-       urd = cdev->dev.driver_data;
+       urd = dev_get_drvdata(&cdev->dev);
        if (urd)
                urdev_get(urd);
        spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
@@ -157,6 +159,28 @@ static void urdev_put(struct urdev *urd)
                urdev_free(urd);
 }
 
+/*
+ * State and contents of ur devices can be changed by class D users issuing
+ * CP commands such as PURGE or TRANSFER, while the Linux guest is suspended.
+ * Also the Linux guest might be logged off, which causes all active spool
+ * files to be closed.
+ * So we cannot guarantee that spool files are still the same when the Linux
+ * guest is resumed. In order to avoid unpredictable results at resume time
+ * we simply refuse to suspend if a ur device node is open.
+ */
+static int ur_pm_suspend(struct ccw_device *cdev)
+{
+       struct urdev *urd = cdev->dev.driver_data;
+
+       TRACE("ur_pm_suspend: cdev=%p\n", cdev);
+       if (urd->open_flag) {
+               pr_err("Unit record device %s is busy, %s refusing to "
+                      "suspend.\n", dev_name(&cdev->dev), ur_banner);
+               return -EBUSY;
+       }
+       return 0;
+}
+
 /*
  * Low-level functions to do I/O to a ur device.
  *     alloc_chan_prog
@@ -286,7 +310,7 @@ static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm,
                TRACE("ur_int_handler: unsolicited interrupt\n");
                return;
        }
-       urd = cdev->dev.driver_data;
+       urd = dev_get_drvdata(&cdev->dev);
        BUG_ON(!urd);
        /* On special conditions irb is an error pointer */
        if (IS_ERR(irb))
@@ -832,7 +856,7 @@ static int ur_probe(struct ccw_device *cdev)
                goto fail_remove_attr;
        }
        spin_lock_irq(get_ccwdev_lock(cdev));
-       cdev->dev.driver_data = urd;
+       dev_set_drvdata(&cdev->dev, urd);
        spin_unlock_irq(get_ccwdev_lock(cdev));
 
        mutex_unlock(&vmur_mutex);
@@ -972,8 +996,8 @@ static void ur_remove(struct ccw_device *cdev)
        ur_remove_attributes(&cdev->dev);
 
        spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
-       urdev_put(cdev->dev.driver_data);
-       cdev->dev.driver_data = NULL;
+       urdev_put(dev_get_drvdata(&cdev->dev));
+       dev_set_drvdata(&cdev->dev, NULL);
        spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
 
        mutex_unlock(&vmur_mutex);
index 21a2a829bf4eb5baf20cfdfd9e71489c5987b77a..cb7854c10c0479585d1879f9c0a3fe8a90a713a1 100644 (file)
@@ -1,17 +1,23 @@
 /*
  * Watchdog implementation based on z/VM Watchdog Timer API
  *
+ * Copyright IBM Corp. 2004,2009
+ *
  * The user space watchdog daemon can use this driver as
  * /dev/vmwatchdog to have z/VM execute the specified CP
  * command when the timeout expires. The default command is
  * "IPL", which which cause an immediate reboot.
  */
+#define KMSG_COMPONENT "vmwatchdog"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/miscdevice.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/suspend.h>
 #include <linux/watchdog.h>
 #include <linux/smp_lock.h>
 
@@ -43,6 +49,9 @@ static unsigned int vmwdt_interval = 60;
 static unsigned long vmwdt_is_open;
 static int vmwdt_expect_close;
 
+#define VMWDT_OPEN     0       /* devnode is open or suspend in progress */
+#define VMWDT_RUNNING  1       /* The watchdog is armed */
+
 enum vmwdt_func {
        /* function codes */
        wdt_init   = 0,
@@ -92,6 +101,7 @@ static int vmwdt_keepalive(void)
        EBC_TOUPPER(ebc_cmd, MAX_CMDLEN);
 
        func = vmwdt_conceal ? (wdt_init | wdt_conceal) : wdt_init;
+       set_bit(VMWDT_RUNNING, &vmwdt_is_open);
        ret = __diag288(func, vmwdt_interval, ebc_cmd, len);
        WARN_ON(ret != 0);
        kfree(ebc_cmd);
@@ -102,6 +112,7 @@ static int vmwdt_disable(void)
 {
        int ret = __diag288(wdt_cancel, 0, "", 0);
        WARN_ON(ret != 0);
+       clear_bit(VMWDT_RUNNING, &vmwdt_is_open);
        return ret;
 }
 
@@ -123,13 +134,13 @@ static int vmwdt_open(struct inode *i, struct file *f)
 {
        int ret;
        lock_kernel();
-       if (test_and_set_bit(0, &vmwdt_is_open)) {
+       if (test_and_set_bit(VMWDT_OPEN, &vmwdt_is_open)) {
                unlock_kernel();
                return -EBUSY;
        }
        ret = vmwdt_keepalive();
        if (ret)
-               clear_bit(0, &vmwdt_is_open);
+               clear_bit(VMWDT_OPEN, &vmwdt_is_open);
        unlock_kernel();
        return ret ? ret : nonseekable_open(i, f);
 }
@@ -139,7 +150,7 @@ static int vmwdt_close(struct inode *i, struct file *f)
        if (vmwdt_expect_close == 42)
                vmwdt_disable();
        vmwdt_expect_close = 0;
-       clear_bit(0, &vmwdt_is_open);
+       clear_bit(VMWDT_OPEN, &vmwdt_is_open);
        return 0;
 }
 
@@ -223,6 +234,57 @@ static ssize_t vmwdt_write(struct file *f, const char __user *buf,
        return count;
 }
 
+static int vmwdt_resume(void)
+{
+       clear_bit(VMWDT_OPEN, &vmwdt_is_open);
+       return NOTIFY_DONE;
+}
+
+/*
+ * It makes no sense to go into suspend while the watchdog is running.
+ * Depending on the memory size, the watchdog might trigger, while we
+ * are still saving the memory.
+ * We reuse the open flag to ensure that suspend and watchdog open are
+ * exclusive operations
+ */
+static int vmwdt_suspend(void)
+{
+       if (test_and_set_bit(VMWDT_OPEN, &vmwdt_is_open)) {
+               pr_err("The watchdog is in use. "
+                       "This prevents hibernation or suspend.\n");
+               return NOTIFY_BAD;
+       }
+       if (test_bit(VMWDT_RUNNING, &vmwdt_is_open)) {
+               clear_bit(VMWDT_OPEN, &vmwdt_is_open);
+               pr_err("The watchdog is running. "
+                       "This prevents hibernation or suspend.\n");
+               return NOTIFY_BAD;
+       }
+       return NOTIFY_DONE;
+}
+
+/*
+ * This function is called for suspend and resume.
+ */
+static int vmwdt_power_event(struct notifier_block *this, unsigned long event,
+                            void *ptr)
+{
+       switch (event) {
+       case PM_POST_HIBERNATION:
+       case PM_POST_SUSPEND:
+               return vmwdt_resume();
+       case PM_HIBERNATION_PREPARE:
+       case PM_SUSPEND_PREPARE:
+               return vmwdt_suspend();
+       default:
+               return NOTIFY_DONE;
+       }
+}
+
+static struct notifier_block vmwdt_power_notifier = {
+       .notifier_call = vmwdt_power_event,
+};
+
 static const struct file_operations vmwdt_fops = {
        .open    = &vmwdt_open,
        .release = &vmwdt_close,
@@ -244,12 +306,21 @@ static int __init vmwdt_init(void)
        ret = vmwdt_probe();
        if (ret)
                return ret;
-       return misc_register(&vmwdt_dev);
+       ret = register_pm_notifier(&vmwdt_power_notifier);
+       if (ret)
+               return ret;
+       ret = misc_register(&vmwdt_dev);
+       if (ret) {
+               unregister_pm_notifier(&vmwdt_power_notifier);
+               return ret;
+       }
+       return 0;
 }
 module_init(vmwdt_init);
 
 static void __exit vmwdt_exit(void)
 {
-       WARN_ON(misc_deregister(&vmwdt_dev) != 0);
+       unregister_pm_notifier(&vmwdt_power_notifier);
+       misc_deregister(&vmwdt_dev);
 }
 module_exit(vmwdt_exit);
index 22ce765d537e9f0bccbca4c769131c07b3c03574..a5a62f1f7747c66107c71ea62be654473765541f 100644 (file)
@@ -1,11 +1,10 @@
 /*
- *  drivers/s390/cio/ccwgroup.c
  *  bus driver for ccwgroup
  *
- *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
- *                       IBM Corporation
- *    Author(s): Arnd Bergmann (arndb@de.ibm.com)
- *               Cornelia Huck (cornelia.huck@de.ibm.com)
+ *  Copyright IBM Corp. 2002, 2009
+ *
+ *  Author(s): Arnd Bergmann (arndb@de.ibm.com)
+ *            Cornelia Huck (cornelia.huck@de.ibm.com)
  */
 #include <linux/module.h>
 #include <linux/errno.h>
@@ -501,6 +500,74 @@ static void ccwgroup_shutdown(struct device *dev)
                gdrv->shutdown(gdev);
 }
 
+static int ccwgroup_pm_prepare(struct device *dev)
+{
+       struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
+       struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver);
+
+       /* Fail while device is being set online/offline. */
+       if (atomic_read(&gdev->onoff))
+               return -EAGAIN;
+
+       if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE)
+               return 0;
+
+       return gdrv->prepare ? gdrv->prepare(gdev) : 0;
+}
+
+static void ccwgroup_pm_complete(struct device *dev)
+{
+       struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
+       struct ccwgroup_driver *gdrv = to_ccwgroupdrv(dev->driver);
+
+       if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE)
+               return;
+
+       if (gdrv->complete)
+               gdrv->complete(gdev);
+}
+
+static int ccwgroup_pm_freeze(struct device *dev)
+{
+       struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
+       struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver);
+
+       if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE)
+               return 0;
+
+       return gdrv->freeze ? gdrv->freeze(gdev) : 0;
+}
+
+static int ccwgroup_pm_thaw(struct device *dev)
+{
+       struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
+       struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver);
+
+       if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE)
+               return 0;
+
+       return gdrv->thaw ? gdrv->thaw(gdev) : 0;
+}
+
+static int ccwgroup_pm_restore(struct device *dev)
+{
+       struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
+       struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver);
+
+       if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE)
+               return 0;
+
+       return gdrv->restore ? gdrv->restore(gdev) : 0;
+}
+
+static struct dev_pm_ops ccwgroup_pm_ops = {
+       .prepare = ccwgroup_pm_prepare,
+       .complete = ccwgroup_pm_complete,
+       .freeze = ccwgroup_pm_freeze,
+       .thaw = ccwgroup_pm_thaw,
+       .restore = ccwgroup_pm_restore,
+};
+
 static struct bus_type ccwgroup_bus_type = {
        .name   = "ccwgroup",
        .match  = ccwgroup_bus_match,
@@ -508,6 +575,7 @@ static struct bus_type ccwgroup_bus_type = {
        .probe  = ccwgroup_probe,
        .remove = ccwgroup_remove,
        .shutdown = ccwgroup_shutdown,
+       .pm = &ccwgroup_pm_ops,
 };
 
 
index 883f16f96f2286ffaa8b617cef0227b239b61799..1ecd3e567648f0cf97dec1b0d63060450aae2037 100644 (file)
@@ -549,8 +549,7 @@ cleanup:
        return ret;
 }
 
-static int
-__chsc_do_secm(struct channel_subsystem *css, int enable, void *page)
+int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page)
 {
        struct {
                struct chsc_header request;
index ba59bceace987968823330fb74abf048286b96e1..425e8f89a6c504c48e41feac82780695bfb911ca 100644 (file)
@@ -90,6 +90,7 @@ extern void chsc_free_sei_area(void);
 extern int chsc_enable_facility(int);
 struct channel_subsystem;
 extern int chsc_secm(struct channel_subsystem *, int);
+int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page);
 
 int chsc_chp_vary(struct chp_id chpid, int on);
 int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt,
index 93eca1731b81a56bb7d934a8c5e62119e8178eb9..cc5144b6f9d9c590f56bdb9112774130f23f97ed 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * Driver for s390 chsc subchannels
  *
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008, 2009
+ *
  * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
  *
  */
@@ -112,6 +113,31 @@ static void chsc_subchannel_shutdown(struct subchannel *sch)
        cio_disable_subchannel(sch);
 }
 
+static int chsc_subchannel_prepare(struct subchannel *sch)
+{
+       int cc;
+       struct schib schib;
+       /*
+        * Don't allow suspend while the subchannel is not idle
+        * since we don't have a way to clear the subchannel and
+        * cannot disable it with a request running.
+        */
+       cc = stsch(sch->schid, &schib);
+       if (!cc && scsw_stctl(&schib.scsw))
+               return -EAGAIN;
+       return 0;
+}
+
+static int chsc_subchannel_freeze(struct subchannel *sch)
+{
+       return cio_disable_subchannel(sch);
+}
+
+static int chsc_subchannel_restore(struct subchannel *sch)
+{
+       return cio_enable_subchannel(sch, (u32)(unsigned long)sch);
+}
+
 static struct css_device_id chsc_subchannel_ids[] = {
        { .match_flags = 0x1, .type =SUBCHANNEL_TYPE_CHSC, },
        { /* end of list */ },
@@ -125,6 +151,10 @@ static struct css_driver chsc_subchannel_driver = {
        .probe = chsc_subchannel_probe,
        .remove = chsc_subchannel_remove,
        .shutdown = chsc_subchannel_shutdown,
+       .prepare = chsc_subchannel_prepare,
+       .freeze = chsc_subchannel_freeze,
+       .thaw = chsc_subchannel_restore,
+       .restore = chsc_subchannel_restore,
        .name = "chsc_subchannel",
 };
 
index dc98b2c638628bf8a3174db78c53ec5823506a1e..30f516111307718234d579af922f51f01418bb49 100644 (file)
@@ -1204,6 +1204,11 @@ static ssize_t cmb_enable_store(struct device *dev,
 
 DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store);
 
+int ccw_set_cmf(struct ccw_device *cdev, int enable)
+{
+       return cmbops->set(cdev, enable ? 2 : 0);
+}
+
 /**
  * enable_cmf() - switch on the channel measurement for a specific device
  *  @cdev:     The ccw device to be enabled
index 0085d89017924c13d0b1ab0686cd3bb7571ba190..85d43c6bcb66a3521de03370d74c399c87440de8 100644 (file)
@@ -1,10 +1,10 @@
 /*
- *  drivers/s390/cio/css.c
- *  driver for channel subsystem
+ * driver for channel subsystem
  *
- *    Copyright IBM Corp. 2002,2008
- *    Author(s): Arnd Bergmann (arndb@de.ibm.com)
- *              Cornelia Huck (cornelia.huck@de.ibm.com)
+ * Copyright IBM Corp. 2002, 2009
+ *
+ * Author(s): Arnd Bergmann (arndb@de.ibm.com)
+ *           Cornelia Huck (cornelia.huck@de.ibm.com)
  */
 
 #define KMSG_COMPONENT "cio"
@@ -17,6 +17,7 @@
 #include <linux/errno.h>
 #include <linux/list.h>
 #include <linux/reboot.h>
+#include <linux/suspend.h>
 #include <asm/isc.h>
 #include <asm/crw.h>
 
@@ -779,6 +780,79 @@ static struct notifier_block css_reboot_notifier = {
        .notifier_call = css_reboot_event,
 };
 
+/*
+ * Since the css devices are neither on a bus nor have a class
+ * nor have a special device type, we cannot stop/restart channel
+ * path measurements via the normal suspend/resume callbacks, but have
+ * to use notifiers.
+ */
+static int css_power_event(struct notifier_block *this, unsigned long event,
+                          void *ptr)
+{
+       void *secm_area;
+       int ret, i;
+
+       switch (event) {
+       case PM_HIBERNATION_PREPARE:
+       case PM_SUSPEND_PREPARE:
+               ret = NOTIFY_DONE;
+               for (i = 0; i <= __MAX_CSSID; i++) {
+                       struct channel_subsystem *css;
+
+                       css = channel_subsystems[i];
+                       mutex_lock(&css->mutex);
+                       if (!css->cm_enabled) {
+                               mutex_unlock(&css->mutex);
+                               continue;
+                       }
+                       secm_area = (void *)get_zeroed_page(GFP_KERNEL |
+                                                           GFP_DMA);
+                       if (secm_area) {
+                               if (__chsc_do_secm(css, 0, secm_area))
+                                       ret = NOTIFY_BAD;
+                               free_page((unsigned long)secm_area);
+                       } else
+                               ret = NOTIFY_BAD;
+
+                       mutex_unlock(&css->mutex);
+               }
+               break;
+       case PM_POST_HIBERNATION:
+       case PM_POST_SUSPEND:
+               ret = NOTIFY_DONE;
+               for (i = 0; i <= __MAX_CSSID; i++) {
+                       struct channel_subsystem *css;
+
+                       css = channel_subsystems[i];
+                       mutex_lock(&css->mutex);
+                       if (!css->cm_enabled) {
+                               mutex_unlock(&css->mutex);
+                               continue;
+                       }
+                       secm_area = (void *)get_zeroed_page(GFP_KERNEL |
+                                                           GFP_DMA);
+                       if (secm_area) {
+                               if (__chsc_do_secm(css, 1, secm_area))
+                                       ret = NOTIFY_BAD;
+                               free_page((unsigned long)secm_area);
+                       } else
+                               ret = NOTIFY_BAD;
+
+                       mutex_unlock(&css->mutex);
+               }
+               /* search for subchannels, which appeared during hibernation */
+               css_schedule_reprobe();
+               break;
+       default:
+               ret = NOTIFY_DONE;
+       }
+       return ret;
+
+}
+static struct notifier_block css_power_notifier = {
+       .notifier_call = css_power_event,
+};
+
 /*
  * Now that the driver core is running, we can setup our channel subsystem.
  * The struct subchannel's are created during probing (except for the
@@ -852,6 +926,11 @@ init_channel_subsystem (void)
        ret = register_reboot_notifier(&css_reboot_notifier);
        if (ret)
                goto out_unregister;
+       ret = register_pm_notifier(&css_power_notifier);
+       if (ret) {
+               unregister_reboot_notifier(&css_reboot_notifier);
+               goto out_unregister;
+       }
        css_init_done = 1;
 
        /* Enable default isc for I/O subchannels. */
@@ -953,6 +1032,73 @@ static int css_uevent(struct device *dev, struct kobj_uevent_env *env)
        return ret;
 }
 
+static int css_pm_prepare(struct device *dev)
+{
+       struct subchannel *sch = to_subchannel(dev);
+       struct css_driver *drv;
+
+       if (mutex_is_locked(&sch->reg_mutex))
+               return -EAGAIN;
+       if (!sch->dev.driver)
+               return 0;
+       drv = to_cssdriver(sch->dev.driver);
+       /* Notify drivers that they may not register children. */
+       return drv->prepare ? drv->prepare(sch) : 0;
+}
+
+static void css_pm_complete(struct device *dev)
+{
+       struct subchannel *sch = to_subchannel(dev);
+       struct css_driver *drv;
+
+       if (!sch->dev.driver)
+               return;
+       drv = to_cssdriver(sch->dev.driver);
+       if (drv->complete)
+               drv->complete(sch);
+}
+
+static int css_pm_freeze(struct device *dev)
+{
+       struct subchannel *sch = to_subchannel(dev);
+       struct css_driver *drv;
+
+       if (!sch->dev.driver)
+               return 0;
+       drv = to_cssdriver(sch->dev.driver);
+       return drv->freeze ? drv->freeze(sch) : 0;
+}
+
+static int css_pm_thaw(struct device *dev)
+{
+       struct subchannel *sch = to_subchannel(dev);
+       struct css_driver *drv;
+
+       if (!sch->dev.driver)
+               return 0;
+       drv = to_cssdriver(sch->dev.driver);
+       return drv->thaw ? drv->thaw(sch) : 0;
+}
+
+static int css_pm_restore(struct device *dev)
+{
+       struct subchannel *sch = to_subchannel(dev);
+       struct css_driver *drv;
+
+       if (!sch->dev.driver)
+               return 0;
+       drv = to_cssdriver(sch->dev.driver);
+       return drv->restore ? drv->restore(sch) : 0;
+}
+
+static struct dev_pm_ops css_pm_ops = {
+       .prepare = css_pm_prepare,
+       .complete = css_pm_complete,
+       .freeze = css_pm_freeze,
+       .thaw = css_pm_thaw,
+       .restore = css_pm_restore,
+};
+
 struct bus_type css_bus_type = {
        .name     = "css",
        .match    = css_bus_match,
@@ -960,6 +1106,7 @@ struct bus_type css_bus_type = {
        .remove   = css_remove,
        .shutdown = css_shutdown,
        .uevent   = css_uevent,
+       .pm = &css_pm_ops,
 };
 
 /**
index 57ebf120f825b00f68ee934e9e9a26324beedd09..9763eeec74587d3a106dc5eae49eacd40505f899 100644 (file)
@@ -70,6 +70,11 @@ struct chp_link;
  * @probe: function called on probe
  * @remove: function called on remove
  * @shutdown: called at device shutdown
+ * @prepare: prepare for pm state transition
+ * @complete: undo work done in @prepare
+ * @freeze: callback for freezing during hibernation snapshotting
+ * @thaw: undo work done in @freeze
+ * @restore: callback for restoring after hibernation
  * @name: name of the device driver
  */
 struct css_driver {
@@ -82,6 +87,11 @@ struct css_driver {
        int (*probe)(struct subchannel *);
        int (*remove)(struct subchannel *);
        void (*shutdown)(struct subchannel *);
+       int (*prepare) (struct subchannel *);
+       void (*complete) (struct subchannel *);
+       int (*freeze)(struct subchannel *);
+       int (*thaw) (struct subchannel *);
+       int (*restore)(struct subchannel *);
        const char *name;
 };
 
index 35441fa16be1de86dcb72dd02d8e319da458edde..3c57c1a18bb8772db79a73159a98244ae4c89972 100644 (file)
@@ -138,6 +138,19 @@ static struct css_device_id io_subchannel_ids[] = {
 };
 MODULE_DEVICE_TABLE(css, io_subchannel_ids);
 
+static int io_subchannel_prepare(struct subchannel *sch)
+{
+       struct ccw_device *cdev;
+       /*
+        * Don't allow suspend while a ccw device registration
+        * is still outstanding.
+        */
+       cdev = sch_get_cdev(sch);
+       if (cdev && !device_is_registered(&cdev->dev))
+               return -EAGAIN;
+       return 0;
+}
+
 static struct css_driver io_subchannel_driver = {
        .owner = THIS_MODULE,
        .subchannel_type = io_subchannel_ids,
@@ -148,6 +161,7 @@ static struct css_driver io_subchannel_driver = {
        .probe = io_subchannel_probe,
        .remove = io_subchannel_remove,
        .shutdown = io_subchannel_shutdown,
+       .prepare = io_subchannel_prepare,
 };
 
 struct workqueue_struct *ccw_device_work;
@@ -1775,6 +1789,15 @@ ccw_device_probe_console(void)
        return &console_cdev;
 }
 
+static int ccw_device_pm_restore(struct device *dev);
+
+int ccw_device_force_console(void)
+{
+       if (!console_cdev_in_use)
+               return -ENODEV;
+       return ccw_device_pm_restore(&console_cdev.dev);
+}
+EXPORT_SYMBOL_GPL(ccw_device_force_console);
 
 const char *cio_get_console_cdev_name(struct subchannel *sch)
 {
@@ -1895,6 +1918,242 @@ static void ccw_device_shutdown(struct device *dev)
        disable_cmf(cdev);
 }
 
+static int ccw_device_pm_prepare(struct device *dev)
+{
+       struct ccw_device *cdev = to_ccwdev(dev);
+
+       if (work_pending(&cdev->private->kick_work))
+               return -EAGAIN;
+       /* Fail while device is being set online/offline. */
+       if (atomic_read(&cdev->private->onoff))
+               return -EAGAIN;
+
+       if (cdev->online && cdev->drv && cdev->drv->prepare)
+               return cdev->drv->prepare(cdev);
+
+       return 0;
+}
+
+static void ccw_device_pm_complete(struct device *dev)
+{
+       struct ccw_device *cdev = to_ccwdev(dev);
+
+       if (cdev->online && cdev->drv && cdev->drv->complete)
+               cdev->drv->complete(cdev);
+}
+
+static int ccw_device_pm_freeze(struct device *dev)
+{
+       struct ccw_device *cdev = to_ccwdev(dev);
+       struct subchannel *sch = to_subchannel(cdev->dev.parent);
+       int ret, cm_enabled;
+
+       /* Fail suspend while device is in transistional state. */
+       if (!dev_fsm_final_state(cdev))
+               return -EAGAIN;
+       if (!cdev->online)
+               return 0;
+       if (cdev->drv && cdev->drv->freeze) {
+               ret = cdev->drv->freeze(cdev);
+               if (ret)
+                       return ret;
+       }
+
+       spin_lock_irq(sch->lock);
+       cm_enabled = cdev->private->cmb != NULL;
+       spin_unlock_irq(sch->lock);
+       if (cm_enabled) {
+               /* Don't have the css write on memory. */
+               ret = ccw_set_cmf(cdev, 0);
+               if (ret)
+                       return ret;
+       }
+       /* From here on, disallow device driver I/O. */
+       spin_lock_irq(sch->lock);
+       ret = cio_disable_subchannel(sch);
+       spin_unlock_irq(sch->lock);
+
+       return ret;
+}
+
+static int ccw_device_pm_thaw(struct device *dev)
+{
+       struct ccw_device *cdev = to_ccwdev(dev);
+       struct subchannel *sch = to_subchannel(cdev->dev.parent);
+       int ret, cm_enabled;
+
+       if (!cdev->online)
+               return 0;
+
+       spin_lock_irq(sch->lock);
+       /* Allow device driver I/O again. */
+       ret = cio_enable_subchannel(sch, (u32)(addr_t)sch);
+       cm_enabled = cdev->private->cmb != NULL;
+       spin_unlock_irq(sch->lock);
+       if (ret)
+               return ret;
+
+       if (cm_enabled) {
+               ret = ccw_set_cmf(cdev, 1);
+               if (ret)
+                       return ret;
+       }
+
+       if (cdev->drv && cdev->drv->thaw)
+               ret = cdev->drv->thaw(cdev);
+
+       return ret;
+}
+
+static void __ccw_device_pm_restore(struct ccw_device *cdev)
+{
+       struct subchannel *sch = to_subchannel(cdev->dev.parent);
+       int ret;
+
+       if (cio_is_console(sch->schid))
+               goto out;
+       /*
+        * While we were sleeping, devices may have gone or become
+        * available again. Kick re-detection.
+        */
+       spin_lock_irq(sch->lock);
+       cdev->private->flags.resuming = 1;
+       ret = ccw_device_recognition(cdev);
+       spin_unlock_irq(sch->lock);
+       if (ret) {
+               CIO_MSG_EVENT(0, "Couldn't start recognition for device "
+                             "%s (ret=%d)\n", dev_name(&cdev->dev), ret);
+               spin_lock_irq(sch->lock);
+               cdev->private->state = DEV_STATE_DISCONNECTED;
+               spin_unlock_irq(sch->lock);
+               /* notify driver after the resume cb */
+               goto out;
+       }
+       wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev) ||
+                  cdev->private->state == DEV_STATE_DISCONNECTED);
+
+out:
+       cdev->private->flags.resuming = 0;
+}
+
+static int resume_handle_boxed(struct ccw_device *cdev)
+{
+       cdev->private->state = DEV_STATE_BOXED;
+       if (ccw_device_notify(cdev, CIO_BOXED))
+               return 0;
+       ccw_device_schedule_sch_unregister(cdev);
+       return -ENODEV;
+}
+
+static int resume_handle_disc(struct ccw_device *cdev)
+{
+       cdev->private->state = DEV_STATE_DISCONNECTED;
+       if (ccw_device_notify(cdev, CIO_GONE))
+               return 0;
+       ccw_device_schedule_sch_unregister(cdev);
+       return -ENODEV;
+}
+
+static int ccw_device_pm_restore(struct device *dev)
+{
+       struct ccw_device *cdev = to_ccwdev(dev);
+       struct subchannel *sch = to_subchannel(cdev->dev.parent);
+       int ret = 0, cm_enabled;
+
+       __ccw_device_pm_restore(cdev);
+       spin_lock_irq(sch->lock);
+       if (cio_is_console(sch->schid)) {
+               cio_enable_subchannel(sch, (u32)(addr_t)sch);
+               spin_unlock_irq(sch->lock);
+               goto out_restore;
+       }
+       cdev->private->flags.donotify = 0;
+       /* check recognition results */
+       switch (cdev->private->state) {
+       case DEV_STATE_OFFLINE:
+               break;
+       case DEV_STATE_BOXED:
+               ret = resume_handle_boxed(cdev);
+               spin_unlock_irq(sch->lock);
+               if (ret)
+                       goto out;
+               goto out_restore;
+       case DEV_STATE_DISCONNECTED:
+               goto out_disc_unlock;
+       default:
+               goto out_unreg_unlock;
+       }
+       /* check if the device id has changed */
+       if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) {
+               CIO_MSG_EVENT(0, "resume: sch %s: failed (devno changed from "
+                             "%04x to %04x)\n", dev_name(&sch->dev),
+                             cdev->private->dev_id.devno,
+                             sch->schib.pmcw.dev);
+               goto out_unreg_unlock;
+       }
+       /* check if the device type has changed */
+       if (!ccw_device_test_sense_data(cdev)) {
+               ccw_device_update_sense_data(cdev);
+               PREPARE_WORK(&cdev->private->kick_work,
+                            ccw_device_do_unbind_bind);
+               queue_work(ccw_device_work, &cdev->private->kick_work);
+               ret = -ENODEV;
+               goto out_unlock;
+       }
+       if (!cdev->online) {
+               ret = 0;
+               goto out_unlock;
+       }
+       ret = ccw_device_online(cdev);
+       if (ret)
+               goto out_disc_unlock;
+
+       cm_enabled = cdev->private->cmb != NULL;
+       spin_unlock_irq(sch->lock);
+
+       wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
+       if (cdev->private->state != DEV_STATE_ONLINE) {
+               spin_lock_irq(sch->lock);
+               goto out_disc_unlock;
+       }
+       if (cm_enabled) {
+               ret = ccw_set_cmf(cdev, 1);
+               if (ret) {
+                       CIO_MSG_EVENT(2, "resume: cdev %s: cmf failed "
+                                     "(rc=%d)\n", dev_name(&cdev->dev), ret);
+                       ret = 0;
+               }
+       }
+
+out_restore:
+       if (cdev->online && cdev->drv && cdev->drv->restore)
+               ret = cdev->drv->restore(cdev);
+out:
+       return ret;
+
+out_disc_unlock:
+       ret = resume_handle_disc(cdev);
+       spin_unlock_irq(sch->lock);
+       if (ret)
+               return ret;
+       goto out_restore;
+
+out_unreg_unlock:
+       ccw_device_schedule_sch_unregister(cdev);
+       ret = -ENODEV;
+out_unlock:
+       spin_unlock_irq(sch->lock);
+       return ret;
+}
+
+static struct dev_pm_ops ccw_pm_ops = {
+       .prepare = ccw_device_pm_prepare,
+       .complete = ccw_device_pm_complete,
+       .freeze = ccw_device_pm_freeze,
+       .thaw = ccw_device_pm_thaw,
+       .restore = ccw_device_pm_restore,
+};
+
 struct bus_type ccw_bus_type = {
        .name   = "ccw",
        .match  = ccw_bus_match,
@@ -1902,6 +2161,7 @@ struct bus_type ccw_bus_type = {
        .probe  = ccw_device_probe,
        .remove = ccw_device_remove,
        .shutdown = ccw_device_shutdown,
+       .pm = &ccw_pm_ops,
 };
 
 /**
index f1cbbd94ad4e76fbaaba927b1988ede2107d515c..e3975107a5787fa314b0ec16feb7c1d313b2d1b1 100644 (file)
@@ -87,6 +87,8 @@ int ccw_device_is_orphan(struct ccw_device *);
 int ccw_device_recognition(struct ccw_device *);
 int ccw_device_online(struct ccw_device *);
 int ccw_device_offline(struct ccw_device *);
+void ccw_device_update_sense_data(struct ccw_device *);
+int ccw_device_test_sense_data(struct ccw_device *);
 void ccw_device_schedule_sch_unregister(struct ccw_device *);
 int ccw_purge_blacklisted(void);
 
@@ -133,5 +135,6 @@ extern struct bus_type ccw_bus_type;
 void retry_set_schib(struct ccw_device *cdev);
 void cmf_retry_copy_block(struct ccw_device *);
 int cmf_reenable(struct ccw_device *);
+int ccw_set_cmf(struct ccw_device *cdev, int enable);
 extern struct device_attribute dev_attr_cmb_enable;
 #endif
index e46049261561986174c8448714e811ef6344a092..3db88c52d2879e9dc4cac73dd40e4967f5719e5a 100644 (file)
@@ -177,29 +177,21 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev)
        panic("Can't stop i/o on subchannel.\n");
 }
 
-static int
-ccw_device_handle_oper(struct ccw_device *cdev)
+void ccw_device_update_sense_data(struct ccw_device *cdev)
 {
-       struct subchannel *sch;
+       memset(&cdev->id, 0, sizeof(cdev->id));
+       cdev->id.cu_type   = cdev->private->senseid.cu_type;
+       cdev->id.cu_model  = cdev->private->senseid.cu_model;
+       cdev->id.dev_type  = cdev->private->senseid.dev_type;
+       cdev->id.dev_model = cdev->private->senseid.dev_model;
+}
 
-       sch = to_subchannel(cdev->dev.parent);
-       cdev->private->flags.recog_done = 1;
-       /*
-        * Check if cu type and device type still match. If
-        * not, it is certainly another device and we have to
-        * de- and re-register.
-        */
-       if (cdev->id.cu_type != cdev->private->senseid.cu_type ||
-           cdev->id.cu_model != cdev->private->senseid.cu_model ||
-           cdev->id.dev_type != cdev->private->senseid.dev_type ||
-           cdev->id.dev_model != cdev->private->senseid.dev_model) {
-               PREPARE_WORK(&cdev->private->kick_work,
-                            ccw_device_do_unbind_bind);
-               queue_work(ccw_device_work, &cdev->private->kick_work);
-               return 0;
-       }
-       cdev->private->flags.donotify = 1;
-       return 1;
+int ccw_device_test_sense_data(struct ccw_device *cdev)
+{
+       return cdev->id.cu_type == cdev->private->senseid.cu_type &&
+               cdev->id.cu_model == cdev->private->senseid.cu_model &&
+               cdev->id.dev_type == cdev->private->senseid.dev_type &&
+               cdev->id.dev_model == cdev->private->senseid.dev_model;
 }
 
 /*
@@ -233,7 +225,7 @@ static void
 ccw_device_recog_done(struct ccw_device *cdev, int state)
 {
        struct subchannel *sch;
-       int notify, old_lpm, same_dev;
+       int old_lpm;
 
        sch = to_subchannel(cdev->dev.parent);
 
@@ -263,8 +255,12 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
                wake_up(&cdev->private->wait_q);
                return;
        }
-       notify = 0;
-       same_dev = 0; /* Keep the compiler quiet... */
+       if (cdev->private->flags.resuming) {
+               cdev->private->state = state;
+               cdev->private->flags.recog_done = 1;
+               wake_up(&cdev->private->wait_q);
+               return;
+       }
        switch (state) {
        case DEV_STATE_NOT_OPER:
                CIO_MSG_EVENT(2, "SenseID : unknown device %04x on "
@@ -273,34 +269,31 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
                              sch->schid.ssid, sch->schid.sch_no);
                break;
        case DEV_STATE_OFFLINE:
-               if (cdev->online) {
-                       same_dev = ccw_device_handle_oper(cdev);
-                       notify = 1;
+               if (!cdev->online) {
+                       ccw_device_update_sense_data(cdev);
+                       /* Issue device info message. */
+                       CIO_MSG_EVENT(4, "SenseID : device 0.%x.%04x reports: "
+                                     "CU  Type/Mod = %04X/%02X, Dev Type/Mod "
+                                     "= %04X/%02X\n",
+                                     cdev->private->dev_id.ssid,
+                                     cdev->private->dev_id.devno,
+                                     cdev->id.cu_type, cdev->id.cu_model,
+                                     cdev->id.dev_type, cdev->id.dev_model);
+                       break;
                }
-               /* fill out sense information */
-               memset(&cdev->id, 0, sizeof(cdev->id));
-               cdev->id.cu_type   = cdev->private->senseid.cu_type;
-               cdev->id.cu_model  = cdev->private->senseid.cu_model;
-               cdev->id.dev_type  = cdev->private->senseid.dev_type;
-               cdev->id.dev_model = cdev->private->senseid.dev_model;
-               if (notify) {
-                       cdev->private->state = DEV_STATE_OFFLINE;
-                       if (same_dev) {
-                               /* Get device online again. */
-                               ccw_device_online(cdev);
-                               wake_up(&cdev->private->wait_q);
-                       }
-                       return;
+               cdev->private->state = DEV_STATE_OFFLINE;
+               cdev->private->flags.recog_done = 1;
+               if (ccw_device_test_sense_data(cdev)) {
+                       cdev->private->flags.donotify = 1;
+                       ccw_device_online(cdev);
+                       wake_up(&cdev->private->wait_q);
+               } else {
+                       ccw_device_update_sense_data(cdev);
+                       PREPARE_WORK(&cdev->private->kick_work,
+                                    ccw_device_do_unbind_bind);
+                       queue_work(ccw_device_work, &cdev->private->kick_work);
                }
-               /* Issue device info message. */
-               CIO_MSG_EVENT(4, "SenseID : device 0.%x.%04x reports: "
-                             "CU  Type/Mod = %04X/%02X, Dev Type/Mod = "
-                             "%04X/%02X\n",
-                             cdev->private->dev_id.ssid,
-                             cdev->private->dev_id.devno,
-                             cdev->id.cu_type, cdev->id.cu_model,
-                             cdev->id.dev_type, cdev->id.dev_model);
-               break;
+               return;
        case DEV_STATE_BOXED:
                CIO_MSG_EVENT(0, "SenseID : boxed device %04x on "
                              " subchannel 0.%x.%04x\n",
@@ -502,9 +495,6 @@ ccw_device_recognition(struct ccw_device *cdev)
        struct subchannel *sch;
        int ret;
 
-       if ((cdev->private->state != DEV_STATE_NOT_OPER) &&
-           (cdev->private->state != DEV_STATE_BOXED))
-               return -EINVAL;
        sch = to_subchannel(cdev->dev.parent);
        ret = cio_enable_subchannel(sch, (u32)(addr_t)sch);
        if (ret != 0)
index bf0a24af39a0542be842f5705cc49ec58da63b2f..2d0efee8a290c54ff9564a156ae05cb8c952a7bd 100644 (file)
@@ -1,10 +1,8 @@
 /*
- *  drivers/s390/cio/device_ops.c
+ * Copyright IBM Corp. 2002, 2009
  *
- *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
- *                      IBM Corporation
- *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
- *               Cornelia Huck (cornelia.huck@de.ibm.com)
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *           Cornelia Huck (cornelia.huck@de.ibm.com)
  */
 #include <linux/module.h>
 #include <linux/init.h>
@@ -116,12 +114,15 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
 
        if (!cdev || !cdev->dev.parent)
                return -ENODEV;
+       sch = to_subchannel(cdev->dev.parent);
+       if (!sch->schib.pmcw.ena)
+               return -EINVAL;
        if (cdev->private->state == DEV_STATE_NOT_OPER)
                return -ENODEV;
        if (cdev->private->state != DEV_STATE_ONLINE &&
            cdev->private->state != DEV_STATE_W4SENSE)
                return -EINVAL;
-       sch = to_subchannel(cdev->dev.parent);
+
        ret = cio_clear(sch);
        if (ret == 0)
                cdev->private->intparm = intparm;
@@ -162,6 +163,8 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
        if (!cdev || !cdev->dev.parent)
                return -ENODEV;
        sch = to_subchannel(cdev->dev.parent);
+       if (!sch->schib.pmcw.ena)
+               return -EINVAL;
        if (cdev->private->state == DEV_STATE_NOT_OPER)
                return -ENODEV;
        if (cdev->private->state == DEV_STATE_VERIFY ||
@@ -337,12 +340,15 @@ int ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
 
        if (!cdev || !cdev->dev.parent)
                return -ENODEV;
+       sch = to_subchannel(cdev->dev.parent);
+       if (!sch->schib.pmcw.ena)
+               return -EINVAL;
        if (cdev->private->state == DEV_STATE_NOT_OPER)
                return -ENODEV;
        if (cdev->private->state != DEV_STATE_ONLINE &&
            cdev->private->state != DEV_STATE_W4SENSE)
                return -EINVAL;
-       sch = to_subchannel(cdev->dev.parent);
+
        ret = cio_halt(sch);
        if (ret == 0)
                cdev->private->intparm = intparm;
@@ -369,6 +375,8 @@ int ccw_device_resume(struct ccw_device *cdev)
        if (!cdev || !cdev->dev.parent)
                return -ENODEV;
        sch = to_subchannel(cdev->dev.parent);
+       if (!sch->schib.pmcw.ena)
+               return -EINVAL;
        if (cdev->private->state == DEV_STATE_NOT_OPER)
                return -ENODEV;
        if (cdev->private->state != DEV_STATE_ONLINE ||
@@ -580,6 +588,8 @@ int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw,
        int rc;
 
        sch = to_subchannel(cdev->dev.parent);
+       if (!sch->schib.pmcw.ena)
+               return -EINVAL;
        if (cdev->private->state != DEV_STATE_ONLINE)
                return -EIO;
        /* Adjust requested path mask to excluded varied off paths. */
@@ -669,6 +679,8 @@ int ccw_device_tm_intrg(struct ccw_device *cdev)
 {
        struct subchannel *sch = to_subchannel(cdev->dev.parent);
 
+       if (!sch->schib.pmcw.ena)
+               return -EINVAL;
        if (cdev->private->state != DEV_STATE_ONLINE)
                return -EIO;
        if (!scsw_is_tm(&sch->schib.scsw) ||
index c4f3e7c9a85482996dbd41b4249651d108be2e4f..0b8f381bd20e888f8ad7ad1c46f9da229337fab6 100644 (file)
@@ -107,6 +107,7 @@ struct ccw_device_private {
                unsigned int recog_done:1;  /* dev. recog. complete */
                unsigned int fake_irb:1;    /* deliver faked irb */
                unsigned int intretry:1;    /* retry internal operation */
+               unsigned int resuming:1;    /* recognition while resume */
        } __attribute__((packed)) flags;
        unsigned long intparm;  /* user interruption parameter */
        struct qdio_irq *qdio_data;
index 7b6f46ddf3c304146b5b7e0afd34233f34b01b42..f370f8d460a721674f5537d79c8e528d23bb4b5e 100644 (file)
@@ -3,12 +3,12 @@
  *    ESCON CLAW network driver
  *
  *  Linux for zSeries version
- *    Copyright (C) 2002,2005 IBM Corporation
+ *    Copyright IBM Corp. 2002, 2009
  *  Author(s) Original code written by:
- *              Kazuo Iimura (iimura@jp.ibm.com)
+ *             Kazuo Iimura <iimura@jp.ibm.com>
  *           Rewritten by
- *              Andy Richter (richtera@us.ibm.com)
- *              Marc Price (mwprice@us.ibm.com)
+ *             Andy Richter <richtera@us.ibm.com>
+ *             Marc Price <mwprice@us.ibm.com>
  *
  *    sysfs parms:
  *   group x.x.rrrr,x.x.wwww
@@ -253,6 +253,11 @@ static void claw_free_wrt_buf(struct net_device *dev);
 /* Functions for unpack reads   */
 static void unpack_read(struct net_device *dev);
 
+static int claw_pm_prepare(struct ccwgroup_device *gdev)
+{
+       return -EPERM;
+}
+
 /* ccwgroup table  */
 
 static struct ccwgroup_driver claw_group_driver = {
@@ -264,6 +269,7 @@ static struct ccwgroup_driver claw_group_driver = {
         .remove      = claw_remove_device,
         .set_online  = claw_new_device,
         .set_offline = claw_shutdown_device,
+       .prepare     = claw_pm_prepare,
 };
 
 /*
@@ -284,7 +290,7 @@ claw_probe(struct ccwgroup_device *cgdev)
        if (!get_device(&cgdev->dev))
                return -ENODEV;
        privptr = kzalloc(sizeof(struct claw_privbk), GFP_KERNEL);
-       cgdev->dev.driver_data = privptr;
+       dev_set_drvdata(&cgdev->dev, privptr);
        if (privptr == NULL) {
                probe_error(cgdev);
                put_device(&cgdev->dev);
@@ -591,14 +597,14 @@ claw_irq_handler(struct ccw_device *cdev,
 
        CLAW_DBF_TEXT(4, trace, "clawirq");
         /* Bypass all 'unsolicited interrupts' */
-       if (!cdev->dev.driver_data) {
+       privptr = dev_get_drvdata(&cdev->dev);
+       if (!privptr) {
                dev_warn(&cdev->dev, "An uninitialized CLAW device received an"
                        " IRQ, c-%02x d-%02x\n",
                        irb->scsw.cmd.cstat, irb->scsw.cmd.dstat);
                CLAW_DBF_TEXT(2, trace, "badirq");
                 return;
         }
-       privptr = (struct claw_privbk *)cdev->dev.driver_data;
 
        /* Try to extract channel from driver data. */
        if (privptr->channel[READ].cdev == cdev)
@@ -1980,9 +1986,9 @@ probe_error( struct ccwgroup_device *cgdev)
        struct claw_privbk *privptr;
 
        CLAW_DBF_TEXT(4, trace, "proberr");
-       privptr = (struct claw_privbk *) cgdev->dev.driver_data;
+       privptr = dev_get_drvdata(&cgdev->dev);
        if (privptr != NULL) {
-               cgdev->dev.driver_data = NULL;
+               dev_set_drvdata(&cgdev->dev, NULL);
                kfree(privptr->p_env);
                kfree(privptr->p_mtc_envelope);
                kfree(privptr);
@@ -2911,9 +2917,9 @@ claw_new_device(struct ccwgroup_device *cgdev)
        dev_info(&cgdev->dev, "add for %s\n",
                 dev_name(&cgdev->cdev[READ]->dev));
        CLAW_DBF_TEXT(2, setup, "new_dev");
-       privptr = cgdev->dev.driver_data;
-       cgdev->cdev[READ]->dev.driver_data = privptr;
-       cgdev->cdev[WRITE]->dev.driver_data = privptr;
+       privptr = dev_get_drvdata(&cgdev->dev);
+       dev_set_drvdata(&cgdev->cdev[READ]->dev, privptr);
+       dev_set_drvdata(&cgdev->cdev[WRITE]->dev, privptr);
        if (!privptr)
                return -ENODEV;
        p_env = privptr->p_env;
@@ -2950,9 +2956,9 @@ claw_new_device(struct ccwgroup_device *cgdev)
                goto out;
        }
        dev->ml_priv = privptr;
-       cgdev->dev.driver_data = privptr;
-        cgdev->cdev[READ]->dev.driver_data = privptr;
-        cgdev->cdev[WRITE]->dev.driver_data = privptr;
+       dev_set_drvdata(&cgdev->dev, privptr);
+       dev_set_drvdata(&cgdev->cdev[READ]->dev, privptr);
+       dev_set_drvdata(&cgdev->cdev[WRITE]->dev, privptr);
        /* sysfs magic */
         SET_NETDEV_DEV(dev, &cgdev->dev);
        if (register_netdev(dev) != 0) {
@@ -3018,7 +3024,7 @@ claw_shutdown_device(struct ccwgroup_device *cgdev)
        int     ret;
 
        CLAW_DBF_TEXT_(2, setup, "%s", dev_name(&cgdev->dev));
-       priv = cgdev->dev.driver_data;
+       priv = dev_get_drvdata(&cgdev->dev);
        if (!priv)
                return -ENODEV;
        ndev = priv->channel[READ].ndev;
@@ -3048,7 +3054,7 @@ claw_remove_device(struct ccwgroup_device *cgdev)
 
        BUG_ON(!cgdev);
        CLAW_DBF_TEXT_(2, setup, "%s", dev_name(&cgdev->dev));
-       priv = cgdev->dev.driver_data;
+       priv = dev_get_drvdata(&cgdev->dev);
        BUG_ON(!priv);
        dev_info(&cgdev->dev, " will be removed.\n");
        if (cgdev->state == CCWGROUP_ONLINE)
@@ -3063,9 +3069,9 @@ claw_remove_device(struct ccwgroup_device *cgdev)
        kfree(priv->channel[1].irb);
        priv->channel[1].irb=NULL;
        kfree(priv);
-       cgdev->dev.driver_data=NULL;
-       cgdev->cdev[READ]->dev.driver_data = NULL;
-       cgdev->cdev[WRITE]->dev.driver_data = NULL;
+       dev_set_drvdata(&cgdev->dev, NULL);
+       dev_set_drvdata(&cgdev->cdev[READ]->dev, NULL);
+       dev_set_drvdata(&cgdev->cdev[WRITE]->dev, NULL);
        put_device(&cgdev->dev);
 
        return;
@@ -3081,7 +3087,7 @@ claw_hname_show(struct device *dev, struct device_attribute *attr, char *buf)
        struct claw_privbk *priv;
        struct claw_env *  p_env;
 
-       priv = dev->driver_data;
+       priv = dev_get_drvdata(dev);
        if (!priv)
                return -ENODEV;
        p_env = priv->p_env;
@@ -3095,7 +3101,7 @@ claw_hname_write(struct device *dev, struct device_attribute *attr,
        struct claw_privbk *priv;
        struct claw_env *  p_env;
 
-       priv = dev->driver_data;
+       priv = dev_get_drvdata(dev);
        if (!priv)
                return -ENODEV;
        p_env = priv->p_env;
@@ -3119,7 +3125,7 @@ claw_adname_show(struct device *dev, struct device_attribute *attr, char *buf)
        struct claw_privbk *priv;
        struct claw_env *  p_env;
 
-       priv = dev->driver_data;
+       priv = dev_get_drvdata(dev);
        if (!priv)
                return -ENODEV;
        p_env = priv->p_env;
@@ -3133,7 +3139,7 @@ claw_adname_write(struct device *dev, struct device_attribute *attr,
        struct claw_privbk *priv;
        struct claw_env *  p_env;
 
-       priv = dev->driver_data;
+       priv = dev_get_drvdata(dev);
        if (!priv)
                return -ENODEV;
        p_env = priv->p_env;
@@ -3157,7 +3163,7 @@ claw_apname_show(struct device *dev, struct device_attribute *attr, char *buf)
        struct claw_privbk *priv;
        struct claw_env *  p_env;
 
-       priv = dev->driver_data;
+       priv = dev_get_drvdata(dev);
        if (!priv)
                return -ENODEV;
        p_env = priv->p_env;
@@ -3172,7 +3178,7 @@ claw_apname_write(struct device *dev, struct device_attribute *attr,
        struct claw_privbk *priv;
        struct claw_env *  p_env;
 
-       priv = dev->driver_data;
+       priv = dev_get_drvdata(dev);
        if (!priv)
                return -ENODEV;
        p_env = priv->p_env;
@@ -3206,7 +3212,7 @@ claw_wbuff_show(struct device *dev, struct device_attribute *attr, char *buf)
        struct claw_privbk *priv;
        struct claw_env * p_env;
 
-       priv = dev->driver_data;
+       priv = dev_get_drvdata(dev);
        if (!priv)
                return -ENODEV;
        p_env = priv->p_env;
@@ -3221,7 +3227,7 @@ claw_wbuff_write(struct device *dev, struct device_attribute *attr,
        struct claw_env *  p_env;
        int nnn,max;
 
-       priv = dev->driver_data;
+       priv = dev_get_drvdata(dev);
        if (!priv)
                return -ENODEV;
        p_env = priv->p_env;
@@ -3248,7 +3254,7 @@ claw_rbuff_show(struct device *dev, struct device_attribute *attr, char *buf)
        struct claw_privbk *priv;
        struct claw_env *  p_env;
 
-       priv = dev->driver_data;
+       priv = dev_get_drvdata(dev);
        if (!priv)
                return -ENODEV;
        p_env = priv->p_env;
@@ -3263,7 +3269,7 @@ claw_rbuff_write(struct device *dev, struct device_attribute *attr,
        struct claw_env *p_env;
        int nnn,max;
 
-       priv = dev->driver_data;
+       priv = dev_get_drvdata(dev);
        if (!priv)
                return -ENODEV;
        p_env = priv->p_env;
index 54c4649a493bd27399f107032926662a79370d15..222e4739443715902dd5e5ce38b1f5a924b4e3cb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * drivers/s390/net/ctcm_main.c
  *
- * Copyright IBM Corp. 2001, 2007
+ * Copyright IBM Corp. 2001, 2009
  * Author(s):
  *     Original CTC driver(s):
  *             Fritz Elfert (felfert@millenux.com)
@@ -1688,6 +1688,38 @@ static void ctcm_remove_device(struct ccwgroup_device *cgdev)
        put_device(&cgdev->dev);
 }
 
+static int ctcm_pm_suspend(struct ccwgroup_device *gdev)
+{
+       struct ctcm_priv *priv = dev_get_drvdata(&gdev->dev);
+
+       if (gdev->state == CCWGROUP_OFFLINE)
+               return 0;
+       netif_device_detach(priv->channel[READ]->netdev);
+       ctcm_close(priv->channel[READ]->netdev);
+       ccw_device_set_offline(gdev->cdev[1]);
+       ccw_device_set_offline(gdev->cdev[0]);
+       return 0;
+}
+
+static int ctcm_pm_resume(struct ccwgroup_device *gdev)
+{
+       struct ctcm_priv *priv = dev_get_drvdata(&gdev->dev);
+       int rc;
+
+       if (gdev->state == CCWGROUP_OFFLINE)
+               return 0;
+       rc = ccw_device_set_online(gdev->cdev[1]);
+       if (rc)
+               goto err_out;
+       rc = ccw_device_set_online(gdev->cdev[0]);
+       if (rc)
+               goto err_out;
+       ctcm_open(priv->channel[READ]->netdev);
+err_out:
+       netif_device_attach(priv->channel[READ]->netdev);
+       return rc;
+}
+
 static struct ccwgroup_driver ctcm_group_driver = {
        .owner       = THIS_MODULE,
        .name        = CTC_DRIVER_NAME,
@@ -1697,6 +1729,9 @@ static struct ccwgroup_driver ctcm_group_driver = {
        .remove      = ctcm_remove_device,
        .set_online  = ctcm_new_device,
        .set_offline = ctcm_shutdown_device,
+       .freeze      = ctcm_pm_suspend,
+       .thaw        = ctcm_pm_resume,
+       .restore     = ctcm_pm_resume,
 };
 
 
index a45bc24eb5f91627c03eabc94575a71ed0a6053f..8c675905448b74c33983c7e5038e4b8688a15ce0 100644 (file)
@@ -1,15 +1,12 @@
 /*
- *  linux/drivers/s390/net/lcs.c
- *
  *  Linux for S/390 Lan Channel Station Network Driver
  *
- *  Copyright (C)  1999-2001 IBM Deutschland Entwicklung GmbH,
- *                          IBM Corporation
- *    Author(s): Original Code written by
- *                       DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
- *              Rewritten by
- *                       Frank Pavlic (fpavlic@de.ibm.com) and
- *                       Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *  Copyright IBM Corp. 1999, 2009
+ *  Author(s): Original Code written by
+ *                     DJ Barrow <djbarrow@de.ibm.com,barrow_dj@yahoo.com>
+ *            Rewritten by
+ *                     Frank Pavlic <fpavlic@de.ibm.com> and
+ *                     Martin Schwidefsky <schwidefsky@de.ibm.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -1939,7 +1936,7 @@ lcs_portno_show (struct device *dev, struct device_attribute *attr, char *buf)
 {
         struct lcs_card *card;
 
-       card = (struct lcs_card *)dev->driver_data;
+       card = dev_get_drvdata(dev);
 
         if (!card)
                 return 0;
@@ -1956,7 +1953,7 @@ lcs_portno_store (struct device *dev, struct device_attribute *attr, const char
         struct lcs_card *card;
         int value;
 
-       card = (struct lcs_card *)dev->driver_data;
+       card = dev_get_drvdata(dev);
 
         if (!card)
                 return 0;
@@ -1990,7 +1987,7 @@ lcs_timeout_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct lcs_card *card;
 
-       card = (struct lcs_card *)dev->driver_data;
+       card = dev_get_drvdata(dev);
 
        return card ? sprintf(buf, "%u\n", card->lancmd_timeout) : 0;
 }
@@ -2001,7 +1998,7 @@ lcs_timeout_store (struct device *dev, struct device_attribute *attr, const char
         struct lcs_card *card;
         int value;
 
-       card = (struct lcs_card *)dev->driver_data;
+       card = dev_get_drvdata(dev);
 
         if (!card)
                 return 0;
@@ -2020,7 +2017,7 @@ static ssize_t
 lcs_dev_recover_store(struct device *dev, struct device_attribute *attr,
                      const char *buf, size_t count)
 {
-       struct lcs_card *card = dev->driver_data;
+       struct lcs_card *card = dev_get_drvdata(dev);
        char *tmp;
        int i;
 
@@ -2073,7 +2070,7 @@ lcs_probe_device(struct ccwgroup_device *ccwgdev)
                put_device(&ccwgdev->dev);
                return ret;
         }
-       ccwgdev->dev.driver_data = card;
+       dev_set_drvdata(&ccwgdev->dev, card);
        ccwgdev->cdev[0]->handler = lcs_irq;
        ccwgdev->cdev[1]->handler = lcs_irq;
        card->gdev = ccwgdev;
@@ -2090,7 +2087,7 @@ lcs_register_netdev(struct ccwgroup_device *ccwgdev)
        struct lcs_card *card;
 
        LCS_DBF_TEXT(2, setup, "regnetdv");
-       card = (struct lcs_card *)ccwgdev->dev.driver_data;
+       card = dev_get_drvdata(&ccwgdev->dev);
        if (card->dev->reg_state != NETREG_UNINITIALIZED)
                return 0;
        SET_NETDEV_DEV(card->dev, &ccwgdev->dev);
@@ -2123,7 +2120,7 @@ lcs_new_device(struct ccwgroup_device *ccwgdev)
        enum lcs_dev_states recover_state;
        int rc;
 
-       card = (struct lcs_card *)ccwgdev->dev.driver_data;
+       card = dev_get_drvdata(&ccwgdev->dev);
        if (!card)
                return -ENODEV;
 
@@ -2229,7 +2226,7 @@ __lcs_shutdown_device(struct ccwgroup_device *ccwgdev, int recovery_mode)
        int ret;
 
        LCS_DBF_TEXT(3, setup, "shtdndev");
-       card = (struct lcs_card *)ccwgdev->dev.driver_data;
+       card = dev_get_drvdata(&ccwgdev->dev);
        if (!card)
                return -ENODEV;
        if (recovery_mode == 0) {
@@ -2296,7 +2293,7 @@ lcs_remove_device(struct ccwgroup_device *ccwgdev)
 {
        struct lcs_card *card;
 
-       card = (struct lcs_card *)ccwgdev->dev.driver_data;
+       card = dev_get_drvdata(&ccwgdev->dev);
        if (!card)
                return;
 
@@ -2313,6 +2310,60 @@ lcs_remove_device(struct ccwgroup_device *ccwgdev)
        put_device(&ccwgdev->dev);
 }
 
+static int lcs_pm_suspend(struct lcs_card *card)
+{
+       if (card->dev)
+               netif_device_detach(card->dev);
+       lcs_set_allowed_threads(card, 0);
+       lcs_wait_for_threads(card, 0xffffffff);
+       if (card->state != DEV_STATE_DOWN)
+               __lcs_shutdown_device(card->gdev, 1);
+       return 0;
+}
+
+static int lcs_pm_resume(struct lcs_card *card)
+{
+       int rc = 0;
+
+       if (card->state == DEV_STATE_RECOVER)
+               rc = lcs_new_device(card->gdev);
+       if (card->dev)
+               netif_device_attach(card->dev);
+       if (rc) {
+               dev_warn(&card->gdev->dev, "The lcs device driver "
+                       "failed to recover the device\n");
+       }
+       return rc;
+}
+
+static int lcs_prepare(struct ccwgroup_device *gdev)
+{
+       return 0;
+}
+
+static void lcs_complete(struct ccwgroup_device *gdev)
+{
+       return;
+}
+
+static int lcs_freeze(struct ccwgroup_device *gdev)
+{
+       struct lcs_card *card = dev_get_drvdata(&gdev->dev);
+       return lcs_pm_suspend(card);
+}
+
+static int lcs_thaw(struct ccwgroup_device *gdev)
+{
+       struct lcs_card *card = dev_get_drvdata(&gdev->dev);
+       return lcs_pm_resume(card);
+}
+
+static int lcs_restore(struct ccwgroup_device *gdev)
+{
+       struct lcs_card *card = dev_get_drvdata(&gdev->dev);
+       return lcs_pm_resume(card);
+}
+
 /**
  * LCS ccwgroup driver registration
  */
@@ -2325,6 +2376,11 @@ static struct ccwgroup_driver lcs_group_driver = {
        .remove      = lcs_remove_device,
        .set_online  = lcs_new_device,
        .set_offline = lcs_shutdown_device,
+       .prepare     = lcs_prepare,
+       .complete    = lcs_complete,
+       .freeze      = lcs_freeze,
+       .thaw        = lcs_thaw,
+       .restore     = lcs_restore,
 };
 
 /**
index d58fea52557dd4338afffcdf06fb93f4d88ae710..6d668642af270e27b6b376ce99c2b3276cbc63a8 100644 (file)
@@ -34,8 +34,8 @@ static inline int lcs_dbf_passes(debug_info_t *dbf_grp, int level)
  *     sysfs related stuff
  */
 #define CARD_FROM_DEV(cdev) \
-       (struct lcs_card *) \
-       ((struct ccwgroup_device *)cdev->dev.driver_data)->dev.driver_data;
+       (struct lcs_card *) dev_get_drvdata( \
+               &((struct ccwgroup_device *)dev_get_drvdata(&cdev->dev))->dev);
 /**
  * CCW commands used in this driver
  */
index aec9e5d3cf4b72ef7830435fccf8c3c708df31b5..52574ce797b24f92e91edf49c20174d08fca28ed 100644 (file)
@@ -1,11 +1,15 @@
 /*
  * IUCV network driver
  *
- * Copyright 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
+ * Copyright IBM Corp. 2001, 2009
  *
- * Sysfs integration and all bugs therein by Cornelia Huck
- * (cornelia.huck@de.ibm.com)
+ * Author(s):
+ *     Original netiucv driver:
+ *             Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
+ *     Sysfs integration and all bugs therein:
+ *             Cornelia Huck (cornelia.huck@de.ibm.com)
+ *     PM functions:
+ *             Ursula Braun (ursula.braun@de.ibm.com)
  *
  * Documentation used:
  *  the source of the original IUCV driver by:
@@ -149,10 +153,27 @@ PRINT_##importance(header "%02x %02x %02x %02x  %02x %02x %02x %02x  " \
 
 #define PRINTK_HEADER " iucv: "       /* for debugging */
 
+/* dummy device to make sure netiucv_pm functions are called */
+static struct device *netiucv_dev;
+
+static int netiucv_pm_prepare(struct device *);
+static void netiucv_pm_complete(struct device *);
+static int netiucv_pm_freeze(struct device *);
+static int netiucv_pm_restore_thaw(struct device *);
+
+static struct dev_pm_ops netiucv_pm_ops = {
+       .prepare = netiucv_pm_prepare,
+       .complete = netiucv_pm_complete,
+       .freeze = netiucv_pm_freeze,
+       .thaw = netiucv_pm_restore_thaw,
+       .restore = netiucv_pm_restore_thaw,
+};
+
 static struct device_driver netiucv_driver = {
        .owner = THIS_MODULE,
        .name = "netiucv",
        .bus  = &iucv_bus,
+       .pm = &netiucv_pm_ops,
 };
 
 static int netiucv_callback_connreq(struct iucv_path *,
@@ -233,6 +254,7 @@ struct netiucv_priv {
        fsm_instance            *fsm;
         struct iucv_connection  *conn;
        struct device           *dev;
+       int                      pm_state;
 };
 
 /**
@@ -1265,6 +1287,72 @@ static int netiucv_close(struct net_device *dev)
        return 0;
 }
 
+static int netiucv_pm_prepare(struct device *dev)
+{
+       IUCV_DBF_TEXT(trace, 3, __func__);
+       return 0;
+}
+
+static void netiucv_pm_complete(struct device *dev)
+{
+       IUCV_DBF_TEXT(trace, 3, __func__);
+       return;
+}
+
+/**
+ * netiucv_pm_freeze() - Freeze PM callback
+ * @dev:       netiucv device
+ *
+ * close open netiucv interfaces
+ */
+static int netiucv_pm_freeze(struct device *dev)
+{
+       struct netiucv_priv *priv = dev->driver_data;
+       struct net_device *ndev = NULL;
+       int rc = 0;
+
+       IUCV_DBF_TEXT(trace, 3, __func__);
+       if (priv && priv->conn)
+               ndev = priv->conn->netdev;
+       if (!ndev)
+               goto out;
+       netif_device_detach(ndev);
+       priv->pm_state = fsm_getstate(priv->fsm);
+       rc = netiucv_close(ndev);
+out:
+       return rc;
+}
+
+/**
+ * netiucv_pm_restore_thaw() - Thaw and restore PM callback
+ * @dev:       netiucv device
+ *
+ * re-open netiucv interfaces closed during freeze
+ */
+static int netiucv_pm_restore_thaw(struct device *dev)
+{
+       struct netiucv_priv *priv = dev->driver_data;
+       struct net_device *ndev = NULL;
+       int rc = 0;
+
+       IUCV_DBF_TEXT(trace, 3, __func__);
+       if (priv && priv->conn)
+               ndev = priv->conn->netdev;
+       if (!ndev)
+               goto out;
+       switch (priv->pm_state) {
+       case DEV_STATE_RUNNING:
+       case DEV_STATE_STARTWAIT:
+               rc = netiucv_open(ndev);
+               break;
+       default:
+               break;
+       }
+       netif_device_attach(ndev);
+out:
+       return rc;
+}
+
 /**
  * Start transmission of a packet.
  * Called from generic network device layer.
@@ -1364,7 +1452,7 @@ static int netiucv_change_mtu(struct net_device * dev, int new_mtu)
 static ssize_t user_show(struct device *dev, struct device_attribute *attr,
                         char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%s\n", netiucv_printname(priv->conn->userid));
@@ -1373,7 +1461,7 @@ static ssize_t user_show(struct device *dev, struct device_attribute *attr,
 static ssize_t user_write(struct device *dev, struct device_attribute *attr,
                          const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
        struct net_device *ndev = priv->conn->netdev;
        char    *p;
        char    *tmp;
@@ -1430,7 +1518,8 @@ static DEVICE_ATTR(user, 0644, user_show, user_write);
 
 static ssize_t buffer_show (struct device *dev, struct device_attribute *attr,
                            char *buf)
-{      struct netiucv_priv *priv = dev->driver_data;
+{
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%d\n", priv->conn->max_buffsize);
@@ -1439,7 +1528,7 @@ static ssize_t buffer_show (struct device *dev, struct device_attribute *attr,
 static ssize_t buffer_write (struct device *dev, struct device_attribute *attr,
                             const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
        struct net_device *ndev = priv->conn->netdev;
        char         *e;
        int          bs1;
@@ -1487,7 +1576,7 @@ static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write);
 static ssize_t dev_fsm_show (struct device *dev, struct device_attribute *attr,
                             char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%s\n", fsm_getstate_str(priv->fsm));
@@ -1498,7 +1587,7 @@ static DEVICE_ATTR(device_fsm_state, 0444, dev_fsm_show, NULL);
 static ssize_t conn_fsm_show (struct device *dev,
                              struct device_attribute *attr, char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%s\n", fsm_getstate_str(priv->conn->fsm));
@@ -1509,7 +1598,7 @@ static DEVICE_ATTR(connection_fsm_state, 0444, conn_fsm_show, NULL);
 static ssize_t maxmulti_show (struct device *dev,
                              struct device_attribute *attr, char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%ld\n", priv->conn->prof.maxmulti);
@@ -1519,7 +1608,7 @@ static ssize_t maxmulti_write (struct device *dev,
                               struct device_attribute *attr,
                               const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 4, __func__);
        priv->conn->prof.maxmulti = 0;
@@ -1531,7 +1620,7 @@ static DEVICE_ATTR(max_tx_buffer_used, 0644, maxmulti_show, maxmulti_write);
 static ssize_t maxcq_show (struct device *dev, struct device_attribute *attr,
                           char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%ld\n", priv->conn->prof.maxcqueue);
@@ -1540,7 +1629,7 @@ static ssize_t maxcq_show (struct device *dev, struct device_attribute *attr,
 static ssize_t maxcq_write (struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 4, __func__);
        priv->conn->prof.maxcqueue = 0;
@@ -1552,7 +1641,7 @@ static DEVICE_ATTR(max_chained_skbs, 0644, maxcq_show, maxcq_write);
 static ssize_t sdoio_show (struct device *dev, struct device_attribute *attr,
                           char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%ld\n", priv->conn->prof.doios_single);
@@ -1561,7 +1650,7 @@ static ssize_t sdoio_show (struct device *dev, struct device_attribute *attr,
 static ssize_t sdoio_write (struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 4, __func__);
        priv->conn->prof.doios_single = 0;
@@ -1573,7 +1662,7 @@ static DEVICE_ATTR(tx_single_write_ops, 0644, sdoio_show, sdoio_write);
 static ssize_t mdoio_show (struct device *dev, struct device_attribute *attr,
                           char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%ld\n", priv->conn->prof.doios_multi);
@@ -1582,7 +1671,7 @@ static ssize_t mdoio_show (struct device *dev, struct device_attribute *attr,
 static ssize_t mdoio_write (struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        priv->conn->prof.doios_multi = 0;
@@ -1594,7 +1683,7 @@ static DEVICE_ATTR(tx_multi_write_ops, 0644, mdoio_show, mdoio_write);
 static ssize_t txlen_show (struct device *dev, struct device_attribute *attr,
                           char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%ld\n", priv->conn->prof.txlen);
@@ -1603,7 +1692,7 @@ static ssize_t txlen_show (struct device *dev, struct device_attribute *attr,
 static ssize_t txlen_write (struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 4, __func__);
        priv->conn->prof.txlen = 0;
@@ -1615,7 +1704,7 @@ static DEVICE_ATTR(netto_bytes, 0644, txlen_show, txlen_write);
 static ssize_t txtime_show (struct device *dev, struct device_attribute *attr,
                            char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%ld\n", priv->conn->prof.tx_time);
@@ -1624,7 +1713,7 @@ static ssize_t txtime_show (struct device *dev, struct device_attribute *attr,
 static ssize_t txtime_write (struct device *dev, struct device_attribute *attr,
                             const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 4, __func__);
        priv->conn->prof.tx_time = 0;
@@ -1636,7 +1725,7 @@ static DEVICE_ATTR(max_tx_io_time, 0644, txtime_show, txtime_write);
 static ssize_t txpend_show (struct device *dev, struct device_attribute *attr,
                            char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%ld\n", priv->conn->prof.tx_pending);
@@ -1645,7 +1734,7 @@ static ssize_t txpend_show (struct device *dev, struct device_attribute *attr,
 static ssize_t txpend_write (struct device *dev, struct device_attribute *attr,
                             const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 4, __func__);
        priv->conn->prof.tx_pending = 0;
@@ -1657,7 +1746,7 @@ static DEVICE_ATTR(tx_pending, 0644, txpend_show, txpend_write);
 static ssize_t txmpnd_show (struct device *dev, struct device_attribute *attr,
                            char *buf)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 5, __func__);
        return sprintf(buf, "%ld\n", priv->conn->prof.tx_max_pending);
@@ -1666,7 +1755,7 @@ static ssize_t txmpnd_show (struct device *dev, struct device_attribute *attr,
 static ssize_t txmpnd_write (struct device *dev, struct device_attribute *attr,
                             const char *buf, size_t count)
 {
-       struct netiucv_priv *priv = dev->driver_data;
+       struct netiucv_priv *priv = dev_get_drvdata(dev);
 
        IUCV_DBF_TEXT(trace, 4, __func__);
        priv->conn->prof.tx_max_pending = 0;
@@ -1731,7 +1820,6 @@ static int netiucv_register_device(struct net_device *ndev)
        struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL);
        int ret;
 
-
        IUCV_DBF_TEXT(trace, 3, __func__);
 
        if (dev) {
@@ -1758,7 +1846,7 @@ static int netiucv_register_device(struct net_device *ndev)
        if (ret)
                goto out_unreg;
        priv->dev = dev;
-       dev->driver_data = priv;
+       dev_set_drvdata(dev, priv);
        return 0;
 
 out_unreg:
@@ -2100,6 +2188,7 @@ static void __exit netiucv_exit(void)
                netiucv_unregister_device(dev);
        }
 
+       device_unregister(netiucv_dev);
        driver_unregister(&netiucv_driver);
        iucv_unregister(&netiucv_handler, 1);
        iucv_unregister_dbf_views();
@@ -2125,10 +2214,25 @@ static int __init netiucv_init(void)
                IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc);
                goto out_iucv;
        }
-
+       /* establish dummy device */
+       netiucv_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+       if (!netiucv_dev) {
+               rc = -ENOMEM;
+               goto out_driver;
+       }
+       dev_set_name(netiucv_dev, "netiucv");
+       netiucv_dev->bus = &iucv_bus;
+       netiucv_dev->parent = iucv_root;
+       netiucv_dev->release = (void (*)(struct device *))kfree;
+       netiucv_dev->driver = &netiucv_driver;
+       rc = device_register(netiucv_dev);
+       if (rc)
+               goto out_driver;
        netiucv_banner();
        return rc;
 
+out_driver:
+       driver_unregister(&netiucv_driver);
 out_iucv:
        iucv_unregister(&netiucv_handler, 1);
 out_dbf:
index 74c49d9a8dba2b76932b5f143bb8e66fb9458068..d53621c4acbbaca813ddd49e630cbf16582cd58e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/net/qeth_core_main.c
  *
- *    Copyright IBM Corp. 2007
+ *    Copyright IBM Corp. 2007, 2009
  *    Author(s): Utz Bacher <utz.bacher@de.ibm.com>,
  *              Frank Pavlic <fpavlic@de.ibm.com>,
  *              Thomas Spatzier <tspat@de.ibm.com>,
@@ -4195,6 +4195,50 @@ static void qeth_core_shutdown(struct ccwgroup_device *gdev)
                card->discipline.ccwgdriver->shutdown(gdev);
 }
 
+static int qeth_core_prepare(struct ccwgroup_device *gdev)
+{
+       struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+       if (card->discipline.ccwgdriver &&
+           card->discipline.ccwgdriver->prepare)
+               return card->discipline.ccwgdriver->prepare(gdev);
+       return 0;
+}
+
+static void qeth_core_complete(struct ccwgroup_device *gdev)
+{
+       struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+       if (card->discipline.ccwgdriver &&
+           card->discipline.ccwgdriver->complete)
+               card->discipline.ccwgdriver->complete(gdev);
+}
+
+static int qeth_core_freeze(struct ccwgroup_device *gdev)
+{
+       struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+       if (card->discipline.ccwgdriver &&
+           card->discipline.ccwgdriver->freeze)
+               return card->discipline.ccwgdriver->freeze(gdev);
+       return 0;
+}
+
+static int qeth_core_thaw(struct ccwgroup_device *gdev)
+{
+       struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+       if (card->discipline.ccwgdriver &&
+           card->discipline.ccwgdriver->thaw)
+               return card->discipline.ccwgdriver->thaw(gdev);
+       return 0;
+}
+
+static int qeth_core_restore(struct ccwgroup_device *gdev)
+{
+       struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+       if (card->discipline.ccwgdriver &&
+           card->discipline.ccwgdriver->restore)
+               return card->discipline.ccwgdriver->restore(gdev);
+       return 0;
+}
+
 static struct ccwgroup_driver qeth_core_ccwgroup_driver = {
        .owner = THIS_MODULE,
        .name = "qeth",
@@ -4204,6 +4248,11 @@ static struct ccwgroup_driver qeth_core_ccwgroup_driver = {
        .set_online = qeth_core_set_online,
        .set_offline = qeth_core_set_offline,
        .shutdown = qeth_core_shutdown,
+       .prepare = qeth_core_prepare,
+       .complete = qeth_core_complete,
+       .freeze = qeth_core_freeze,
+       .thaw = qeth_core_thaw,
+       .restore = qeth_core_restore,
 };
 
 static ssize_t
index ecd3d06c0d5cc464b7c3ac90197e05a1bc3c17ce..81d7f268418a41aa4c1a52ac2c959fd570cee35f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/net/qeth_l2_main.c
  *
- *    Copyright IBM Corp. 2007
+ *    Copyright IBM Corp. 2007, 2009
  *    Author(s): Utz Bacher <utz.bacher@de.ibm.com>,
  *              Frank Pavlic <fpavlic@de.ibm.com>,
  *              Thomas Spatzier <tspat@de.ibm.com>,
@@ -1141,12 +1141,62 @@ static void qeth_l2_shutdown(struct ccwgroup_device *gdev)
        qeth_clear_qdio_buffers(card);
 }
 
+static int qeth_l2_pm_suspend(struct ccwgroup_device *gdev)
+{
+       struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+
+       if (card->dev)
+               netif_device_detach(card->dev);
+       qeth_set_allowed_threads(card, 0, 1);
+       wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
+       if (gdev->state == CCWGROUP_OFFLINE)
+               return 0;
+       if (card->state == CARD_STATE_UP) {
+               card->use_hard_stop = 1;
+               __qeth_l2_set_offline(card->gdev, 1);
+       } else
+               __qeth_l2_set_offline(card->gdev, 0);
+       return 0;
+}
+
+static int qeth_l2_pm_resume(struct ccwgroup_device *gdev)
+{
+       struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+       int rc = 0;
+
+       if (gdev->state == CCWGROUP_OFFLINE)
+               goto out;
+
+       if (card->state == CARD_STATE_RECOVER) {
+               rc = __qeth_l2_set_online(card->gdev, 1);
+               if (rc) {
+                       if (card->dev) {
+                               rtnl_lock();
+                               dev_close(card->dev);
+                               rtnl_unlock();
+                       }
+               }
+       } else
+               rc = __qeth_l2_set_online(card->gdev, 0);
+out:
+       qeth_set_allowed_threads(card, 0xffffffff, 0);
+       if (card->dev)
+               netif_device_attach(card->dev);
+       if (rc)
+               dev_warn(&card->gdev->dev, "The qeth device driver "
+                       "failed to recover an error on the device\n");
+       return rc;
+}
+
 struct ccwgroup_driver qeth_l2_ccwgroup_driver = {
        .probe = qeth_l2_probe_device,
        .remove = qeth_l2_remove_device,
        .set_online = qeth_l2_set_online,
        .set_offline = qeth_l2_set_offline,
        .shutdown = qeth_l2_shutdown,
+       .freeze = qeth_l2_pm_suspend,
+       .thaw = qeth_l2_pm_resume,
+       .restore = qeth_l2_pm_resume,
 };
 EXPORT_SYMBOL_GPL(qeth_l2_ccwgroup_driver);
 
index 6f2386e9d6e2b2c8466da5e99c23496430cd8f65..54872406864e006bcccfb75549b2ffd39ed1f180 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  drivers/s390/net/qeth_l3_main.c
  *
- *    Copyright IBM Corp. 2007
+ *    Copyright IBM Corp. 2007, 2009
  *    Author(s): Utz Bacher <utz.bacher@de.ibm.com>,
  *              Frank Pavlic <fpavlic@de.ibm.com>,
  *              Thomas Spatzier <tspat@de.ibm.com>,
@@ -3283,12 +3283,62 @@ static void qeth_l3_shutdown(struct ccwgroup_device *gdev)
        qeth_clear_qdio_buffers(card);
 }
 
+static int qeth_l3_pm_suspend(struct ccwgroup_device *gdev)
+{
+       struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+
+       if (card->dev)
+               netif_device_detach(card->dev);
+       qeth_set_allowed_threads(card, 0, 1);
+       wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
+       if (gdev->state == CCWGROUP_OFFLINE)
+               return 0;
+       if (card->state == CARD_STATE_UP) {
+               card->use_hard_stop = 1;
+               __qeth_l3_set_offline(card->gdev, 1);
+       } else
+               __qeth_l3_set_offline(card->gdev, 0);
+       return 0;
+}
+
+static int qeth_l3_pm_resume(struct ccwgroup_device *gdev)
+{
+       struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+       int rc = 0;
+
+       if (gdev->state == CCWGROUP_OFFLINE)
+               goto out;
+
+       if (card->state == CARD_STATE_RECOVER) {
+               rc = __qeth_l3_set_online(card->gdev, 1);
+               if (rc) {
+                       if (card->dev) {
+                               rtnl_lock();
+                               dev_close(card->dev);
+                               rtnl_unlock();
+                       }
+               }
+       } else
+               rc = __qeth_l3_set_online(card->gdev, 0);
+out:
+       qeth_set_allowed_threads(card, 0xffffffff, 0);
+       if (card->dev)
+               netif_device_attach(card->dev);
+       if (rc)
+               dev_warn(&card->gdev->dev, "The qeth device driver "
+                       "failed to recover an error on the device\n");
+       return rc;
+}
+
 struct ccwgroup_driver qeth_l3_ccwgroup_driver = {
        .probe = qeth_l3_probe_device,
        .remove = qeth_l3_remove_device,
        .set_online = qeth_l3_set_online,
        .set_offline = qeth_l3_set_offline,
        .shutdown = qeth_l3_shutdown,
+       .freeze = qeth_l3_pm_suspend,
+       .thaw = qeth_l3_pm_resume,
+       .restore = qeth_l3_pm_resume,
 };
 EXPORT_SYMBOL_GPL(qeth_l3_ccwgroup_driver);
 
index 164e090c2625b03b8218c1e90286ca4b04b4559e..e76a320d373baeb99e32b16a9ac954ad65a00380 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * IUCV special message driver
  *
- * Copyright 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright IBM Corp. 2003, 2009
+ *
  * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
  *
  * This program is free software; you can redistribute it and/or modify
@@ -40,6 +41,8 @@ MODULE_AUTHOR
 MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver");
 
 static struct iucv_path *smsg_path;
+/* dummy device used as trigger for PM functions */
+static struct device *smsg_dev;
 
 static DEFINE_SPINLOCK(smsg_list_lock);
 static LIST_HEAD(smsg_list);
@@ -132,14 +135,51 @@ void smsg_unregister_callback(char *prefix,
        kfree(cb);
 }
 
+static int smsg_pm_freeze(struct device *dev)
+{
+#ifdef CONFIG_PM_DEBUG
+       printk(KERN_WARNING "smsg_pm_freeze\n");
+#endif
+       if (smsg_path)
+               iucv_path_sever(smsg_path, NULL);
+       return 0;
+}
+
+static int smsg_pm_restore_thaw(struct device *dev)
+{
+       int rc;
+
+#ifdef CONFIG_PM_DEBUG
+       printk(KERN_WARNING "smsg_pm_restore_thaw\n");
+#endif
+       if (smsg_path) {
+               memset(smsg_path, 0, sizeof(*smsg_path));
+               smsg_path->msglim = 255;
+               smsg_path->flags = 0;
+               rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG    ",
+                                      NULL, NULL, NULL);
+               printk(KERN_ERR "iucv_path_connect returned with rc %i\n", rc);
+       }
+       return 0;
+}
+
+static struct dev_pm_ops smsg_pm_ops = {
+       .freeze = smsg_pm_freeze,
+       .thaw = smsg_pm_restore_thaw,
+       .restore = smsg_pm_restore_thaw,
+};
+
 static struct device_driver smsg_driver = {
+       .owner = THIS_MODULE,
        .name = "SMSGIUCV",
        .bus  = &iucv_bus,
+       .pm = &smsg_pm_ops,
 };
 
 static void __exit smsg_exit(void)
 {
        cpcmd("SET SMSG IUCV", NULL, 0, NULL);
+       device_unregister(smsg_dev);
        iucv_unregister(&smsg_handler, 1);
        driver_unregister(&smsg_driver);
 }
@@ -166,12 +206,29 @@ static int __init smsg_init(void)
        rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG    ",
                               NULL, NULL, NULL);
        if (rc)
-               goto out_free;
+               goto out_free_path;
+       smsg_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+       if (!smsg_dev) {
+               rc = -ENOMEM;
+               goto out_free_path;
+       }
+       dev_set_name(smsg_dev, "smsg_iucv");
+       smsg_dev->bus = &iucv_bus;
+       smsg_dev->parent = iucv_root;
+       smsg_dev->release = (void (*)(struct device *))kfree;
+       smsg_dev->driver = &smsg_driver;
+       rc = device_register(smsg_dev);
+       if (rc)
+               goto out_free_dev;
+
        cpcmd("SET SMSG IUCV", NULL, 0, NULL);
        return 0;
 
-out_free:
+out_free_dev:
+       kfree(smsg_dev);
+out_free_path:
        iucv_path_free(smsg_path);
+       smsg_path = NULL;
 out_register:
        iucv_unregister(&smsg_handler, 1);
 out_driver:
index b2fe5cdbcaeec3cb4462b22040fa6282bd70c7b5..d9da5c42ccbe6ca617bf4f304f0f9ecb1c058ef2 100644 (file)
 
 #define ZFCP_MODEL_PRIV 0x4
 
+static int zfcp_ccw_suspend(struct ccw_device *cdev)
+
+{
+       struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev);
+
+       down(&zfcp_data.config_sema);
+
+       zfcp_erp_adapter_shutdown(adapter, 0, "ccsusp1", NULL);
+       zfcp_erp_wait(adapter);
+
+       up(&zfcp_data.config_sema);
+
+       return 0;
+}
+
+static int zfcp_ccw_activate(struct ccw_device *cdev)
+
+{
+       struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev);
+
+       zfcp_erp_modify_adapter_status(adapter, "ccresu1", NULL,
+                                      ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);
+       zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
+                               "ccresu2", NULL);
+       zfcp_erp_wait(adapter);
+       flush_work(&adapter->scan_work);
+
+       return 0;
+}
+
 static struct ccw_device_id zfcp_ccw_device_id[] = {
        { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x3) },
        { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, ZFCP_MODEL_PRIV) },
@@ -227,6 +257,9 @@ static struct ccw_driver zfcp_ccw_driver = {
        .set_offline = zfcp_ccw_set_offline,
        .notify      = zfcp_ccw_notify,
        .shutdown    = zfcp_ccw_shutdown,
+       .freeze      = zfcp_ccw_suspend,
+       .thaw        = zfcp_ccw_activate,
+       .restore     = zfcp_ccw_activate,
 };
 
 /**
index 124f660a0383173b8426fe9c9a1c7fd9e5fba0bb..75ac19b1192ff40d144fec752b7937b158abe86e 100644 (file)
@@ -303,7 +303,7 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
                                struct device_node *dp)
 {
        DATA *data = file->private_data;
-       struct openpromio *opp;
+       struct openpromio *opp = NULL;
        int bufsize, error = 0;
        static int cnt;
        void __user *argp = (void __user *)arg;
index ed0e3e55652afdec9c99d480458a5577e1e1a0d0..538135783aab017b0c2ba0ea782801912b0b93a1 100644 (file)
@@ -646,7 +646,7 @@ static int aha1740_probe (struct device *dev)
 
 static __devexit int aha1740_remove (struct device *dev)
 {
-       struct Scsi_Host *shpnt = dev->driver_data;
+       struct Scsi_Host *shpnt = dev_get_drvdata(dev);
        struct aha1740_hostdata *host = HOSTDATA (shpnt);
 
        scsi_remove_host(shpnt);
index 11d2602ae88ecd2ffd4c2ab8b759538dac8a02c8..869a11bdccbdf3cf63773b2bebc1ff1358d623a8 100644 (file)
@@ -1877,7 +1877,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        unsigned long wait_switch = 0;
        int rc;
 
-       vdev->dev.driver_data = NULL;
+       dev_set_drvdata(&vdev->dev, NULL);
 
        host = scsi_host_alloc(&driver_template, sizeof(*hostdata));
        if (!host) {
@@ -1949,7 +1949,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
                        scsi_scan_host(host);
        }
 
-       vdev->dev.driver_data = hostdata;
+       dev_set_drvdata(&vdev->dev, hostdata);
        return 0;
 
       add_srp_port_failed:
@@ -1968,7 +1968,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
 
 static int ibmvscsi_remove(struct vio_dev *vdev)
 {
-       struct ibmvscsi_host_data *hostdata = vdev->dev.driver_data;
+       struct ibmvscsi_host_data *hostdata = dev_get_drvdata(&vdev->dev);
        unmap_persist_bufs(hostdata);
        release_event_pool(&hostdata->pool, hostdata);
        ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata,
index e2dd6a45924a5f598f6dafa05eff545b2aa5292b..d5eaf972710978a9b24464c4e20fadbdac5babae 100644 (file)
@@ -892,7 +892,7 @@ free_vport:
 
 static int ibmvstgt_remove(struct vio_dev *dev)
 {
-       struct srp_target *target = (struct srp_target *) dev->dev.driver_data;
+       struct srp_target *target = dev_get_drvdata(&dev->dev);
        struct Scsi_Host *shost = target->shost;
        struct vio_port *vport = target->ldata;
 
index 15e2d132e8b9e07b99d39c4079557a3d16604cc3..2742ae8a3d091a13b989fb4f5a7de57e4f7d0490 100644 (file)
@@ -135,7 +135,7 @@ int srp_target_alloc(struct srp_target *target, struct device *dev,
        INIT_LIST_HEAD(&target->cmd_queue);
 
        target->dev = dev;
-       target->dev->driver_data = target;
+       dev_set_drvdata(target->dev, target);
 
        target->srp_iu_size = iu_size;
        target->rx_ring_size = nr;
index 2b02b1fb39a09842a1b18216699ac31b83eef3bb..8d0f0de76b6336098e3c76411002d1f8529244ae 100644 (file)
@@ -53,8 +53,7 @@
  * debugfs interface
  *
  * To access this interface the user should:
- * # mkdir /debug
- * # mount -t debugfs none /debug
+ * # mount -t debugfs none /sys/kernel/debug
  *
  * The lpfc debugfs directory hierarchy is:
  * lpfc/lpfcX/vportY
index b3497d7e5354dec9ab0ba49cd754f5e47867c45b..338b15c0a548e9f2d6d630d1ea3eb52954abff0a 100644 (file)
@@ -1104,11 +1104,13 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
        /* update the per-port timeout */
        uart_update_timeout(port, termios->c_cflag, baud);
 
-       /* save/disable interrupts and drain transmitter */
+       /*
+        * save/disable interrupts. The tty layer will ensure that the
+        * transmitter is empty if requested by the caller, so there's
+        * no need to wait for it here.
+        */
        imr = UART_GET_IMR(port);
        UART_PUT_IDR(port, -1);
-       while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY))
-               cpu_relax();
 
        /* disable receiver and transmitter */
        UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS);
index 285b414f30546d0a89285f823d802979adbbcac9..5d7b58f1fe42a38596072ba9355d619ffcfd54a2 100644 (file)
@@ -924,11 +924,13 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
        rational_best_approximation(16 * div * baud, sport->port.uartclk,
                1 << 16, 1 << 16, &num, &denom);
 
-       tdiv64 = sport->port.uartclk;
-       tdiv64 *= num;
-       do_div(tdiv64, denom * 16 * div);
-       tty_encode_baud_rate(sport->port.info->port.tty,
-               (speed_t)tdiv64, (speed_t)tdiv64);
+       if (port->info && port->info->port.tty) {
+               tdiv64 = sport->port.uartclk;
+               tdiv64 *= num;
+               do_div(tdiv64, denom * 16 * div);
+               tty_encode_baud_rate(sport->port.info->port.tty,
+                               (speed_t)tdiv64, (speed_t)tdiv64);
+       }
 
        num -= 1;
        denom -= 1;
index 14f8fa9135be49c664f64d80c9633bf1d405f85c..54483cd3529e00e85df152efb5cb95c3c654d924 100644 (file)
@@ -122,7 +122,7 @@ static int __devinit of_platform_serial_probe(struct of_device *ofdev,
 
        info->type = port_type;
        info->line = ret;
-       ofdev->dev.driver_data = info;
+       dev_set_drvdata(&ofdev->dev, info);
        return 0;
 out:
        kfree(info);
@@ -135,7 +135,7 @@ out:
  */
 static int of_platform_serial_remove(struct of_device *ofdev)
 {
-       struct of_serial_info *info = ofdev->dev.driver_data;
+       struct of_serial_info *info = dev_get_drvdata(&ofdev->dev);
        switch (info->type) {
 #ifdef CONFIG_SERIAL_8250
        case PORT_8250 ... PORT_MAX_8250:
index a4cf1079b3129e4892fb711b5f95276055552458..66f52674ca0cb6872cfd580571b29d485dd59a44 100644 (file)
@@ -1332,44 +1332,46 @@ err_unreg:
        return ret;
 }
 
-static int sci_suspend(struct platform_device *dev, pm_message_t state)
+static int sci_suspend(struct device *dev)
 {
-       struct sh_sci_priv *priv = platform_get_drvdata(dev);
+       struct sh_sci_priv *priv = dev_get_drvdata(dev);
        struct sci_port *p;
        unsigned long flags;
 
        spin_lock_irqsave(&priv->lock, flags);
        list_for_each_entry(p, &priv->ports, node)
                uart_suspend_port(&sci_uart_driver, &p->port);
-
        spin_unlock_irqrestore(&priv->lock, flags);
 
        return 0;
 }
 
-static int sci_resume(struct platform_device *dev)
+static int sci_resume(struct device *dev)
 {
-       struct sh_sci_priv *priv = platform_get_drvdata(dev);
+       struct sh_sci_priv *priv = dev_get_drvdata(dev);
        struct sci_port *p;
        unsigned long flags;
 
        spin_lock_irqsave(&priv->lock, flags);
        list_for_each_entry(p, &priv->ports, node)
                uart_resume_port(&sci_uart_driver, &p->port);
-
        spin_unlock_irqrestore(&priv->lock, flags);
 
        return 0;
 }
 
+static struct dev_pm_ops sci_dev_pm_ops = {
+       .suspend        = sci_suspend,
+       .resume         = sci_resume,
+};
+
 static struct platform_driver sci_driver = {
        .probe          = sci_probe,
        .remove         = __devexit_p(sci_remove),
-       .suspend        = sci_suspend,
-       .resume         = sci_resume,
        .driver         = {
                .name   = "sh-sci",
                .owner  = THIS_MODULE,
+               .pm     = &sci_dev_pm_ops,
        },
 };
 
index d687a9b93d03bac737e02d02ce4d292fd1ef018d..3dd231a643b5edabe44d1b156ffb9de426d640cd 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/module.h>
 #include <linux/io.h>
 #include <linux/interrupt.h>
-#include <linux/bootmem.h>
 #include <linux/sh_intc.h>
 #include <linux/sysdev.h>
 #include <linux/list.h>
@@ -675,7 +674,7 @@ void __init register_intc_controller(struct intc_desc *desc)
        unsigned int i, k, smp;
        struct intc_desc_int *d;
 
-       d = alloc_bootmem(sizeof(*d));
+       d = kzalloc(sizeof(*d), GFP_NOWAIT);
 
        INIT_LIST_HEAD(&d->list);
        list_add(&d->list, &intc_list);
@@ -687,9 +686,9 @@ void __init register_intc_controller(struct intc_desc *desc)
 #if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4A)
        d->nr_reg += desc->ack_regs ? desc->nr_ack_regs : 0;
 #endif
-       d->reg = alloc_bootmem(d->nr_reg * sizeof(*d->reg));
+       d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT);
 #ifdef CONFIG_SMP
-       d->smp = alloc_bootmem(d->nr_reg * sizeof(*d->smp));
+       d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT);
 #endif
        k = 0;
 
@@ -702,7 +701,7 @@ void __init register_intc_controller(struct intc_desc *desc)
        }
 
        if (desc->prio_regs) {
-               d->prio = alloc_bootmem(desc->nr_vectors * sizeof(*d->prio));
+               d->prio = kzalloc(desc->nr_vectors * sizeof(*d->prio), GFP_NOWAIT);
 
                for (i = 0; i < desc->nr_prio_regs; i++) {
                        smp = IS_SMP(desc->prio_regs[i]);
@@ -712,7 +711,7 @@ void __init register_intc_controller(struct intc_desc *desc)
        }
 
        if (desc->sense_regs) {
-               d->sense = alloc_bootmem(desc->nr_vectors * sizeof(*d->sense));
+               d->sense = kzalloc(desc->nr_vectors * sizeof(*d->sense), GFP_NOWAIT);
 
                for (i = 0; i < desc->nr_sense_regs; i++) {
                        k += save_reg(d, k, desc->sense_regs[i].reg, 0);
@@ -757,7 +756,7 @@ void __init register_intc_controller(struct intc_desc *desc)
                        vect2->enum_id = 0;
 
                        if (!intc_evt2irq_table)
-                               intc_evt2irq_table = alloc_bootmem(NR_IRQS);
+                               intc_evt2irq_table = kzalloc(NR_IRQS, GFP_NOWAIT);
 
                        if (!intc_evt2irq_table) {
                                pr_warning("intc: cannot allocate evt2irq!\n");
index f014cc21e8131051542a0641129ce9018ec51020..011c5bddba6a52b9741ee39c9a573efcb9f972df 100644 (file)
@@ -803,7 +803,7 @@ static void bfin_spi_pump_transfers(unsigned long data)
                                drv_data->rx, drv_data->len_in_bytes);
 
                        /* invalidate caches, if needed */
-                       if (bfin_addr_dcachable((unsigned long) drv_data->rx))
+                       if (bfin_addr_dcacheable((unsigned long) drv_data->rx))
                                invalidate_dcache_range((unsigned long) drv_data->rx,
                                                        (unsigned long) (drv_data->rx +
                                                        drv_data->len_in_bytes));
@@ -816,7 +816,7 @@ static void bfin_spi_pump_transfers(unsigned long data)
                        dev_dbg(&drv_data->pdev->dev, "doing DMA out.\n");
 
                        /* flush caches, if needed */
-                       if (bfin_addr_dcachable((unsigned long) drv_data->tx))
+                       if (bfin_addr_dcacheable((unsigned long) drv_data->tx))
                                flush_dcache_range((unsigned long) drv_data->tx,
                                                (unsigned long) (drv_data->tx +
                                                drv_data->len_in_bytes));
index f4573a96af2459620b0b4b4d5f09c6f87acaf11a..a32ccb44065eb58df94d84dbfe11d24c7952723f 100644 (file)
@@ -711,12 +711,12 @@ static int of_mpc83xx_spi_get_chipselects(struct device *dev)
                return 0;
        }
 
-       pinfo->gpios = kmalloc(ngpios * sizeof(pinfo->gpios), GFP_KERNEL);
+       pinfo->gpios = kmalloc(ngpios * sizeof(*pinfo->gpios), GFP_KERNEL);
        if (!pinfo->gpios)
                return -ENOMEM;
-       memset(pinfo->gpios, -1, ngpios * sizeof(pinfo->gpios));
+       memset(pinfo->gpios, -1, ngpios * sizeof(*pinfo->gpios));
 
-       pinfo->alow_flags = kzalloc(ngpios * sizeof(pinfo->alow_flags),
+       pinfo->alow_flags = kzalloc(ngpios * sizeof(*pinfo->alow_flags),
                                    GFP_KERNEL);
        if (!pinfo->alow_flags) {
                ret = -ENOMEM;
index 0dcf9ca0b0ac758786299a99ea412c8ba1245529..d0fcf36c2ab2382bbce64d5976b3719aa2100545 100644 (file)
@@ -115,5 +115,7 @@ source "drivers/staging/line6/Kconfig"
 
 source "drivers/staging/serqt_usb/Kconfig"
 
+source "drivers/gpu/drm/radeon/Kconfig"
+
 endif # !STAGING_EXCLUDE_BUILD
 endif # STAGING
index 9c62f787cc9cde11ed7b866a9c53e8f82c5eff18..39d0926d1a9015394043091929bfdbce0ce1ed28 100644 (file)
@@ -2336,7 +2336,7 @@ static int ATEN2011_startup(struct usb_serial *serial)
        return 0;
 }
 
-static void ATEN2011_shutdown(struct usb_serial *serial)
+static void ATEN2011_release(struct usb_serial *serial)
 {
        int i;
        struct ATENINTL_port *ATEN2011_port;
@@ -2382,7 +2382,7 @@ static struct usb_serial_driver aten_serial_driver = {
        .tiocmget =             ATEN2011_tiocmget,
        .tiocmset =             ATEN2011_tiocmset,
        .attach =               ATEN2011_startup,
-       .shutdown =             ATEN2011_shutdown,
+       .release =              ATEN2011_release,
        .read_bulk_callback =   ATEN2011_bulk_in_callback,
        .read_int_callback =    ATEN2011_interrupt_callback,
 };
index 5e38ba10a3a90ed2a35687c4e73d636e1626a817..0a69672097a8195e3671e1d63b164c19fa0ababc 100644 (file)
@@ -417,7 +417,7 @@ static LIST_HEAD(thermal_hwmon_list);
 static ssize_t
 name_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct thermal_hwmon_device *hwmon = dev->driver_data;
+       struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
        return sprintf(buf, "%s\n", hwmon->type);
 }
 static DEVICE_ATTR(name, 0444, name_show, NULL);
@@ -488,7 +488,7 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
                result = PTR_ERR(hwmon->device);
                goto free_mem;
        }
-       hwmon->device->driver_data = hwmon;
+       dev_set_drvdata(hwmon->device, hwmon);
        result = device_create_file(hwmon->device, &dev_attr_name);
        if (result)
                goto unregister_hwmon_device;
index 5eee3f82be5d98d0cb1df531c9d78573c482ddbc..dcd49f1e96d006d1abb04271687d90f0f52a9ef5 100644 (file)
@@ -64,6 +64,7 @@ config USB_ARCH_HAS_EHCI
 config USB
        tristate "Support for Host-side USB"
        depends on USB_ARCH_HAS_HCD
+       select NLS  # for UTF-8 strings
        ---help---
          Universal Serial Bus (USB) is a specification for a serial bus
          subsystem which offers higher speeds and more features than the
index 0a3dc5ece634ba641167a738a1aed2cbe793e269..19cb7d5480d78636f3eb036dbd77c37fc99a16d9 100644 (file)
@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_ISP116X_HCD) += host/
 obj-$(CONFIG_USB_OHCI_HCD)     += host/
 obj-$(CONFIG_USB_UHCI_HCD)     += host/
 obj-$(CONFIG_USB_FHCI_HCD)     += host/
+obj-$(CONFIG_USB_XHCI_HCD)     += host/
 obj-$(CONFIG_USB_SL811_HCD)    += host/
 obj-$(CONFIG_USB_U132_HCD)     += host/
 obj-$(CONFIG_USB_R8A66597_HCD) += host/
index 9cf9ff69e3e3505e08f9c2346b4d4095775a9981..d171b563e94c7e2bb10c092834799a434b6b8956 100644 (file)
@@ -306,6 +306,7 @@ enum {
 #define FW_GET_BYTE(p) *((__u8 *) (p))
 
 #define FW_DIR "ueagle-atm/"
+#define UEA_FW_NAME_MAX 30
 #define NB_MODEM 4
 
 #define BULK_TIMEOUT 300
@@ -1564,9 +1565,9 @@ static void cmvs_file_name(struct uea_softc *sc, char *const cmv_name, int ver)
                file = cmv_file[sc->modem_index];
 
        strcpy(cmv_name, FW_DIR);
-       strlcat(cmv_name, file, FIRMWARE_NAME_MAX);
+       strlcat(cmv_name, file, UEA_FW_NAME_MAX);
        if (ver == 2)
-               strlcat(cmv_name, ".v2", FIRMWARE_NAME_MAX);
+               strlcat(cmv_name, ".v2", UEA_FW_NAME_MAX);
 }
 
 static int request_cmvs_old(struct uea_softc *sc,
@@ -1574,7 +1575,7 @@ static int request_cmvs_old(struct uea_softc *sc,
 {
        int ret, size;
        u8 *data;
-       char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
+       char cmv_name[UEA_FW_NAME_MAX]; /* 30 bytes stack variable */
 
        cmvs_file_name(sc, cmv_name, 1);
        ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev);
@@ -1608,7 +1609,7 @@ static int request_cmvs(struct uea_softc *sc,
        int ret, size;
        u32 crc;
        u8 *data;
-       char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
+       char cmv_name[UEA_FW_NAME_MAX]; /* 30 bytes stack variable */
 
        cmvs_file_name(sc, cmv_name, 2);
        ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev);
index ddeb6919253734ebcb3b7a92b6294b30bb305d52..38bfdb0f666058061081e6035512843cb0eaa850 100644 (file)
@@ -937,9 +937,9 @@ static int acm_probe(struct usb_interface *intf,
        int buflen = intf->altsetting->extralen;
        struct usb_interface *control_interface;
        struct usb_interface *data_interface;
-       struct usb_endpoint_descriptor *epctrl;
-       struct usb_endpoint_descriptor *epread;
-       struct usb_endpoint_descriptor *epwrite;
+       struct usb_endpoint_descriptor *epctrl = NULL;
+       struct usb_endpoint_descriptor *epread = NULL;
+       struct usb_endpoint_descriptor *epwrite = NULL;
        struct usb_device *usb_dev = interface_to_usbdev(intf);
        struct acm *acm;
        int minor;
@@ -952,6 +952,7 @@ static int acm_probe(struct usb_interface *intf,
        unsigned long quirks;
        int num_rx_buf;
        int i;
+       int combined_interfaces = 0;
 
        /* normal quirks */
        quirks = (unsigned long)id->driver_info;
@@ -1033,9 +1034,15 @@ next_desc:
                        data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
                        control_interface = intf;
                } else {
-                       dev_dbg(&intf->dev,
-                                       "No union descriptor, giving up\n");
-                       return -ENODEV;
+                       if (intf->cur_altsetting->desc.bNumEndpoints != 3) {
+                               dev_dbg(&intf->dev,"No union descriptor, giving up\n");
+                               return -ENODEV;
+                       } else {
+                               dev_warn(&intf->dev,"No union descriptor, testing for castrated device\n");
+                               combined_interfaces = 1;
+                               control_interface = data_interface = intf;
+                               goto look_for_collapsed_interface;
+                       }
                }
        } else {
                control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
@@ -1049,6 +1056,36 @@ next_desc:
        if (data_interface_num != call_interface_num)
                dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n");
 
+       if (control_interface == data_interface) {
+               /* some broken devices designed for windows work this way */
+               dev_warn(&intf->dev,"Control and data interfaces are not separated!\n");
+               combined_interfaces = 1;
+               /* a popular other OS doesn't use it */
+               quirks |= NO_CAP_LINE;
+               if (data_interface->cur_altsetting->desc.bNumEndpoints != 3) {
+                       dev_err(&intf->dev, "This needs exactly 3 endpoints\n");
+                       return -EINVAL;
+               }
+look_for_collapsed_interface:
+               for (i = 0; i < 3; i++) {
+                       struct usb_endpoint_descriptor *ep;
+                       ep = &data_interface->cur_altsetting->endpoint[i].desc;
+
+                       if (usb_endpoint_is_int_in(ep))
+                               epctrl = ep;
+                       else if (usb_endpoint_is_bulk_out(ep))
+                               epwrite = ep;
+                       else if (usb_endpoint_is_bulk_in(ep))
+                               epread = ep;
+                       else
+                               return -EINVAL;
+               }
+               if (!epctrl || !epread || !epwrite)
+                       return -ENODEV;
+               else
+                       goto made_compressed_probe;
+       }
+
 skip_normal_probe:
 
        /*workaround for switched interfaces */
@@ -1068,10 +1105,11 @@ skip_normal_probe:
        }
 
        /* Accept probe requests only for the control interface */
-       if (intf != control_interface)
+       if (!combined_interfaces && intf != control_interface)
                return -ENODEV;
 
-       if (usb_interface_claimed(data_interface)) { /* valid in this context */
+       if (!combined_interfaces && usb_interface_claimed(data_interface)) {
+               /* valid in this context */
                dev_dbg(&intf->dev, "The data interface isn't available\n");
                return -EBUSY;
        }
@@ -1095,6 +1133,7 @@ skip_normal_probe:
                epread = epwrite;
                epwrite = t;
        }
+made_compressed_probe:
        dbg("interfaces are valid");
        for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
 
@@ -1112,12 +1151,15 @@ skip_normal_probe:
        ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
        readsize = le16_to_cpu(epread->wMaxPacketSize) *
                                (quirks == SINGLE_RX_URB ? 1 : 2);
+       acm->combined_interfaces = combined_interfaces;
        acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20;
        acm->control = control_interface;
        acm->data = data_interface;
        acm->minor = minor;
        acm->dev = usb_dev;
        acm->ctrl_caps = ac_management_function;
+       if (quirks & NO_CAP_LINE)
+               acm->ctrl_caps &= ~USB_CDC_CAP_LINE;
        acm->ctrlsize = ctrlsize;
        acm->readsize = readsize;
        acm->rx_buflimit = num_rx_buf;
@@ -1223,9 +1265,10 @@ skip_normal_probe:
 
 skip_countries:
        usb_fill_int_urb(acm->ctrlurb, usb_dev,
-                       usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
-                       acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm,
-                       epctrl->bInterval);
+                        usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
+                        acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm,
+                        /* works around buggy devices */
+                        epctrl->bInterval ? epctrl->bInterval : 0xff);
        acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
        acm->ctrlurb->transfer_dma = acm->ctrl_dma;
 
@@ -1312,7 +1355,8 @@ static void acm_disconnect(struct usb_interface *intf)
                                                                acm->ctrl_dma);
        acm_read_buffers_free(acm);
 
-       usb_driver_release_interface(&acm_driver, intf == acm->control ?
+       if (!acm->combined_interfaces)
+               usb_driver_release_interface(&acm_driver, intf == acm->control ?
                                        acm->data : acm->control);
 
        if (acm->port.count == 0) {
@@ -1451,6 +1495,9 @@ static struct usb_device_id acm_ids[] = {
                                           Maybe we should define a new
                                           quirk for this. */
        },
+       { USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */
+       .driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
+       },
 
        /* control interfaces with various AT-command sets */
        { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
index 4c3856420adde6c55761950e0697822d9e496d1b..1602324808bafb510e374520b9eb0a264617dc02 100644 (file)
@@ -125,6 +125,7 @@ struct acm {
        unsigned char clocal;                           /* termios CLOCAL */
        unsigned int ctrl_caps;                         /* control capabilities from the class specific header */
        unsigned int susp_count;                        /* number of suspended interfaces */
+       int combined_interfaces:1;                      /* control and data collapsed */
        struct acm_wb *delayed_wb;                      /* write queued for a device about to be woken */
 };
 
@@ -133,3 +134,4 @@ struct acm {
 /* constants describing various quirks and errors */
 #define NO_UNION_NORMAL                        1
 #define SINGLE_RX_URB                  2
+#define NO_CAP_LINE                    4
index d2747a49b9744bacf2962abbe2ea1b8bd3b087b5..26c09f0257dbeff29a9c8f25f39eaf15453570c0 100644 (file)
@@ -1057,8 +1057,14 @@ static const struct file_operations usblp_fops = {
        .release =      usblp_release,
 };
 
+static char *usblp_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev));
+}
+
 static struct usb_class_driver usblp_class = {
        .name =         "lp%d",
+       .nodename =     usblp_nodename,
        .fops =         &usblp_fops,
        .minor_base =   USBLP_MINOR_BASE,
 };
index c40a9b284cc94217d9a45c1b09d838904571fa67..3703789d0d2af8a7459138adb5903c548e704425 100644 (file)
@@ -927,21 +927,27 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        switch (cmd) {
        case USBTMC_IOCTL_CLEAR_OUT_HALT:
                retval = usbtmc_ioctl_clear_out_halt(data);
+               break;
 
        case USBTMC_IOCTL_CLEAR_IN_HALT:
                retval = usbtmc_ioctl_clear_in_halt(data);
+               break;
 
        case USBTMC_IOCTL_INDICATOR_PULSE:
                retval = usbtmc_ioctl_indicator_pulse(data);
+               break;
 
        case USBTMC_IOCTL_CLEAR:
                retval = usbtmc_ioctl_clear(data);
+               break;
 
        case USBTMC_IOCTL_ABORT_BULK_OUT:
                retval = usbtmc_ioctl_abort_bulk_out(data);
+               break;
 
        case USBTMC_IOCTL_ABORT_BULK_IN:
                retval = usbtmc_ioctl_abort_bulk_in(data);
+               break;
        }
 
        mutex_unlock(&data->io_mutex);
index e1759d17ac5d17ca9cafeea4d67094954af07462..69280c35b5cbc6d93cc50c99d7f4a7f747c1fc99 100644 (file)
@@ -28,7 +28,7 @@ comment "Miscellaneous USB options"
        depends on USB
 
 config USB_DEVICEFS
-       bool "USB device filesystem"
+       bool "USB device filesystem (DEPRECATED)" if EMBEDDED
        depends on USB
        ---help---
          If you say Y here (and to "/proc file system support" in the "File
@@ -46,11 +46,15 @@ config USB_DEVICEFS
          For the format of the various /proc/bus/usb/ files, please read
          <file:Documentation/usb/proc_usb_info.txt>.
 
-         Usbfs files can't handle Access Control Lists (ACL), which are the
-         default way to grant access to USB devices for untrusted users of a
-         desktop system. The usbfs functionality is replaced by real
-         device-nodes managed by udev. These nodes live in /dev/bus/usb and
-         are used by libusb.
+         Modern Linux systems do not use this.
+
+         Usbfs entries are files and not character devices; usbfs can't
+         handle Access Control Lists (ACL) which are the default way to
+         grant access to USB devices for untrusted users of a desktop
+         system.
+
+         The usbfs functionality is replaced by real device-nodes managed by
+         udev.  These nodes lived in /dev/bus/usb and are used by libusb.
 
 config USB_DEVICE_CLASS
        bool "USB device class-devices (DEPRECATED)"
index b6078706fb939d7f1d3aeb9466f6498f8857f366..ec16e60299050ab046f9a02dfb15e0207e264516 100644 (file)
@@ -4,14 +4,14 @@
 
 usbcore-objs   := usb.o hub.o hcd.o urb.o message.o driver.o \
                        config.o file.o buffer.o sysfs.o endpoint.o \
-                       devio.o notify.o generic.o quirks.o
+                       devio.o notify.o generic.o quirks.o devices.o
 
 ifeq ($(CONFIG_PCI),y)
        usbcore-objs    += hcd-pci.o
 endif
 
 ifeq ($(CONFIG_USB_DEVICEFS),y)
-       usbcore-objs    += inode.o devices.o
+       usbcore-objs    += inode.o
 endif
 
 obj-$(CONFIG_USB)      += usbcore.o
index 568244c99bdc0f5d7b0e03d2177d1153e9d49d49..24dfb33f90cb0fbc2268572ee0ed90ecc15efbb5 100644 (file)
@@ -19,6 +19,32 @@ static inline const char *plural(int n)
        return (n == 1 ? "" : "s");
 }
 
+/* FIXME: this is a kludge */
+static int find_next_descriptor_more(unsigned char *buffer, int size,
+    int dt1, int dt2, int dt3, int *num_skipped)
+{
+       struct usb_descriptor_header *h;
+       int n = 0;
+       unsigned char *buffer0 = buffer;
+
+       /* Find the next descriptor of type dt1 or dt2 or dt3 */
+       while (size > 0) {
+               h = (struct usb_descriptor_header *) buffer;
+               if (h->bDescriptorType == dt1 || h->bDescriptorType == dt2 ||
+                               h->bDescriptorType == dt3)
+                       break;
+               buffer += h->bLength;
+               size -= h->bLength;
+               ++n;
+       }
+
+       /* Store the number of descriptors skipped and return the
+        * number of bytes skipped */
+       if (num_skipped)
+               *num_skipped = n;
+       return buffer - buffer0;
+}
+
 static int find_next_descriptor(unsigned char *buffer, int size,
     int dt1, int dt2, int *num_skipped)
 {
@@ -43,6 +69,129 @@ static int find_next_descriptor(unsigned char *buffer, int size,
        return buffer - buffer0;
 }
 
+static int usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
+               int inum, int asnum, struct usb_host_endpoint *ep,
+               int num_ep, unsigned char *buffer, int size)
+{
+       unsigned char *buffer_start = buffer;
+       struct usb_ss_ep_comp_descriptor        *desc;
+       int retval;
+       int num_skipped;
+       int max_tx;
+       int i;
+
+       /* Allocate space for the SS endpoint companion descriptor */
+       ep->ss_ep_comp = kzalloc(sizeof(struct usb_host_ss_ep_comp),
+                       GFP_KERNEL);
+       if (!ep->ss_ep_comp)
+               return -ENOMEM;
+       desc = (struct usb_ss_ep_comp_descriptor *) buffer;
+       if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP) {
+               dev_warn(ddev, "No SuperSpeed endpoint companion for config %d "
+                               " interface %d altsetting %d ep %d: "
+                               "using minimum values\n",
+                               cfgno, inum, asnum, ep->desc.bEndpointAddress);
+               ep->ss_ep_comp->desc.bLength = USB_DT_SS_EP_COMP_SIZE;
+               ep->ss_ep_comp->desc.bDescriptorType = USB_DT_SS_ENDPOINT_COMP;
+               ep->ss_ep_comp->desc.bMaxBurst = 0;
+               /*
+                * Leave bmAttributes as zero, which will mean no streams for
+                * bulk, and isoc won't support multiple bursts of packets.
+                * With bursts of only one packet, and a Mult of 1, the max
+                * amount of data moved per endpoint service interval is one
+                * packet.
+                */
+               if (usb_endpoint_xfer_isoc(&ep->desc) ||
+                               usb_endpoint_xfer_int(&ep->desc))
+                       ep->ss_ep_comp->desc.wBytesPerInterval =
+                               ep->desc.wMaxPacketSize;
+               /*
+                * The next descriptor is for an Endpoint or Interface,
+                * no extra descriptors to copy into the companion structure,
+                * and we didn't eat up any of the buffer.
+                */
+               retval = 0;
+               goto valid;
+       }
+       memcpy(&ep->ss_ep_comp->desc, desc, USB_DT_SS_EP_COMP_SIZE);
+       desc = &ep->ss_ep_comp->desc;
+       buffer += desc->bLength;
+       size -= desc->bLength;
+
+       /* Eat up the other descriptors we don't care about */
+       ep->ss_ep_comp->extra = buffer;
+       i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
+                       USB_DT_INTERFACE, &num_skipped);
+       ep->ss_ep_comp->extralen = i;
+       buffer += i;
+       size -= i;
+       retval = buffer - buffer_start + i;
+       if (num_skipped > 0)
+               dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
+                               num_skipped, plural(num_skipped),
+                               "SuperSpeed endpoint companion");
+
+       /* Check the various values */
+       if (usb_endpoint_xfer_control(&ep->desc) && desc->bMaxBurst != 0) {
+               dev_warn(ddev, "Control endpoint with bMaxBurst = %d in "
+                               "config %d interface %d altsetting %d ep %d: "
+                               "setting to zero\n", desc->bMaxBurst,
+                               cfgno, inum, asnum, ep->desc.bEndpointAddress);
+               desc->bMaxBurst = 0;
+       }
+       if (desc->bMaxBurst > 15) {
+               dev_warn(ddev, "Endpoint with bMaxBurst = %d in "
+                               "config %d interface %d altsetting %d ep %d: "
+                               "setting to 15\n", desc->bMaxBurst,
+                               cfgno, inum, asnum, ep->desc.bEndpointAddress);
+               desc->bMaxBurst = 15;
+       }
+       if ((usb_endpoint_xfer_control(&ep->desc) || usb_endpoint_xfer_int(&ep->desc))
+                       && desc->bmAttributes != 0) {
+               dev_warn(ddev, "%s endpoint with bmAttributes = %d in "
+                               "config %d interface %d altsetting %d ep %d: "
+                               "setting to zero\n",
+                               usb_endpoint_xfer_control(&ep->desc) ? "Control" : "Bulk",
+                               desc->bmAttributes,
+                               cfgno, inum, asnum, ep->desc.bEndpointAddress);
+               desc->bmAttributes = 0;
+       }
+       if (usb_endpoint_xfer_bulk(&ep->desc) && desc->bmAttributes > 16) {
+               dev_warn(ddev, "Bulk endpoint with more than 65536 streams in "
+                               "config %d interface %d altsetting %d ep %d: "
+                               "setting to max\n",
+                               cfgno, inum, asnum, ep->desc.bEndpointAddress);
+               desc->bmAttributes = 16;
+       }
+       if (usb_endpoint_xfer_isoc(&ep->desc) && desc->bmAttributes > 2) {
+               dev_warn(ddev, "Isoc endpoint has Mult of %d in "
+                               "config %d interface %d altsetting %d ep %d: "
+                               "setting to 3\n", desc->bmAttributes + 1,
+                               cfgno, inum, asnum, ep->desc.bEndpointAddress);
+               desc->bmAttributes = 2;
+       }
+       if (usb_endpoint_xfer_isoc(&ep->desc)) {
+               max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1) *
+                       (desc->bmAttributes + 1);
+       } else if (usb_endpoint_xfer_int(&ep->desc)) {
+               max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1);
+       } else {
+               goto valid;
+       }
+       if (desc->wBytesPerInterval > max_tx) {
+               dev_warn(ddev, "%s endpoint with wBytesPerInterval of %d in "
+                               "config %d interface %d altsetting %d ep %d: "
+                               "setting to %d\n",
+                               usb_endpoint_xfer_isoc(&ep->desc) ? "Isoc" : "Int",
+                               desc->wBytesPerInterval,
+                               cfgno, inum, asnum, ep->desc.bEndpointAddress,
+                               max_tx);
+               desc->wBytesPerInterval = max_tx;
+       }
+valid:
+       return retval;
+}
+
 static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
     int asnum, struct usb_host_interface *ifp, int num_ep,
     unsigned char *buffer, int size)
@@ -50,7 +199,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
        unsigned char *buffer0 = buffer;
        struct usb_endpoint_descriptor *d;
        struct usb_host_endpoint *endpoint;
-       int n, i, j;
+       int n, i, j, retval;
 
        d = (struct usb_endpoint_descriptor *) buffer;
        buffer += d->bLength;
@@ -92,6 +241,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
        if (usb_endpoint_xfer_int(d)) {
                i = 1;
                switch (to_usb_device(ddev)->speed) {
+               case USB_SPEED_SUPER:
                case USB_SPEED_HIGH:
                        /* Many device manufacturers are using full-speed
                         * bInterval values in high-speed interrupt endpoint
@@ -161,17 +311,39 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
                                cfgno, inum, asnum, d->bEndpointAddress,
                                maxp);
        }
-
-       /* Skip over any Class Specific or Vendor Specific descriptors;
-        * find the next endpoint or interface descriptor */
-       endpoint->extra = buffer;
-       i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
-           USB_DT_INTERFACE, &n);
-       endpoint->extralen = i;
+       /* Allocate room for and parse any SS endpoint companion descriptors */
+       if (to_usb_device(ddev)->speed == USB_SPEED_SUPER) {
+               endpoint->extra = buffer;
+               i = find_next_descriptor_more(buffer, size, USB_DT_SS_ENDPOINT_COMP,
+                               USB_DT_ENDPOINT, USB_DT_INTERFACE, &n);
+               endpoint->extralen = i;
+               buffer += i;
+               size -= i;
+
+               if (size > 0) {
+                       retval = usb_parse_ss_endpoint_companion(ddev, cfgno,
+                                       inum, asnum, endpoint, num_ep, buffer,
+                                       size);
+                       if (retval >= 0) {
+                               buffer += retval;
+                               retval = buffer - buffer0;
+                       }
+               } else {
+                       retval = buffer - buffer0;
+               }
+       } else {
+               /* Skip over any Class Specific or Vendor Specific descriptors;
+                * find the next endpoint or interface descriptor */
+               endpoint->extra = buffer;
+               i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
+                               USB_DT_INTERFACE, &n);
+               endpoint->extralen = i;
+               retval = buffer - buffer0 + i;
+       }
        if (n > 0)
                dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
                    n, plural(n), "endpoint");
-       return buffer - buffer0 + i;
+       return retval;
 
 skip_to_next_endpoint_or_interface_descriptor:
        i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
@@ -452,6 +624,8 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx,
                kref_init(&intfc->ref);
        }
 
+       /* FIXME: parse the BOS descriptor */
+
        /* Skip over any Class Specific or Vendor Specific descriptors;
         * find the first interface descriptor */
        config->extra = buffer;
index d0a21a5f82017bf246c62108009b5280c5d1c90b..69e5773abfce2459cd65d11a939f9f6250ab7468 100644 (file)
@@ -154,16 +154,11 @@ static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *in
 static int usb_probe_device(struct device *dev)
 {
        struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
-       struct usb_device *udev;
+       struct usb_device *udev = to_usb_device(dev);
        int error = -ENODEV;
 
        dev_dbg(dev, "%s\n", __func__);
 
-       if (!is_usb_device(dev))        /* Sanity check */
-               return error;
-
-       udev = to_usb_device(dev);
-
        /* TODO: Add real matching code */
 
        /* The device should always appear to be in use
@@ -203,18 +198,13 @@ static void usb_cancel_queued_reset(struct usb_interface *iface)
 static int usb_probe_interface(struct device *dev)
 {
        struct usb_driver *driver = to_usb_driver(dev->driver);
-       struct usb_interface *intf;
-       struct usb_device *udev;
+       struct usb_interface *intf = to_usb_interface(dev);
+       struct usb_device *udev = interface_to_usbdev(intf);
        const struct usb_device_id *id;
        int error = -ENODEV;
 
        dev_dbg(dev, "%s\n", __func__);
 
-       if (is_usb_device(dev))         /* Sanity check */
-               return error;
-
-       intf = to_usb_interface(dev);
-       udev = interface_to_usbdev(intf);
        intf->needs_binding = 0;
 
        if (udev->authorized == 0) {
@@ -385,7 +375,6 @@ void usb_driver_release_interface(struct usb_driver *driver,
                                        struct usb_interface *iface)
 {
        struct device *dev = &iface->dev;
-       struct usb_device *udev = interface_to_usbdev(iface);
 
        /* this should never happen, don't release something that's not ours */
        if (!dev->driver || dev->driver != &driver->drvwrap.driver)
@@ -394,23 +383,19 @@ void usb_driver_release_interface(struct usb_driver *driver,
        /* don't release from within disconnect() */
        if (iface->condition != USB_INTERFACE_BOUND)
                return;
+       iface->condition = USB_INTERFACE_UNBINDING;
 
-       /* don't release if the interface hasn't been added yet */
+       /* Release via the driver core only if the interface
+        * has already been registered
+        */
        if (device_is_registered(dev)) {
-               iface->condition = USB_INTERFACE_UNBINDING;
                device_release_driver(dev);
        } else {
-               iface->condition = USB_INTERFACE_UNBOUND;
-               usb_cancel_queued_reset(iface);
+               down(&dev->sem);
+               usb_unbind_interface(dev);
+               dev->driver = NULL;
+               up(&dev->sem);
        }
-       dev->driver = NULL;
-       usb_set_intfdata(iface, NULL);
-
-       usb_pm_lock(udev);
-       iface->condition = USB_INTERFACE_UNBOUND;
-       mark_quiesced(iface);
-       iface->needs_remote_wakeup = 0;
-       usb_pm_unlock(udev);
 }
 EXPORT_SYMBOL_GPL(usb_driver_release_interface);
 
@@ -598,7 +583,7 @@ static int usb_device_match(struct device *dev, struct device_driver *drv)
                /* TODO: Add real matching code */
                return 1;
 
-       } else {
+       } else if (is_usb_interface(dev)) {
                struct usb_interface *intf;
                struct usb_driver *usb_drv;
                const struct usb_device_id *id;
@@ -630,11 +615,14 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
        /* driver is often null here; dev_dbg() would oops */
        pr_debug("usb %s: uevent\n", dev_name(dev));
 
-       if (is_usb_device(dev))
+       if (is_usb_device(dev)) {
                usb_dev = to_usb_device(dev);
-       else {
+       } else if (is_usb_interface(dev)) {
                struct usb_interface *intf = to_usb_interface(dev);
+
                usb_dev = interface_to_usbdev(intf);
+       } else {
+               return 0;
        }
 
        if (usb_dev->devnum < 0) {
@@ -1762,6 +1750,7 @@ int usb_suspend(struct device *dev, pm_message_t msg)
 int usb_resume(struct device *dev, pm_message_t msg)
 {
        struct usb_device       *udev;
+       int                     status;
 
        udev = to_usb_device(dev);
 
@@ -1771,7 +1760,14 @@ int usb_resume(struct device *dev, pm_message_t msg)
         */
        if (udev->skip_sys_resume)
                return 0;
-       return usb_external_resume_device(udev, msg);
+       status = usb_external_resume_device(udev, msg);
+
+       /* Avoid PM error messages for devices disconnected while suspended
+        * as we'll display regular disconnect messages just a bit later.
+        */
+       if (status == -ENODEV)
+               return 0;
+       return status;
 }
 
 #endif /* CONFIG_PM */
index 40dee2ac0133740ee97e37932a6181247b94e22a..bc39fc40bbde20781d2467ec227ae48a9bdf46f0 100644 (file)
 #include <linux/usb.h>
 #include "usb.h"
 
-#define MAX_ENDPOINT_MINORS (64*128*32)
-static int usb_endpoint_major;
-static DEFINE_IDR(endpoint_idr);
-
 struct ep_device {
        struct usb_endpoint_descriptor *desc;
        struct usb_device *udev;
        struct device dev;
-       int minor;
 };
 #define to_ep_device(_dev) \
        container_of(_dev, struct ep_device, dev)
 
+struct device_type usb_ep_device_type = {
+       .name =         "usb_endpoint",
+};
+
 struct ep_attribute {
        struct attribute attr;
        ssize_t (*show)(struct usb_device *,
@@ -160,118 +159,10 @@ static struct attribute_group *ep_dev_groups[] = {
        NULL
 };
 
-static int usb_endpoint_major_init(void)
-{
-       dev_t dev;
-       int error;
-
-       error = alloc_chrdev_region(&dev, 0, MAX_ENDPOINT_MINORS,
-                                   "usb_endpoint");
-       if (error) {
-               printk(KERN_ERR "Unable to get a dynamic major for "
-                      "usb endpoints.\n");
-               return error;
-       }
-       usb_endpoint_major = MAJOR(dev);
-
-       return error;
-}
-
-static void usb_endpoint_major_cleanup(void)
-{
-       unregister_chrdev_region(MKDEV(usb_endpoint_major, 0),
-                                MAX_ENDPOINT_MINORS);
-}
-
-static int endpoint_get_minor(struct ep_device *ep_dev)
-{
-       static DEFINE_MUTEX(minor_lock);
-       int retval = -ENOMEM;
-       int id;
-
-       mutex_lock(&minor_lock);
-       if (idr_pre_get(&endpoint_idr, GFP_KERNEL) == 0)
-               goto exit;
-
-       retval = idr_get_new(&endpoint_idr, ep_dev, &id);
-       if (retval < 0) {
-               if (retval == -EAGAIN)
-                       retval = -ENOMEM;
-               goto exit;
-       }
-       ep_dev->minor = id & MAX_ID_MASK;
-exit:
-       mutex_unlock(&minor_lock);
-       return retval;
-}
-
-static void endpoint_free_minor(struct ep_device *ep_dev)
-{
-       idr_remove(&endpoint_idr, ep_dev->minor);
-}
-
-static struct endpoint_class {
-       struct kref kref;
-       struct class *class;
-} *ep_class;
-
-static int init_endpoint_class(void)
-{
-       int result = 0;
-
-       if (ep_class != NULL) {
-               kref_get(&ep_class->kref);
-               goto exit;
-       }
-
-       ep_class = kmalloc(sizeof(*ep_class), GFP_KERNEL);
-       if (!ep_class) {
-               result = -ENOMEM;
-               goto exit;
-       }
-
-       kref_init(&ep_class->kref);
-       ep_class->class = class_create(THIS_MODULE, "usb_endpoint");
-       if (IS_ERR(ep_class->class)) {
-               result = PTR_ERR(ep_class->class);
-               goto class_create_error;
-       }
-
-       result = usb_endpoint_major_init();
-       if (result)
-               goto endpoint_major_error;
-
-       goto exit;
-
-endpoint_major_error:
-       class_destroy(ep_class->class);
-class_create_error:
-       kfree(ep_class);
-       ep_class = NULL;
-exit:
-       return result;
-}
-
-static void release_endpoint_class(struct kref *kref)
-{
-       /* Ok, we cheat as we know we only have one ep_class */
-       class_destroy(ep_class->class);
-       kfree(ep_class);
-       ep_class = NULL;
-       usb_endpoint_major_cleanup();
-}
-
-static void destroy_endpoint_class(void)
-{
-       if (ep_class)
-               kref_put(&ep_class->kref, release_endpoint_class);
-}
-
 static void ep_device_release(struct device *dev)
 {
        struct ep_device *ep_dev = to_ep_device(dev);
 
-       endpoint_free_minor(ep_dev);
        kfree(ep_dev);
 }
 
@@ -279,62 +170,32 @@ int usb_create_ep_devs(struct device *parent,
                        struct usb_host_endpoint *endpoint,
                        struct usb_device *udev)
 {
-       char name[8];
        struct ep_device *ep_dev;
        int retval;
 
-       retval = init_endpoint_class();
-       if (retval)
-               goto exit;
-
        ep_dev = kzalloc(sizeof(*ep_dev), GFP_KERNEL);
        if (!ep_dev) {
                retval = -ENOMEM;
-               goto error_alloc;
-       }
-
-       retval = endpoint_get_minor(ep_dev);
-       if (retval) {
-               dev_err(parent, "can not allocate minor number for %s\n",
-                       dev_name(&ep_dev->dev));
-               goto error_register;
+               goto exit;
        }
 
        ep_dev->desc = &endpoint->desc;
        ep_dev->udev = udev;
        ep_dev->dev.groups = ep_dev_groups;
-       ep_dev->dev.devt = MKDEV(usb_endpoint_major, ep_dev->minor);
-       ep_dev->dev.class = ep_class->class;
+       ep_dev->dev.type = &usb_ep_device_type;
        ep_dev->dev.parent = parent;
        ep_dev->dev.release = ep_device_release;
-       dev_set_name(&ep_dev->dev, "usbdev%d.%d_ep%02x",
-                udev->bus->busnum, udev->devnum,
-                endpoint->desc.bEndpointAddress);
+       dev_set_name(&ep_dev->dev, "ep_%02x", endpoint->desc.bEndpointAddress);
 
        retval = device_register(&ep_dev->dev);
        if (retval)
-               goto error_chrdev;
+               goto error_register;
 
-       /* create the symlink to the old-style "ep_XX" directory */
-       sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
-       retval = sysfs_create_link(&parent->kobj, &ep_dev->dev.kobj, name);
-       if (retval)
-               goto error_link;
        endpoint->ep_dev = ep_dev;
        return retval;
 
-error_link:
-       device_unregister(&ep_dev->dev);
-       destroy_endpoint_class();
-       return retval;
-
-error_chrdev:
-       endpoint_free_minor(ep_dev);
-
 error_register:
        kfree(ep_dev);
-error_alloc:
-       destroy_endpoint_class();
 exit:
        return retval;
 }
@@ -344,12 +205,7 @@ void usb_remove_ep_devs(struct usb_host_endpoint *endpoint)
        struct ep_device *ep_dev = endpoint->ep_dev;
 
        if (ep_dev) {
-               char name[8];
-
-               sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
-               sysfs_remove_link(&ep_dev->dev.parent->kobj, name);
                device_unregister(&ep_dev->dev);
                endpoint->ep_dev = NULL;
-               destroy_endpoint_class();
        }
 }
index 997e659ff693eeb5ed083c2a8e76bdce76a33f97..5cef88929b3ee609af666c0d3e18772be10b1039 100644 (file)
@@ -67,6 +67,16 @@ static struct usb_class {
        struct class *class;
 } *usb_class;
 
+static char *usb_nodename(struct device *dev)
+{
+       struct usb_class_driver *drv;
+
+       drv = dev_get_drvdata(dev);
+       if (!drv || !drv->nodename)
+               return NULL;
+       return drv->nodename(dev);
+}
+
 static int init_usb_class(void)
 {
        int result = 0;
@@ -90,6 +100,7 @@ static int init_usb_class(void)
                kfree(usb_class);
                usb_class = NULL;
        }
+       usb_class->class->nodename = usb_nodename;
 
 exit:
        return result;
@@ -198,7 +209,7 @@ int usb_register_dev(struct usb_interface *intf,
        else
                temp = name;
        intf->usb_dev = device_create(usb_class->class, &intf->dev,
-                                     MKDEV(USB_MAJOR, minor), NULL,
+                                     MKDEV(USB_MAJOR, minor), class_driver,
                                      "%s", temp);
        if (IS_ERR(intf->usb_dev)) {
                down_write(&minor_rwsem);
index a4301dc02d275c1f28c77cde42183d1a2d435792..91f2885b6ee10ca8f6ca396289e0b1ea2ee7060b 100644 (file)
@@ -185,194 +185,198 @@ void usb_hcd_pci_remove(struct pci_dev *dev)
 }
 EXPORT_SYMBOL_GPL(usb_hcd_pci_remove);
 
-
-#ifdef CONFIG_PM
-
 /**
- * usb_hcd_pci_suspend - power management suspend of a PCI-based HCD
- * @dev: USB Host Controller being suspended
- * @message: Power Management message describing this state transition
- *
- * Store this function in the HCD's struct pci_driver as .suspend.
+ * usb_hcd_pci_shutdown - shutdown host controller
+ * @dev: USB Host Controller being shutdown
  */
-int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message)
+void usb_hcd_pci_shutdown(struct pci_dev *dev)
+{
+       struct usb_hcd          *hcd;
+
+       hcd = pci_get_drvdata(dev);
+       if (!hcd)
+               return;
+
+       if (hcd->driver->shutdown)
+               hcd->driver->shutdown(hcd);
+}
+EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown);
+
+#ifdef CONFIG_PM_SLEEP
+
+static int check_root_hub_suspended(struct device *dev)
+{
+       struct pci_dev          *pci_dev = to_pci_dev(dev);
+       struct usb_hcd          *hcd = pci_get_drvdata(pci_dev);
+
+       if (!(hcd->state == HC_STATE_SUSPENDED ||
+                       hcd->state == HC_STATE_HALT)) {
+               dev_warn(dev, "Root hub is not suspended\n");
+               return -EBUSY;
+       }
+       return 0;
+}
+
+static int hcd_pci_suspend(struct device *dev)
 {
-       struct usb_hcd          *hcd = pci_get_drvdata(dev);
-       int                     retval = 0;
-       int                     wake, w;
-       int                     has_pci_pm;
+       struct pci_dev          *pci_dev = to_pci_dev(dev);
+       struct usb_hcd          *hcd = pci_get_drvdata(pci_dev);
+       int                     retval;
 
        /* Root hub suspend should have stopped all downstream traffic,
         * and all bus master traffic.  And done so for both the interface
         * and the stub usb_device (which we check here).  But maybe it
         * didn't; writing sysfs power/state files ignores such rules...
-        *
-        * We must ignore the FREEZE vs SUSPEND distinction here, because
-        * otherwise the swsusp will save (and restore) garbage state.
         */
-       if (!(hcd->state == HC_STATE_SUSPENDED ||
-                       hcd->state == HC_STATE_HALT)) {
-               dev_warn(&dev->dev, "Root hub is not suspended\n");
-               retval = -EBUSY;
-               goto done;
-       }
+       retval = check_root_hub_suspended(dev);
+       if (retval)
+               return retval;
 
        /* We might already be suspended (runtime PM -- not yet written) */
-       if (dev->current_state != PCI_D0)
-               goto done;
+       if (pci_dev->current_state != PCI_D0)
+               return retval;
 
        if (hcd->driver->pci_suspend) {
-               retval = hcd->driver->pci_suspend(hcd, message);
+               retval = hcd->driver->pci_suspend(hcd);
                suspend_report_result(hcd->driver->pci_suspend, retval);
                if (retval)
-                       goto done;
+                       return retval;
        }
 
-       synchronize_irq(dev->irq);
+       synchronize_irq(pci_dev->irq);
 
        /* Downstream ports from this root hub should already be quiesced, so
         * there will be no DMA activity.  Now we can shut down the upstream
-        * link (except maybe for PME# resume signaling) and enter some PCI
-        * low power state, if the hardware allows.
+        * link (except maybe for PME# resume signaling).  We'll enter a
+        * low power state during suspend_noirq, if the hardware allows.
         */
-       pci_disable_device(dev);
+       pci_disable_device(pci_dev);
+       return retval;
+}
+
+static int hcd_pci_suspend_noirq(struct device *dev)
+{
+       struct pci_dev          *pci_dev = to_pci_dev(dev);
+       struct usb_hcd          *hcd = pci_get_drvdata(pci_dev);
+       int                     retval;
+
+       retval = check_root_hub_suspended(dev);
+       if (retval)
+               return retval;
 
-       pci_save_state(dev);
+       pci_save_state(pci_dev);
 
-       /* Don't fail on error to enable wakeup.  We rely on pci code
-        * to reject requests the hardware can't implement, rather
-        * than coding the same thing.
+       /* If the root hub is HALTed rather than SUSPENDed,
+        * disallow remote wakeup.
         */
-       wake = (hcd->state == HC_STATE_SUSPENDED &&
-                       device_may_wakeup(&dev->dev));
-       w = pci_wake_from_d3(dev, wake);
-       if (w < 0)
-               wake = w;
-       dev_dbg(&dev->dev, "wakeup: %d\n", wake);
-
-       /* Don't change state if we don't need to */
-       if (message.event == PM_EVENT_FREEZE ||
-                       message.event == PM_EVENT_PRETHAW) {
-               dev_dbg(&dev->dev, "--> no state change\n");
-               goto done;
-       }
+       if (hcd->state == HC_STATE_HALT)
+               device_set_wakeup_enable(dev, 0);
+       dev_dbg(dev, "wakeup: %d\n", device_may_wakeup(dev));
 
-       has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
-       if (!has_pci_pm) {
-               dev_dbg(&dev->dev, "--> PCI D0 legacy\n");
+       /* Possibly enable remote wakeup,
+        * choose the appropriate low-power state, and go to that state.
+        */
+       retval = pci_prepare_to_sleep(pci_dev);
+       if (retval == -EIO) {           /* Low-power not supported */
+               dev_dbg(dev, "--> PCI D0 legacy\n");
+               retval = 0;
+       } else if (retval == 0) {
+               dev_dbg(dev, "--> PCI %s\n",
+                               pci_power_name(pci_dev->current_state));
        } else {
-
-               /* NOTE:  dev->current_state becomes nonzero only here, and
-                * only for devices that support PCI PM.  Also, exiting
-                * PCI_D3 (but not PCI_D1 or PCI_D2) is allowed to reset
-                * some device state (e.g. as part of clock reinit).
-                */
-               retval = pci_set_power_state(dev, PCI_D3hot);
-               suspend_report_result(pci_set_power_state, retval);
-               if (retval == 0) {
-                       dev_dbg(&dev->dev, "--> PCI D3\n");
-               } else {
-                       dev_dbg(&dev->dev, "PCI D3 suspend fail, %d\n",
-                                       retval);
-                       pci_restore_state(dev);
-               }
+               suspend_report_result(pci_prepare_to_sleep, retval);
+               return retval;
        }
 
 #ifdef CONFIG_PPC_PMAC
-       if (retval == 0) {
-               /* Disable ASIC clocks for USB */
-               if (machine_is(powermac)) {
-                       struct device_node      *of_node;
-
-                       of_node = pci_device_to_OF_node(dev);
-                       if (of_node)
-                               pmac_call_feature(PMAC_FTR_USB_ENABLE,
-                                                       of_node, 0, 0);
-               }
+       /* Disable ASIC clocks for USB */
+       if (machine_is(powermac)) {
+               struct device_node      *of_node;
+
+               of_node = pci_device_to_OF_node(pci_dev);
+               if (of_node)
+                       pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
        }
 #endif
-
- done:
        return retval;
 }
-EXPORT_SYMBOL_GPL(usb_hcd_pci_suspend);
 
-/**
- * usb_hcd_pci_resume - power management resume of a PCI-based HCD
- * @dev: USB Host Controller being resumed
- *
- * Store this function in the HCD's struct pci_driver as .resume.
- */
-int usb_hcd_pci_resume(struct pci_dev *dev)
+static int hcd_pci_resume_noirq(struct device *dev)
 {
-       struct usb_hcd          *hcd;
-       int                     retval;
+       struct pci_dev          *pci_dev = to_pci_dev(dev);
 
 #ifdef CONFIG_PPC_PMAC
        /* Reenable ASIC clocks for USB */
        if (machine_is(powermac)) {
                struct device_node *of_node;
 
-               of_node = pci_device_to_OF_node(dev);
+               of_node = pci_device_to_OF_node(pci_dev);
                if (of_node)
                        pmac_call_feature(PMAC_FTR_USB_ENABLE,
                                                of_node, 0, 1);
        }
 #endif
 
-       pci_restore_state(dev);
+       /* Go back to D0 and disable remote wakeup */
+       pci_back_from_sleep(pci_dev);
+       return 0;
+}
+
+static int resume_common(struct device *dev, bool hibernated)
+{
+       struct pci_dev          *pci_dev = to_pci_dev(dev);
+       struct usb_hcd          *hcd = pci_get_drvdata(pci_dev);
+       int                     retval;
 
-       hcd = pci_get_drvdata(dev);
        if (hcd->state != HC_STATE_SUSPENDED) {
-               dev_dbg(hcd->self.controller,
-                               "can't resume, not suspended!\n");
+               dev_dbg(dev, "can't resume, not suspended!\n");
                return 0;
        }
 
-       pci_enable_wake(dev, PCI_D0, false);
-
-       retval = pci_enable_device(dev);
+       retval = pci_enable_device(pci_dev);
        if (retval < 0) {
-               dev_err(&dev->dev, "can't re-enable after resume, %d!\n",
-                               retval);
+               dev_err(dev, "can't re-enable after resume, %d!\n", retval);
                return retval;
        }
 
-       pci_set_master(dev);
-
-       /* yes, ignore this result too... */
-       (void) pci_wake_from_d3(dev, 0);
+       pci_set_master(pci_dev);
 
        clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
 
        if (hcd->driver->pci_resume) {
-               retval = hcd->driver->pci_resume(hcd);
+               retval = hcd->driver->pci_resume(hcd, hibernated);
                if (retval) {
-                       dev_err(hcd->self.controller,
-                               "PCI post-resume error %d!\n", retval);
+                       dev_err(dev, "PCI post-resume error %d!\n", retval);
                        usb_hc_died(hcd);
                }
        }
        return retval;
 }
-EXPORT_SYMBOL_GPL(usb_hcd_pci_resume);
 
-#endif /* CONFIG_PM */
-
-/**
- * usb_hcd_pci_shutdown - shutdown host controller
- * @dev: USB Host Controller being shutdown
- */
-void usb_hcd_pci_shutdown(struct pci_dev *dev)
+static int hcd_pci_resume(struct device *dev)
 {
-       struct usb_hcd          *hcd;
-
-       hcd = pci_get_drvdata(dev);
-       if (!hcd)
-               return;
+       return resume_common(dev, false);
+}
 
-       if (hcd->driver->shutdown)
-               hcd->driver->shutdown(hcd);
+static int hcd_pci_restore(struct device *dev)
+{
+       return resume_common(dev, true);
 }
-EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown);
 
+struct dev_pm_ops usb_hcd_pci_pm_ops = {
+       .suspend        = hcd_pci_suspend,
+       .suspend_noirq  = hcd_pci_suspend_noirq,
+       .resume_noirq   = hcd_pci_resume_noirq,
+       .resume         = hcd_pci_resume,
+       .freeze         = check_root_hub_suspended,
+       .freeze_noirq   = check_root_hub_suspended,
+       .thaw_noirq     = NULL,
+       .thaw           = NULL,
+       .poweroff       = hcd_pci_suspend,
+       .poweroff_noirq = hcd_pci_suspend_noirq,
+       .restore_noirq  = hcd_pci_resume_noirq,
+       .restore        = hcd_pci_restore,
+};
+EXPORT_SYMBOL_GPL(usb_hcd_pci_pm_ops);
+
+#endif /* CONFIG_PM_SLEEP */
index 42b93da1085d00ab52da7cd36843510945520d60..ce3f453f02ef5efe5b5034f3bedfa5a062e0db25 100644 (file)
@@ -128,6 +128,27 @@ static inline int is_root_hub(struct usb_device *udev)
 #define KERNEL_REL     ((LINUX_VERSION_CODE >> 16) & 0x0ff)
 #define KERNEL_VER     ((LINUX_VERSION_CODE >> 8) & 0x0ff)
 
+/* usb 3.0 root hub device descriptor */
+static const u8 usb3_rh_dev_descriptor[18] = {
+       0x12,       /*  __u8  bLength; */
+       0x01,       /*  __u8  bDescriptorType; Device */
+       0x00, 0x03, /*  __le16 bcdUSB; v3.0 */
+
+       0x09,       /*  __u8  bDeviceClass; HUB_CLASSCODE */
+       0x00,       /*  __u8  bDeviceSubClass; */
+       0x03,       /*  __u8  bDeviceProtocol; USB 3.0 hub */
+       0x09,       /*  __u8  bMaxPacketSize0; 2^9 = 512 Bytes */
+
+       0x6b, 0x1d, /*  __le16 idVendor; Linux Foundation */
+       0x02, 0x00, /*  __le16 idProduct; device 0x0002 */
+       KERNEL_VER, KERNEL_REL, /*  __le16 bcdDevice */
+
+       0x03,       /*  __u8  iManufacturer; */
+       0x02,       /*  __u8  iProduct; */
+       0x01,       /*  __u8  iSerialNumber; */
+       0x01        /*  __u8  bNumConfigurations; */
+};
+
 /* usb 2.0 root hub device descriptor */
 static const u8 usb2_rh_dev_descriptor [18] = {
        0x12,       /*  __u8  bLength; */
@@ -273,6 +294,47 @@ static const u8 hs_rh_config_descriptor [] = {
        0x0c        /*  __u8  ep_bInterval; (256ms -- usb 2.0 spec) */
 };
 
+static const u8 ss_rh_config_descriptor[] = {
+       /* one configuration */
+       0x09,       /*  __u8  bLength; */
+       0x02,       /*  __u8  bDescriptorType; Configuration */
+       0x19, 0x00, /*  __le16 wTotalLength; FIXME */
+       0x01,       /*  __u8  bNumInterfaces; (1) */
+       0x01,       /*  __u8  bConfigurationValue; */
+       0x00,       /*  __u8  iConfiguration; */
+       0xc0,       /*  __u8  bmAttributes;
+                                Bit 7: must be set,
+                                    6: Self-powered,
+                                    5: Remote wakeup,
+                                    4..0: resvd */
+       0x00,       /*  __u8  MaxPower; */
+
+       /* one interface */
+       0x09,       /*  __u8  if_bLength; */
+       0x04,       /*  __u8  if_bDescriptorType; Interface */
+       0x00,       /*  __u8  if_bInterfaceNumber; */
+       0x00,       /*  __u8  if_bAlternateSetting; */
+       0x01,       /*  __u8  if_bNumEndpoints; */
+       0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+       0x00,       /*  __u8  if_bInterfaceSubClass; */
+       0x00,       /*  __u8  if_bInterfaceProtocol; */
+       0x00,       /*  __u8  if_iInterface; */
+
+       /* one endpoint (status change endpoint) */
+       0x07,       /*  __u8  ep_bLength; */
+       0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
+       0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+       0x03,       /*  __u8  ep_bmAttributes; Interrupt */
+                   /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8)
+                    * see hub.c:hub_configure() for details. */
+       (USB_MAXCHILDREN + 1 + 7) / 8, 0x00,
+       0x0c        /*  __u8  ep_bInterval; (256ms -- usb 2.0 spec) */
+       /*
+        * All 3.0 hubs should have an endpoint companion descriptor,
+        * but we're ignoring that for now.  FIXME?
+        */
+};
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -426,23 +488,39 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
        case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
                switch (wValue & 0xff00) {
                case USB_DT_DEVICE << 8:
-                       if (hcd->driver->flags & HCD_USB2)
+                       switch (hcd->driver->flags & HCD_MASK) {
+                       case HCD_USB3:
+                               bufp = usb3_rh_dev_descriptor;
+                               break;
+                       case HCD_USB2:
                                bufp = usb2_rh_dev_descriptor;
-                       else if (hcd->driver->flags & HCD_USB11)
+                               break;
+                       case HCD_USB11:
                                bufp = usb11_rh_dev_descriptor;
-                       else
+                               break;
+                       default:
                                goto error;
+                       }
                        len = 18;
                        if (hcd->has_tt)
                                patch_protocol = 1;
                        break;
                case USB_DT_CONFIG << 8:
-                       if (hcd->driver->flags & HCD_USB2) {
+                       switch (hcd->driver->flags & HCD_MASK) {
+                       case HCD_USB3:
+                               bufp = ss_rh_config_descriptor;
+                               len = sizeof ss_rh_config_descriptor;
+                               break;
+                       case HCD_USB2:
                                bufp = hs_rh_config_descriptor;
                                len = sizeof hs_rh_config_descriptor;
-                       } else {
+                               break;
+                       case HCD_USB11:
                                bufp = fs_rh_config_descriptor;
                                len = sizeof fs_rh_config_descriptor;
+                               break;
+                       default:
+                               goto error;
                        }
                        if (device_can_wakeup(&hcd->self.root_hub->dev))
                                patch_wakeup = 1;
@@ -755,23 +833,6 @@ static struct attribute_group usb_bus_attr_group = {
 
 /*-------------------------------------------------------------------------*/
 
-static struct class *usb_host_class;
-
-int usb_host_init(void)
-{
-       int retval = 0;
-
-       usb_host_class = class_create(THIS_MODULE, "usb_host");
-       if (IS_ERR(usb_host_class))
-               retval = PTR_ERR(usb_host_class);
-       return retval;
-}
-
-void usb_host_cleanup(void)
-{
-       class_destroy(usb_host_class);
-}
-
 /**
  * usb_bus_init - shared initialization code
  * @bus: the bus structure being initialized
@@ -818,12 +879,6 @@ static int usb_register_bus(struct usb_bus *bus)
        set_bit (busnum, busmap.busmap);
        bus->busnum = busnum;
 
-       bus->dev = device_create(usb_host_class, bus->controller, MKDEV(0, 0),
-                                bus, "usb_host%d", busnum);
-       result = PTR_ERR(bus->dev);
-       if (IS_ERR(bus->dev))
-               goto error_create_class_dev;
-
        /* Add it to the local list of buses */
        list_add (&bus->bus_list, &usb_bus_list);
        mutex_unlock(&usb_bus_list_lock);
@@ -834,8 +889,6 @@ static int usb_register_bus(struct usb_bus *bus)
                  "number %d\n", bus->busnum);
        return 0;
 
-error_create_class_dev:
-       clear_bit(busnum, busmap.busmap);
 error_find_busnum:
        mutex_unlock(&usb_bus_list_lock);
        return result;
@@ -865,8 +918,6 @@ static void usb_deregister_bus (struct usb_bus *bus)
        usb_notify_remove_bus(bus);
 
        clear_bit (bus->busnum, busmap.busmap);
-
-       device_unregister(bus->dev);
 }
 
 /**
@@ -1199,7 +1250,8 @@ static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
 
        /* Map the URB's buffers for DMA access.
         * Lower level HCD code should use *_dma exclusively,
-        * unless it uses pio or talks to another transport.
+        * unless it uses pio or talks to another transport,
+        * or uses the provided scatter gather list for bulk.
         */
        if (is_root_hub(urb->dev))
                return 0;
@@ -1520,6 +1572,92 @@ rescan:
        }
 }
 
+/* Check whether a new configuration or alt setting for an interface
+ * will exceed the bandwidth for the bus (or the host controller resources).
+ * Only pass in a non-NULL config or interface, not both!
+ * Passing NULL for both new_config and new_intf means the device will be
+ * de-configured by issuing a set configuration 0 command.
+ */
+int usb_hcd_check_bandwidth(struct usb_device *udev,
+               struct usb_host_config *new_config,
+               struct usb_interface *new_intf)
+{
+       int num_intfs, i, j;
+       struct usb_interface_cache *intf_cache;
+       struct usb_host_interface *alt = 0;
+       int ret = 0;
+       struct usb_hcd *hcd;
+       struct usb_host_endpoint *ep;
+
+       hcd = bus_to_hcd(udev->bus);
+       if (!hcd->driver->check_bandwidth)
+               return 0;
+
+       /* Configuration is being removed - set configuration 0 */
+       if (!new_config && !new_intf) {
+               for (i = 1; i < 16; ++i) {
+                       ep = udev->ep_out[i];
+                       if (ep)
+                               hcd->driver->drop_endpoint(hcd, udev, ep);
+                       ep = udev->ep_in[i];
+                       if (ep)
+                               hcd->driver->drop_endpoint(hcd, udev, ep);
+               }
+               hcd->driver->check_bandwidth(hcd, udev);
+               return 0;
+       }
+       /* Check if the HCD says there's enough bandwidth.  Enable all endpoints
+        * each interface's alt setting 0 and ask the HCD to check the bandwidth
+        * of the bus.  There will always be bandwidth for endpoint 0, so it's
+        * ok to exclude it.
+        */
+       if (new_config) {
+               num_intfs = new_config->desc.bNumInterfaces;
+               /* Remove endpoints (except endpoint 0, which is always on the
+                * schedule) from the old config from the schedule
+                */
+               for (i = 1; i < 16; ++i) {
+                       ep = udev->ep_out[i];
+                       if (ep) {
+                               ret = hcd->driver->drop_endpoint(hcd, udev, ep);
+                               if (ret < 0)
+                                       goto reset;
+                       }
+                       ep = udev->ep_in[i];
+                       if (ep) {
+                               ret = hcd->driver->drop_endpoint(hcd, udev, ep);
+                               if (ret < 0)
+                                       goto reset;
+                       }
+               }
+               for (i = 0; i < num_intfs; ++i) {
+
+                       /* Dig the endpoints for alt setting 0 out of the
+                        * interface cache for this interface
+                        */
+                       intf_cache = new_config->intf_cache[i];
+                       for (j = 0; j < intf_cache->num_altsetting; j++) {
+                               if (intf_cache->altsetting[j].desc.bAlternateSetting == 0)
+                                       alt = &intf_cache->altsetting[j];
+                       }
+                       if (!alt) {
+                               printk(KERN_DEBUG "Did not find alt setting 0 for intf %d\n", i);
+                               continue;
+                       }
+                       for (j = 0; j < alt->desc.bNumEndpoints; j++) {
+                               ret = hcd->driver->add_endpoint(hcd, udev, &alt->endpoint[j]);
+                               if (ret < 0)
+                                       goto reset;
+                       }
+               }
+       }
+       ret = hcd->driver->check_bandwidth(hcd, udev);
+reset:
+       if (ret < 0)
+               hcd->driver->reset_bandwidth(hcd, udev);
+       return ret;
+}
+
 /* Disables the endpoint: synchronizes with the hcd to make sure all
  * endpoint state is gone from hardware.  usb_hcd_flush_endpoint() must
  * have been called previously.  Use for set_configuration, set_interface,
@@ -1897,8 +2035,20 @@ int usb_add_hcd(struct usb_hcd *hcd,
                retval = -ENOMEM;
                goto err_allocate_root_hub;
        }
-       rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH :
-                       USB_SPEED_FULL;
+
+       switch (hcd->driver->flags & HCD_MASK) {
+       case HCD_USB11:
+               rhdev->speed = USB_SPEED_FULL;
+               break;
+       case HCD_USB2:
+               rhdev->speed = USB_SPEED_HIGH;
+               break;
+       case HCD_USB3:
+               rhdev->speed = USB_SPEED_SUPER;
+               break;
+       default:
+               goto err_allocate_root_hub;
+       }
        hcd->self.root_hub = rhdev;
 
        /* wakeup flag init defaults to "everything works" for root hubs,
index e7d4479de41cd04b692d1fe659275f9cadd8c69a..d397ecfd5b178d881f97c72e51989bfccbe2a064 100644 (file)
@@ -173,6 +173,8 @@ struct hc_driver {
 #define        HCD_LOCAL_MEM   0x0002          /* HC needs local memory */
 #define        HCD_USB11       0x0010          /* USB 1.1 */
 #define        HCD_USB2        0x0020          /* USB 2.0 */
+#define        HCD_USB3        0x0040          /* USB 3.0 */
+#define        HCD_MASK        0x0070
 
        /* called to init HCD and root hub */
        int     (*reset) (struct usb_hcd *hcd);
@@ -182,10 +184,10 @@ struct hc_driver {
         * a whole, not just the root hub; they're for PCI bus glue.
         */
        /* called after suspending the hub, before entering D3 etc */
-       int     (*pci_suspend) (struct usb_hcd *hcd, pm_message_t message);
+       int     (*pci_suspend)(struct usb_hcd *hcd);
 
        /* called after entering D0 (etc), before resuming the hub */
-       int     (*pci_resume) (struct usb_hcd *hcd);
+       int     (*pci_resume)(struct usb_hcd *hcd, bool hibernated);
 
        /* cleanly make HCD stop writing memory and doing I/O */
        void    (*stop) (struct usb_hcd *hcd);
@@ -224,6 +226,43 @@ struct hc_driver {
        void    (*relinquish_port)(struct usb_hcd *, int);
                /* has a port been handed over to a companion? */
        int     (*port_handed_over)(struct usb_hcd *, int);
+
+       /* xHCI specific functions */
+               /* Called by usb_alloc_dev to alloc HC device structures */
+       int     (*alloc_dev)(struct usb_hcd *, struct usb_device *);
+               /* Called by usb_release_dev to free HC device structures */
+       void    (*free_dev)(struct usb_hcd *, struct usb_device *);
+
+       /* Bandwidth computation functions */
+       /* Note that add_endpoint() can only be called once per endpoint before
+        * check_bandwidth() or reset_bandwidth() must be called.
+        * drop_endpoint() can only be called once per endpoint also.
+        * A call to xhci_drop_endpoint() followed by a call to xhci_add_endpoint() will
+        * add the endpoint to the schedule with possibly new parameters denoted by a
+        * different endpoint descriptor in usb_host_endpoint.
+        * A call to xhci_add_endpoint() followed by a call to xhci_drop_endpoint() is
+        * not allowed.
+        */
+               /* Allocate endpoint resources and add them to a new schedule */
+       int     (*add_endpoint)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint *);
+               /* Drop an endpoint from a new schedule */
+       int     (*drop_endpoint)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint *);
+               /* Check that a new hardware configuration, set using
+                * endpoint_enable and endpoint_disable, does not exceed bus
+                * bandwidth.  This must be called before any set configuration
+                * or set interface requests are sent to the device.
+                */
+       int     (*check_bandwidth)(struct usb_hcd *, struct usb_device *);
+               /* Reset the device schedule to the last known good schedule,
+                * which was set from a previous successful call to
+                * check_bandwidth().  This reverts any add_endpoint() and
+                * drop_endpoint() calls since that last successful call.
+                * Used for when a check_bandwidth() call fails due to resource
+                * or bandwidth constraints.
+                */
+       void    (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
+               /* Returns the hardware-chosen device address */
+       int     (*address_device)(struct usb_hcd *, struct usb_device *udev);
 };
 
 extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
@@ -242,6 +281,9 @@ extern void usb_hcd_disable_endpoint(struct usb_device *udev,
 extern void usb_hcd_reset_endpoint(struct usb_device *udev,
                struct usb_host_endpoint *ep);
 extern void usb_hcd_synchronize_unlinks(struct usb_device *udev);
+extern int usb_hcd_check_bandwidth(struct usb_device *udev,
+               struct usb_host_config *new_config,
+               struct usb_interface *new_intf);
 extern int usb_hcd_get_frame_number(struct usb_device *udev);
 
 extern struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
@@ -261,14 +303,11 @@ struct pci_device_id;
 extern int usb_hcd_pci_probe(struct pci_dev *dev,
                                const struct pci_device_id *id);
 extern void usb_hcd_pci_remove(struct pci_dev *dev);
-
-#ifdef CONFIG_PM
-extern int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t msg);
-extern int usb_hcd_pci_resume(struct pci_dev *dev);
-#endif /* CONFIG_PM */
-
 extern void usb_hcd_pci_shutdown(struct pci_dev *dev);
 
+#ifdef CONFIG_PM_SLEEP
+extern struct dev_pm_ops       usb_hcd_pci_pm_ops;
+#endif
 #endif /* CONFIG_PCI */
 
 /* pci-ish (pdev null is ok) buffer alloc/mapping support */
index be86ae3f40881516d529a894319ed52c71086b82..2af3b4f0605405dd723b1ccd4f853f7f85dc1848 100644 (file)
@@ -155,6 +155,8 @@ static inline char *portspeed(int portstatus)
                return "480 Mb/s";
        else if (portstatus & (1 << USB_PORT_FEAT_LOWSPEED))
                return "1.5 Mb/s";
+       else if (portstatus & (1 << USB_PORT_FEAT_SUPERSPEED))
+               return "5.0 Gb/s";
        else
                return "12 Mb/s";
 }
@@ -457,13 +459,13 @@ static void hub_tt_kevent (struct work_struct *work)
 
        spin_lock_irqsave (&hub->tt.lock, flags);
        while (--limit && !list_empty (&hub->tt.clear_list)) {
-               struct list_head        *temp;
+               struct list_head        *next;
                struct usb_tt_clear     *clear;
                struct usb_device       *hdev = hub->hdev;
                int                     status;
 
-               temp = hub->tt.clear_list.next;
-               clear = list_entry (temp, struct usb_tt_clear, clear_list);
+               next = hub->tt.clear_list.next;
+               clear = list_entry (next, struct usb_tt_clear, clear_list);
                list_del (&clear->clear_list);
 
                /* drop lock so HCD can concurrently report other TT errors */
@@ -951,6 +953,9 @@ static int hub_configure(struct usb_hub *hub,
                                        ret);
                        hub->tt.hub = hdev;
                        break;
+               case 3:
+                       /* USB 3.0 hubs don't have a TT */
+                       break;
                default:
                        dev_dbg(hub_dev, "Unrecognized hub protocol %d\n",
                                hdev->descriptor.bDeviceProtocol);
@@ -1323,6 +1328,11 @@ EXPORT_SYMBOL_GPL(usb_set_device_state);
  * 0 is reserved by USB for default address; (b) Linux's USB stack
  * uses always #1 for the root hub of the controller. So USB stack's
  * port #1, which is wusb virtual-port #0 has address #2.
+ *
+ * Devices connected under xHCI are not as simple.  The host controller
+ * supports virtualization, so the hardware assigns device addresses and
+ * the HCD must setup data structures before issuing a set address
+ * command to the hardware.
  */
 static void choose_address(struct usb_device *udev)
 {
@@ -1642,6 +1652,9 @@ int usb_new_device(struct usb_device *udev)
        err = usb_configure_device(udev);       /* detect & probe dev/intfs */
        if (err < 0)
                goto fail;
+       dev_dbg(&udev->dev, "udev %d, busnum %d, minor = %d\n",
+                       udev->devnum, udev->bus->busnum,
+                       (((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
        /* export the usbdev device-node for libusb */
        udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
                        (((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
@@ -2395,19 +2408,29 @@ EXPORT_SYMBOL_GPL(usb_ep0_reinit);
 static int hub_set_address(struct usb_device *udev, int devnum)
 {
        int retval;
+       struct usb_hcd *hcd = bus_to_hcd(udev->bus);
 
-       if (devnum <= 1)
+       /*
+        * The host controller will choose the device address,
+        * instead of the core having chosen it earlier
+        */
+       if (!hcd->driver->address_device && devnum <= 1)
                return -EINVAL;
        if (udev->state == USB_STATE_ADDRESS)
                return 0;
        if (udev->state != USB_STATE_DEFAULT)
                return -EINVAL;
-       retval = usb_control_msg(udev, usb_sndaddr0pipe(),
-               USB_REQ_SET_ADDRESS, 0, devnum, 0,
-               NULL, 0, USB_CTRL_SET_TIMEOUT);
+       if (hcd->driver->address_device) {
+               retval = hcd->driver->address_device(hcd, udev);
+       } else {
+               retval = usb_control_msg(udev, usb_sndaddr0pipe(),
+                               USB_REQ_SET_ADDRESS, 0, devnum, 0,
+                               NULL, 0, USB_CTRL_SET_TIMEOUT);
+               if (retval == 0)
+                       update_address(udev, devnum);
+       }
        if (retval == 0) {
                /* Device now using proper address. */
-               update_address(udev, devnum);
                usb_set_device_state(udev, USB_STATE_ADDRESS);
                usb_ep0_reinit(udev);
        }
@@ -2430,6 +2453,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
        static DEFINE_MUTEX(usb_address0_mutex);
 
        struct usb_device       *hdev = hub->hdev;
+       struct usb_hcd          *hcd = bus_to_hcd(hdev->bus);
        int                     i, j, retval;
        unsigned                delay = HUB_SHORT_RESET_TIME;
        enum usb_device_speed   oldspeed = udev->speed;
@@ -2452,11 +2476,24 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 
        mutex_lock(&usb_address0_mutex);
 
-       /* Reset the device; full speed may morph to high speed */
-       retval = hub_port_reset(hub, port1, udev, delay);
-       if (retval < 0)         /* error or disconnect */
+       if ((hcd->driver->flags & HCD_USB3) && udev->config) {
+               /* FIXME this will need special handling by the xHCI driver. */
+               dev_dbg(&udev->dev,
+                               "xHCI reset of configured device "
+                               "not supported yet.\n");
+               retval = -EINVAL;
                goto fail;
-                               /* success, speed is known */
+       } else if (!udev->config && oldspeed == USB_SPEED_SUPER) {
+               /* Don't reset USB 3.0 devices during an initial setup */
+               usb_set_device_state(udev, USB_STATE_DEFAULT);
+       } else {
+               /* Reset the device; full speed may morph to high speed */
+               /* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
+               retval = hub_port_reset(hub, port1, udev, delay);
+               if (retval < 0)         /* error or disconnect */
+                       goto fail;
+               /* success, speed is known */
+       }
        retval = -ENODEV;
 
        if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {
@@ -2471,6 +2508,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
         * reported as 0xff in the device descriptor). WUSB1.0[4.8.1].
         */
        switch (udev->speed) {
+       case USB_SPEED_SUPER:
        case USB_SPEED_VARIABLE:        /* fixed at 512 */
                udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
                break;
@@ -2496,16 +2534,20 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
        case USB_SPEED_LOW:     speed = "low";  break;
        case USB_SPEED_FULL:    speed = "full"; break;
        case USB_SPEED_HIGH:    speed = "high"; break;
+       case USB_SPEED_SUPER:
+                               speed = "super";
+                               break;
        case USB_SPEED_VARIABLE:
                                speed = "variable";
                                type = "Wireless ";
                                break;
        default:                speed = "?";    break;
        }
-       dev_info (&udev->dev,
-                 "%s %s speed %sUSB device using %s and address %d\n",
-                 (udev->config) ? "reset" : "new", speed, type,
-                 udev->bus->controller->driver->name, devnum);
+       if (udev->speed != USB_SPEED_SUPER)
+               dev_info(&udev->dev,
+                               "%s %s speed %sUSB device using %s and address %d\n",
+                               (udev->config) ? "reset" : "new", speed, type,
+                               udev->bus->controller->driver->name, devnum);
 
        /* Set up TT records, if needed  */
        if (hdev->tt) {
@@ -2530,7 +2572,11 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
         * value.
         */
        for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
-               if (USE_NEW_SCHEME(retry_counter)) {
+               /*
+                * An xHCI controller cannot send any packets to a device until
+                * a set address command successfully completes.
+                */
+               if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) {
                        struct usb_device_descriptor *buf;
                        int r = 0;
 
@@ -2596,7 +2642,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
                 * unauthorized address in the Connect Ack sequence;
                 * authorization will assign the final address.
                 */
-               if (udev->wusb == 0) {
+               if (udev->wusb == 0) {
                        for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
                                retval = hub_set_address(udev, devnum);
                                if (retval >= 0)
@@ -2609,13 +2655,20 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
                                        devnum, retval);
                                goto fail;
                        }
+                       if (udev->speed == USB_SPEED_SUPER) {
+                               devnum = udev->devnum;
+                               dev_info(&udev->dev,
+                                               "%s SuperSpeed USB device using %s and address %d\n",
+                                               (udev->config) ? "reset" : "new",
+                                               udev->bus->controller->driver->name, devnum);
+                       }
 
                        /* cope with hardware quirkiness:
                         *  - let SET_ADDRESS settle, some device hardware wants it
                         *  - read ep0 maxpacket even for high and low speed,
                         */
                        msleep(10);
-                       if (USE_NEW_SCHEME(retry_counter))
+                       if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3))
                                break;
                }
 
@@ -2634,8 +2687,11 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
        if (retval)
                goto fail;
 
-       i = udev->descriptor.bMaxPacketSize0 == 0xff?   /* wusb device? */
-           512 : udev->descriptor.bMaxPacketSize0;
+       if (udev->descriptor.bMaxPacketSize0 == 0xff ||
+                       udev->speed == USB_SPEED_SUPER)
+               i = 512;
+       else
+               i = udev->descriptor.bMaxPacketSize0;
        if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) {
                if (udev->speed != USB_SPEED_FULL ||
                                !(i == 8 || i == 16 || i == 32 || i == 64)) {
@@ -2847,19 +2903,41 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
                }
 
                usb_set_device_state(udev, USB_STATE_POWERED);
-               udev->speed = USB_SPEED_UNKNOWN;
                udev->bus_mA = hub->mA_per_port;
                udev->level = hdev->level + 1;
                udev->wusb = hub_is_wusb(hub);
 
-               /* set the address */
-               choose_address(udev);
-               if (udev->devnum <= 0) {
-                       status = -ENOTCONN;     /* Don't retry */
-                       goto loop;
+               /*
+                * USB 3.0 devices are reset automatically before the connect
+                * port status change appears, and the root hub port status
+                * shows the correct speed.  We also get port change
+                * notifications for USB 3.0 devices from the USB 3.0 portion of
+                * an external USB 3.0 hub, but this isn't handled correctly yet
+                * FIXME.
+                */
+
+               if (!(hcd->driver->flags & HCD_USB3))
+                       udev->speed = USB_SPEED_UNKNOWN;
+               else if ((hdev->parent == NULL) &&
+                               (portstatus & (1 << USB_PORT_FEAT_SUPERSPEED)))
+                       udev->speed = USB_SPEED_SUPER;
+               else
+                       udev->speed = USB_SPEED_UNKNOWN;
+
+               /*
+                * xHCI needs to issue an address device command later
+                * in the hub_port_init sequence for SS/HS/FS/LS devices.
+                */
+               if (!(hcd->driver->flags & HCD_USB3)) {
+                       /* set the address */
+                       choose_address(udev);
+                       if (udev->devnum <= 0) {
+                               status = -ENOTCONN;     /* Don't retry */
+                               goto loop;
+                       }
                }
 
-               /* reset and get descriptor */
+               /* reset (non-USB 3.0 devices) and get descriptor */
                status = hub_port_init(hub, udev, port1, i);
                if (status < 0)
                        goto loop;
index 2a116ce53c9b8e441f942b5b1b386a06a90cf738..889c0f32a40b729431f2dab51d13aead39f5f3e8 100644 (file)
 #define USB_PORT_FEAT_L1               5       /* L1 suspend */
 #define USB_PORT_FEAT_POWER            8
 #define USB_PORT_FEAT_LOWSPEED         9
+/* This value was never in Table 11-17 */
 #define USB_PORT_FEAT_HIGHSPEED                10
+/* This value is also fake */
+#define USB_PORT_FEAT_SUPERSPEED       11
 #define USB_PORT_FEAT_C_CONNECTION     16
 #define USB_PORT_FEAT_C_ENABLE         17
 #define USB_PORT_FEAT_C_SUSPEND                18
index b626283776541fe192c0442a46ab0e33415cc167..2bed83caacb1a0c714a2e05af21242bbb504dcad 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/mm.h>
 #include <linux/timer.h>
 #include <linux/ctype.h>
+#include <linux/nls.h>
 #include <linux/device.h>
 #include <linux/scatterlist.h>
 #include <linux/usb/quirks.h>
@@ -364,6 +365,7 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
        int i;
        int urb_flags;
        int dma;
+       int use_sg;
 
        if (!io || !dev || !sg
                        || usb_pipecontrol(pipe)
@@ -391,7 +393,19 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
        if (io->entries <= 0)
                return io->entries;
 
-       io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags);
+       /* If we're running on an xHCI host controller, queue the whole scatter
+        * gather list with one call to urb_enqueue().  This is only for bulk,
+        * as that endpoint type does not care how the data gets broken up
+        * across frames.
+        */
+       if (usb_pipebulk(pipe) &&
+                       bus_to_hcd(dev->bus)->driver->flags & HCD_USB3) {
+               io->urbs = kmalloc(sizeof *io->urbs, mem_flags);
+               use_sg = true;
+       } else {
+               io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags);
+               use_sg = false;
+       }
        if (!io->urbs)
                goto nomem;
 
@@ -401,62 +415,92 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
        if (usb_pipein(pipe))
                urb_flags |= URB_SHORT_NOT_OK;
 
-       for_each_sg(sg, sg, io->entries, i) {
-               unsigned len;
-
-               io->urbs[i] = usb_alloc_urb(0, mem_flags);
-               if (!io->urbs[i]) {
-                       io->entries = i;
+       if (use_sg) {
+               io->urbs[0] = usb_alloc_urb(0, mem_flags);
+               if (!io->urbs[0]) {
+                       io->entries = 0;
                        goto nomem;
                }
 
-               io->urbs[i]->dev = NULL;
-               io->urbs[i]->pipe = pipe;
-               io->urbs[i]->interval = period;
-               io->urbs[i]->transfer_flags = urb_flags;
-
-               io->urbs[i]->complete = sg_complete;
-               io->urbs[i]->context = io;
-
-               /*
-                * Some systems need to revert to PIO when DMA is temporarily
-                * unavailable.  For their sakes, both transfer_buffer and
-                * transfer_dma are set when possible.  However this can only
-                * work on systems without:
-                *
-                *  - HIGHMEM, since DMA buffers located in high memory are
-                *    not directly addressable by the CPU for PIO;
-                *
-                *  - IOMMU, since dma_map_sg() is allowed to use an IOMMU to
-                *    make virtually discontiguous buffers be "dma-contiguous"
-                *    so that PIO and DMA need diferent numbers of URBs.
-                *
-                * So when HIGHMEM or IOMMU are in use, transfer_buffer is NULL
-                * to prevent stale pointers and to help spot bugs.
-                */
-               if (dma) {
-                       io->urbs[i]->transfer_dma = sg_dma_address(sg);
-                       len = sg_dma_len(sg);
+               io->urbs[0]->dev = NULL;
+               io->urbs[0]->pipe = pipe;
+               io->urbs[0]->interval = period;
+               io->urbs[0]->transfer_flags = urb_flags;
+
+               io->urbs[0]->complete = sg_complete;
+               io->urbs[0]->context = io;
+               /* A length of zero means transfer the whole sg list */
+               io->urbs[0]->transfer_buffer_length = length;
+               if (length == 0) {
+                       for_each_sg(sg, sg, io->entries, i) {
+                               io->urbs[0]->transfer_buffer_length +=
+                                       sg_dma_len(sg);
+                       }
+               }
+               io->urbs[0]->sg = io;
+               io->urbs[0]->num_sgs = io->entries;
+               io->entries = 1;
+       } else {
+               for_each_sg(sg, sg, io->entries, i) {
+                       unsigned len;
+
+                       io->urbs[i] = usb_alloc_urb(0, mem_flags);
+                       if (!io->urbs[i]) {
+                               io->entries = i;
+                               goto nomem;
+                       }
+
+                       io->urbs[i]->dev = NULL;
+                       io->urbs[i]->pipe = pipe;
+                       io->urbs[i]->interval = period;
+                       io->urbs[i]->transfer_flags = urb_flags;
+
+                       io->urbs[i]->complete = sg_complete;
+                       io->urbs[i]->context = io;
+
+                       /*
+                        * Some systems need to revert to PIO when DMA is
+                        * temporarily unavailable.  For their sakes, both
+                        * transfer_buffer and transfer_dma are set when
+                        * possible.  However this can only work on systems
+                        * without:
+                        *
+                        *  - HIGHMEM, since DMA buffers located in high memory
+                        *    are not directly addressable by the CPU for PIO;
+                        *
+                        *  - IOMMU, since dma_map_sg() is allowed to use an
+                        *    IOMMU to make virtually discontiguous buffers be
+                        *    "dma-contiguous" so that PIO and DMA need diferent
+                        *    numbers of URBs.
+                        *
+                        * So when HIGHMEM or IOMMU are in use, transfer_buffer
+                        * is NULL to prevent stale pointers and to help spot
+                        * bugs.
+                        */
+                       if (dma) {
+                               io->urbs[i]->transfer_dma = sg_dma_address(sg);
+                               len = sg_dma_len(sg);
 #if defined(CONFIG_HIGHMEM) || defined(CONFIG_GART_IOMMU)
-                       io->urbs[i]->transfer_buffer = NULL;
+                               io->urbs[i]->transfer_buffer = NULL;
 #else
-                       io->urbs[i]->transfer_buffer = sg_virt(sg);
+                               io->urbs[i]->transfer_buffer = sg_virt(sg);
 #endif
-               } else {
-                       /* hc may use _only_ transfer_buffer */
-                       io->urbs[i]->transfer_buffer = sg_virt(sg);
-                       len = sg->length;
-               }
+                       } else {
+                               /* hc may use _only_ transfer_buffer */
+                               io->urbs[i]->transfer_buffer = sg_virt(sg);
+                               len = sg->length;
+                       }
 
-               if (length) {
-                       len = min_t(unsigned, len, length);
-                       length -= len;
-                       if (length == 0)
-                               io->entries = i + 1;
+                       if (length) {
+                               len = min_t(unsigned, len, length);
+                               length -= len;
+                               if (length == 0)
+                                       io->entries = i + 1;
+                       }
+                       io->urbs[i]->transfer_buffer_length = len;
                }
-               io->urbs[i]->transfer_buffer_length = len;
+               io->urbs[--i]->transfer_flags &= ~URB_NO_INTERRUPT;
        }
-       io->urbs[--i]->transfer_flags &= ~URB_NO_INTERRUPT;
 
        /* transaction state */
        io->count = io->entries;
@@ -509,6 +553,10 @@ EXPORT_SYMBOL_GPL(usb_sg_init);
  * could be transferred.  That capability is less useful for low or full
  * speed interrupt endpoints, which allow at most one packet per millisecond,
  * of at most 8 or 64 bytes (respectively).
+ *
+ * It is not necessary to call this function to reserve bandwidth for devices
+ * under an xHCI host controller, as the bandwidth is reserved when the
+ * configuration or interface alt setting is selected.
  */
 void usb_sg_wait(struct usb_sg_request *io)
 {
@@ -759,7 +807,7 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid,
 }
 
 /**
- * usb_string - returns ISO 8859-1 version of a string descriptor
+ * usb_string - returns UTF-8 version of a string descriptor
  * @dev: the device whose string descriptor is being retrieved
  * @index: the number of the descriptor
  * @buf: where to put the string
@@ -767,17 +815,10 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid,
  * Context: !in_interrupt ()
  *
  * This converts the UTF-16LE encoded strings returned by devices, from
- * usb_get_string_descriptor(), to null-terminated ISO-8859-1 encoded ones
- * that are more usable in most kernel contexts.  Note that all characters
- * in the chosen descriptor that can't be encoded using ISO-8859-1
- * are converted to the question mark ("?") character, and this function
+ * usb_get_string_descriptor(), to null-terminated UTF-8 encoded ones
+ * that are more usable in most kernel contexts.  Note that this function
  * chooses strings in the first language supported by the device.
  *
- * The ASCII (or, redundantly, "US-ASCII") character set is the seven-bit
- * subset of ISO 8859-1. ISO-8859-1 is the eight-bit subset of Unicode,
- * and is appropriate for use many uses of English and several other
- * Western European languages.  (But it doesn't include the "Euro" symbol.)
- *
  * This call is synchronous, and may not be used in an interrupt context.
  *
  * Returns length of the string (>= 0) or usb_control_msg status (< 0).
@@ -786,7 +827,6 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
 {
        unsigned char *tbuf;
        int err;
-       unsigned int u, idx;
 
        if (dev->state == USB_STATE_SUSPENDED)
                return -EHOSTUNREACH;
@@ -821,16 +861,9 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
                goto errout;
 
        size--;         /* leave room for trailing NULL char in output buffer */
-       for (idx = 0, u = 2; u < err; u += 2) {
-               if (idx >= size)
-                       break;
-               if (tbuf[u+1])                  /* high byte */
-                       buf[idx++] = '?';  /* non ISO-8859-1 character */
-               else
-                       buf[idx++] = tbuf[u];
-       }
-       buf[idx] = 0;
-       err = idx;
+       err = utf16s_to_utf8s((wchar_t *) &tbuf[2], (err - 2) / 2,
+                       UTF16_LITTLE_ENDIAN, buf, size);
+       buf[err] = 0;
 
        if (tbuf[1] != USB_DT_STRING)
                dev_dbg(&dev->dev,
@@ -843,6 +876,9 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
 }
 EXPORT_SYMBOL_GPL(usb_string);
 
+/* one UTF-8-encoded 16-bit character has at most three bytes */
+#define MAX_USB_STRING_SIZE (127 * 3 + 1)
+
 /**
  * usb_cache_string - read a string descriptor and cache it for later use
  * @udev: the device whose string descriptor is being read
@@ -860,9 +896,9 @@ char *usb_cache_string(struct usb_device *udev, int index)
        if (index <= 0)
                return NULL;
 
-       buf = kmalloc(256, GFP_KERNEL);
+       buf = kmalloc(MAX_USB_STRING_SIZE, GFP_KERNEL);
        if (buf) {
-               len = usb_string(udev, index, buf, 256);
+               len = usb_string(udev, index, buf, MAX_USB_STRING_SIZE);
                if (len > 0) {
                        smallbuf = kmalloc(++len, GFP_KERNEL);
                        if (!smallbuf)
@@ -1664,6 +1700,21 @@ free_interfaces:
        if (ret)
                goto free_interfaces;
 
+       /* Make sure we have bandwidth (and available HCD resources) for this
+        * configuration.  Remove endpoints from the schedule if we're dropping
+        * this configuration to set configuration 0.  After this point, the
+        * host controller will not allow submissions to dropped endpoints.  If
+        * this call fails, the device state is unchanged.
+        */
+       if (cp)
+               ret = usb_hcd_check_bandwidth(dev, cp, NULL);
+       else
+               ret = usb_hcd_check_bandwidth(dev, NULL, NULL);
+       if (ret < 0) {
+               usb_autosuspend_device(dev);
+               goto free_interfaces;
+       }
+
        /* if it's already configured, clear out old state first.
         * getting rid of old interfaces means unbinding their drivers.
         */
@@ -1686,6 +1737,7 @@ free_interfaces:
        dev->actconfig = cp;
        if (!cp) {
                usb_set_device_state(dev, USB_STATE_ADDRESS);
+               usb_hcd_check_bandwidth(dev, NULL, NULL);
                usb_autosuspend_device(dev);
                goto free_interfaces;
        }
index c6678919792729b0c0548f6aa15592efc50e1fd1..b5c72e458943f753d5981c20596de1ffe376fb4a 100644 (file)
@@ -552,8 +552,8 @@ static struct attribute *dev_string_attrs[] = {
 static mode_t dev_string_attrs_are_visible(struct kobject *kobj,
                struct attribute *a, int n)
 {
-       struct usb_device *udev = to_usb_device(
-                       container_of(kobj, struct device, kobj));
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct usb_device *udev = to_usb_device(dev);
 
        if (a == &dev_attr_manufacturer.attr) {
                if (udev->manufacturer == NULL)
@@ -585,8 +585,8 @@ static ssize_t
 read_descriptors(struct kobject *kobj, struct bin_attribute *attr,
                char *buf, loff_t off, size_t count)
 {
-       struct usb_device *udev = to_usb_device(
-                       container_of(kobj, struct device, kobj));
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct usb_device *udev = to_usb_device(dev);
        size_t nleft = count;
        size_t srclen, n;
        int cfgno;
@@ -786,8 +786,8 @@ static struct attribute *intf_assoc_attrs[] = {
 static mode_t intf_assoc_attrs_are_visible(struct kobject *kobj,
                struct attribute *a, int n)
 {
-       struct usb_interface *intf = to_usb_interface(
-                       container_of(kobj, struct device, kobj));
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct usb_interface *intf = to_usb_interface(dev);
 
        if (intf->intf_assoc == NULL)
                return 0;
index 3376055f36e7349057531b41c080832c5bd04623..0885d4abdc6265d0b7775da9b9f5503fc2be0dff 100644 (file)
@@ -241,6 +241,12 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
  * If the USB subsystem can't allocate sufficient bandwidth to perform
  * the periodic request, submitting such a periodic request should fail.
  *
+ * For devices under xHCI, the bandwidth is reserved at configuration time, or
+ * when the alt setting is selected.  If there is not enough bus bandwidth, the
+ * configuration/alt setting request will fail.  Therefore, submissions to
+ * periodic endpoints on devices under xHCI should never fail due to bandwidth
+ * constraints.
+ *
  * Device drivers must explicitly request that repetition, by ensuring that
  * some URB is always on the endpoint's queue (except possibly for short
  * periods during completion callacks).  When there is no longer an urb
@@ -351,6 +357,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
        if (xfertype == USB_ENDPOINT_XFER_ISOC) {
                int     n, len;
 
+               /* FIXME SuperSpeed isoc endpoints have up to 16 bursts */
                /* "high bandwidth" mode, 1-3 packets/uframe? */
                if (dev->speed == USB_SPEED_HIGH) {
                        int     mult = 1 + ((max >> 11) & 0x03);
@@ -426,6 +433,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
                        return -EINVAL;
                /* too big? */
                switch (dev->speed) {
+               case USB_SPEED_SUPER:   /* units are 125us */
+                       /* Handle up to 2^(16-1) microframes */
+                       if (urb->interval > (1 << 15))
+                               return -EINVAL;
+                       max = 1 << 15;
                case USB_SPEED_HIGH:    /* units are microframes */
                        /* NOTE usb handles 2^15 */
                        if (urb->interval > (1024 * 8))
index 7eee400d3e32cac6486cb7809234792012ed4689..a26f73880c32388340fad1ef0639c8233d1c3be4 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/usb.h>
 #include <linux/mutex.h>
 #include <linux/workqueue.h>
+#include <linux/debugfs.h>
 
 #include <asm/io.h>
 #include <linux/scatterlist.h>
@@ -139,8 +140,7 @@ static int __find_interface(struct device *dev, void *data)
        struct find_interface_arg *arg = data;
        struct usb_interface *intf;
 
-       /* can't look at usb devices, only interfaces */
-       if (is_usb_device(dev))
+       if (!is_usb_interface(dev))
                return 0;
 
        intf = to_usb_interface(dev);
@@ -184,11 +184,16 @@ EXPORT_SYMBOL_GPL(usb_find_interface);
 static void usb_release_dev(struct device *dev)
 {
        struct usb_device *udev;
+       struct usb_hcd *hcd;
 
        udev = to_usb_device(dev);
+       hcd = bus_to_hcd(udev->bus);
 
        usb_destroy_configuration(udev);
-       usb_put_hcd(bus_to_hcd(udev->bus));
+       /* Root hubs aren't real devices, so don't free HCD resources */
+       if (hcd->driver->free_dev && udev->parent)
+               hcd->driver->free_dev(hcd, udev);
+       usb_put_hcd(hcd);
        kfree(udev->product);
        kfree(udev->manufacturer);
        kfree(udev->serial);
@@ -305,10 +310,21 @@ static struct dev_pm_ops usb_device_pm_ops = {
 
 #endif /* CONFIG_PM */
 
+
+static char *usb_nodename(struct device *dev)
+{
+       struct usb_device *usb_dev;
+
+       usb_dev = to_usb_device(dev);
+       return kasprintf(GFP_KERNEL, "bus/usb/%03d/%03d",
+                        usb_dev->bus->busnum, usb_dev->devnum);
+}
+
 struct device_type usb_device_type = {
        .name =         "usb_device",
        .release =      usb_release_dev,
        .uevent =       usb_dev_uevent,
+       .nodename =     usb_nodename,
        .pm =           &usb_device_pm_ops,
 };
 
@@ -348,6 +364,13 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
                kfree(dev);
                return NULL;
        }
+       /* Root hubs aren't true devices, so don't allocate HCD resources */
+       if (usb_hcd->driver->alloc_dev && parent &&
+               !usb_hcd->driver->alloc_dev(usb_hcd, dev)) {
+               usb_put_hcd(bus_to_hcd(bus));
+               kfree(dev);
+               return NULL;
+       }
 
        device_initialize(&dev->dev);
        dev->dev.bus = &usb_bus_type;
@@ -375,18 +398,24 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
         */
        if (unlikely(!parent)) {
                dev->devpath[0] = '0';
+               dev->route = 0;
 
                dev->dev.parent = bus->controller;
                dev_set_name(&dev->dev, "usb%d", bus->busnum);
                root_hub = 1;
        } else {
                /* match any labeling on the hubs; it's one-based */
-               if (parent->devpath[0] == '0')
+               if (parent->devpath[0] == '0') {
                        snprintf(dev->devpath, sizeof dev->devpath,
                                "%d", port1);
-               else
+                       /* Root ports are not counted in route string */
+                       dev->route = 0;
+               } else {
                        snprintf(dev->devpath, sizeof dev->devpath,
                                "%s.%d", parent->devpath, port1);
+                       dev->route = parent->route +
+                               (port1 << ((parent->level - 1)*4));
+               }
 
                dev->dev.parent = &parent->dev;
                dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath);
@@ -799,12 +828,12 @@ void usb_buffer_dmasync(struct urb *urb)
                return;
 
        if (controller->dma_mask) {
-               dma_sync_single(controller,
+               dma_sync_single_for_cpu(controller,
                        urb->transfer_dma, urb->transfer_buffer_length,
                        usb_pipein(urb->pipe)
                                ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
                if (usb_pipecontrol(urb->pipe))
-                       dma_sync_single(controller,
+                       dma_sync_single_for_cpu(controller,
                                        urb->setup_dma,
                                        sizeof(struct usb_ctrlrequest),
                                        DMA_TO_DEVICE);
@@ -922,8 +951,8 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
                        || !controller->dma_mask)
                return;
 
-       dma_sync_sg(controller, sg, n_hw_ents,
-                       is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+       dma_sync_sg_for_cpu(controller, sg, n_hw_ents,
+                           is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 EXPORT_SYMBOL_GPL(usb_buffer_dmasync_sg);
 #endif
@@ -1001,6 +1030,35 @@ static struct notifier_block usb_bus_nb = {
        .notifier_call = usb_bus_notify,
 };
 
+struct dentry *usb_debug_root;
+EXPORT_SYMBOL_GPL(usb_debug_root);
+
+struct dentry *usb_debug_devices;
+
+static int usb_debugfs_init(void)
+{
+       usb_debug_root = debugfs_create_dir("usb", NULL);
+       if (!usb_debug_root)
+               return -ENOENT;
+
+       usb_debug_devices = debugfs_create_file("devices", 0444,
+                                               usb_debug_root, NULL,
+                                               &usbfs_devices_fops);
+       if (!usb_debug_devices) {
+               debugfs_remove(usb_debug_root);
+               usb_debug_root = NULL;
+               return -ENOENT;
+       }
+
+       return 0;
+}
+
+static void usb_debugfs_cleanup(void)
+{
+       debugfs_remove(usb_debug_devices);
+       debugfs_remove(usb_debug_root);
+}
+
 /*
  * Init
  */
@@ -1012,6 +1070,10 @@ static int __init usb_init(void)
                return 0;
        }
 
+       retval = usb_debugfs_init();
+       if (retval)
+               goto out;
+
        retval = ksuspend_usb_init();
        if (retval)
                goto out;
@@ -1021,9 +1083,6 @@ static int __init usb_init(void)
        retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb);
        if (retval)
                goto bus_notifier_failed;
-       retval = usb_host_init();
-       if (retval)
-               goto host_init_failed;
        retval = usb_major_init();
        if (retval)
                goto major_init_failed;
@@ -1053,8 +1112,6 @@ usb_devio_init_failed:
 driver_register_failed:
        usb_major_cleanup();
 major_init_failed:
-       usb_host_cleanup();
-host_init_failed:
        bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
 bus_notifier_failed:
        bus_unregister(&usb_bus_type);
@@ -1079,10 +1136,10 @@ static void __exit usb_exit(void)
        usb_deregister(&usbfs_driver);
        usb_devio_cleanup();
        usb_hub_cleanup();
-       usb_host_cleanup();
        bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
        bus_unregister(&usb_bus_type);
        ksuspend_usb_cleanup();
+       usb_debugfs_cleanup();
 }
 
 subsys_initcall(usb_init);
index 79d8a9ea559ba7dc635f268419f9918bdfcf6c08..e2a8cfaade1ddbc7c5bb4c43c7d1f91f580c6230 100644 (file)
@@ -41,8 +41,6 @@ extern int  usb_hub_init(void);
 extern void usb_hub_cleanup(void);
 extern int usb_major_init(void);
 extern void usb_major_cleanup(void);
-extern int usb_host_init(void);
-extern void usb_host_cleanup(void);
 
 #ifdef CONFIG_PM
 
@@ -106,6 +104,7 @@ extern struct workqueue_struct *ksuspend_usb_wq;
 extern struct bus_type usb_bus_type;
 extern struct device_type usb_device_type;
 extern struct device_type usb_if_device_type;
+extern struct device_type usb_ep_device_type;
 extern struct usb_device_driver usb_generic_driver;
 
 static inline int is_usb_device(const struct device *dev)
@@ -113,6 +112,16 @@ static inline int is_usb_device(const struct device *dev)
        return dev->type == &usb_device_type;
 }
 
+static inline int is_usb_interface(const struct device *dev)
+{
+       return dev->type == &usb_if_device_type;
+}
+
+static inline int is_usb_endpoint(const struct device *dev)
+{
+       return dev->type == &usb_ep_device_type;
+}
+
 /* Do the same for device drivers and interface drivers. */
 
 static inline int is_usb_device_driver(struct device_driver *drv)
index 080bb1e4b847aebcd862b71480596edcf7f8b37e..5d1ddf485d1eb6d5d55e12a4eca7536e10a75838 100644 (file)
@@ -156,7 +156,7 @@ config USB_ATMEL_USBA
 
 config USB_GADGET_FSL_USB2
        boolean "Freescale Highspeed USB DR Peripheral Controller"
-       depends on FSL_SOC
+       depends on FSL_SOC || ARCH_MXC
        select USB_GADGET_DUALSPEED
        help
           Some of Freescale PowerPC processors have a High Speed
@@ -253,7 +253,7 @@ config USB_PXA25X_SMALL
 
 config USB_GADGET_PXA27X
        boolean "PXA 27x"
-       depends on ARCH_PXA && PXA27x
+       depends on ARCH_PXA && (PXA27x || PXA3xx)
        select USB_OTG_UTILS
        help
           Intel's PXA 27x series XScale ARM v5TE processors include
@@ -272,6 +272,20 @@ config USB_PXA27X
        default USB_GADGET
        select USB_GADGET_SELECTED
 
+config USB_GADGET_S3C_HSOTG
+       boolean "S3C HS/OtG USB Device controller"
+       depends on S3C_DEV_USB_HSOTG
+       select USB_GADGET_S3C_HSOTG_PIO
+       help
+         The Samsung S3C64XX USB2.0 high-speed gadget controller
+         integrated into the S3C64XX series SoC.
+
+config USB_S3C_HSOTG
+       tristate
+       depends on USB_GADGET_S3C_HSOTG
+       default USB_GADGET
+       select USB_GADGET_SELECTED
+
 config USB_GADGET_S3C2410
        boolean "S3C2410 USB Device Controller"
        depends on ARCH_S3C2410
@@ -460,6 +474,27 @@ config USB_GOKU
        default USB_GADGET
        select USB_GADGET_SELECTED
 
+config USB_GADGET_LANGWELL
+       boolean "Intel Langwell USB Device Controller"
+       depends on PCI
+       select USB_GADGET_DUALSPEED
+       help
+          Intel Langwell USB Device Controller is a High-Speed USB
+          On-The-Go device controller.
+
+          The number of programmable endpoints is different through
+          controller revision.
+
+          Say "y" to link the driver statically, or "m" to build a
+          dynamically linked module called "langwell_udc" and force all
+          gadget drivers to also be dynamically linked.
+
+config USB_LANGWELL
+       tristate
+       depends on USB_GADGET_LANGWELL
+       default USB_GADGET
+       select USB_GADGET_SELECTED
+
 
 #
 # LAST -- dummy/emulated controller
@@ -566,6 +601,20 @@ config USB_ZERO_HNPTEST
          the "B-Peripheral" role, that device will use HNP to let this
          one serve as the USB host instead (in the "B-Host" role).
 
+config USB_AUDIO
+       tristate "Audio Gadget (EXPERIMENTAL)"
+       depends on SND
+       help
+         Gadget Audio is compatible with USB Audio Class specification 1.0.
+         It will include at least one AudioControl interface, zero or more
+         AudioStream interface and zero or more MIDIStream interface.
+
+         Gadget Audio will use on-board ALSA (CONFIG_SND) audio card to
+         playback or capture audio stream.
+
+         Say "y" to link the driver statically, or "m" to build a
+         dynamically linked module called "g_audio".
+
 config USB_ETH
        tristate "Ethernet Gadget (with CDC Ethernet support)"
        depends on NET
index 39a51d746cb76d1eb796fb9798e121b9409ab771..e6017e6bf6da2c7531dae908330231acfbb7649c 100644 (file)
@@ -18,14 +18,21 @@ obj-$(CONFIG_USB_S3C2410)   += s3c2410_udc.o
 obj-$(CONFIG_USB_AT91)         += at91_udc.o
 obj-$(CONFIG_USB_ATMEL_USBA)   += atmel_usba_udc.o
 obj-$(CONFIG_USB_FSL_USB2)     += fsl_usb2_udc.o
+fsl_usb2_udc-objs              := fsl_udc_core.o
+ifeq ($(CONFIG_ARCH_MXC),y)
+fsl_usb2_udc-objs              += fsl_mx3_udc.o
+endif
 obj-$(CONFIG_USB_M66592)       += m66592-udc.o
 obj-$(CONFIG_USB_FSL_QE)       += fsl_qe_udc.o
 obj-$(CONFIG_USB_CI13XXX)      += ci13xxx_udc.o
+obj-$(CONFIG_USB_S3C_HSOTG)    += s3c-hsotg.o
+obj-$(CONFIG_USB_LANGWELL)     += langwell_udc.o
 
 #
 # USB gadget drivers
 #
 g_zero-objs                    := zero.o
+g_audio-objs                   := audio.o
 g_ether-objs                   := ether.o
 g_serial-objs                  := serial.o
 g_midi-objs                    := gmidi.o
@@ -35,6 +42,7 @@ g_printer-objs                        := printer.o
 g_cdc-objs                     := cdc2.o
 
 obj-$(CONFIG_USB_ZERO)         += g_zero.o
+obj-$(CONFIG_USB_AUDIO)                += g_audio.o
 obj-$(CONFIG_USB_ETH)          += g_ether.o
 obj-$(CONFIG_USB_GADGETFS)     += gadgetfs.o
 obj-$(CONFIG_USB_FILE_STORAGE) += g_file_storage.o
index 0b2bb8f0706df6ec99a6f357a6cb58a86ca25ba6..72bae8f39d814310ef477df5c987318e79000835 100644 (file)
@@ -485,7 +485,7 @@ static int at91_ep_enable(struct usb_ep *_ep,
                return -ESHUTDOWN;
        }
 
-       tmp = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+       tmp = usb_endpoint_type(desc);
        switch (tmp) {
        case USB_ENDPOINT_XFER_CONTROL:
                DBG("only one control endpoint\n");
@@ -517,7 +517,7 @@ ok:
        local_irq_save(flags);
 
        /* initialize endpoint to match this descriptor */
-       ep->is_in = (desc->bEndpointAddress & USB_DIR_IN) != 0;
+       ep->is_in = usb_endpoint_dir_in(desc);
        ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC);
        ep->stopped = 0;
        if (ep->is_in)
@@ -1574,7 +1574,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
 
        udc->driver = driver;
        udc->gadget.dev.driver = &driver->driver;
-       udc->gadget.dev.driver_data = &driver->driver;
+       dev_set_drvdata(&udc->gadget.dev, &driver->driver);
        udc->enabled = 1;
        udc->selfpowered = 1;
 
@@ -1583,7 +1583,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
                DBG("driver->bind() returned %d\n", retval);
                udc->driver = NULL;
                udc->gadget.dev.driver = NULL;
-               udc->gadget.dev.driver_data = NULL;
+               dev_set_drvdata(&udc->gadget.dev, NULL);
                udc->enabled = 0;
                udc->selfpowered = 0;
                return retval;
@@ -1613,7 +1613,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
 
        driver->unbind(&udc->gadget);
        udc->gadget.dev.driver = NULL;
-       udc->gadget.dev.driver_data = NULL;
+       dev_set_drvdata(&udc->gadget.dev, NULL);
        udc->driver = NULL;
 
        DBG("unbound from %s\n", driver->driver.name);
index 05c913cc3658f0389ab0ace117a8f50c8a166785..4e970cf0e29ae364b34c5e7436906e95db313952 100644 (file)
@@ -326,13 +326,7 @@ static int vbus_is_present(struct usba_udc *udc)
        return 1;
 }
 
-#if defined(CONFIG_AVR32)
-
-static void toggle_bias(int is_on)
-{
-}
-
-#elif defined(CONFIG_ARCH_AT91)
+#if defined(CONFIG_ARCH_AT91SAM9RL)
 
 #include <mach/at91_pmc.h>
 
@@ -346,7 +340,13 @@ static void toggle_bias(int is_on)
                at91_sys_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
 }
 
-#endif /* CONFIG_ARCH_AT91 */
+#else
+
+static void toggle_bias(int is_on)
+{
+}
+
+#endif /* CONFIG_ARCH_AT91SAM9RL */
 
 static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
 {
@@ -550,12 +550,12 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
        DBG(DBG_HW, "%s: EPT_SIZE = %lu (maxpacket = %lu)\n",
                        ep->ep.name, ept_cfg, maxpacket);
 
-       if ((desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+       if (usb_endpoint_dir_in(desc)) {
                ep->is_in = 1;
                ept_cfg |= USBA_EPT_DIR_IN;
        }
 
-       switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+       switch (usb_endpoint_type(desc)) {
        case USB_ENDPOINT_XFER_CONTROL:
                ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL);
                ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE);
diff --git a/drivers/usb/gadget/audio.c b/drivers/usb/gadget/audio.c
new file mode 100644 (file)
index 0000000..94de7e8
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * audio.c -- Audio gadget driver
+ *
+ * Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
+ * Copyright (C) 2008 Analog Devices, Inc
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+/* #define VERBOSE_DEBUG */
+
+#include <linux/kernel.h>
+#include <linux/utsname.h>
+
+#include "u_audio.h"
+
+#define DRIVER_DESC            "Linux USB Audio Gadget"
+#define DRIVER_VERSION         "Dec 18, 2008"
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Kbuild is not very cooperative with respect to linking separately
+ * compiled library objects into one module.  So for now we won't use
+ * separate compilation ... ensuring init/exit sections work to shrink
+ * the runtime footprint, and giving us at least some parts of what
+ * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
+ */
+#include "composite.c"
+#include "usbstring.c"
+#include "config.c"
+#include "epautoconf.c"
+
+#include "u_audio.c"
+#include "f_audio.c"
+
+/*-------------------------------------------------------------------------*/
+
+/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
+ * Instead:  allocate your own, using normal USB-IF procedures.
+ */
+
+/* Thanks to NetChip Technologies for donating this product ID. */
+#define AUDIO_VENDOR_NUM               0x0525  /* NetChip */
+#define AUDIO_PRODUCT_NUM              0xa4a1  /* Linux-USB Audio Gadget */
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_device_descriptor device_desc = {
+       .bLength =              sizeof device_desc,
+       .bDescriptorType =      USB_DT_DEVICE,
+
+       .bcdUSB =               __constant_cpu_to_le16(0x200),
+
+       .bDeviceClass =         USB_CLASS_PER_INTERFACE,
+       .bDeviceSubClass =      0,
+       .bDeviceProtocol =      0,
+       /* .bMaxPacketSize0 = f(hardware) */
+
+       /* Vendor and product id defaults change according to what configs
+        * we support.  (As does bNumConfigurations.)  These values can
+        * also be overridden by module parameters.
+        */
+       .idVendor =             __constant_cpu_to_le16(AUDIO_VENDOR_NUM),
+       .idProduct =            __constant_cpu_to_le16(AUDIO_PRODUCT_NUM),
+       /* .bcdDevice = f(hardware) */
+       /* .iManufacturer = DYNAMIC */
+       /* .iProduct = DYNAMIC */
+       /* NO SERIAL NUMBER */
+       .bNumConfigurations =   1,
+};
+
+static struct usb_otg_descriptor otg_descriptor = {
+       .bLength =              sizeof otg_descriptor,
+       .bDescriptorType =      USB_DT_OTG,
+
+       /* REVISIT SRP-only hardware is possible, although
+        * it would not be called "OTG" ...
+        */
+       .bmAttributes =         USB_OTG_SRP | USB_OTG_HNP,
+};
+
+static const struct usb_descriptor_header *otg_desc[] = {
+       (struct usb_descriptor_header *) &otg_descriptor,
+       NULL,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * Handle USB audio endpoint set/get command in setup class request
+ */
+
+static int audio_set_endpoint_req(struct usb_configuration *c,
+               const struct usb_ctrlrequest *ctrl)
+{
+       struct usb_composite_dev *cdev = c->cdev;
+       int                     value = -EOPNOTSUPP;
+       u16                     ep = le16_to_cpu(ctrl->wIndex);
+       u16                     len = le16_to_cpu(ctrl->wLength);
+       u16                     w_value = le16_to_cpu(ctrl->wValue);
+
+       DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
+                       ctrl->bRequest, w_value, len, ep);
+
+       switch (ctrl->bRequest) {
+       case SET_CUR:
+               value = 0;
+               break;
+
+       case SET_MIN:
+               break;
+
+       case SET_MAX:
+               break;
+
+       case SET_RES:
+               break;
+
+       case SET_MEM:
+               break;
+
+       default:
+               break;
+       }
+
+       return value;
+}
+
+static int audio_get_endpoint_req(struct usb_configuration *c,
+               const struct usb_ctrlrequest *ctrl)
+{
+       struct usb_composite_dev *cdev = c->cdev;
+       int value = -EOPNOTSUPP;
+       u8 ep = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF);
+       u16 len = le16_to_cpu(ctrl->wLength);
+       u16 w_value = le16_to_cpu(ctrl->wValue);
+
+       DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
+                       ctrl->bRequest, w_value, len, ep);
+
+       switch (ctrl->bRequest) {
+       case GET_CUR:
+       case GET_MIN:
+       case GET_MAX:
+       case GET_RES:
+               value = 3;
+               break;
+       case GET_MEM:
+               break;
+       default:
+               break;
+       }
+
+       return value;
+}
+
+static int
+audio_setup(struct usb_configuration *c, const struct usb_ctrlrequest *ctrl)
+{
+       struct usb_composite_dev *cdev = c->cdev;
+       struct usb_request *req = cdev->req;
+       int value = -EOPNOTSUPP;
+       u16 w_index = le16_to_cpu(ctrl->wIndex);
+       u16 w_value = le16_to_cpu(ctrl->wValue);
+       u16 w_length = le16_to_cpu(ctrl->wLength);
+
+       /* composite driver infrastructure handles everything except
+        * Audio class messages; interface activation uses set_alt().
+        */
+       switch (ctrl->bRequestType) {
+       case USB_AUDIO_SET_ENDPOINT:
+               value = audio_set_endpoint_req(c, ctrl);
+               break;
+
+       case USB_AUDIO_GET_ENDPOINT:
+               value = audio_get_endpoint_req(c, ctrl);
+               break;
+
+       default:
+               ERROR(cdev, "Invalid control req%02x.%02x v%04x i%04x l%d\n",
+                       ctrl->bRequestType, ctrl->bRequest,
+                       w_value, w_index, w_length);
+       }
+
+       /* respond with data transfer or status phase? */
+       if (value >= 0) {
+               DBG(cdev, "Audio req%02x.%02x v%04x i%04x l%d\n",
+                       ctrl->bRequestType, ctrl->bRequest,
+                       w_value, w_index, w_length);
+               req->zero = 0;
+               req->length = value;
+               value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+               if (value < 0)
+                       ERROR(cdev, "Audio response on err %d\n", value);
+       }
+
+       /* device either stalls (value < 0) or reports success */
+       return value;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int __init audio_do_config(struct usb_configuration *c)
+{
+       /* FIXME alloc iConfiguration string, set it in c->strings */
+
+       if (gadget_is_otg(c->cdev->gadget)) {
+               c->descriptors = otg_desc;
+               c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+       }
+
+       audio_bind_config(c);
+
+       return 0;
+}
+
+static struct usb_configuration audio_config_driver = {
+       .label                  = DRIVER_DESC,
+       .bind                   = audio_do_config,
+       .setup                  = audio_setup,
+       .bConfigurationValue    = 1,
+       /* .iConfiguration = DYNAMIC */
+       .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init audio_bind(struct usb_composite_dev *cdev)
+{
+       int                     gcnum;
+       int                     status;
+
+       gcnum = usb_gadget_controller_number(cdev->gadget);
+       if (gcnum >= 0)
+               device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
+       else {
+               ERROR(cdev, "controller '%s' not recognized; trying %s\n",
+                       cdev->gadget->name,
+                       audio_config_driver.label);
+               device_desc.bcdDevice =
+                       __constant_cpu_to_le16(0x0300 | 0x0099);
+       }
+
+       /* device descriptor strings: manufacturer, product */
+       snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
+               init_utsname()->sysname, init_utsname()->release,
+               cdev->gadget->name);
+       status = usb_string_id(cdev);
+       if (status < 0)
+               goto fail;
+       strings_dev[STRING_MANUFACTURER_IDX].id = status;
+       device_desc.iManufacturer = status;
+
+       status = usb_string_id(cdev);
+       if (status < 0)
+               goto fail;
+       strings_dev[STRING_PRODUCT_IDX].id = status;
+       device_desc.iProduct = status;
+
+       status = usb_add_config(cdev, &audio_config_driver);
+       if (status < 0)
+               goto fail;
+
+       INFO(cdev, "%s, version: %s\n", DRIVER_DESC, DRIVER_VERSION);
+       return 0;
+
+fail:
+       return status;
+}
+
+static int __exit audio_unbind(struct usb_composite_dev *cdev)
+{
+       return 0;
+}
+
+static struct usb_composite_driver audio_driver = {
+       .name           = "g_audio",
+       .dev            = &device_desc,
+       .strings        = audio_strings,
+       .bind           = audio_bind,
+       .unbind         = __exit_p(audio_unbind),
+};
+
+static int __init init(void)
+{
+       return usb_composite_register(&audio_driver);
+}
+module_init(init);
+
+static void __exit cleanup(void)
+{
+       usb_composite_unregister(&audio_driver);
+}
+module_exit(cleanup);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Bryan Wu <cooloney@kernel.org>");
+MODULE_LICENSE("GPL");
+
index 38e531ecae4d310066e7813f2550420aa33e3ab3..c7cb87a6fee22a4519a0f720fcf3f3451eb22920 100644 (file)
@@ -1977,9 +1977,9 @@ static int ep_enable(struct usb_ep *ep,
        if (!list_empty(&mEp->qh[mEp->dir].queue))
                warn("enabling a non-empty endpoint!");
 
-       mEp->dir  = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? TX : RX;
-       mEp->num  =  desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
-       mEp->type =  desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+       mEp->dir  = usb_endpoint_dir_in(desc) ? TX : RX;
+       mEp->num  = usb_endpoint_num(desc);
+       mEp->type = usb_endpoint_type(desc);
 
        mEp->ep.maxpacket = __constant_le16_to_cpu(desc->wMaxPacketSize);
 
diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c
new file mode 100644 (file)
index 0000000..66527ba
--- /dev/null
@@ -0,0 +1,707 @@
+/*
+ * f_audio.c -- USB Audio class function driver
+  *
+ * Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
+ * Copyright (C) 2008 Analog Devices, Inc
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <asm/atomic.h>
+
+#include "u_audio.h"
+
+#define OUT_EP_MAX_PACKET_SIZE 200
+static int req_buf_size = OUT_EP_MAX_PACKET_SIZE;
+module_param(req_buf_size, int, S_IRUGO);
+MODULE_PARM_DESC(req_buf_size, "ISO OUT endpoint request buffer size");
+
+static int req_count = 256;
+module_param(req_count, int, S_IRUGO);
+MODULE_PARM_DESC(req_count, "ISO OUT endpoint request count");
+
+static int audio_buf_size = 48000;
+module_param(audio_buf_size, int, S_IRUGO);
+MODULE_PARM_DESC(audio_buf_size, "Audio buffer size");
+
+/*
+ * DESCRIPTORS ... most are static, but strings and full
+ * configuration descriptors are built on demand.
+ */
+
+/*
+ * We have two interfaces- AudioControl and AudioStreaming
+ * TODO: only supcard playback currently
+ */
+#define F_AUDIO_AC_INTERFACE   0
+#define F_AUDIO_AS_INTERFACE   1
+#define F_AUDIO_NUM_INTERFACES 2
+
+/* B.3.1  Standard AC Interface Descriptor */
+static struct usb_interface_descriptor ac_interface_desc __initdata = {
+       .bLength =              USB_DT_INTERFACE_SIZE,
+       .bDescriptorType =      USB_DT_INTERFACE,
+       .bNumEndpoints =        0,
+       .bInterfaceClass =      USB_CLASS_AUDIO,
+       .bInterfaceSubClass =   USB_SUBCLASS_AUDIOCONTROL,
+};
+
+DECLARE_USB_AC_HEADER_DESCRIPTOR(2);
+
+#define USB_DT_AC_HEADER_LENGH USB_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES)
+/* B.3.2  Class-Specific AC Interface Descriptor */
+static struct usb_ac_header_descriptor_2 ac_header_desc = {
+       .bLength =              USB_DT_AC_HEADER_LENGH,
+       .bDescriptorType =      USB_DT_CS_INTERFACE,
+       .bDescriptorSubtype =   HEADER,
+       .bcdADC =               __constant_cpu_to_le16(0x0100),
+       .wTotalLength =         __constant_cpu_to_le16(USB_DT_AC_HEADER_LENGH),
+       .bInCollection =        F_AUDIO_NUM_INTERFACES,
+       .baInterfaceNr = {
+               [0] =           F_AUDIO_AC_INTERFACE,
+               [1] =           F_AUDIO_AS_INTERFACE,
+       }
+};
+
+#define INPUT_TERMINAL_ID      1
+static struct usb_input_terminal_descriptor input_terminal_desc = {
+       .bLength =              USB_DT_AC_INPUT_TERMINAL_SIZE,
+       .bDescriptorType =      USB_DT_CS_INTERFACE,
+       .bDescriptorSubtype =   INPUT_TERMINAL,
+       .bTerminalID =          INPUT_TERMINAL_ID,
+       .wTerminalType =        USB_AC_TERMINAL_STREAMING,
+       .bAssocTerminal =       0,
+       .wChannelConfig =       0x3,
+};
+
+DECLARE_USB_AC_FEATURE_UNIT_DESCRIPTOR(0);
+
+#define FEATURE_UNIT_ID                2
+static struct usb_ac_feature_unit_descriptor_0 feature_unit_desc = {
+       .bLength                = USB_DT_AC_FEATURE_UNIT_SIZE(0),
+       .bDescriptorType        = USB_DT_CS_INTERFACE,
+       .bDescriptorSubtype     = FEATURE_UNIT,
+       .bUnitID                = FEATURE_UNIT_ID,
+       .bSourceID              = INPUT_TERMINAL_ID,
+       .bControlSize           = 2,
+       .bmaControls[0]         = (FU_MUTE | FU_VOLUME),
+};
+
+static struct usb_audio_control mute_control = {
+       .list = LIST_HEAD_INIT(mute_control.list),
+       .name = "Mute Control",
+       .type = MUTE_CONTROL,
+       /* Todo: add real Mute control code */
+       .set = generic_set_cmd,
+       .get = generic_get_cmd,
+};
+
+static struct usb_audio_control volume_control = {
+       .list = LIST_HEAD_INIT(volume_control.list),
+       .name = "Volume Control",
+       .type = VOLUME_CONTROL,
+       /* Todo: add real Volume control code */
+       .set = generic_set_cmd,
+       .get = generic_get_cmd,
+};
+
+static struct usb_audio_control_selector feature_unit = {
+       .list = LIST_HEAD_INIT(feature_unit.list),
+       .id = FEATURE_UNIT_ID,
+       .name = "Mute & Volume Control",
+       .type = FEATURE_UNIT,
+       .desc = (struct usb_descriptor_header *)&feature_unit_desc,
+};
+
+#define OUTPUT_TERMINAL_ID     3
+static struct usb_output_terminal_descriptor output_terminal_desc = {
+       .bLength                = USB_DT_AC_OUTPUT_TERMINAL_SIZE,
+       .bDescriptorType        = USB_DT_CS_INTERFACE,
+       .bDescriptorSubtype     = OUTPUT_TERMINAL,
+       .bTerminalID            = OUTPUT_TERMINAL_ID,
+       .wTerminalType          = USB_AC_OUTPUT_TERMINAL_SPEAKER,
+       .bAssocTerminal         = FEATURE_UNIT_ID,
+       .bSourceID              = FEATURE_UNIT_ID,
+};
+
+/* B.4.1  Standard AS Interface Descriptor */
+static struct usb_interface_descriptor as_interface_alt_0_desc = {
+       .bLength =              USB_DT_INTERFACE_SIZE,
+       .bDescriptorType =      USB_DT_INTERFACE,
+       .bAlternateSetting =    0,
+       .bNumEndpoints =        0,
+       .bInterfaceClass =      USB_CLASS_AUDIO,
+       .bInterfaceSubClass =   USB_SUBCLASS_AUDIOSTREAMING,
+};
+
+static struct usb_interface_descriptor as_interface_alt_1_desc = {
+       .bLength =              USB_DT_INTERFACE_SIZE,
+       .bDescriptorType =      USB_DT_INTERFACE,
+       .bAlternateSetting =    1,
+       .bNumEndpoints =        1,
+       .bInterfaceClass =      USB_CLASS_AUDIO,
+       .bInterfaceSubClass =   USB_SUBCLASS_AUDIOSTREAMING,
+};
+
+/* B.4.2  Class-Specific AS Interface Descriptor */
+static struct usb_as_header_descriptor as_header_desc = {
+       .bLength =              USB_DT_AS_HEADER_SIZE,
+       .bDescriptorType =      USB_DT_CS_INTERFACE,
+       .bDescriptorSubtype =   AS_GENERAL,
+       .bTerminalLink =        INPUT_TERMINAL_ID,
+       .bDelay =               1,
+       .wFormatTag =           USB_AS_AUDIO_FORMAT_TYPE_I_PCM,
+};
+
+DECLARE_USB_AS_FORMAT_TYPE_I_DISCRETE_DESC(1);
+
+static struct usb_as_formate_type_i_discrete_descriptor_1 as_type_i_desc = {
+       .bLength =              USB_AS_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1),
+       .bDescriptorType =      USB_DT_CS_INTERFACE,
+       .bDescriptorSubtype =   FORMAT_TYPE,
+       .bFormatType =          USB_AS_FORMAT_TYPE_I,
+       .bSubframeSize =        2,
+       .bBitResolution =       16,
+       .bSamFreqType =         1,
+};
+
+/* Standard ISO OUT Endpoint Descriptor */
+static struct usb_endpoint_descriptor as_out_ep_desc __initdata = {
+       .bLength =              USB_DT_ENDPOINT_AUDIO_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bEndpointAddress =     USB_DIR_OUT,
+       .bmAttributes =         USB_AS_ENDPOINT_ADAPTIVE
+                               | USB_ENDPOINT_XFER_ISOC,
+       .wMaxPacketSize =       __constant_cpu_to_le16(OUT_EP_MAX_PACKET_SIZE),
+       .bInterval =            4,
+};
+
+/* Class-specific AS ISO OUT Endpoint Descriptor */
+static struct usb_as_iso_endpoint_descriptor as_iso_out_desc __initdata = {
+       .bLength =              USB_AS_ISO_ENDPOINT_DESC_SIZE,
+       .bDescriptorType =      USB_DT_CS_ENDPOINT,
+       .bDescriptorSubtype =   EP_GENERAL,
+       .bmAttributes =         1,
+       .bLockDelayUnits =      1,
+       .wLockDelay =           __constant_cpu_to_le16(1),
+};
+
+static struct usb_descriptor_header *f_audio_desc[] __initdata = {
+       (struct usb_descriptor_header *)&ac_interface_desc,
+       (struct usb_descriptor_header *)&ac_header_desc,
+
+       (struct usb_descriptor_header *)&input_terminal_desc,
+       (struct usb_descriptor_header *)&output_terminal_desc,
+       (struct usb_descriptor_header *)&feature_unit_desc,
+
+       (struct usb_descriptor_header *)&as_interface_alt_0_desc,
+       (struct usb_descriptor_header *)&as_interface_alt_1_desc,
+       (struct usb_descriptor_header *)&as_header_desc,
+
+       (struct usb_descriptor_header *)&as_type_i_desc,
+
+       (struct usb_descriptor_header *)&as_out_ep_desc,
+       (struct usb_descriptor_header *)&as_iso_out_desc,
+       NULL,
+};
+
+/* string IDs are assigned dynamically */
+
+#define STRING_MANUFACTURER_IDX                0
+#define STRING_PRODUCT_IDX             1
+
+static char manufacturer[50];
+
+static struct usb_string strings_dev[] = {
+       [STRING_MANUFACTURER_IDX].s = manufacturer,
+       [STRING_PRODUCT_IDX].s = DRIVER_DESC,
+       {  } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dev = {
+       .language       = 0x0409,       /* en-us */
+       .strings        = strings_dev,
+};
+
+static struct usb_gadget_strings *audio_strings[] = {
+       &stringtab_dev,
+       NULL,
+};
+
+/*
+ * This function is an ALSA sound card following USB Audio Class Spec 1.0.
+ */
+
+/*-------------------------------------------------------------------------*/
+struct f_audio_buf {
+       u8 *buf;
+       int actual;
+       struct list_head list;
+};
+
+static struct f_audio_buf *f_audio_buffer_alloc(int buf_size)
+{
+       struct f_audio_buf *copy_buf;
+
+       copy_buf = kzalloc(sizeof *copy_buf, GFP_ATOMIC);
+       if (!copy_buf)
+               return (struct f_audio_buf *)-ENOMEM;
+
+       copy_buf->buf = kzalloc(buf_size, GFP_ATOMIC);
+       if (!copy_buf->buf) {
+               kfree(copy_buf);
+               return (struct f_audio_buf *)-ENOMEM;
+       }
+
+       return copy_buf;
+}
+
+static void f_audio_buffer_free(struct f_audio_buf *audio_buf)
+{
+       kfree(audio_buf->buf);
+       kfree(audio_buf);
+}
+/*-------------------------------------------------------------------------*/
+
+struct f_audio {
+       struct gaudio                   card;
+
+       /* endpoints handle full and/or high speeds */
+       struct usb_ep                   *out_ep;
+       struct usb_endpoint_descriptor  *out_desc;
+
+       spinlock_t                      lock;
+       struct f_audio_buf *copy_buf;
+       struct work_struct playback_work;
+       struct list_head play_queue;
+
+       /* Control Set command */
+       struct list_head cs;
+       u8 set_cmd;
+       struct usb_audio_control *set_con;
+};
+
+static inline struct f_audio *func_to_audio(struct usb_function *f)
+{
+       return container_of(f, struct f_audio, card.func);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void f_audio_playback_work(struct work_struct *data)
+{
+       struct f_audio *audio = container_of(data, struct f_audio,
+                                       playback_work);
+       struct f_audio_buf *play_buf;
+
+       spin_lock_irq(&audio->lock);
+       if (list_empty(&audio->play_queue)) {
+               spin_unlock_irq(&audio->lock);
+               return;
+       }
+       play_buf = list_first_entry(&audio->play_queue,
+                       struct f_audio_buf, list);
+       list_del(&play_buf->list);
+       spin_unlock_irq(&audio->lock);
+
+       u_audio_playback(&audio->card, play_buf->buf, play_buf->actual);
+       f_audio_buffer_free(play_buf);
+
+       return;
+}
+
+static int f_audio_out_ep_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct f_audio *audio = req->context;
+       struct usb_composite_dev *cdev = audio->card.func.config->cdev;
+       struct f_audio_buf *copy_buf = audio->copy_buf;
+       int err;
+
+       if (!copy_buf)
+               return -EINVAL;
+
+       /* Copy buffer is full, add it to the play_queue */
+       if (audio_buf_size - copy_buf->actual < req->actual) {
+               list_add_tail(&copy_buf->list, &audio->play_queue);
+               schedule_work(&audio->playback_work);
+               copy_buf = f_audio_buffer_alloc(audio_buf_size);
+               if (copy_buf < 0)
+                       return -ENOMEM;
+       }
+
+       memcpy(copy_buf->buf + copy_buf->actual, req->buf, req->actual);
+       copy_buf->actual += req->actual;
+       audio->copy_buf = copy_buf;
+
+       err = usb_ep_queue(ep, req, GFP_ATOMIC);
+       if (err)
+               ERROR(cdev, "%s queue req: %d\n", ep->name, err);
+
+       return 0;
+
+}
+
+static void f_audio_complete(struct usb_ep *ep, struct usb_request *req)
+{
+       struct f_audio *audio = req->context;
+       int status = req->status;
+       u32 data = 0;
+       struct usb_ep *out_ep = audio->out_ep;
+
+       switch (status) {
+
+       case 0:                         /* normal completion? */
+               if (ep == out_ep)
+                       f_audio_out_ep_complete(ep, req);
+               else if (audio->set_con) {
+                       memcpy(&data, req->buf, req->length);
+                       audio->set_con->set(audio->set_con, audio->set_cmd,
+                                       le16_to_cpu(data));
+                       audio->set_con = NULL;
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+static int audio_set_intf_req(struct usb_function *f,
+               const struct usb_ctrlrequest *ctrl)
+{
+       struct f_audio          *audio = func_to_audio(f);
+       struct usb_composite_dev *cdev = f->config->cdev;
+       struct usb_request      *req = cdev->req;
+       u8                      id = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF);
+       u16                     len = le16_to_cpu(ctrl->wLength);
+       u16                     w_value = le16_to_cpu(ctrl->wValue);
+       u8                      con_sel = (w_value >> 8) & 0xFF;
+       u8                      cmd = (ctrl->bRequest & 0x0F);
+       struct usb_audio_control_selector *cs;
+       struct usb_audio_control *con;
+
+       DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, entity %d\n",
+                       ctrl->bRequest, w_value, len, id);
+
+       list_for_each_entry(cs, &audio->cs, list) {
+               if (cs->id == id) {
+                       list_for_each_entry(con, &cs->control, list) {
+                               if (con->type == con_sel) {
+                                       audio->set_con = con;
+                                       break;
+                               }
+                       }
+                       break;
+               }
+       }
+
+       audio->set_cmd = cmd;
+       req->context = audio;
+       req->complete = f_audio_complete;
+
+       return len;
+}
+
+static int audio_get_intf_req(struct usb_function *f,
+               const struct usb_ctrlrequest *ctrl)
+{
+       struct f_audio          *audio = func_to_audio(f);
+       struct usb_composite_dev *cdev = f->config->cdev;
+       struct usb_request      *req = cdev->req;
+       int                     value = -EOPNOTSUPP;
+       u8                      id = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF);
+       u16                     len = le16_to_cpu(ctrl->wLength);
+       u16                     w_value = le16_to_cpu(ctrl->wValue);
+       u8                      con_sel = (w_value >> 8) & 0xFF;
+       u8                      cmd = (ctrl->bRequest & 0x0F);
+       struct usb_audio_control_selector *cs;
+       struct usb_audio_control *con;
+
+       DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, entity %d\n",
+                       ctrl->bRequest, w_value, len, id);
+
+       list_for_each_entry(cs, &audio->cs, list) {
+               if (cs->id == id) {
+                       list_for_each_entry(con, &cs->control, list) {
+                               if (con->type == con_sel && con->get) {
+                                       value = con->get(con, cmd);
+                                       break;
+                               }
+                       }
+                       break;
+               }
+       }
+
+       req->context = audio;
+       req->complete = f_audio_complete;
+       memcpy(req->buf, &value, len);
+
+       return len;
+}
+
+static int
+f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
+{
+       struct usb_composite_dev *cdev = f->config->cdev;
+       struct usb_request      *req = cdev->req;
+       int                     value = -EOPNOTSUPP;
+       u16                     w_index = le16_to_cpu(ctrl->wIndex);
+       u16                     w_value = le16_to_cpu(ctrl->wValue);
+       u16                     w_length = le16_to_cpu(ctrl->wLength);
+
+       /* composite driver infrastructure handles everything except
+        * Audio class messages; interface activation uses set_alt().
+        */
+       switch (ctrl->bRequestType) {
+       case USB_AUDIO_SET_INTF:
+               value = audio_set_intf_req(f, ctrl);
+               break;
+
+       case USB_AUDIO_GET_INTF:
+               value = audio_get_intf_req(f, ctrl);
+               break;
+
+       default:
+               ERROR(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
+                       ctrl->bRequestType, ctrl->bRequest,
+                       w_value, w_index, w_length);
+       }
+
+       /* respond with data transfer or status phase? */
+       if (value >= 0) {
+               DBG(cdev, "audio req%02x.%02x v%04x i%04x l%d\n",
+                       ctrl->bRequestType, ctrl->bRequest,
+                       w_value, w_index, w_length);
+               req->zero = 0;
+               req->length = value;
+               value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+               if (value < 0)
+                       ERROR(cdev, "audio response on err %d\n", value);
+       }
+
+       /* device either stalls (value < 0) or reports success */
+       return value;
+}
+
+static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+       struct f_audio          *audio = func_to_audio(f);
+       struct usb_composite_dev *cdev = f->config->cdev;
+       struct usb_ep *out_ep = audio->out_ep;
+       struct usb_request *req;
+       int i = 0, err = 0;
+
+       DBG(cdev, "intf %d, alt %d\n", intf, alt);
+
+       if (intf == 1) {
+               if (alt == 1) {
+                       usb_ep_enable(out_ep, audio->out_desc);
+                       out_ep->driver_data = audio;
+                       audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
+
+                       /*
+                        * allocate a bunch of read buffers
+                        * and queue them all at once.
+                        */
+                       for (i = 0; i < req_count && err == 0; i++) {
+                               req = usb_ep_alloc_request(out_ep, GFP_ATOMIC);
+                               if (req) {
+                                       req->buf = kzalloc(req_buf_size,
+                                                       GFP_ATOMIC);
+                                       if (req->buf) {
+                                               req->length = req_buf_size;
+                                               req->context = audio;
+                                               req->complete =
+                                                       f_audio_complete;
+                                               err = usb_ep_queue(out_ep,
+                                                       req, GFP_ATOMIC);
+                                               if (err)
+                                                       ERROR(cdev,
+                                                       "%s queue req: %d\n",
+                                                       out_ep->name, err);
+                                       } else
+                                               err = -ENOMEM;
+                               } else
+                                       err = -ENOMEM;
+                       }
+
+               } else {
+                       struct f_audio_buf *copy_buf = audio->copy_buf;
+                       if (copy_buf) {
+                               list_add_tail(&copy_buf->list,
+                                               &audio->play_queue);
+                               schedule_work(&audio->playback_work);
+                       }
+               }
+       }
+
+       return err;
+}
+
+static void f_audio_disable(struct usb_function *f)
+{
+       return;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void f_audio_build_desc(struct f_audio *audio)
+{
+       struct gaudio *card = &audio->card;
+       u8 *sam_freq;
+       int rate;
+
+       /* Set channel numbers */
+       input_terminal_desc.bNrChannels = u_audio_get_playback_channels(card);
+       as_type_i_desc.bNrChannels = u_audio_get_playback_channels(card);
+
+       /* Set sample rates */
+       rate = u_audio_get_playback_rate(card);
+       sam_freq = as_type_i_desc.tSamFreq[0];
+       memcpy(sam_freq, &rate, 3);
+
+       /* Todo: Set Sample bits and other parameters */
+
+       return;
+}
+
+/* audio function driver setup/binding */
+static int __init
+f_audio_bind(struct usb_configuration *c, struct usb_function *f)
+{
+       struct usb_composite_dev *cdev = c->cdev;
+       struct f_audio          *audio = func_to_audio(f);
+       int                     status;
+       struct usb_ep           *ep;
+
+       f_audio_build_desc(audio);
+
+       /* allocate instance-specific interface IDs, and patch descriptors */
+       status = usb_interface_id(c, f);
+       if (status < 0)
+               goto fail;
+       ac_interface_desc.bInterfaceNumber = status;
+
+       status = usb_interface_id(c, f);
+       if (status < 0)
+               goto fail;
+       as_interface_alt_0_desc.bInterfaceNumber = status;
+       as_interface_alt_1_desc.bInterfaceNumber = status;
+
+       status = -ENODEV;
+
+       /* allocate instance-specific endpoints */
+       ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_desc);
+       if (!ep)
+               goto fail;
+       audio->out_ep = ep;
+       ep->driver_data = cdev; /* claim */
+
+       status = -ENOMEM;
+
+       /* supcard all relevant hardware speeds... we expect that when
+        * hardware is dual speed, all bulk-capable endpoints work at
+        * both speeds
+        */
+
+       /* copy descriptors, and track endpoint copies */
+       if (gadget_is_dualspeed(c->cdev->gadget)) {
+               c->highspeed = true;
+               f->hs_descriptors = usb_copy_descriptors(f_audio_desc);
+       } else
+               f->descriptors = usb_copy_descriptors(f_audio_desc);
+
+       return 0;
+
+fail:
+
+       return status;
+}
+
+static void
+f_audio_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+       struct f_audio          *audio = func_to_audio(f);
+
+       usb_free_descriptors(f->descriptors);
+       kfree(audio);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Todo: add more control selecotor dynamically */
+int __init control_selector_init(struct f_audio *audio)
+{
+       INIT_LIST_HEAD(&audio->cs);
+       list_add(&feature_unit.list, &audio->cs);
+
+       INIT_LIST_HEAD(&feature_unit.control);
+       list_add(&mute_control.list, &feature_unit.control);
+       list_add(&volume_control.list, &feature_unit.control);
+
+       volume_control.data[_CUR] = 0xffc0;
+       volume_control.data[_MIN] = 0xe3a0;
+       volume_control.data[_MAX] = 0xfff0;
+       volume_control.data[_RES] = 0x0030;
+
+       return 0;
+}
+
+/**
+ * audio_bind_config - add USB audio fucntion to a configuration
+ * @c: the configuration to supcard the USB audio function
+ * Context: single threaded during gadget setup
+ *
+ * Returns zero on success, else negative errno.
+ */
+int __init audio_bind_config(struct usb_configuration *c)
+{
+       struct f_audio *audio;
+       int status;
+
+       /* allocate and initialize one new instance */
+       audio = kzalloc(sizeof *audio, GFP_KERNEL);
+       if (!audio)
+               return -ENOMEM;
+
+       audio->card.func.name = "g_audio";
+       audio->card.gadget = c->cdev->gadget;
+
+       INIT_LIST_HEAD(&audio->play_queue);
+       spin_lock_init(&audio->lock);
+
+       /* set up ASLA audio devices */
+       status = gaudio_setup(&audio->card);
+       if (status < 0)
+               goto setup_fail;
+
+       audio->card.func.strings = audio_strings;
+       audio->card.func.bind = f_audio_bind;
+       audio->card.func.unbind = f_audio_unbind;
+       audio->card.func.set_alt = f_audio_set_alt;
+       audio->card.func.setup = f_audio_setup;
+       audio->card.func.disable = f_audio_disable;
+       audio->out_desc = &as_out_ep_desc;
+
+       control_selector_init(audio);
+
+       INIT_WORK(&audio->playback_work, f_audio_playback_work);
+
+       status = usb_add_function(c, &audio->card.func);
+       if (status)
+               goto add_fail;
+
+       INFO(c->cdev, "audio_buf_size %d, req_buf_size %d, req_count %d\n",
+               audio_buf_size, req_buf_size, req_count);
+
+       return status;
+
+add_fail:
+       gaudio_cleanup(&audio->card);
+setup_fail:
+       kfree(audio);
+       return status;
+}
index 3279a47260428a1122cc409ae64ac8994f4c3eee..424a37c5773f5ac341b9659bc4480cb9ee3e9df6 100644 (file)
@@ -475,7 +475,9 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
                if (rndis->port.in_ep->driver_data) {
                        DBG(cdev, "reset rndis\n");
                        gether_disconnect(&rndis->port);
-               } else {
+               }
+
+               if (!rndis->port.in) {
                        DBG(cdev, "init rndis\n");
                        rndis->port.in = ep_choose(cdev->gadget,
                                        rndis->hs.in, rndis->fs.in);
index 381a53b3e11c4a4e4dcd3308bdfcbfd1f2323c6d..1e6aa504d58a9390d196a0b5c3823e3e4f299e69 100644 (file)
 #include <linux/freezer.h>
 #include <linux/utsname.h>
 
+#include <asm/unaligned.h>
+
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 
@@ -799,29 +801,9 @@ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
 
 /* Routines for unaligned data access */
 
-static u16 get_be16(u8 *buf)
-{
-       return ((u16) buf[0] << 8) | ((u16) buf[1]);
-}
-
-static u32 get_be32(u8 *buf)
-{
-       return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) |
-                       ((u32) buf[2] << 8) | ((u32) buf[3]);
-}
-
-static void put_be16(u8 *buf, u16 val)
-{
-       buf[0] = val >> 8;
-       buf[1] = val;
-}
-
-static void put_be32(u8 *buf, u32 val)
+static u32 get_unaligned_be24(u8 *buf)
 {
-       buf[0] = val >> 24;
-       buf[1] = val >> 16;
-       buf[2] = val >> 8;
-       buf[3] = val & 0xff;
+       return 0xffffff & (u32) get_unaligned_be32(buf - 1);
 }
 
 
@@ -1582,9 +1564,9 @@ static int do_read(struct fsg_dev *fsg)
        /* Get the starting Logical Block Address and check that it's
         * not too big */
        if (fsg->cmnd[0] == SC_READ_6)
-               lba = (fsg->cmnd[1] << 16) | get_be16(&fsg->cmnd[2]);
+               lba = get_unaligned_be24(&fsg->cmnd[1]);
        else {
-               lba = get_be32(&fsg->cmnd[2]);
+               lba = get_unaligned_be32(&fsg->cmnd[2]);
 
                /* We allow DPO (Disable Page Out = don't save data in the
                 * cache) and FUA (Force Unit Access = don't read from the
@@ -1717,9 +1699,9 @@ static int do_write(struct fsg_dev *fsg)
        /* Get the starting Logical Block Address and check that it's
         * not too big */
        if (fsg->cmnd[0] == SC_WRITE_6)
-               lba = (fsg->cmnd[1] << 16) | get_be16(&fsg->cmnd[2]);
+               lba = get_unaligned_be24(&fsg->cmnd[1]);
        else {
-               lba = get_be32(&fsg->cmnd[2]);
+               lba = get_unaligned_be32(&fsg->cmnd[2]);
 
                /* We allow DPO (Disable Page Out = don't save data in the
                 * cache) and FUA (Force Unit Access = write directly to the
@@ -1940,7 +1922,7 @@ static int do_verify(struct fsg_dev *fsg)
 
        /* Get the starting Logical Block Address and check that it's
         * not too big */
-       lba = get_be32(&fsg->cmnd[2]);
+       lba = get_unaligned_be32(&fsg->cmnd[2]);
        if (lba >= curlun->num_sectors) {
                curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
                return -EINVAL;
@@ -1953,7 +1935,7 @@ static int do_verify(struct fsg_dev *fsg)
                return -EINVAL;
        }
 
-       verification_length = get_be16(&fsg->cmnd[7]);
+       verification_length = get_unaligned_be16(&fsg->cmnd[7]);
        if (unlikely(verification_length == 0))
                return -EIO;            // No default reply
 
@@ -2103,7 +2085,7 @@ static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
        memset(buf, 0, 18);
        buf[0] = valid | 0x70;                  // Valid, current error
        buf[2] = SK(sd);
-       put_be32(&buf[3], sdinfo);              // Sense information
+       put_unaligned_be32(sdinfo, &buf[3]);    /* Sense information */
        buf[7] = 18 - 8;                        // Additional sense length
        buf[12] = ASC(sd);
        buf[13] = ASCQ(sd);
@@ -2114,7 +2096,7 @@ static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
 static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh)
 {
        struct lun      *curlun = fsg->curlun;
-       u32             lba = get_be32(&fsg->cmnd[2]);
+       u32             lba = get_unaligned_be32(&fsg->cmnd[2]);
        int             pmi = fsg->cmnd[8];
        u8              *buf = (u8 *) bh->buf;
 
@@ -2124,8 +2106,9 @@ static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh)
                return -EINVAL;
        }
 
-       put_be32(&buf[0], curlun->num_sectors - 1);     // Max logical block
-       put_be32(&buf[4], 512);                         // Block length
+       put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
+                                               /* Max logical block */
+       put_unaligned_be32(512, &buf[4]);       /* Block length */
        return 8;
 }
 
@@ -2144,7 +2127,7 @@ static void store_cdrom_address(u8 *dest, int msf, u32 addr)
                dest[0] = 0;            /* Reserved */
        } else {
                /* Absolute sector */
-               put_be32(dest, addr);
+               put_unaligned_be32(addr, dest);
        }
 }
 
@@ -2152,7 +2135,7 @@ static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh)
 {
        struct lun      *curlun = fsg->curlun;
        int             msf = fsg->cmnd[1] & 0x02;
-       u32             lba = get_be32(&fsg->cmnd[2]);
+       u32             lba = get_unaligned_be32(&fsg->cmnd[2]);
        u8              *buf = (u8 *) bh->buf;
 
        if ((fsg->cmnd[1] & ~0x02) != 0) {              /* Mask away MSF */
@@ -2252,10 +2235,13 @@ static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
                        buf[2] = 0x04;  // Write cache enable,
                                        // Read cache not disabled
                                        // No cache retention priorities
-                       put_be16(&buf[4], 0xffff);  // Don't disable prefetch
-                                       // Minimum prefetch = 0
-                       put_be16(&buf[8], 0xffff);  // Maximum prefetch
-                       put_be16(&buf[10], 0xffff); // Maximum prefetch ceiling
+                       put_unaligned_be16(0xffff, &buf[4]);
+                                       /* Don't disable prefetch */
+                                       /* Minimum prefetch = 0 */
+                       put_unaligned_be16(0xffff, &buf[8]);
+                                       /* Maximum prefetch */
+                       put_unaligned_be16(0xffff, &buf[10]);
+                                       /* Maximum prefetch ceiling */
                }
                buf += 12;
        }
@@ -2272,7 +2258,7 @@ static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
        if (mscmnd == SC_MODE_SENSE_6)
                buf0[0] = len - 1;
        else
-               put_be16(buf0, len - 2);
+               put_unaligned_be16(len - 2, buf0);
        return len;
 }
 
@@ -2360,9 +2346,10 @@ static int do_read_format_capacities(struct fsg_dev *fsg,
        buf[3] = 8;             // Only the Current/Maximum Capacity Descriptor
        buf += 4;
 
-       put_be32(&buf[0], curlun->num_sectors);         // Number of blocks
-       put_be32(&buf[4], 512);                         // Block length
-       buf[4] = 0x02;                                  // Current capacity
+       put_unaligned_be32(curlun->num_sectors, &buf[0]);
+                                               /* Number of blocks */
+       put_unaligned_be32(512, &buf[4]);       /* Block length */
+       buf[4] = 0x02;                          /* Current capacity */
        return 12;
 }
 
@@ -2882,7 +2869,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
                break;
 
        case SC_MODE_SELECT_10:
-               fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]);
+               fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
                if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
                                (1<<1) | (3<<7), 0,
                                "MODE SELECT(10)")) == 0)
@@ -2898,7 +2885,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
                break;
 
        case SC_MODE_SENSE_10:
-               fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]);
+               fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
                if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
                                (1<<1) | (1<<2) | (3<<7), 0,
                                "MODE SENSE(10)")) == 0)
@@ -2923,7 +2910,8 @@ static int do_scsi_command(struct fsg_dev *fsg)
                break;
 
        case SC_READ_10:
-               fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]) << 9;
+               fsg->data_size_from_cmnd =
+                               get_unaligned_be16(&fsg->cmnd[7]) << 9;
                if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
                                (1<<1) | (0xf<<2) | (3<<7), 1,
                                "READ(10)")) == 0)
@@ -2931,7 +2919,8 @@ static int do_scsi_command(struct fsg_dev *fsg)
                break;
 
        case SC_READ_12:
-               fsg->data_size_from_cmnd = get_be32(&fsg->cmnd[6]) << 9;
+               fsg->data_size_from_cmnd =
+                               get_unaligned_be32(&fsg->cmnd[6]) << 9;
                if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST,
                                (1<<1) | (0xf<<2) | (0xf<<6), 1,
                                "READ(12)")) == 0)
@@ -2949,7 +2938,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
        case SC_READ_HEADER:
                if (!mod_data.cdrom)
                        goto unknown_cmnd;
-               fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]);
+               fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
                if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
                                (3<<7) | (0x1f<<1), 1,
                                "READ HEADER")) == 0)
@@ -2959,7 +2948,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
        case SC_READ_TOC:
                if (!mod_data.cdrom)
                        goto unknown_cmnd;
-               fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]);
+               fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
                if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
                                (7<<6) | (1<<1), 1,
                                "READ TOC")) == 0)
@@ -2967,7 +2956,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
                break;
 
        case SC_READ_FORMAT_CAPACITIES:
-               fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]);
+               fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
                if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
                                (3<<7), 1,
                                "READ FORMAT CAPACITIES")) == 0)
@@ -3025,7 +3014,8 @@ static int do_scsi_command(struct fsg_dev *fsg)
                break;
 
        case SC_WRITE_10:
-               fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]) << 9;
+               fsg->data_size_from_cmnd =
+                               get_unaligned_be16(&fsg->cmnd[7]) << 9;
                if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
                                (1<<1) | (0xf<<2) | (3<<7), 1,
                                "WRITE(10)")) == 0)
@@ -3033,7 +3023,8 @@ static int do_scsi_command(struct fsg_dev *fsg)
                break;
 
        case SC_WRITE_12:
-               fsg->data_size_from_cmnd = get_be32(&fsg->cmnd[6]) << 9;
+               fsg->data_size_from_cmnd =
+                               get_unaligned_be32(&fsg->cmnd[6]) << 9;
                if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST,
                                (1<<1) | (0xf<<2) | (0xf<<6), 1,
                                "WRITE(12)")) == 0)
diff --git a/drivers/usb/gadget/fsl_mx3_udc.c b/drivers/usb/gadget/fsl_mx3_udc.c
new file mode 100644 (file)
index 0000000..4bc2bf3
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2009
+ * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
+ *
+ * Description:
+ * Helper routines for i.MX3x SoCs from Freescale, needed by the fsl_usb2_udc.c
+ * driver to function correctly on these systems.
+ *
+ * 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/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/fsl_devices.h>
+#include <linux/platform_device.h>
+
+static struct clk *mxc_ahb_clk;
+static struct clk *mxc_usb_clk;
+
+int fsl_udc_clk_init(struct platform_device *pdev)
+{
+       struct fsl_usb2_platform_data *pdata;
+       unsigned long freq;
+       int ret;
+
+       pdata = pdev->dev.platform_data;
+
+       mxc_ahb_clk = clk_get(&pdev->dev, "usb_ahb");
+       if (IS_ERR(mxc_ahb_clk))
+               return PTR_ERR(mxc_ahb_clk);
+
+       ret = clk_enable(mxc_ahb_clk);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "clk_enable(\"usb_ahb\") failed\n");
+               goto eenahb;
+       }
+
+       /* make sure USB_CLK is running at 60 MHz +/- 1000 Hz */
+       mxc_usb_clk = clk_get(&pdev->dev, "usb");
+       if (IS_ERR(mxc_usb_clk)) {
+               dev_err(&pdev->dev, "clk_get(\"usb\") failed\n");
+               ret = PTR_ERR(mxc_usb_clk);
+               goto egusb;
+       }
+
+       freq = clk_get_rate(mxc_usb_clk);
+       if (pdata->phy_mode != FSL_USB2_PHY_ULPI &&
+           (freq < 59999000 || freq > 60001000)) {
+               dev_err(&pdev->dev, "USB_CLK=%lu, should be 60MHz\n", freq);
+               goto eclkrate;
+       }
+
+       ret = clk_enable(mxc_usb_clk);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "clk_enable(\"usb_clk\") failed\n");
+               goto eenusb;
+       }
+
+       return 0;
+
+eenusb:
+eclkrate:
+       clk_put(mxc_usb_clk);
+       mxc_usb_clk = NULL;
+egusb:
+       clk_disable(mxc_ahb_clk);
+eenahb:
+       clk_put(mxc_ahb_clk);
+       return ret;
+}
+
+void fsl_udc_clk_finalize(struct platform_device *pdev)
+{
+       struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+
+       /* ULPI transceivers don't need usbpll */
+       if (pdata->phy_mode == FSL_USB2_PHY_ULPI) {
+               clk_disable(mxc_usb_clk);
+               clk_put(mxc_usb_clk);
+               mxc_usb_clk = NULL;
+       }
+}
+
+void fsl_udc_clk_release(void)
+{
+       if (mxc_usb_clk) {
+               clk_disable(mxc_usb_clk);
+               clk_put(mxc_usb_clk);
+       }
+       clk_disable(mxc_ahb_clk);
+       clk_put(mxc_ahb_clk);
+}
similarity index 99%
rename from drivers/usb/gadget/fsl_usb2_udc.c
rename to drivers/usb/gadget/fsl_udc_core.c
index 9d7b95d4e3d2e523b7792f6b412b39bf6958b914..42a74b8a0bb82e3dcc0ab0becf156e44db9c32a1 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/platform_device.h>
 #include <linux/fsl_devices.h>
 #include <linux/dmapool.h>
+#include <linux/delay.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
@@ -57,7 +58,9 @@ static const char driver_name[] = "fsl-usb2-udc";
 static const char driver_desc[] = DRIVER_DESC;
 
 static struct usb_dr_device *dr_regs;
+#ifndef CONFIG_ARCH_MXC
 static struct usb_sys_interface *usb_sys_regs;
+#endif
 
 /* it is initialized in probe()  */
 static struct fsl_udc *udc_controller = NULL;
@@ -174,10 +177,34 @@ static void nuke(struct fsl_ep *ep, int status)
 
 static int dr_controller_setup(struct fsl_udc *udc)
 {
-       unsigned int tmp = 0, portctrl = 0, ctrl = 0;
+       unsigned int tmp, portctrl;
+#ifndef CONFIG_ARCH_MXC
+       unsigned int ctrl;
+#endif
        unsigned long timeout;
 #define FSL_UDC_RESET_TIMEOUT 1000
 
+       /* Config PHY interface */
+       portctrl = fsl_readl(&dr_regs->portsc1);
+       portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH);
+       switch (udc->phy_mode) {
+       case FSL_USB2_PHY_ULPI:
+               portctrl |= PORTSCX_PTS_ULPI;
+               break;
+       case FSL_USB2_PHY_UTMI_WIDE:
+               portctrl |= PORTSCX_PTW_16BIT;
+               /* fall through */
+       case FSL_USB2_PHY_UTMI:
+               portctrl |= PORTSCX_PTS_UTMI;
+               break;
+       case FSL_USB2_PHY_SERIAL:
+               portctrl |= PORTSCX_PTS_FSLS;
+               break;
+       default:
+               return -EINVAL;
+       }
+       fsl_writel(portctrl, &dr_regs->portsc1);
+
        /* Stop and reset the usb controller */
        tmp = fsl_readl(&dr_regs->usbcmd);
        tmp &= ~USB_CMD_RUN_STOP;
@@ -215,31 +242,12 @@ static int dr_controller_setup(struct fsl_udc *udc)
                udc->ep_qh, (int)tmp,
                fsl_readl(&dr_regs->endpointlistaddr));
 
-       /* Config PHY interface */
-       portctrl = fsl_readl(&dr_regs->portsc1);
-       portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH);
-       switch (udc->phy_mode) {
-       case FSL_USB2_PHY_ULPI:
-               portctrl |= PORTSCX_PTS_ULPI;
-               break;
-       case FSL_USB2_PHY_UTMI_WIDE:
-               portctrl |= PORTSCX_PTW_16BIT;
-               /* fall through */
-       case FSL_USB2_PHY_UTMI:
-               portctrl |= PORTSCX_PTS_UTMI;
-               break;
-       case FSL_USB2_PHY_SERIAL:
-               portctrl |= PORTSCX_PTS_FSLS;
-               break;
-       default:
-               return -EINVAL;
-       }
-       fsl_writel(portctrl, &dr_regs->portsc1);
-
        /* Config control enable i/o output, cpu endian register */
+#ifndef CONFIG_ARCH_MXC
        ctrl = __raw_readl(&usb_sys_regs->control);
        ctrl |= USB_CTRL_IOENB;
        __raw_writel(ctrl, &usb_sys_regs->control);
+#endif
 
 #if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
        /* Turn on cache snooping hardware, since some PowerPC platforms
@@ -2043,6 +2051,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
        size -= t;
        next += t;
 
+#ifndef CONFIG_ARCH_MXC
        tmp_reg = usb_sys_regs->snoop1;
        t = scnprintf(next, size, "Snoop1 Reg : = [0x%x]\n\n", tmp_reg);
        size -= t;
@@ -2053,6 +2062,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
                        tmp_reg);
        size -= t;
        next += t;
+#endif
 
        /* ------fsl_udc, fsl_ep, fsl_request structure information ----- */
        ep = &udc->eps[0];
@@ -2263,14 +2273,21 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
                goto err_kfree;
        }
 
-       dr_regs = ioremap(res->start, res->end - res->start + 1);
+       dr_regs = ioremap(res->start, resource_size(res));
        if (!dr_regs) {
                ret = -ENOMEM;
                goto err_release_mem_region;
        }
 
+#ifndef CONFIG_ARCH_MXC
        usb_sys_regs = (struct usb_sys_interface *)
                        ((u32)dr_regs + USB_DR_SYS_OFFSET);
+#endif
+
+       /* Initialize USB clocks */
+       ret = fsl_udc_clk_init(pdev);
+       if (ret < 0)
+               goto err_iounmap_noclk;
 
        /* Read Device Controller Capability Parameters register */
        dccparams = fsl_readl(&dr_regs->dccparams);
@@ -2308,6 +2325,8 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
         * leave usbintr reg untouched */
        dr_controller_setup(udc_controller);
 
+       fsl_udc_clk_finalize(pdev);
+
        /* Setup gadget structure */
        udc_controller->gadget.ops = &fsl_gadget_ops;
        udc_controller->gadget.is_dualspeed = 1;
@@ -2362,6 +2381,8 @@ err_unregister:
 err_free_irq:
        free_irq(udc_controller->irq, udc_controller);
 err_iounmap:
+       fsl_udc_clk_release();
+err_iounmap_noclk:
        iounmap(dr_regs);
 err_release_mem_region:
        release_mem_region(res->start, res->end - res->start + 1);
@@ -2384,6 +2405,8 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
                return -ENODEV;
        udc_controller->done = &done;
 
+       fsl_udc_clk_release();
+
        /* DR has been stopped in usb_gadget_unregister_driver() */
        remove_proc_file();
 
index e63ef12645f5524582a65059875f404f438a6554..20aeceed48c712e1db819b0047f970787923205f 100644 (file)
@@ -563,4 +563,22 @@ static void dump_msg(const char *label, const u8 * buf, unsigned int length)
                                        * 2 + ((windex & USB_DIR_IN) ? 1 : 0))
 #define get_pipe_by_ep(EP)     (ep_index(EP) * 2 + ep_is_in(EP))
 
+struct platform_device;
+#ifdef CONFIG_ARCH_MXC
+int fsl_udc_clk_init(struct platform_device *pdev);
+void fsl_udc_clk_finalize(struct platform_device *pdev);
+void fsl_udc_clk_release(void);
+#else
+static inline int fsl_udc_clk_init(struct platform_device *pdev)
+{
+       return 0;
+}
+static inline void fsl_udc_clk_finalize(struct platform_device *pdev)
+{
+}
+static inline void fsl_udc_clk_release(void)
+{
+}
+#endif
+
 #endif
index ec6d439a2aa588c0872e86335ff22079f6463f6c..8e0e9a0b736479a77aa59a8e73bce9a2c28aa512 100644 (file)
 #define gadget_is_musbhdrc(g)  0
 #endif
 
+#ifdef CONFIG_USB_GADGET_LANGWELL
+#define gadget_is_langwell(g)  (!strcmp("langwell_udc", (g)->name))
+#else
+#define gadget_is_langwell(g)  0
+#endif
+
 /* from Montavista kernel (?) */
 #ifdef CONFIG_USB_GADGET_MPC8272
 #define gadget_is_mpc8272(g)   !strcmp("mpc8272_udc", (g)->name)
@@ -231,6 +237,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
                return 0x22;
        else if (gadget_is_ci13xxx(gadget))
                return 0x23;
+       else if (gadget_is_langwell(gadget))
+               return 0x24;
        return -ENOENT;
 }
 
index de010c939dbbca672c5f992f85471aab5d0b6dec..112bb40a427cd4a217ed69af61d73effc8863959 100644 (file)
@@ -110,10 +110,10 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
                return -EINVAL;
        if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
                return -ESHUTDOWN;
-       if (ep->num != (desc->bEndpointAddress & 0x0f))
+       if (ep->num != usb_endpoint_num(desc))
                return -EINVAL;
 
-       switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+       switch (usb_endpoint_type(desc)) {
        case USB_ENDPOINT_XFER_BULK:
        case USB_ENDPOINT_XFER_INT:
                break;
@@ -142,7 +142,7 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
        /* ep1/ep2 dma direction is chosen early; it works in the other
         * direction, with pio.  be cautious with out-dma.
         */
-       ep->is_in = (USB_DIR_IN & desc->bEndpointAddress) != 0;
+       ep->is_in = usb_endpoint_dir_in(desc);
        if (ep->is_in) {
                mode |= 1;
                ep->dma = (use_dma != 0) && (ep->num == UDC_MSTRD_ENDPOINT);
index 168658b4b4e26d2bc7b2614cf5b8cb891a3614e5..c52a681f376cba495303fe843e9cd0839a15a234 100644 (file)
@@ -415,6 +415,13 @@ static int write_packet(struct imx_ep_struct *imx_ep, struct imx_request *req)
        u8      *buf;
        int     length, count, temp;
 
+       if (unlikely(__raw_readl(imx_ep->imx_usb->base +
+                                USB_EP_STAT(EP_NO(imx_ep))) & EPSTAT_ZLPS)) {
+               D_TRX(imx_ep->imx_usb->dev, "<%s> zlp still queued in EP %s\n",
+                       __func__, imx_ep->ep.name);
+               return -1;
+       }
+
        buf = req->req.buf + req->req.actual;
        prefetch(buf);
 
@@ -734,9 +741,12 @@ static struct usb_request *imx_ep_alloc_request
 {
        struct imx_request *req;
 
+       if (!usb_ep)
+               return NULL;
+
        req = kzalloc(sizeof *req, gfp_flags);
-       if (!req || !usb_ep)
-               return 0;
+       if (!req)
+               return NULL;
 
        INIT_LIST_HEAD(&req->queue);
        req->in_use = 0;
index d20937f28a1988209557a356f061900ec2706d35..7d33f50b5874bc683ed42db17aa87c8b59544035 100644 (file)
@@ -384,9 +384,8 @@ ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
                return value;
 
        /* halt any endpoint by doing a "wrong direction" i/o call */
-       if (data->desc.bEndpointAddress & USB_DIR_IN) {
-               if ((data->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-                               == USB_ENDPOINT_XFER_ISOC)
+       if (usb_endpoint_dir_in(&data->desc)) {
+               if (usb_endpoint_xfer_isoc(&data->desc))
                        return -EINVAL;
                DBG (data->dev, "%s halt\n", data->name);
                spin_lock_irq (&data->dev->lock);
@@ -428,9 +427,8 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
                return value;
 
        /* halt any endpoint by doing a "wrong direction" i/o call */
-       if (!(data->desc.bEndpointAddress & USB_DIR_IN)) {
-               if ((data->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-                               == USB_ENDPOINT_XFER_ISOC)
+       if (!usb_endpoint_dir_in(&data->desc)) {
+               if (usb_endpoint_xfer_isoc(&data->desc))
                        return -EINVAL;
                DBG (data->dev, "%s halt\n", data->name);
                spin_lock_irq (&data->dev->lock);
@@ -691,7 +689,7 @@ ep_aio_read(struct kiocb *iocb, const struct iovec *iov,
        struct ep_data          *epdata = iocb->ki_filp->private_data;
        char                    *buf;
 
-       if (unlikely(epdata->desc.bEndpointAddress & USB_DIR_IN))
+       if (unlikely(usb_endpoint_dir_in(&epdata->desc)))
                return -EINVAL;
 
        buf = kmalloc(iocb->ki_left, GFP_KERNEL);
@@ -711,7 +709,7 @@ ep_aio_write(struct kiocb *iocb, const struct iovec *iov,
        size_t                  len = 0;
        int                     i = 0;
 
-       if (unlikely(!(epdata->desc.bEndpointAddress & USB_DIR_IN)))
+       if (unlikely(!usb_endpoint_dir_in(&epdata->desc)))
                return -EINVAL;
 
        buf = kmalloc(iocb->ki_left, GFP_KERNEL);
diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c
new file mode 100644 (file)
index 0000000..6829d59
--- /dev/null
@@ -0,0 +1,3373 @@
+/*
+ * Intel Langwell USB Device Controller driver
+ * Copyright (C) 2008-2009, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+
+/* #undef      DEBUG */
+/* #undef      VERBOSE */
+
+#if defined(CONFIG_USB_LANGWELL_OTG)
+#define        OTG_TRANSCEIVER
+#endif
+
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/pm.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+#include "langwell_udc.h"
+
+
+#define        DRIVER_DESC             "Intel Langwell USB Device Controller driver"
+#define        DRIVER_VERSION          "16 May 2009"
+
+static const char driver_name[] = "langwell_udc";
+static const char driver_desc[] = DRIVER_DESC;
+
+
+/* controller device global variable */
+static struct langwell_udc     *the_controller;
+
+/* for endpoint 0 operations */
+static const struct usb_endpoint_descriptor
+langwell_ep0_desc = {
+       .bLength =              USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType =      USB_DT_ENDPOINT,
+       .bEndpointAddress =     0,
+       .bmAttributes =         USB_ENDPOINT_XFER_CONTROL,
+       .wMaxPacketSize =       EP0_MAX_PKT_SIZE,
+};
+
+
+/*-------------------------------------------------------------------------*/
+/* debugging */
+
+#ifdef DEBUG
+#define        DBG(dev, fmt, args...) \
+       pr_debug("%s %s: " fmt , driver_name, \
+                       pci_name(dev->pdev), ## args)
+#else
+#define        DBG(dev, fmt, args...) \
+       do { } while (0)
+#endif /* DEBUG */
+
+
+#ifdef VERBOSE
+#define        VDBG DBG
+#else
+#define        VDBG(dev, fmt, args...) \
+       do { } while (0)
+#endif /* VERBOSE */
+
+
+#define        ERROR(dev, fmt, args...) \
+       pr_err("%s %s: " fmt , driver_name, \
+                       pci_name(dev->pdev), ## args)
+
+#define        WARNING(dev, fmt, args...) \
+       pr_warning("%s %s: " fmt , driver_name, \
+                       pci_name(dev->pdev), ## args)
+
+#define        INFO(dev, fmt, args...) \
+       pr_info("%s %s: " fmt , driver_name, \
+                       pci_name(dev->pdev), ## args)
+
+
+#ifdef VERBOSE
+static inline void print_all_registers(struct langwell_udc *dev)
+{
+       int     i;
+
+       /* Capability Registers */
+       printk(KERN_DEBUG "Capability Registers (offset: "
+                       "0x%04x, length: 0x%08x)\n",
+                       CAP_REG_OFFSET,
+                       (u32)sizeof(struct langwell_cap_regs));
+       printk(KERN_DEBUG "caplength=0x%02x\n",
+                       readb(&dev->cap_regs->caplength));
+       printk(KERN_DEBUG "hciversion=0x%04x\n",
+                       readw(&dev->cap_regs->hciversion));
+       printk(KERN_DEBUG "hcsparams=0x%08x\n",
+                       readl(&dev->cap_regs->hcsparams));
+       printk(KERN_DEBUG "hccparams=0x%08x\n",
+                       readl(&dev->cap_regs->hccparams));
+       printk(KERN_DEBUG "dciversion=0x%04x\n",
+                       readw(&dev->cap_regs->dciversion));
+       printk(KERN_DEBUG "dccparams=0x%08x\n",
+                       readl(&dev->cap_regs->dccparams));
+
+       /* Operational Registers */
+       printk(KERN_DEBUG "Operational Registers (offset: "
+                       "0x%04x, length: 0x%08x)\n",
+                       OP_REG_OFFSET,
+                       (u32)sizeof(struct langwell_op_regs));
+       printk(KERN_DEBUG "extsts=0x%08x\n",
+                       readl(&dev->op_regs->extsts));
+       printk(KERN_DEBUG "extintr=0x%08x\n",
+                       readl(&dev->op_regs->extintr));
+       printk(KERN_DEBUG "usbcmd=0x%08x\n",
+                       readl(&dev->op_regs->usbcmd));
+       printk(KERN_DEBUG "usbsts=0x%08x\n",
+                       readl(&dev->op_regs->usbsts));
+       printk(KERN_DEBUG "usbintr=0x%08x\n",
+                       readl(&dev->op_regs->usbintr));
+       printk(KERN_DEBUG "frindex=0x%08x\n",
+                       readl(&dev->op_regs->frindex));
+       printk(KERN_DEBUG "ctrldssegment=0x%08x\n",
+                       readl(&dev->op_regs->ctrldssegment));
+       printk(KERN_DEBUG "deviceaddr=0x%08x\n",
+                       readl(&dev->op_regs->deviceaddr));
+       printk(KERN_DEBUG "endpointlistaddr=0x%08x\n",
+                       readl(&dev->op_regs->endpointlistaddr));
+       printk(KERN_DEBUG "ttctrl=0x%08x\n",
+                       readl(&dev->op_regs->ttctrl));
+       printk(KERN_DEBUG "burstsize=0x%08x\n",
+                       readl(&dev->op_regs->burstsize));
+       printk(KERN_DEBUG "txfilltuning=0x%08x\n",
+                       readl(&dev->op_regs->txfilltuning));
+       printk(KERN_DEBUG "txttfilltuning=0x%08x\n",
+                       readl(&dev->op_regs->txttfilltuning));
+       printk(KERN_DEBUG "ic_usb=0x%08x\n",
+                       readl(&dev->op_regs->ic_usb));
+       printk(KERN_DEBUG "ulpi_viewport=0x%08x\n",
+                       readl(&dev->op_regs->ulpi_viewport));
+       printk(KERN_DEBUG "configflag=0x%08x\n",
+                       readl(&dev->op_regs->configflag));
+       printk(KERN_DEBUG "portsc1=0x%08x\n",
+                       readl(&dev->op_regs->portsc1));
+       printk(KERN_DEBUG "devlc=0x%08x\n",
+                       readl(&dev->op_regs->devlc));
+       printk(KERN_DEBUG "otgsc=0x%08x\n",
+                       readl(&dev->op_regs->otgsc));
+       printk(KERN_DEBUG "usbmode=0x%08x\n",
+                       readl(&dev->op_regs->usbmode));
+       printk(KERN_DEBUG "endptnak=0x%08x\n",
+                       readl(&dev->op_regs->endptnak));
+       printk(KERN_DEBUG "endptnaken=0x%08x\n",
+                       readl(&dev->op_regs->endptnaken));
+       printk(KERN_DEBUG "endptsetupstat=0x%08x\n",
+                       readl(&dev->op_regs->endptsetupstat));
+       printk(KERN_DEBUG "endptprime=0x%08x\n",
+                       readl(&dev->op_regs->endptprime));
+       printk(KERN_DEBUG "endptflush=0x%08x\n",
+                       readl(&dev->op_regs->endptflush));
+       printk(KERN_DEBUG "endptstat=0x%08x\n",
+                       readl(&dev->op_regs->endptstat));
+       printk(KERN_DEBUG "endptcomplete=0x%08x\n",
+                       readl(&dev->op_regs->endptcomplete));
+
+       for (i = 0; i < dev->ep_max / 2; i++) {
+               printk(KERN_DEBUG "endptctrl[%d]=0x%08x\n",
+                               i, readl(&dev->op_regs->endptctrl[i]));
+       }
+}
+#endif /* VERBOSE */
+
+
+/*-------------------------------------------------------------------------*/
+
+#define        DIR_STRING(bAddress)    (((bAddress) & USB_DIR_IN) ? "in" : "out")
+
+#define is_in(ep)      (((ep)->ep_num == 0) ? ((ep)->dev->ep0_dir == \
+                       USB_DIR_IN) : ((ep)->desc->bEndpointAddress \
+                       & USB_DIR_IN) == USB_DIR_IN)
+
+
+#ifdef DEBUG
+static char *type_string(u8 bmAttributes)
+{
+       switch ((bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK) {
+       case USB_ENDPOINT_XFER_BULK:
+               return "bulk";
+       case USB_ENDPOINT_XFER_ISOC:
+               return "iso";
+       case USB_ENDPOINT_XFER_INT:
+               return "int";
+       };
+
+       return "control";
+}
+#endif
+
+
+/* configure endpoint control registers */
+static void ep_reset(struct langwell_ep *ep, unsigned char ep_num,
+               unsigned char is_in, unsigned char ep_type)
+{
+       struct langwell_udc     *dev;
+       u32                     endptctrl;
+
+       dev = ep->dev;
+       VDBG(dev, "---> %s()\n", __func__);
+
+       endptctrl = readl(&dev->op_regs->endptctrl[ep_num]);
+       if (is_in) {    /* TX */
+               if (ep_num)
+                       endptctrl |= EPCTRL_TXR;
+               endptctrl |= EPCTRL_TXE;
+               endptctrl |= ep_type << EPCTRL_TXT_SHIFT;
+       } else {        /* RX */
+               if (ep_num)
+                       endptctrl |= EPCTRL_RXR;
+               endptctrl |= EPCTRL_RXE;
+               endptctrl |= ep_type << EPCTRL_RXT_SHIFT;
+       }
+
+       writel(endptctrl, &dev->op_regs->endptctrl[ep_num]);
+
+       VDBG(dev, "<--- %s()\n", __func__);
+}
+
+
+/* reset ep0 dQH and endptctrl */
+static void ep0_reset(struct langwell_udc *dev)
+{
+       struct langwell_ep      *ep;
+       int                     i;
+
+       VDBG(dev, "---> %s()\n", __func__);
+
+       /* ep0 in and out */
+       for (i = 0; i < 2; i++) {
+               ep = &dev->ep[i];
+               ep->dev = dev;
+
+               /* ep0 dQH */
+               ep->dqh = &dev->ep_dqh[i];
+
+               /* configure ep0 endpoint capabilities in dQH */
+               ep->dqh->dqh_ios = 1;
+               ep->dqh->dqh_mpl = EP0_MAX_PKT_SIZE;
+
+               /* FIXME: enable ep0-in HW zero length termination select */
+               if (is_in(ep))
+                       ep->dqh->dqh_zlt = 0;
+               ep->dqh->dqh_mult = 0;
+
+               /* configure ep0 control registers */
+               ep_reset(&dev->ep[0], 0, i, USB_ENDPOINT_XFER_CONTROL);
+       }
+
+       VDBG(dev, "<--- %s()\n", __func__);
+       return;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* endpoints operations */
+
+/* configure endpoint, making it usable */
+static int langwell_ep_enable(struct usb_ep *_ep,
+               const struct usb_endpoint_descriptor *desc)
+{
+       struct langwell_udc     *dev;
+       struct langwell_ep      *ep;
+       u16                     max = 0;
+       unsigned long           flags;
+       int                     retval = 0;
+       unsigned char           zlt, ios = 0, mult = 0;
+
+       ep = container_of(_ep, struct langwell_ep, ep);
+       dev = ep->dev;
+       VDBG(dev, "---> %s()\n", __func__);
+
+       if (!_ep || !desc || ep->desc
+                       || desc->bDescriptorType != USB_DT_ENDPOINT)
+               return -EINVAL;
+
+       if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+               return -ESHUTDOWN;
+
+       max = le16_to_cpu(desc->wMaxPacketSize);
+
+       /*
+        * disable HW zero length termination select
+        * driver handles zero length packet through req->req.zero
+        */
+       zlt = 1;
+
+       /*
+        * sanity check type, direction, address, and then
+        * initialize the endpoint capabilities fields in dQH
+        */
+       switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+       case USB_ENDPOINT_XFER_CONTROL:
+               ios = 1;
+               break;
+       case USB_ENDPOINT_XFER_BULK:
+               if ((dev->gadget.speed == USB_SPEED_HIGH
+                                       && max != 512)
+                               || (dev->gadget.speed == USB_SPEED_FULL
+                                       && max > 64)) {
+                       goto done;
+               }
+               break;
+       case USB_ENDPOINT_XFER_INT:
+               if (strstr(ep->ep.name, "-iso")) /* bulk is ok */
+                       goto done;
+
+               switch (dev->gadget.speed) {
+               case USB_SPEED_HIGH:
+                       if (max <= 1024)
+                               break;
+               case USB_SPEED_FULL:
+                       if (max <= 64)
+                               break;
+               default:
+                       if (max <= 8)
+                               break;
+                       goto done;
+               }
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               if (strstr(ep->ep.name, "-bulk")
+                               || strstr(ep->ep.name, "-int"))
+                       goto done;
+
+               switch (dev->gadget.speed) {
+               case USB_SPEED_HIGH:
+                       if (max <= 1024)
+                               break;
+               case USB_SPEED_FULL:
+                       if (max <= 1023)
+                               break;
+               default:
+                       goto done;
+               }
+               /*
+                * FIXME:
+                * calculate transactions needed for high bandwidth iso
+                */
+               mult = (unsigned char)(1 + ((max >> 11) & 0x03));
+               max = max & 0x8ff;      /* bit 0~10 */
+               /* 3 transactions at most */
+               if (mult > 3)
+                       goto done;
+               break;
+       default:
+               goto done;
+       }
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       /* configure endpoint capabilities in dQH */
+       ep->dqh->dqh_ios = ios;
+       ep->dqh->dqh_mpl = cpu_to_le16(max);
+       ep->dqh->dqh_zlt = zlt;
+       ep->dqh->dqh_mult = mult;
+
+       ep->ep.maxpacket = max;
+       ep->desc = desc;
+       ep->stopped = 0;
+       ep->ep_num = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+
+       /* ep_type */
+       ep->ep_type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+       /* configure endpoint control registers */
+       ep_reset(ep, ep->ep_num, is_in(ep), ep->ep_type);
+
+       DBG(dev, "enabled %s (ep%d%s-%s), max %04x\n",
+                       _ep->name,
+                       ep->ep_num,
+                       DIR_STRING(desc->bEndpointAddress),
+                       type_string(desc->bmAttributes),
+                       max);
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+done:
+       VDBG(dev, "<--- %s()\n", __func__);
+       return retval;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* retire a request */
+static void done(struct langwell_ep *ep, struct langwell_request *req,
+               int status)
+{
+       struct langwell_udc     *dev = ep->dev;
+       unsigned                stopped = ep->stopped;
+       struct langwell_dtd     *curr_dtd, *next_dtd;
+       int                     i;
+
+       VDBG(dev, "---> %s()\n", __func__);
+
+       /* remove the req from ep->queue */
+       list_del_init(&req->queue);
+
+       if (req->req.status == -EINPROGRESS)
+               req->req.status = status;
+       else
+               status = req->req.status;
+
+       /* free dTD for the request */
+       next_dtd = req->head;
+       for (i = 0; i < req->dtd_count; i++) {
+               curr_dtd = next_dtd;
+               if (i != req->dtd_count - 1)
+                       next_dtd = curr_dtd->next_dtd_virt;
+               dma_pool_free(dev->dtd_pool, curr_dtd, curr_dtd->dtd_dma);
+       }
+
+       if (req->mapped) {
+               dma_unmap_single(&dev->pdev->dev, req->req.dma, req->req.length,
+                       is_in(ep) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+               req->req.dma = DMA_ADDR_INVALID;
+               req->mapped = 0;
+       } else
+               dma_sync_single_for_cpu(&dev->pdev->dev, req->req.dma,
+                               req->req.length,
+                               is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+
+       if (status != -ESHUTDOWN)
+               DBG(dev, "complete %s, req %p, stat %d, len %u/%u\n",
+                       ep->ep.name, &req->req, status,
+                       req->req.actual, req->req.length);
+
+       /* don't modify queue heads during completion callback */
+       ep->stopped = 1;
+
+       spin_unlock(&dev->lock);
+       /* complete routine from gadget driver */
+       if (req->req.complete)
+               req->req.complete(&ep->ep, &req->req);
+
+       spin_lock(&dev->lock);
+       ep->stopped = stopped;
+
+       VDBG(dev, "<--- %s()\n", __func__);
+}
+
+
+static void langwell_ep_fifo_flush(struct usb_ep *_ep);
+
+/* delete all endpoint requests, called with spinlock held */
+static void nuke(struct langwell_ep *ep, int status)
+{
+       /* called with spinlock held */
+       ep->stopped = 1;
+
+       /* endpoint fifo flush */
+       if (&ep->ep && ep->desc)
+               langwell_ep_fifo_flush(&ep->ep);
+
+       while (!list_empty(&ep->queue)) {
+               struct langwell_request *req = NULL;
+               req = list_entry(ep->queue.next, struct langwell_request,
+                               queue);
+               done(ep, req, status);
+       }
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* endpoint is no longer usable */
+static int langwell_ep_disable(struct usb_ep *_ep)
+{
+       struct langwell_ep      *ep;
+       unsigned long           flags;
+       struct langwell_udc     *dev;
+       int                     ep_num;
+       u32                     endptctrl;
+
+       ep = container_of(_ep, struct langwell_ep, ep);
+       dev = ep->dev;
+       VDBG(dev, "---> %s()\n", __func__);
+
+       if (!_ep || !ep->desc)
+               return -EINVAL;
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       /* disable endpoint control register */
+       ep_num = ep->ep_num;
+       endptctrl = readl(&dev->op_regs->endptctrl[ep_num]);
+       if (is_in(ep))
+               endptctrl &= ~EPCTRL_TXE;
+       else
+               endptctrl &= ~EPCTRL_RXE;
+       writel(endptctrl, &dev->op_regs->endptctrl[ep_num]);
+
+       /* nuke all pending requests (does flush) */
+       nuke(ep, -ESHUTDOWN);
+
+       ep->desc = NULL;
+       ep->stopped = 1;
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       DBG(dev, "disabled %s\n", _ep->name);
+       VDBG(dev, "<--- %s()\n", __func__);
+
+       return 0;
+}
+
+
+/* allocate a request object to use with this endpoint */
+static struct usb_request *langwell_alloc_request(struct usb_ep *_ep,
+               gfp_t gfp_flags)
+{
+       struct langwell_ep      *ep;
+       struct langwell_udc     *dev;
+       struct langwell_request *req = NULL;
+
+       if (!_ep)
+               return NULL;
+
+       ep = container_of(_ep, struct langwell_ep, ep);
+       dev = ep->dev;
+       VDBG(dev, "---> %s()\n", __func__);
+
+       req = kzalloc(sizeof(*req), gfp_flags);
+       if (!req)
+               return NULL;
+
+       req->req.dma = DMA_ADDR_INVALID;
+       INIT_LIST_HEAD(&req->queue);
+
+       VDBG(dev, "alloc request for %s\n", _ep->name);
+       VDBG(dev, "<--- %s()\n", __func__);
+       return &req->req;
+}
+
+
+/* free a request object */
+static void langwell_free_request(struct usb_ep *_ep,
+               struct usb_request *_req)
+{
+       struct langwell_ep      *ep;
+       struct langwell_udc     *dev;
+       struct langwell_request *req = NULL;
+
+       ep = container_of(_ep, struct langwell_ep, ep);
+       dev = ep->dev;
+       VDBG(dev, "---> %s()\n", __func__);
+
+       if (!_ep || !_req)
+               return;
+
+       req = container_of(_req, struct langwell_request, req);
+       WARN_ON(!list_empty(&req->queue));
+
+       if (_req)
+               kfree(req);
+
+       VDBG(dev, "free request for %s\n", _ep->name);
+       VDBG(dev, "<--- %s()\n", __func__);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* queue dTD and PRIME endpoint */
+static int queue_dtd(struct langwell_ep *ep, struct langwell_request *req)
+{
+       u32                     bit_mask, usbcmd, endptstat, dtd_dma;
+       u8                      dtd_status;
+       int                     i;
+       struct langwell_dqh     *dqh;
+       struct langwell_udc     *dev;
+
+       dev = ep->dev;
+       VDBG(dev, "---> %s()\n", __func__);
+
+       i = ep->ep_num * 2 + is_in(ep);
+       dqh = &dev->ep_dqh[i];
+
+       if (ep->ep_num)
+               VDBG(dev, "%s\n", ep->name);
+       else
+               /* ep0 */
+               VDBG(dev, "%s-%s\n", ep->name, is_in(ep) ? "in" : "out");
+
+       VDBG(dev, "ep_dqh[%d] addr: 0x%08x\n", i, (u32)&(dev->ep_dqh[i]));
+
+       bit_mask = is_in(ep) ?
+               (1 << (ep->ep_num + 16)) : (1 << (ep->ep_num));
+
+       VDBG(dev, "bit_mask = 0x%08x\n", bit_mask);
+
+       /* check if the pipe is empty */
+       if (!(list_empty(&ep->queue))) {
+               /* add dTD to the end of linked list */
+               struct langwell_request *lastreq;
+               lastreq = list_entry(ep->queue.prev,
+                               struct langwell_request, queue);
+
+               lastreq->tail->dtd_next =
+                       cpu_to_le32(req->head->dtd_dma & DTD_NEXT_MASK);
+
+               /* read prime bit, if 1 goto out */
+               if (readl(&dev->op_regs->endptprime) & bit_mask)
+                       goto out;
+
+               do {
+                       /* set ATDTW bit in USBCMD */
+                       usbcmd = readl(&dev->op_regs->usbcmd);
+                       writel(usbcmd | CMD_ATDTW, &dev->op_regs->usbcmd);
+
+                       /* read correct status bit */
+                       endptstat = readl(&dev->op_regs->endptstat) & bit_mask;
+
+               } while (!(readl(&dev->op_regs->usbcmd) & CMD_ATDTW));
+
+               /* write ATDTW bit to 0 */
+               usbcmd = readl(&dev->op_regs->usbcmd);
+               writel(usbcmd & ~CMD_ATDTW, &dev->op_regs->usbcmd);
+
+               if (endptstat)
+                       goto out;
+       }
+
+       /* write dQH next pointer and terminate bit to 0 */
+       dtd_dma = req->head->dtd_dma & DTD_NEXT_MASK;
+       dqh->dtd_next = cpu_to_le32(dtd_dma);
+
+       /* clear active and halt bit */
+       dtd_status = (u8) ~(DTD_STS_ACTIVE | DTD_STS_HALTED);
+       dqh->dtd_status &= dtd_status;
+       VDBG(dev, "dqh->dtd_status = 0x%x\n", dqh->dtd_status);
+
+       /* write 1 to endptprime register to PRIME endpoint */
+       bit_mask = is_in(ep) ? (1 << (ep->ep_num + 16)) : (1 << ep->ep_num);
+       VDBG(dev, "endprime bit_mask = 0x%08x\n", bit_mask);
+       writel(bit_mask, &dev->op_regs->endptprime);
+out:
+       VDBG(dev, "<--- %s()\n", __func__);
+       return 0;
+}
+
+
+/* fill in the dTD structure to build a transfer descriptor */
+static struct langwell_dtd *build_dtd(struct langwell_request *req,
+               unsigned *length, dma_addr_t *dma, int *is_last)
+{
+       u32                      buf_ptr;
+       struct langwell_dtd     *dtd;
+       struct langwell_udc     *dev;
+       int                     i;
+
+       dev = req->ep->dev;
+       VDBG(dev, "---> %s()\n", __func__);
+
+       /* the maximum transfer length, up to 16k bytes */
+       *length = min(req->req.length - req->req.actual,
+                       (unsigned)DTD_MAX_TRANSFER_LENGTH);
+
+       /* create dTD dma_pool resource */
+       dtd = dma_pool_alloc(dev->dtd_pool, GFP_KERNEL, dma);
+       if (dtd == NULL)
+               return dtd;
+       dtd->dtd_dma = *dma;
+
+       /* initialize buffer page pointers */
+       buf_ptr = (u32)(req->req.dma + req->req.actual);
+       for (i = 0; i < 5; i++)
+               dtd->dtd_buf[i] = cpu_to_le32(buf_ptr + i * PAGE_SIZE);
+
+       req->req.actual += *length;
+
+       /* fill in total bytes with transfer size */
+       dtd->dtd_total = cpu_to_le16(*length);
+       VDBG(dev, "dtd->dtd_total = %d\n", dtd->dtd_total);
+
+       /* set is_last flag if req->req.zero is set or not */
+       if (req->req.zero) {
+               if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0)
+                       *is_last = 1;
+               else
+                       *is_last = 0;
+       } else if (req->req.length == req->req.actual) {
+               *is_last = 1;
+       } else
+               *is_last = 0;
+
+       if (*is_last == 0)
+               VDBG(dev, "multi-dtd request!\n");
+
+       /* set interrupt on complete bit for the last dTD */
+       if (*is_last && !req->req.no_interrupt)
+               dtd->dtd_ioc = 1;
+
+       /* set multiplier override 0 for non-ISO and non-TX endpoint */
+       dtd->dtd_multo = 0;
+
+       /* set the active bit of status field to 1 */
+       dtd->dtd_status = DTD_STS_ACTIVE;
+       VDBG(dev, "dtd->dtd_status = 0x%02x\n", dtd->dtd_status);
+
+       VDBG(dev, "length = %d, dma addr= 0x%08x\n", *length, (int)*dma);
+       VDBG(dev, "<--- %s()\n", __func__);
+       return dtd;
+}
+
+
+/* generate dTD linked list for a request */
+static int req_to_dtd(struct langwell_request *req)
+{
+       unsigned                count;
+       int                     is_last, is_first = 1;
+       struct langwell_dtd     *dtd, *last_dtd = NULL;
+       struct langwell_udc     *dev;
+       dma_addr_t              dma;
+
+       dev = req->ep->dev;
+       VDBG(dev, "---> %s()\n", __func__);
+       do {
+               dtd = build_dtd(req, &count, &dma, &is_last);
+               if (dtd == NULL)
+                       return -ENOMEM;
+
+               if (is_first) {
+                       is_first = 0;
+                       req->head = dtd;
+               } else {
+                       last_dtd->dtd_next = cpu_to_le32(dma);
+                       last_dtd->next_dtd_virt = dtd;
+               }
+               last_dtd = dtd;
+               req->dtd_count++;
+       } while (!is_last);
+
+       /* set terminate bit to 1 for the last dTD */
+       dtd->dtd_next = DTD_TERM;
+
+       req->tail = dtd;
+
+       VDBG(dev, "<--- %s()\n", __func__);
+       return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* queue (submits) an I/O requests to an endpoint */
+static int langwell_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
+               gfp_t gfp_flags)
+{
+       struct langwell_request *req;
+       struct langwell_ep      *ep;
+       struct langwell_udc     *dev;
+       unsigned long           flags;
+       int                     is_iso = 0, zlflag = 0;
+
+       /* always require a cpu-view buffer */
+       req = container_of(_req, struct langwell_request, req);
+       ep = container_of(_ep, struct langwell_ep, ep);
+
+       if (!_req || !_req->complete || !_req->buf
+                       || !list_empty(&req->queue)) {
+               return -EINVAL;
+       }
+
+       if (unlikely(!_ep || !ep->desc))
+               return -EINVAL;
+
+       dev = ep->dev;
+       req->ep = ep;
+       VDBG(dev, "---> %s()\n", __func__);
+
+       if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+               if (req->req.length > ep->ep.maxpacket)
+                       return -EMSGSIZE;
+               is_iso = 1;
+       }
+
+       if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN))
+               return -ESHUTDOWN;
+
+       /* set up dma mapping in case the caller didn't */
+       if (_req->dma == DMA_ADDR_INVALID) {
+               /* WORKAROUND: WARN_ON(size == 0) */
+               if (_req->length == 0) {
+                       VDBG(dev, "req->length: 0->1\n");
+                       zlflag = 1;
+                       _req->length++;
+               }
+
+               _req->dma = dma_map_single(&dev->pdev->dev,
+                               _req->buf, _req->length,
+                               is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               if (zlflag && (_req->length == 1)) {
+                       VDBG(dev, "req->length: 1->0\n");
+                       zlflag = 0;
+                       _req->length = 0;
+               }
+
+               req->mapped = 1;
+               VDBG(dev, "req->mapped = 1\n");
+       } else {
+               dma_sync_single_for_device(&dev->pdev->dev,
+                               _req->dma, _req->length,
+                               is_in(ep) ?  DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               req->mapped = 0;
+               VDBG(dev, "req->mapped = 0\n");
+       }
+
+       DBG(dev, "%s queue req %p, len %u, buf %p, dma 0x%08x\n",
+                       _ep->name,
+                       _req, _req->length, _req->buf, _req->dma);
+
+       _req->status = -EINPROGRESS;
+       _req->actual = 0;
+       req->dtd_count = 0;
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       /* build and put dTDs to endpoint queue */
+       if (!req_to_dtd(req)) {
+               queue_dtd(ep, req);
+       } else {
+               spin_unlock_irqrestore(&dev->lock, flags);
+               return -ENOMEM;
+       }
+
+       /* update ep0 state */
+       if (ep->ep_num == 0)
+               dev->ep0_state = DATA_STATE_XMIT;
+
+       if (likely(req != NULL)) {
+               list_add_tail(&req->queue, &ep->queue);
+               VDBG(dev, "list_add_tail() \n");
+       }
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       VDBG(dev, "<--- %s()\n", __func__);
+       return 0;
+}
+
+
+/* dequeue (cancels, unlinks) an I/O request from an endpoint */
+static int langwell_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+       struct langwell_ep      *ep;
+       struct langwell_udc     *dev;
+       struct langwell_request *req;
+       unsigned long           flags;
+       int                     stopped, ep_num, retval = 0;
+       u32                     endptctrl;
+
+       ep = container_of(_ep, struct langwell_ep, ep);
+       dev = ep->dev;
+       VDBG(dev, "---> %s()\n", __func__);
+
+       if (!_ep || !ep->desc || !_req)
+               return -EINVAL;
+
+       if (!dev->driver)
+               return -ESHUTDOWN;
+
+       spin_lock_irqsave(&dev->lock, flags);
+       stopped = ep->stopped;
+
+       /* quiesce dma while we patch the queue */
+       ep->stopped = 1;
+       ep_num = ep->ep_num;
+
+       /* disable endpoint control register */
+       endptctrl = readl(&dev->op_regs->endptctrl[ep_num]);
+       if (is_in(ep))
+               endptctrl &= ~EPCTRL_TXE;
+       else
+               endptctrl &= ~EPCTRL_RXE;
+       writel(endptctrl, &dev->op_regs->endptctrl[ep_num]);
+
+       /* make sure it's still queued on this endpoint */
+       list_for_each_entry(req, &ep->queue, queue) {
+               if (&req->req == _req)
+                       break;
+       }
+
+       if (&req->req != _req) {
+               retval = -EINVAL;
+               goto done;
+       }
+
+       /* queue head may be partially complete. */
+       if (ep->queue.next == &req->queue) {
+               DBG(dev, "unlink (%s) dma\n", _ep->name);
+               _req->status = -ECONNRESET;
+               langwell_ep_fifo_flush(&ep->ep);
+
+               /* not the last request in endpoint queue */
+               if (likely(ep->queue.next == &req->queue)) {
+                       struct langwell_dqh     *dqh;
+                       struct langwell_request *next_req;
+
+                       dqh = ep->dqh;
+                       next_req = list_entry(req->queue.next,
+                                       struct langwell_request, queue);
+
+                       /* point the dQH to the first dTD of next request */
+                       writel((u32) next_req->head, &dqh->dqh_current);
+               }
+       } else {
+               struct langwell_request *prev_req;
+
+               prev_req = list_entry(req->queue.prev,
+                               struct langwell_request, queue);
+               writel(readl(&req->tail->dtd_next),
+                               &prev_req->tail->dtd_next);
+       }
+
+       done(ep, req, -ECONNRESET);
+
+done:
+       /* enable endpoint again */
+       endptctrl = readl(&dev->op_regs->endptctrl[ep_num]);
+       if (is_in(ep))
+               endptctrl |= EPCTRL_TXE;
+       else
+               endptctrl |= EPCTRL_RXE;
+       writel(endptctrl, &dev->op_regs->endptctrl[ep_num]);
+
+       ep->stopped = stopped;
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       VDBG(dev, "<--- %s()\n", __func__);
+       return retval;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* endpoint set/clear halt */
+static void ep_set_halt(struct langwell_ep *ep, int value)
+{
+       u32                     endptctrl = 0;
+       int                     ep_num;
+       struct langwell_udc     *dev = ep->dev;
+       VDBG(dev, "---> %s()\n", __func__);
+
+       ep_num = ep->ep_num;
+       endptctrl = readl(&dev->op_regs->endptctrl[ep_num]);
+
+       /* value: 1 - set halt, 0 - clear halt */
+       if (value) {
+               /* set the stall bit */
+               if (is_in(ep))
+                       endptctrl |= EPCTRL_TXS;
+               else
+                       endptctrl |= EPCTRL_RXS;
+       } else {
+               /* clear the stall bit and reset data toggle */
+               if (is_in(ep)) {
+                       endptctrl &= ~EPCTRL_TXS;
+                       endptctrl |= EPCTRL_TXR;
+               } else {
+                       endptctrl &= ~EPCTRL_RXS;
+                       endptctrl |= EPCTRL_RXR;
+               }
+       }
+
+       writel(endptctrl, &dev->op_regs->endptctrl[ep_num]);
+
+       VDBG(dev, "<--- %s()\n", __func__);
+}
+
+
+/* set the endpoint halt feature */
+static int langwell_ep_set_halt(struct usb_ep *_ep, int value)
+{
+       struct langwell_ep      *ep;
+       struct langwell_udc     *dev;
+       unsigned long           flags;
+       int                     retval = 0;
+
+       ep = container_of(_ep, struct langwell_ep, ep);
+       dev = ep->dev;
+
+       VDBG(dev, "---> %s()\n", __func__);
+
+       if (!_ep || !ep->desc)
+               return -EINVAL;
+
+       if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+               return -ESHUTDOWN;
+
+       if (ep->desc && (ep->desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+                       == USB_ENDPOINT_XFER_ISOC)
+               return  -EOPNOTSUPP;
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       /*
+        * attempt to halt IN ep will fail if any transfer requests
+        * are still queue
+        */
+       if (!list_empty(&ep->queue) && is_in(ep) && value) {
+               /* IN endpoint FIFO holds bytes */
+               DBG(dev, "%s FIFO holds bytes\n", _ep->name);
+               retval = -EAGAIN;
+               goto done;
+       }
+
+       /* endpoint set/clear halt */
+       if (ep->ep_num) {
+               ep_set_halt(ep, value);
+       } else { /* endpoint 0 */
+               dev->ep0_state = WAIT_FOR_SETUP;
+               dev->ep0_dir = USB_DIR_OUT;
+       }
+done:
+       spin_unlock_irqrestore(&dev->lock, flags);
+       DBG(dev, "%s %s halt\n", _ep->name, value ? "set" : "clear");
+       VDBG(dev, "<--- %s()\n", __func__);
+       return retval;
+}
+
+
+/* set the halt feature and ignores clear requests */
+static int langwell_ep_set_wedge(struct usb_ep *_ep)
+{
+       struct langwell_ep      *ep;
+       struct langwell_udc     *dev;
+
+       ep = container_of(_ep, struct langwell_ep, ep);
+       dev = ep->dev;
+
+       VDBG(dev, "---> %s()\n", __func__);
+
+       if (!_ep || !ep->desc)
+               return -EINVAL;
+
+       VDBG(dev, "<--- %s()\n", __func__);
+       return usb_ep_set_halt(_ep);
+}
+
+
+/* flush contents of a fifo */
+static void langwell_ep_fifo_flush(struct usb_ep *_ep)
+{
+       struct langwell_ep      *ep;
+       struct langwell_udc     *dev;
+       u32                     flush_bit;
+       unsigned long           timeout;
+
+       ep = container_of(_ep, struct langwell_ep, ep);
+       dev = ep->dev;
+
+       VDBG(dev, "---> %s()\n", __func__);
+
+       if (!_ep || !ep->desc) {
+               VDBG(dev, "ep or ep->desc is NULL\n");
+               VDBG(dev, "<--- %s()\n", __func__);
+               return;
+       }
+
+       VDBG(dev, "%s-%s fifo flush\n", _ep->name, is_in(ep) ? "in" : "out");
+
+       /* flush endpoint buffer */
+       if (ep->ep_num == 0)
+               flush_bit = (1 << 16) | 1;
+       else if (is_in(ep))
+               flush_bit = 1 << (ep->ep_num + 16);     /* TX */
+       else
+               flush_bit = 1 << ep->ep_num;            /* RX */
+
+       /* wait until flush complete */
+       timeout = jiffies + FLUSH_TIMEOUT;
+       do {
+               writel(flush_bit, &dev->op_regs->endptflush);
+               while (readl(&dev->op_regs->endptflush)) {
+                       if (time_after(jiffies, timeout)) {
+                               ERROR(dev, "ep flush timeout\n");
+                               goto done;
+                       }
+                       cpu_relax();
+               }
+       } while (readl(&dev->op_regs->endptstat) & flush_bit);
+done:
+       VDBG(dev, "<--- %s()\n", __func__);
+}
+
+
+/* endpoints operations structure */
+static const struct usb_ep_ops langwell_ep_ops = {
+
+       /* configure endpoint, making it usable */
+       .enable         = langwell_ep_enable,
+
+       /* endpoint is no longer usable */
+       .disable        = langwell_ep_disable,
+
+       /* allocate a request object to use with this endpoint */
+       .alloc_request  = langwell_alloc_request,
+
+       /* free a request object */
+       .free_request   = langwell_free_request,
+
+       /* queue (submits) an I/O requests to an endpoint */
+       .queue          = langwell_ep_queue,
+
+       /* dequeue (cancels, unlinks) an I/O request from an endpoint */
+       .dequeue        = langwell_ep_dequeue,
+
+       /* set the endpoint halt feature */
+       .set_halt       = langwell_ep_set_halt,
+
+       /* set the halt feature and ignores clear requests */
+       .set_wedge      = langwell_ep_set_wedge,
+
+       /* flush contents of a fifo */
+       .fifo_flush     = langwell_ep_fifo_flush,
+};
+
+
+/*-------------------------------------------------------------------------*/
+
+/* device controller usb_gadget_ops structure */
+
+/* returns the current frame number */
+static int langwell_get_frame(struct usb_gadget *_gadget)
+{
+       struct langwell_udc     *dev;
+       u16                     retval;
+
+       if (!_gadget)
+               return -ENODEV;
+
+       dev = container_of(_gadget, struct langwell_udc, gadget);
+       VDBG(dev, "---> %s()\n", __func__);
+
+       retval = readl(&dev->op_regs->frindex) & FRINDEX_MASK;
+
+       VDBG(dev, "<--- %s()\n", __func__);
+       return retval;
+}
+
+
+/* tries to wake up the host connected to this gadget */
+static int langwell_wakeup(struct usb_gadget *_gadget)
+{
+       struct langwell_udc     *dev;
+       u32                     portsc1, devlc;
+       unsigned long           flags;
+
+       if (!_gadget)
+               return 0;
+
+       dev = container_of(_gadget, struct langwell_udc, gadget);
+       VDBG(dev, "---> %s()\n", __func__);
+
+       /* Remote Wakeup feature not enabled by host */
+       if (!dev->remote_wakeup)
+               return -ENOTSUPP;
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       portsc1 = readl(&dev->op_regs->portsc1);
+       if (!(portsc1 & PORTS_SUSP)) {
+               spin_unlock_irqrestore(&dev->lock, flags);
+               return 0;
+       }
+
+       /* LPM L1 to L0, remote wakeup */
+       if (dev->lpm && dev->lpm_state == LPM_L1) {
+               portsc1 |= PORTS_SLP;
+               writel(portsc1, &dev->op_regs->portsc1);
+       }
+
+       /* force port resume */
+       if (dev->usb_state == USB_STATE_SUSPENDED) {
+               portsc1 |= PORTS_FPR;
+               writel(portsc1, &dev->op_regs->portsc1);
+       }
+
+       /* exit PHY low power suspend */
+       devlc = readl(&dev->op_regs->devlc);
+       VDBG(dev, "devlc = 0x%08x\n", devlc);
+       devlc &= ~LPM_PHCD;
+       writel(devlc, &dev->op_regs->devlc);
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       VDBG(dev, "<--- %s()\n", __func__);
+       return 0;
+}
+
+
+/* notify controller that VBUS is powered or not */
+static int langwell_vbus_session(struct usb_gadget *_gadget, int is_active)
+{
+       struct langwell_udc     *dev;
+       unsigned long           flags;
+       u32                     usbcmd;
+
+       if (!_gadget)
+               return -ENODEV;
+
+       dev = container_of(_gadget, struct langwell_udc, gadget);
+       VDBG(dev, "---> %s()\n", __func__);
+
+       spin_lock_irqsave(&dev->lock, flags);
+       VDBG(dev, "VBUS status: %s\n", is_active ? "on" : "off");
+
+       dev->vbus_active = (is_active != 0);
+       if (dev->driver && dev->softconnected && dev->vbus_active) {
+               usbcmd = readl(&dev->op_regs->usbcmd);
+               usbcmd |= CMD_RUNSTOP;
+               writel(usbcmd, &dev->op_regs->usbcmd);
+       } else {
+               usbcmd = readl(&dev->op_regs->usbcmd);
+               usbcmd &= ~CMD_RUNSTOP;
+               writel(usbcmd, &dev->op_regs->usbcmd);
+       }
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       VDBG(dev, "<--- %s()\n", __func__);
+       return 0;
+}
+
+
+/* constrain controller's VBUS power usage */
+static int langwell_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
+{
+       struct langwell_udc     *dev;
+
+       if (!_gadget)
+               return -ENODEV;
+
+       dev = container_of(_gadget, struct langwell_udc, gadget);
+       VDBG(dev, "---> %s()\n", __func__);
+
+       if (dev->transceiver) {
+               VDBG(dev, "otg_set_power\n");
+               VDBG(dev, "<--- %s()\n", __func__);
+               return otg_set_power(dev->transceiver, mA);
+       }
+
+       VDBG(dev, "<--- %s()\n", __func__);
+       return -ENOTSUPP;
+}
+
+
+/* D+ pullup, software-controlled connect/disconnect to USB host */
+static int langwell_pullup(struct usb_gadget *_gadget, int is_on)
+{
+       struct langwell_udc     *dev;
+       u32                     usbcmd;
+       unsigned long           flags;
+
+       if (!_gadget)
+               return -ENODEV;
+
+       dev = container_of(_gadget, struct langwell_udc, gadget);
+
+       VDBG(dev, "---> %s()\n", __func__);
+
+       spin_lock_irqsave(&dev->lock, flags);
+       dev->softconnected = (is_on != 0);
+
+       if (dev->driver && dev->softconnected && dev->vbus_active) {
+               usbcmd = readl(&dev->op_regs->usbcmd);
+               usbcmd |= CMD_RUNSTOP;
+               writel(usbcmd, &dev->op_regs->usbcmd);
+       } else {
+               usbcmd = readl(&dev->op_regs->usbcmd);
+               usbcmd &= ~CMD_RUNSTOP;
+               writel(usbcmd, &dev->op_regs->usbcmd);
+       }
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       VDBG(dev, "<--- %s()\n", __func__);
+       return 0;
+}
+
+
+/* device controller usb_gadget_ops structure */
+static const struct usb_gadget_ops langwell_ops = {
+
+       /* returns the current frame number */
+       .get_frame      = langwell_get_frame,
+
+       /* tries to wake up the host connected to this gadget */
+       .wakeup         = langwell_wakeup,
+
+       /* set the device selfpowered feature, always selfpowered */
+       /* .set_selfpowered = langwell_set_selfpowered, */
+
+       /* notify controller that VBUS is powered or not */
+       .vbus_session   = langwell_vbus_session,
+
+       /* constrain controller's VBUS power usage */
+       .vbus_draw      = langwell_vbus_draw,
+
+       /* D+ pullup, software-controlled connect/disconnect to USB host */
+       .pullup         = langwell_pullup,
+};
+
+
+/*-------------------------------------------------------------------------*/
+
+/* device controller operations */
+
+/* reset device controller */
+static int langwell_udc_reset(struct langwell_udc *dev)
+{
+       u32             usbcmd, usbmode, devlc, endpointlistaddr;
+       unsigned long   timeout;
+
+       if (!dev)
+               return -EINVAL;
+
+       DBG(dev, "---> %s()\n", __func__);
+
+       /* set controller to stop state */
+       usbcmd = readl(&dev->op_regs->usbcmd);
+       usbcmd &= ~CMD_RUNSTOP;
+       writel(usbcmd, &dev->op_regs->usbcmd);
+
+       /* reset device controller */
+       usbcmd = readl(&dev->op_regs->usbcmd);
+       usbcmd |= CMD_RST;
+       writel(usbcmd, &dev->op_regs->usbcmd);
+
+       /* wait for reset to complete */
+       timeout = jiffies + RESET_TIMEOUT;
+       while (readl(&dev->op_regs->usbcmd) & CMD_RST) {
+               if (time_after(jiffies, timeout)) {
+                       ERROR(dev, "device reset timeout\n");
+                       return -ETIMEDOUT;
+               }
+               cpu_relax();
+       }
+
+       /* set controller to device mode */
+       usbmode = readl(&dev->op_regs->usbmode);
+       usbmode |= MODE_DEVICE;
+
+       /* turn setup lockout off, require setup tripwire in usbcmd */
+       usbmode |= MODE_SLOM;
+
+       writel(usbmode, &dev->op_regs->usbmode);
+       usbmode = readl(&dev->op_regs->usbmode);
+       VDBG(dev, "usbmode=0x%08x\n", usbmode);
+
+       /* Write-Clear setup status */
+       writel(0, &dev->op_regs->usbsts);
+
+       /* if support USB LPM, ACK all LPM token */
+       if (dev->lpm) {
+               devlc = readl(&dev->op_regs->devlc);
+               devlc &= ~LPM_STL;      /* don't STALL LPM token */
+               devlc &= ~LPM_NYT_ACK;  /* ACK LPM token */
+               writel(devlc, &dev->op_regs->devlc);
+       }
+
+       /* fill endpointlistaddr register */
+       endpointlistaddr = dev->ep_dqh_dma;
+       endpointlistaddr &= ENDPOINTLISTADDR_MASK;
+       writel(endpointlistaddr, &dev->op_regs->endpointlistaddr);
+
+       VDBG(dev, "dQH base (vir: %p, phy: 0x%08x), endpointlistaddr=0x%08x\n",
+                       dev->ep_dqh, endpointlistaddr,
+                       readl(&dev->op_regs->endpointlistaddr));
+       DBG(dev, "<--- %s()\n", __func__);
+       return 0;
+}
+
+
+/* reinitialize device controller endpoints */
+static int eps_reinit(struct langwell_udc *dev)
+{
+       struct langwell_ep      *ep;
+       char                    name[14];
+       int                     i;
+
+       VDBG(dev, "---> %s()\n", __func__);
+
+       /* initialize ep0 */
+       ep = &dev->ep[0];
+       ep->dev = dev;
+       strncpy(ep->name, "ep0", sizeof(ep->name));
+       ep->ep.name = ep->name;
+       ep->ep.ops = &langwell_ep_ops;
+       ep->stopped = 0;
+       ep->ep.maxpacket = EP0_MAX_PKT_SIZE;
+       ep->ep_num = 0;
+       ep->desc = &langwell_ep0_desc;
+       INIT_LIST_HEAD(&ep->queue);
+
+       ep->ep_type = USB_ENDPOINT_XFER_CONTROL;
+
+       /* initialize other endpoints */
+       for (i = 2; i < dev->ep_max; i++) {
+               ep = &dev->ep[i];
+               if (i % 2)
+                       snprintf(name, sizeof(name), "ep%din", i / 2);
+               else
+                       snprintf(name, sizeof(name), "ep%dout", i / 2);
+               ep->dev = dev;
+               strncpy(ep->name, name, sizeof(ep->name));
+               ep->ep.name = ep->name;
+
+               ep->ep.ops = &langwell_ep_ops;
+               ep->stopped = 0;
+               ep->ep.maxpacket = (unsigned short) ~0;
+               ep->ep_num = i / 2;
+
+               INIT_LIST_HEAD(&ep->queue);
+               list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);
+
+               ep->dqh = &dev->ep_dqh[i];
+       }
+
+       VDBG(dev, "<--- %s()\n", __func__);
+       return 0;
+}
+
+
+/* enable interrupt and set controller to run state */
+static void langwell_udc_start(struct langwell_udc *dev)
+{
+       u32     usbintr, usbcmd;
+       DBG(dev, "---> %s()\n", __func__);
+
+       /* enable interrupts */
+       usbintr = INTR_ULPIE    /* ULPI */
+               | INTR_SLE      /* suspend */
+               /* | INTR_SRE   SOF received */
+               | INTR_URE      /* USB reset */
+               | INTR_AAE      /* async advance */
+               | INTR_SEE      /* system error */
+               | INTR_FRE      /* frame list rollover */
+               | INTR_PCE      /* port change detect */
+               | INTR_UEE      /* USB error interrupt */
+               | INTR_UE;      /* USB interrupt */
+       writel(usbintr, &dev->op_regs->usbintr);
+
+       /* clear stopped bit */
+       dev->stopped = 0;
+
+       /* set controller to run */
+       usbcmd = readl(&dev->op_regs->usbcmd);
+       usbcmd |= CMD_RUNSTOP;
+       writel(usbcmd, &dev->op_regs->usbcmd);
+
+       DBG(dev, "<--- %s()\n", __func__);
+       return;
+}
+
+
+/* disable interrupt and set controller to stop state */
+static void langwell_udc_stop(struct langwell_udc *dev)
+{
+       u32     usbcmd;
+
+       DBG(dev, "---> %s()\n", __func__);
+
+       /* disable all interrupts */
+       writel(0, &dev->op_regs->usbintr);
+
+       /* set stopped bit */
+       dev->stopped = 1;
+
+       /* set controller to stop state */
+       usbcmd = readl(&dev->op_regs->usbcmd);
+       usbcmd &= ~CMD_RUNSTOP;
+       writel(usbcmd, &dev->op_regs->usbcmd);
+
+       DBG(dev, "<--- %s()\n", __func__);
+       return;
+}
+
+
+/* stop all USB activities */
+static void stop_activity(struct langwell_udc *dev,
+               struct usb_gadget_driver *driver)
+{
+       struct langwell_ep      *ep;
+       DBG(dev, "---> %s()\n", __func__);
+
+       nuke(&dev->ep[0], -ESHUTDOWN);
+
+       list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) {
+               nuke(ep, -ESHUTDOWN);
+       }
+
+       /* report disconnect; the driver is already quiesced */
+       if (driver) {
+               spin_unlock(&dev->lock);
+               driver->disconnect(&dev->gadget);
+               spin_lock(&dev->lock);
+       }
+
+       DBG(dev, "<--- %s()\n", __func__);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* device "function" sysfs attribute file */
+static ssize_t show_function(struct device *_dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct langwell_udc     *dev = the_controller;
+
+       if (!dev->driver || !dev->driver->function
+                       || strlen(dev->driver->function) > PAGE_SIZE)
+               return 0;
+
+       return scnprintf(buf, PAGE_SIZE, "%s\n", dev->driver->function);
+}
+static DEVICE_ATTR(function, S_IRUGO, show_function, NULL);
+
+
+/* device "langwell_udc" sysfs attribute file */
+static ssize_t show_langwell_udc(struct device *_dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct langwell_udc     *dev = the_controller;
+       struct langwell_request *req;
+       struct langwell_ep      *ep = NULL;
+       char                    *next;
+       unsigned                size;
+       unsigned                t;
+       unsigned                i;
+       unsigned long           flags;
+       u32                     tmp_reg;
+
+       next = buf;
+       size = PAGE_SIZE;
+       spin_lock_irqsave(&dev->lock, flags);
+
+       /* driver basic information */
+       t = scnprintf(next, size,
+                       DRIVER_DESC "\n"
+                       "%s version: %s\n"
+                       "Gadget driver: %s\n\n",
+                       driver_name, DRIVER_VERSION,
+                       dev->driver ? dev->driver->driver.name : "(none)");
+       size -= t;
+       next += t;
+
+       /* device registers */
+       tmp_reg = readl(&dev->op_regs->usbcmd);
+       t = scnprintf(next, size,
+                       "USBCMD reg:\n"
+                       "SetupTW: %d\n"
+                       "Run/Stop: %s\n\n",
+                       (tmp_reg & CMD_SUTW) ? 1 : 0,
+                       (tmp_reg & CMD_RUNSTOP) ? "Run" : "Stop");
+       size -= t;
+       next += t;
+
+       tmp_reg = readl(&dev->op_regs->usbsts);
+       t = scnprintf(next, size,
+                       "USB Status Reg:\n"
+                       "Device Suspend: %d\n"
+                       "Reset Received: %d\n"
+                       "System Error: %s\n"
+                       "USB Error Interrupt: %s\n\n",
+                       (tmp_reg & STS_SLI) ? 1 : 0,
+                       (tmp_reg & STS_URI) ? 1 : 0,
+                       (tmp_reg & STS_SEI) ? "Error" : "No error",
+                       (tmp_reg & STS_UEI) ? "Error detected" : "No error");
+       size -= t;
+       next += t;
+
+       tmp_reg = readl(&dev->op_regs->usbintr);
+       t = scnprintf(next, size,
+                       "USB Intrrupt Enable Reg:\n"
+                       "Sleep Enable: %d\n"
+                       "SOF Received Enable: %d\n"
+                       "Reset Enable: %d\n"
+                       "System Error Enable: %d\n"
+                       "Port Change Dectected Enable: %d\n"
+                       "USB Error Intr Enable: %d\n"
+                       "USB Intr Enable: %d\n\n",
+                       (tmp_reg & INTR_SLE) ? 1 : 0,
+                       (tmp_reg & INTR_SRE) ? 1 : 0,
+                       (tmp_reg & INTR_URE) ? 1 : 0,
+                       (tmp_reg & INTR_SEE) ? 1 : 0,
+                       (tmp_reg & INTR_PCE) ? 1 : 0,
+                       (tmp_reg & INTR_UEE) ? 1 : 0,
+                       (tmp_reg & INTR_UE) ? 1 : 0);
+       size -= t;
+       next += t;
+
+       tmp_reg = readl(&dev->op_regs->frindex);
+       t = scnprintf(next, size,
+                       "USB Frame Index Reg:\n"
+                       "Frame Number is 0x%08x\n\n",
+                       (tmp_reg & FRINDEX_MASK));
+       size -= t;
+       next += t;
+
+       tmp_reg = readl(&dev->op_regs->deviceaddr);
+       t = scnprintf(next, size,
+                       "USB Device Address Reg:\n"
+                       "Device Addr is 0x%x\n\n",
+                       USBADR(tmp_reg));
+       size -= t;
+       next += t;
+
+       tmp_reg = readl(&dev->op_regs->endpointlistaddr);
+       t = scnprintf(next, size,
+                       "USB Endpoint List Address Reg:\n"
+                       "Endpoint List Pointer is 0x%x\n\n",
+                       EPBASE(tmp_reg));
+       size -= t;
+       next += t;
+
+       tmp_reg = readl(&dev->op_regs->portsc1);
+       t = scnprintf(next, size,
+               "USB Port Status & Control Reg:\n"
+               "Port Reset: %s\n"
+               "Port Suspend Mode: %s\n"
+               "Over-current Change: %s\n"
+               "Port Enable/Disable Change: %s\n"
+               "Port Enabled/Disabled: %s\n"
+               "Current Connect Status: %s\n\n",
+               (tmp_reg & PORTS_PR) ? "Reset" : "Not Reset",
+               (tmp_reg & PORTS_SUSP) ? "Suspend " : "Not Suspend",
+               (tmp_reg & PORTS_OCC) ? "Detected" : "No",
+               (tmp_reg & PORTS_PEC) ? "Changed" : "Not Changed",
+               (tmp_reg & PORTS_PE) ? "Enable" : "Not Correct",
+               (tmp_reg & PORTS_CCS) ?  "Attached" : "Not Attached");
+       size -= t;
+       next += t;
+
+       tmp_reg = readl(&dev->op_regs->devlc);
+       t = scnprintf(next, size,
+               "Device LPM Control Reg:\n"
+               "Parallel Transceiver : %d\n"
+               "Serial Transceiver : %d\n"
+               "Port Speed: %s\n"
+               "Port Force Full Speed Connenct: %s\n"
+               "PHY Low Power Suspend Clock Disable: %s\n"
+               "BmAttributes: %d\n\n",
+               LPM_PTS(tmp_reg),
+               (tmp_reg & LPM_STS) ? 1 : 0,
+               ({
+                       char    *s;
+                       switch (LPM_PSPD(tmp_reg)) {
+                       case LPM_SPEED_FULL:
+                               s = "Full Speed"; break;
+                       case LPM_SPEED_LOW:
+                               s = "Low Speed"; break;
+                       case LPM_SPEED_HIGH:
+                               s = "High Speed"; break;
+                       default:
+                               s = "Unknown Speed"; break;
+                       }
+                       s;
+               }),
+               (tmp_reg & LPM_PFSC) ? "Force Full Speed" : "Not Force",
+               (tmp_reg & LPM_PHCD) ? "Disabled" : "Enabled",
+               LPM_BA(tmp_reg));
+       size -= t;
+       next += t;
+
+       tmp_reg = readl(&dev->op_regs->usbmode);
+       t = scnprintf(next, size,
+                       "USB Mode Reg:\n"
+                       "Controller Mode is : %s\n\n", ({
+                               char *s;
+                               switch (MODE_CM(tmp_reg)) {
+                               case MODE_IDLE:
+                                       s = "Idle"; break;
+                               case MODE_DEVICE:
+                                       s = "Device Controller"; break;
+                               case MODE_HOST:
+                                       s = "Host Controller"; break;
+                               default:
+                                       s = "None"; break;
+                               }
+                               s;
+                       }));
+       size -= t;
+       next += t;
+
+       tmp_reg = readl(&dev->op_regs->endptsetupstat);
+       t = scnprintf(next, size,
+                       "Endpoint Setup Status Reg:\n"
+                       "SETUP on ep 0x%04x\n\n",
+                       tmp_reg & SETUPSTAT_MASK);
+       size -= t;
+       next += t;
+
+       for (i = 0; i < dev->ep_max / 2; i++) {
+               tmp_reg = readl(&dev->op_regs->endptctrl[i]);
+               t = scnprintf(next, size, "EP Ctrl Reg [%d]: 0x%08x\n",
+                               i, tmp_reg);
+               size -= t;
+               next += t;
+       }
+       tmp_reg = readl(&dev->op_regs->endptprime);
+       t = scnprintf(next, size, "EP Prime Reg: 0x%08x\n\n", tmp_reg);
+       size -= t;
+       next += t;
+
+       /* langwell_udc, langwell_ep, langwell_request structure information */
+       ep = &dev->ep[0];
+       t = scnprintf(next, size, "%s MaxPacketSize: 0x%x, ep_num: %d\n",
+                       ep->ep.name, ep->ep.maxpacket, ep->ep_num);
+       size -= t;
+       next += t;
+
+       if (list_empty(&ep->queue)) {
+               t = scnprintf(next, size, "its req queue is empty\n\n");
+               size -= t;
+               next += t;
+       } else {
+               list_for_each_entry(req, &ep->queue, queue) {
+                       t = scnprintf(next, size,
+                               "req %p actual 0x%x length 0x%x  buf %p\n",
+                               &req->req, req->req.actual,
+                               req->req.length, req->req.buf);
+                       size -= t;
+                       next += t;
+               }
+       }
+       /* other gadget->eplist ep */
+       list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) {
+               if (ep->desc) {
+                       t = scnprintf(next, size,
+                                       "\n%s MaxPacketSize: 0x%x, "
+                                       "ep_num: %d\n",
+                                       ep->ep.name, ep->ep.maxpacket,
+                                       ep->ep_num);
+                       size -= t;
+                       next += t;
+
+                       if (list_empty(&ep->queue)) {
+                               t = scnprintf(next, size,
+                                               "its req queue is empty\n\n");
+                               size -= t;
+                               next += t;
+                       } else {
+                               list_for_each_entry(req, &ep->queue, queue) {
+                                       t = scnprintf(next, size,
+                                               "req %p actual 0x%x length "
+                                               "0x%x  buf %p\n",
+                                               &req->req, req->req.actual,
+                                               req->req.length, req->req.buf);
+                                       size -= t;
+                                       next += t;
+                               }
+                       }
+               }
+       }
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+       return PAGE_SIZE - size;
+}
+static DEVICE_ATTR(langwell_udc, S_IRUGO, show_langwell_udc, NULL);
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * when a driver is successfully registered, it will receive
+ * control requests including set_configuration(), which enables
+ * non-control requests.  then usb traffic follows until a
+ * disconnect is reported.  then a host may connect again, or
+ * the driver might get unbound.
+ */
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+       struct langwell_udc     *dev = the_controller;
+       unsigned long           flags;
+       int                     retval;
+
+       if (!dev)
+               return -ENODEV;
+
+       DBG(dev, "---> %s()\n", __func__);
+
+       if (dev->driver)
+               return -EBUSY;
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       /* hook up the driver ... */
+       driver->driver.bus = NULL;
+       dev->driver = driver;
+       dev->gadget.dev.driver = &driver->driver;
+
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       retval = driver->bind(&dev->gadget);
+       if (retval) {
+               DBG(dev, "bind to driver %s --> %d\n",
+                               driver->driver.name, retval);
+               dev->driver = NULL;
+               dev->gadget.dev.driver = NULL;
+               return retval;
+       }
+
+       retval = device_create_file(&dev->pdev->dev, &dev_attr_function);
+       if (retval)
+               goto err_unbind;
+
+       dev->usb_state = USB_STATE_ATTACHED;
+       dev->ep0_state = WAIT_FOR_SETUP;
+       dev->ep0_dir = USB_DIR_OUT;
+
+       /* enable interrupt and set controller to run state */
+       if (dev->got_irq)
+               langwell_udc_start(dev);
+
+       VDBG(dev, "After langwell_udc_start(), print all registers:\n");
+#ifdef VERBOSE
+       print_all_registers(dev);
+#endif
+
+       INFO(dev, "register driver: %s\n", driver->driver.name);
+       VDBG(dev, "<--- %s()\n", __func__);
+       return 0;
+
+err_unbind:
+       driver->unbind(&dev->gadget);
+       dev->gadget.dev.driver = NULL;
+       dev->driver = NULL;
+
+       DBG(dev, "<--- %s()\n", __func__);
+       return retval;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+
+/* unregister gadget driver */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+       struct langwell_udc     *dev = the_controller;
+       unsigned long           flags;
+
+       if (!dev)
+               return -ENODEV;
+
+       DBG(dev, "---> %s()\n", __func__);
+
+       if (unlikely(!driver || !driver->bind || !driver->unbind))
+               return -EINVAL;
+
+       /* unbind OTG transceiver */
+       if (dev->transceiver)
+               (void)otg_set_peripheral(dev->transceiver, 0);
+
+       /* disable interrupt and set controller to stop state */
+       langwell_udc_stop(dev);
+
+       dev->usb_state = USB_STATE_ATTACHED;
+       dev->ep0_state = WAIT_FOR_SETUP;
+       dev->ep0_dir = USB_DIR_OUT;
+
+       spin_lock_irqsave(&dev->lock, flags);
+
+       /* stop all usb activities */
+       dev->gadget.speed = USB_SPEED_UNKNOWN;
+       stop_activity(dev, driver);
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       /* unbind gadget driver */
+       driver->unbind(&dev->gadget);
+       dev->gadget.dev.driver = NULL;
+       dev->driver = NULL;
+
+       device_remove_file(&dev->pdev->dev, &dev_attr_function);
+
+       INFO(dev, "unregistered driver '%s'\n", driver->driver.name);
+       DBG(dev, "<--- %s()\n", __func__);
+       return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * setup tripwire is used as a semaphore to ensure that the setup data
+ * payload is extracted from a dQH without being corrupted
+ */
+static void setup_tripwire(struct langwell_udc *dev)
+{
+       u32                     usbcmd,
+                               endptsetupstat;
+       unsigned long           timeout;
+       struct langwell_dqh     *dqh;
+
+       VDBG(dev, "---> %s()\n", __func__);
+
+       /* ep0 OUT dQH */
+       dqh = &dev->ep_dqh[EP_DIR_OUT];
+
+       /* Write-Clear endptsetupstat */
+       endptsetupstat = readl(&dev->op_regs->endptsetupstat);
+       writel(endptsetupstat, &dev->op_regs->endptsetupstat);
+
+       /* wait until endptsetupstat is cleared */
+       timeout = jiffies + SETUPSTAT_TIMEOUT;
+       while (readl(&dev->op_regs->endptsetupstat)) {
+               if (time_after(jiffies, timeout)) {
+                       ERROR(dev, "setup_tripwire timeout\n");
+                       break;
+               }
+               cpu_relax();
+       }
+
+       /* while a hazard exists when setup packet arrives */
+       do {
+               /* set setup tripwire bit */
+               usbcmd = readl(&dev->op_regs->usbcmd);
+               writel(usbcmd | CMD_SUTW, &dev->op_regs->usbcmd);
+
+               /* copy the setup packet to local buffer */
+               memcpy(&dev->local_setup_buff, &dqh->dqh_setup, 8);
+       } while (!(readl(&dev->op_regs->usbcmd) & CMD_SUTW));
+
+       /* Write-Clear setup tripwire bit */
+       usbcmd = readl(&dev->op_regs->usbcmd);
+       writel(usbcmd & ~CMD_SUTW, &dev->op_regs->usbcmd);
+
+       VDBG(dev, "<--- %s()\n", __func__);
+}
+
+
+/* protocol ep0 stall, will automatically be cleared on new transaction */
+static void ep0_stall(struct langwell_udc *dev)
+{
+       u32     endptctrl;
+
+       VDBG(dev, "---> %s()\n", __func__);
+
+       /* set TX and RX to stall */
+       endptctrl = readl(&dev->op_regs->endptctrl[0]);
+       endptctrl |= EPCTRL_TXS | EPCTRL_RXS;
+       writel(endptctrl, &dev->op_regs->endptctrl[0]);
+
+       /* update ep0 state */
+       dev->ep0_state = WAIT_FOR_SETUP;
+       dev->ep0_dir = USB_DIR_OUT;
+
+       VDBG(dev, "<--- %s()\n", __func__);
+}
+
+
+/* PRIME a status phase for ep0 */
+static int prime_status_phase(struct langwell_udc *dev, int dir)
+{
+       struct langwell_request *req;
+       struct langwell_ep      *ep;
+       int                     status = 0;
+
+       VDBG(dev, "---> %s()\n", __func__);
+
+       if (dir == EP_DIR_IN)
+               dev->ep0_dir = USB_DIR_IN;
+       else
+               dev->ep0_dir = USB_DIR_OUT;
+
+       ep = &dev->ep[0];
+       dev->ep0_state = WAIT_FOR_OUT_STATUS;
+
+       req = dev->status_req;
+
+       req->ep = ep;
+       req->req.length = 0;
+       req->req.status = -EINPROGRESS;
+       req->req.actual = 0;
+       req->req.complete = NULL;
+       req->dtd_count = 0;
+
+       if (!req_to_dtd(req))
+               status = queue_dtd(ep, req);
+       else
+               return -ENOMEM;
+
+       if (status)
+               ERROR(dev, "can't queue ep0 status request\n");
+
+       list_add_tail(&req->queue, &ep->queue);
+
+       VDBG(dev, "<--- %s()\n", __func__);
+       return status;
+}
+
+
+/* SET_ADDRESS request routine */
+static void set_address(struct langwell_udc *dev, u16 value,
+               u16 index, u16 length)
+{
+       VDBG(dev, "---> %s()\n", __func__);
+
+       /* save the new address to device struct */
+       dev->dev_addr = (u8) value;
+       VDBG(dev, "dev->dev_addr = %d\n", dev->dev_addr);
+
+       /* update usb state */
+       dev->usb_state = USB_STATE_ADDRESS;
+
+       /* STATUS phase */
+       if (prime_status_phase(dev, EP_DIR_IN))
+               ep0_stall(dev);
+
+       VDBG(dev, "<--- %s()\n", __func__);
+}
+
+
+/* return endpoint by windex */
+static struct langwell_ep *get_ep_by_windex(struct langwell_udc *dev,
+               u16 wIndex)
+{
+       struct langwell_ep              *ep;
+       VDBG(dev, "---> %s()\n", __func__);
+
+       if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0)
+               return &dev->ep[0];
+
+       list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) {
+               u8      bEndpointAddress;
+               if (!ep->desc)
+                       continue;
+
+               bEndpointAddress = ep->desc->bEndpointAddress;
+               if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)
+                       continue;
+
+               if ((wIndex & USB_ENDPOINT_NUMBER_MASK)
+                       == (bEndpointAddress & USB_ENDPOINT_NUMBER_MASK))
+                       return ep;
+       }
+
+       VDBG(dev, "<--- %s()\n", __func__);
+       return NULL;
+}
+
+
+/* return whether endpoint is stalled, 0: not stalled; 1: stalled */
+static int ep_is_stall(struct langwell_ep *ep)
+{
+       struct langwell_udc     *dev = ep->dev;
+       u32                     endptctrl;
+       int                     retval;
+
+       VDBG(dev, "---> %s()\n", __func__);
+
+       endptctrl = readl(&dev->op_regs->endptctrl[ep->ep_num]);
+       if (is_in(ep))
+               retval = endptctrl & EPCTRL_TXS ? 1 : 0;
+       else
+               retval = endptctrl & EPCTRL_RXS ? 1 : 0;
+
+       VDBG(dev, "<--- %s()\n", __func__);
+       return retval;
+}
+
+
+/* GET_STATUS request routine */
+static void get_status(struct langwell_udc *dev, u8 request_type, u16 value,
+               u16 index, u16 length)
+{
+       struct langwell_request *req;
+       struct langwell_ep      *ep;
+       u16     status_data = 0;        /* 16 bits cpu view status data */
+       int     status = 0;
+
+       VDBG(dev, "---> %s()\n", __func__);
+
+       ep = &dev->ep[0];
+
+       if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
+               /* get device status */
+               status_data = 1 << USB_DEVICE_SELF_POWERED;
+               status_data |= dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP;
+       } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) {
+               /* get interface status */
+               status_data = 0;
+       } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) {
+               /* get endpoint status */
+               struct langwell_ep      *epn;
+               epn = get_ep_by_windex(dev, index);
+               /* stall if endpoint doesn't exist */
+               if (!epn)
+                       goto stall;
+
+               status_data = ep_is_stall(epn) << USB_ENDPOINT_HALT;
+       }
+
+       dev->ep0_dir = USB_DIR_IN;
+
+       /* borrow the per device status_req */
+       req = dev->status_req;
+
+       /* fill in the reqest structure */
+       *((u16 *) req->req.buf) = cpu_to_le16(status_data);
+       req->ep = ep;
+       req->req.length = 2;
+       req->req.status = -EINPROGRESS;
+       req->req.actual = 0;
+       req->req.complete = NULL;
+       req->dtd_count = 0;
+
+       /* prime the data phase */
+       if (!req_to_dtd(req))
+               status = queue_dtd(ep, req);
+       else                    /* no mem */
+               goto stall;
+
+       if (status) {
+               ERROR(dev, "response error on GET_STATUS request\n");
+               goto stall;
+       }
+
+       list_add_tail(&req->queue, &ep->queue);
+       dev->ep0_state = DATA_STATE_XMIT;
+
+       VDBG(dev, "<--- %s()\n", __func__);
+       return;
+stall:
+       ep0_stall(dev);
+       VDBG(dev, "<--- %s()\n", __func__);
+}
+
+
+/* setup packet interrupt handler */
+static void handle_setup_packet(struct langwell_udc *dev,
+               struct usb_ctrlrequest *setup)
+{
+       u16     wValue = le16_to_cpu(setup->wValue);
+       u16     wIndex = le16_to_cpu(setup->wIndex);
+       u16     wLength = le16_to_cpu(setup->wLength);
+
+       VDBG(dev, "---> %s()\n", __func__);
+
+       /* ep0 fifo flush */
+       nuke(&dev->ep[0], -ESHUTDOWN);
+
+       DBG(dev, "SETUP %02x.%02x v%04x i%04x l%04x\n",
+                       setup->bRequestType, setup->bRequest,
+                       wValue, wIndex, wLength);
+
+       /* RNDIS gadget delegate */
+       if ((setup->bRequestType == 0x21) && (setup->bRequest == 0x00)) {
+               /* USB_CDC_SEND_ENCAPSULATED_COMMAND */
+               goto delegate;
+       }
+
+       /* USB_CDC_GET_ENCAPSULATED_RESPONSE */
+       if ((setup->bRequestType == 0xa1) && (setup->bRequest == 0x01)) {
+               /* USB_CDC_GET_ENCAPSULATED_RESPONSE */
+               goto delegate;
+       }
+
+       /* We process some stardard setup requests here */
+       switch (setup->bRequest) {
+       case USB_REQ_GET_STATUS:
+               DBG(dev, "SETUP: USB_REQ_GET_STATUS\n");
+               /* get status, DATA and STATUS phase */
+               if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK))
+                                       != (USB_DIR_IN | USB_TYPE_STANDARD))
+                       break;
+               get_status(dev, setup->bRequestType, wValue, wIndex, wLength);
+               goto end;
+
+       case USB_REQ_SET_ADDRESS:
+               DBG(dev, "SETUP: USB_REQ_SET_ADDRESS\n");
+               /* STATUS phase */
+               if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD
+                                               | USB_RECIP_DEVICE))
+                       break;
+               set_address(dev, wValue, wIndex, wLength);
+               goto end;
+
+       case USB_REQ_CLEAR_FEATURE:
+       case USB_REQ_SET_FEATURE:
+               /* STATUS phase */
+       {
+               int rc = -EOPNOTSUPP;
+               if (setup->bRequest == USB_REQ_SET_FEATURE)
+                       DBG(dev, "SETUP: USB_REQ_SET_FEATURE\n");
+               else if (setup->bRequest == USB_REQ_CLEAR_FEATURE)
+                       DBG(dev, "SETUP: USB_REQ_CLEAR_FEATURE\n");
+
+               if ((setup->bRequestType & (USB_RECIP_MASK | USB_TYPE_MASK))
+                               == (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) {
+                       struct langwell_ep      *epn;
+                       epn = get_ep_by_windex(dev, wIndex);
+                       /* stall if endpoint doesn't exist */
+                       if (!epn) {
+                               ep0_stall(dev);
+                               goto end;
+                       }
+
+                       if (wValue != 0 || wLength != 0
+                                       || epn->ep_num > dev->ep_max)
+                               break;
+
+                       spin_unlock(&dev->lock);
+                       rc = langwell_ep_set_halt(&epn->ep,
+                                       (setup->bRequest == USB_REQ_SET_FEATURE)
+                                               ? 1 : 0);
+                       spin_lock(&dev->lock);
+
+               } else if ((setup->bRequestType & (USB_RECIP_MASK
+                               | USB_TYPE_MASK)) == (USB_RECIP_DEVICE
+                               | USB_TYPE_STANDARD)) {
+                       if (!gadget_is_otg(&dev->gadget))
+                               break;
+                       else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE) {
+                               dev->gadget.b_hnp_enable = 1;
+#ifdef OTG_TRANSCEIVER
+                               if (!dev->lotg->otg.default_a)
+                                       dev->lotg->hsm.b_hnp_enable = 1;
+#endif
+                       } else if (setup->bRequest == USB_DEVICE_A_HNP_SUPPORT)
+                               dev->gadget.a_hnp_support = 1;
+                       else if (setup->bRequest ==
+                                       USB_DEVICE_A_ALT_HNP_SUPPORT)
+                               dev->gadget.a_alt_hnp_support = 1;
+                       else
+                               break;
+                       rc = 0;
+               } else
+                       break;
+
+               if (rc == 0) {
+                       if (prime_status_phase(dev, EP_DIR_IN))
+                               ep0_stall(dev);
+               }
+               goto end;
+       }
+
+       case USB_REQ_GET_DESCRIPTOR:
+               DBG(dev, "SETUP: USB_REQ_GET_DESCRIPTOR\n");
+               goto delegate;
+
+       case USB_REQ_SET_DESCRIPTOR:
+               DBG(dev, "SETUP: USB_REQ_SET_DESCRIPTOR unsupported\n");
+               goto delegate;
+
+       case USB_REQ_GET_CONFIGURATION:
+               DBG(dev, "SETUP: USB_REQ_GET_CONFIGURATION\n");
+               goto delegate;
+
+       case USB_REQ_SET_CONFIGURATION:
+               DBG(dev, "SETUP: USB_REQ_SET_CONFIGURATION\n");
+               goto delegate;
+
+       case USB_REQ_GET_INTERFACE:
+               DBG(dev, "SETUP: USB_REQ_GET_INTERFACE\n");
+               goto delegate;
+
+       case USB_REQ_SET_INTERFACE:
+               DBG(dev, "SETUP: USB_REQ_SET_INTERFACE\n");
+               goto delegate;
+
+       case USB_REQ_SYNCH_FRAME:
+               DBG(dev, "SETUP: USB_REQ_SYNCH_FRAME unsupported\n");
+               goto delegate;
+
+       default:
+               /* delegate USB standard requests to the gadget driver */
+               goto delegate;
+delegate:
+               /* USB requests handled by gadget */
+               if (wLength) {
+                       /* DATA phase from gadget, STATUS phase from udc */
+                       dev->ep0_dir = (setup->bRequestType & USB_DIR_IN)
+                                       ?  USB_DIR_IN : USB_DIR_OUT;
+                       VDBG(dev, "dev->ep0_dir = 0x%x, wLength = %d\n",
+                                       dev->ep0_dir, wLength);
+                       spin_unlock(&dev->lock);
+                       if (dev->driver->setup(&dev->gadget,
+                                       &dev->local_setup_buff) < 0)
+                               ep0_stall(dev);
+                       spin_lock(&dev->lock);
+                       dev->ep0_state = (setup->bRequestType & USB_DIR_IN)
+                                       ?  DATA_STATE_XMIT : DATA_STATE_RECV;
+               } else {
+                       /* no DATA phase, IN STATUS phase from gadget */
+                       dev->ep0_dir = USB_DIR_IN;
+                       VDBG(dev, "dev->ep0_dir = 0x%x, wLength = %d\n",
+                                       dev->ep0_dir, wLength);
+                       spin_unlock(&dev->lock);
+                       if (dev->driver->setup(&dev->gadget,
+                                       &dev->local_setup_buff) < 0)
+                               ep0_stall(dev);
+                       spin_lock(&dev->lock);
+                       dev->ep0_state = WAIT_FOR_OUT_STATUS;
+               }
+               break;
+       }
+end:
+       VDBG(dev, "<--- %s()\n", __func__);
+       return;
+}
+
+
+/* transfer completion, process endpoint request and free the completed dTDs
+ * for this request
+ */
+static int process_ep_req(struct langwell_udc *dev, int index,
+               struct langwell_request *curr_req)
+{
+       struct langwell_dtd     *curr_dtd;
+       struct langwell_dqh     *curr_dqh;
+       int                     td_complete, actual, remaining_length;
+       int                     i, dir;
+       u8                      dtd_status = 0;
+       int                     retval = 0;
+
+       curr_dqh = &dev->ep_dqh[index];
+       dir = index % 2;
+
+       curr_dtd = curr_req->head;
+       td_complete = 0;
+       actual = curr_req->req.length;
+
+       VDBG(dev, "---> %s()\n", __func__);
+
+       for (i = 0; i < curr_req->dtd_count; i++) {
+               remaining_length = le16_to_cpu(curr_dtd->dtd_total);
+               actual -= remaining_length;
+
+               /* command execution states by dTD */
+               dtd_status = curr_dtd->dtd_status;
+
+               if (!dtd_status) {
+                       /* transfers completed successfully */
+                       if (!remaining_length) {
+                               td_complete++;
+                               VDBG(dev, "dTD transmitted successfully\n");
+                       } else {
+                               if (dir) {
+                                       VDBG(dev, "TX dTD remains data\n");
+                                       retval = -EPROTO;
+                                       break;
+
+                               } else {
+                                       td_complete++;
+                                       break;
+                               }
+                       }
+               } else {
+                       /* transfers completed with errors */
+                       if (dtd_status & DTD_STS_ACTIVE) {
+                               DBG(dev, "request not completed\n");
+                               retval = 1;
+                               return retval;
+                       } else if (dtd_status & DTD_STS_HALTED) {
+                               ERROR(dev, "dTD error %08x dQH[%d]\n",
+                                               dtd_status, index);
+                               /* clear the errors and halt condition */
+                               curr_dqh->dtd_status = 0;
+                               retval = -EPIPE;
+                               break;
+                       } else if (dtd_status & DTD_STS_DBE) {
+                               DBG(dev, "data buffer (overflow) error\n");
+                               retval = -EPROTO;
+                               break;
+                       } else if (dtd_status & DTD_STS_TRE) {
+                               DBG(dev, "transaction(ISO) error\n");
+                               retval = -EILSEQ;
+                               break;
+                       } else
+                               ERROR(dev, "unknown error (0x%x)!\n",
+                                               dtd_status);
+               }
+
+               if (i != curr_req->dtd_count - 1)
+                       curr_dtd = (struct langwell_dtd *)
+                               curr_dtd->next_dtd_virt;
+       }
+
+       if (retval)
+               return retval;
+
+       curr_req->req.actual = actual;
+
+       VDBG(dev, "<--- %s()\n", __func__);
+       return 0;
+}
+
+
+/* complete DATA or STATUS phase of ep0 prime status phase if needed */
+static void ep0_req_complete(struct langwell_udc *dev,
+               struct langwell_ep *ep0, struct langwell_request *req)
+{
+       u32     new_addr;
+       VDBG(dev, "---> %s()\n", __func__);
+
+       if (dev->usb_state == USB_STATE_ADDRESS) {
+               /* set the new address */
+               new_addr = (u32)dev->dev_addr;
+               writel(new_addr << USBADR_SHIFT, &dev->op_regs->deviceaddr);
+
+               new_addr = USBADR(readl(&dev->op_regs->deviceaddr));
+               VDBG(dev, "new_addr = %d\n", new_addr);
+       }
+
+       done(ep0, req, 0);
+
+       switch (dev->ep0_state) {
+       case DATA_STATE_XMIT:
+               /* receive status phase */
+               if (prime_status_phase(dev, EP_DIR_OUT))
+                       ep0_stall(dev);
+               break;
+       case DATA_STATE_RECV:
+               /* send status phase */
+               if (prime_status_phase(dev, EP_DIR_IN))
+                       ep0_stall(dev);
+               break;
+       case WAIT_FOR_OUT_STATUS:
+               dev->ep0_state = WAIT_FOR_SETUP;
+               break;
+       case WAIT_FOR_SETUP:
+               ERROR(dev, "unexpect ep0 packets\n");
+               break;
+       default:
+               ep0_stall(dev);
+               break;
+       }
+
+       VDBG(dev, "<--- %s()\n", __func__);
+}
+
+
+/* USB transfer completion interrupt */
+static void handle_trans_complete(struct langwell_udc *dev)
+{
+       u32                     complete_bits;
+       int                     i, ep_num, dir, bit_mask, status;
+       struct langwell_ep      *epn;
+       struct langwell_request *curr_req, *temp_req;
+
+       VDBG(dev, "---> %s()\n", __func__);
+
+       complete_bits = readl(&dev->op_regs->endptcomplete);
+       VDBG(dev, "endptcomplete register: 0x%08x\n", complete_bits);
+
+       /* Write-Clear the bits in endptcomplete register */
+       writel(complete_bits, &dev->op_regs->endptcomplete);
+
+       if (!complete_bits) {
+               DBG(dev, "complete_bits = 0\n");
+               goto done;
+       }
+
+       for (i = 0; i < dev->ep_max; i++) {
+               ep_num = i / 2;
+               dir = i % 2;
+
+               bit_mask = 1 << (ep_num + 16 * dir);
+
+               if (!(complete_bits & bit_mask))
+                       continue;
+
+               /* ep0 */
+               if (i == 1)
+                       epn = &dev->ep[0];
+               else
+                       epn = &dev->ep[i];
+
+               if (epn->name == NULL) {
+                       WARNING(dev, "invalid endpoint\n");
+                       continue;
+               }
+
+               if (i < 2)
+                       /* ep0 in and out */
+                       DBG(dev, "%s-%s transfer completed\n",
+                                       epn->name,
+                                       is_in(epn) ? "in" : "out");
+               else
+                       DBG(dev, "%s transfer completed\n", epn->name);
+
+               /* process the req queue until an uncomplete request */
+               list_for_each_entry_safe(curr_req, temp_req,
+                               &epn->queue, queue) {
+                       status = process_ep_req(dev, i, curr_req);
+                       VDBG(dev, "%s req status: %d\n", epn->name, status);
+
+                       if (status)
+                               break;
+
+                       /* write back status to req */
+                       curr_req->req.status = status;
+
+                       /* ep0 request completion */
+                       if (ep_num == 0) {
+                               ep0_req_complete(dev, epn, curr_req);
+                               break;
+                       } else {
+                               done(epn, curr_req, status);
+                       }
+               }
+       }
+done:
+       VDBG(dev, "<--- %s()\n", __func__);
+       return;
+}
+
+
+/* port change detect interrupt handler */
+static void handle_port_change(struct langwell_udc *dev)
+{
+       u32     portsc1, devlc;
+       u32     speed;
+
+       VDBG(dev, "---> %s()\n", __func__);
+
+       if (dev->bus_reset)
+               dev->bus_reset = 0;
+
+       portsc1 = readl(&dev->op_regs->portsc1);
+       devlc = readl(&dev->op_regs->devlc);
+       VDBG(dev, "portsc1 = 0x%08x, devlc = 0x%08x\n",
+                       portsc1, devlc);
+
+       /* bus reset is finished */
+       if (!(portsc1 & PORTS_PR)) {
+               /* get the speed */
+               speed = LPM_PSPD(devlc);
+               switch (speed) {
+               case LPM_SPEED_HIGH:
+                       dev->gadget.speed = USB_SPEED_HIGH;
+                       break;
+               case LPM_SPEED_FULL:
+                       dev->gadget.speed = USB_SPEED_FULL;
+                       break;
+               case LPM_SPEED_LOW:
+                       dev->gadget.speed = USB_SPEED_LOW;
+                       break;
+               default:
+                       dev->gadget.speed = USB_SPEED_UNKNOWN;
+                       break;
+               }
+               VDBG(dev, "speed = %d, dev->gadget.speed = %d\n",
+                               speed, dev->gadget.speed);
+       }
+
+       /* LPM L0 to L1 */
+       if (dev->lpm && dev->lpm_state == LPM_L0)
+               if (portsc1 & PORTS_SUSP && portsc1 & PORTS_SLP) {
+                               INFO(dev, "LPM L0 to L1\n");
+                               dev->lpm_state = LPM_L1;
+               }
+
+       /* LPM L1 to L0, force resume or remote wakeup finished */
+       if (dev->lpm && dev->lpm_state == LPM_L1)
+               if (!(portsc1 & PORTS_SUSP)) {
+                       if (portsc1 & PORTS_SLP)
+                               INFO(dev, "LPM L1 to L0, force resume\n");
+                       else
+                               INFO(dev, "LPM L1 to L0, remote wakeup\n");
+
+                       dev->lpm_state = LPM_L0;
+               }
+
+       /* update USB state */
+       if (!dev->resume_state)
+               dev->usb_state = USB_STATE_DEFAULT;
+
+       VDBG(dev, "<--- %s()\n", __func__);
+}
+
+
+/* USB reset interrupt handler */
+static void handle_usb_reset(struct langwell_udc *dev)
+{
+       u32             deviceaddr,
+                       endptsetupstat,
+                       endptcomplete;
+       unsigned long   timeout;
+
+       VDBG(dev, "---> %s()\n", __func__);
+
+       /* Write-Clear the device address */
+       deviceaddr = readl(&dev->op_regs->deviceaddr);
+       writel(deviceaddr & ~USBADR_MASK, &dev->op_regs->deviceaddr);
+
+       dev->dev_addr = 0;
+
+       /* clear usb state */
+       dev->resume_state = 0;
+
+       /* LPM L1 to L0, reset */
+       if (dev->lpm)
+               dev->lpm_state = LPM_L0;
+
+       dev->ep0_dir = USB_DIR_OUT;
+       dev->ep0_state = WAIT_FOR_SETUP;
+       dev->remote_wakeup = 0;         /* default to 0 on reset */
+       dev->gadget.b_hnp_enable = 0;
+       dev->gadget.a_hnp_support = 0;
+       dev->gadget.a_alt_hnp_support = 0;
+
+       /* Write-Clear all the setup token semaphores */
+       endptsetupstat = readl(&dev->op_regs->endptsetupstat);
+       writel(endptsetupstat, &dev->op_regs->endptsetupstat);
+
+       /* Write-Clear all the endpoint complete status bits */
+       endptcomplete = readl(&dev->op_regs->endptcomplete);
+       writel(endptcomplete, &dev->op_regs->endptcomplete);
+
+       /* wait until all endptprime bits cleared */
+       timeout = jiffies + PRIME_TIMEOUT;
+       while (readl(&dev->op_regs->endptprime)) {
+               if (time_after(jiffies, timeout)) {
+                       ERROR(dev, "USB reset timeout\n");
+                       break;
+               }
+               cpu_relax();
+       }
+
+       /* write 1s to endptflush register to clear any primed buffers */
+       writel((u32) ~0, &dev->op_regs->endptflush);
+
+       if (readl(&dev->op_regs->portsc1) & PORTS_PR) {
+               VDBG(dev, "USB bus reset\n");
+               /* bus is reseting */
+               dev->bus_reset = 1;
+
+               /* reset all the queues, stop all USB activities */
+               stop_activity(dev, dev->driver);
+               dev->usb_state = USB_STATE_DEFAULT;
+       } else {
+               VDBG(dev, "device controller reset\n");
+               /* controller reset */
+               langwell_udc_reset(dev);
+
+               /* reset all the queues, stop all USB activities */
+               stop_activity(dev, dev->driver);
+
+               /* reset ep0 dQH and endptctrl */
+               ep0_reset(dev);
+
+               /* enable interrupt and set controller to run state */
+               langwell_udc_start(dev);
+
+               dev->usb_state = USB_STATE_ATTACHED;
+       }
+
+#ifdef OTG_TRANSCEIVER
+       /* refer to USB OTG 6.6.2.3 b_hnp_en is cleared */
+       if (!dev->lotg->otg.default_a)
+               dev->lotg->hsm.b_hnp_enable = 0;
+#endif
+
+       VDBG(dev, "<--- %s()\n", __func__);
+}
+
+
+/* USB bus suspend/resume interrupt */
+static void handle_bus_suspend(struct langwell_udc *dev)
+{
+       u32             devlc;
+       DBG(dev, "---> %s()\n", __func__);
+
+       dev->resume_state = dev->usb_state;
+       dev->usb_state = USB_STATE_SUSPENDED;
+
+#ifdef OTG_TRANSCEIVER
+       if (dev->lotg->otg.default_a) {
+               if (dev->lotg->hsm.b_bus_suspend_vld == 1) {
+                       dev->lotg->hsm.b_bus_suspend = 1;
+                       /* notify transceiver the state changes */
+                       if (spin_trylock(&dev->lotg->wq_lock)) {
+                               langwell_update_transceiver();
+                               spin_unlock(&dev->lotg->wq_lock);
+                       }
+               }
+               dev->lotg->hsm.b_bus_suspend_vld++;
+       } else {
+               if (!dev->lotg->hsm.a_bus_suspend) {
+                       dev->lotg->hsm.a_bus_suspend = 1;
+                       /* notify transceiver the state changes */
+                       if (spin_trylock(&dev->lotg->wq_lock)) {
+                               langwell_update_transceiver();
+                               spin_unlock(&dev->lotg->wq_lock);
+                       }
+               }
+       }
+#endif
+
+       /* report suspend to the driver */
+       if (dev->driver) {
+               if (dev->driver->suspend) {
+                       spin_unlock(&dev->lock);
+                       dev->driver->suspend(&dev->gadget);
+                       spin_lock(&dev->lock);
+                       DBG(dev, "suspend %s\n", dev->driver->driver.name);
+               }
+       }
+
+       /* enter PHY low power suspend */
+       devlc = readl(&dev->op_regs->devlc);
+       VDBG(dev, "devlc = 0x%08x\n", devlc);
+       devlc |= LPM_PHCD;
+       writel(devlc, &dev->op_regs->devlc);
+
+       DBG(dev, "<--- %s()\n", __func__);
+}
+
+
+static void handle_bus_resume(struct langwell_udc *dev)
+{
+       u32             devlc;
+       DBG(dev, "---> %s()\n", __func__);
+
+       dev->usb_state = dev->resume_state;
+       dev->resume_state = 0;
+
+       /* exit PHY low power suspend */
+       devlc = readl(&dev->op_regs->devlc);
+       VDBG(dev, "devlc = 0x%08x\n", devlc);
+       devlc &= ~LPM_PHCD;
+       writel(devlc, &dev->op_regs->devlc);
+
+#ifdef OTG_TRANSCEIVER
+       if (dev->lotg->otg.default_a == 0)
+               dev->lotg->hsm.a_bus_suspend = 0;
+#endif
+
+       /* report resume to the driver */
+       if (dev->driver) {
+               if (dev->driver->resume) {
+                       spin_unlock(&dev->lock);
+                       dev->driver->resume(&dev->gadget);
+                       spin_lock(&dev->lock);
+                       DBG(dev, "resume %s\n", dev->driver->driver.name);
+               }
+       }
+
+       DBG(dev, "<--- %s()\n", __func__);
+}
+
+
+/* USB device controller interrupt handler */
+static irqreturn_t langwell_irq(int irq, void *_dev)
+{
+       struct langwell_udc     *dev = _dev;
+       u32                     usbsts,
+                               usbintr,
+                               irq_sts,
+                               portsc1;
+
+       VDBG(dev, "---> %s()\n", __func__);
+
+       if (dev->stopped) {
+               VDBG(dev, "handle IRQ_NONE\n");
+               VDBG(dev, "<--- %s()\n", __func__);
+               return IRQ_NONE;
+       }
+
+       spin_lock(&dev->lock);
+
+       /* USB status */
+       usbsts = readl(&dev->op_regs->usbsts);
+
+       /* USB interrupt enable */
+       usbintr = readl(&dev->op_regs->usbintr);
+
+       irq_sts = usbsts & usbintr;
+       VDBG(dev, "usbsts = 0x%08x, usbintr = 0x%08x, irq_sts = 0x%08x\n",
+                       usbsts, usbintr, irq_sts);
+
+       if (!irq_sts) {
+               VDBG(dev, "handle IRQ_NONE\n");
+               VDBG(dev, "<--- %s()\n", __func__);
+               spin_unlock(&dev->lock);
+               return IRQ_NONE;
+       }
+
+       /* Write-Clear interrupt status bits */
+       writel(irq_sts, &dev->op_regs->usbsts);
+
+       /* resume from suspend */
+       portsc1 = readl(&dev->op_regs->portsc1);
+       if (dev->usb_state == USB_STATE_SUSPENDED)
+               if (!(portsc1 & PORTS_SUSP))
+                       handle_bus_resume(dev);
+
+       /* USB interrupt */
+       if (irq_sts & STS_UI) {
+               VDBG(dev, "USB interrupt\n");
+
+               /* setup packet received from ep0 */
+               if (readl(&dev->op_regs->endptsetupstat)
+                               & EP0SETUPSTAT_MASK) {
+                       VDBG(dev, "USB SETUP packet received interrupt\n");
+                       /* setup tripwire semaphone */
+                       setup_tripwire(dev);
+                       handle_setup_packet(dev, &dev->local_setup_buff);
+               }
+
+               /* USB transfer completion */
+               if (readl(&dev->op_regs->endptcomplete)) {
+                       VDBG(dev, "USB transfer completion interrupt\n");
+                       handle_trans_complete(dev);
+               }
+       }
+
+       /* SOF received interrupt (for ISO transfer) */
+       if (irq_sts & STS_SRI) {
+               /* FIXME */
+               /* VDBG(dev, "SOF received interrupt\n"); */
+       }
+
+       /* port change detect interrupt */
+       if (irq_sts & STS_PCI) {
+               VDBG(dev, "port change detect interrupt\n");
+               handle_port_change(dev);
+       }
+
+       /* suspend interrrupt */
+       if (irq_sts & STS_SLI) {
+               VDBG(dev, "suspend interrupt\n");
+               handle_bus_suspend(dev);
+       }
+
+       /* USB reset interrupt */
+       if (irq_sts & STS_URI) {
+               VDBG(dev, "USB reset interrupt\n");
+               handle_usb_reset(dev);
+       }
+
+       /* USB error or system error interrupt */
+       if (irq_sts & (STS_UEI | STS_SEI)) {
+               /* FIXME */
+               WARNING(dev, "error IRQ, irq_sts: %x\n", irq_sts);
+       }
+
+       spin_unlock(&dev->lock);
+
+       VDBG(dev, "<--- %s()\n", __func__);
+       return IRQ_HANDLED;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/* release device structure */
+static void gadget_release(struct device *_dev)
+{
+       struct langwell_udc     *dev = the_controller;
+
+       DBG(dev, "---> %s()\n", __func__);
+
+       complete(dev->done);
+
+       DBG(dev, "<--- %s()\n", __func__);
+       kfree(dev);
+}
+
+
+/* tear down the binding between this driver and the pci device */
+static void langwell_udc_remove(struct pci_dev *pdev)
+{
+       struct langwell_udc     *dev = the_controller;
+
+       DECLARE_COMPLETION(done);
+
+       BUG_ON(dev->driver);
+       DBG(dev, "---> %s()\n", __func__);
+
+       dev->done = &done;
+
+       /* free memory allocated in probe */
+       if (dev->dtd_pool)
+               dma_pool_destroy(dev->dtd_pool);
+
+       if (dev->status_req) {
+               kfree(dev->status_req->req.buf);
+               kfree(dev->status_req);
+       }
+
+       if (dev->ep_dqh)
+               dma_free_coherent(&pdev->dev, dev->ep_dqh_size,
+                       dev->ep_dqh, dev->ep_dqh_dma);
+
+       kfree(dev->ep);
+
+       /* diable IRQ handler */
+       if (dev->got_irq)
+               free_irq(pdev->irq, dev);
+
+#ifndef        OTG_TRANSCEIVER
+       if (dev->cap_regs)
+               iounmap(dev->cap_regs);
+
+       if (dev->region)
+               release_mem_region(pci_resource_start(pdev, 0),
+                               pci_resource_len(pdev, 0));
+
+       if (dev->enabled)
+               pci_disable_device(pdev);
+#else
+       if (dev->transceiver) {
+               otg_put_transceiver(dev->transceiver);
+               dev->transceiver = NULL;
+               dev->lotg = NULL;
+       }
+#endif
+
+       dev->cap_regs = NULL;
+
+       INFO(dev, "unbind\n");
+       DBG(dev, "<--- %s()\n", __func__);
+
+       device_unregister(&dev->gadget.dev);
+       device_remove_file(&pdev->dev, &dev_attr_langwell_udc);
+
+#ifndef        OTG_TRANSCEIVER
+       pci_set_drvdata(pdev, NULL);
+#endif
+
+       /* free dev, wait for the release() finished */
+       wait_for_completion(&done);
+
+       the_controller = NULL;
+}
+
+
+/*
+ * wrap this driver around the specified device, but
+ * don't respond over USB until a gadget driver binds to us.
+ */
+static int langwell_udc_probe(struct pci_dev *pdev,
+               const struct pci_device_id *id)
+{
+       struct langwell_udc     *dev;
+#ifndef        OTG_TRANSCEIVER
+       unsigned long           resource, len;
+#endif
+       void                    __iomem *base = NULL;
+       size_t                  size;
+       int                     retval;
+
+       if (the_controller) {
+               dev_warn(&pdev->dev, "ignoring\n");
+               return -EBUSY;
+       }
+
+       /* alloc, and start init */
+       dev = kzalloc(sizeof *dev, GFP_KERNEL);
+       if (dev == NULL) {
+               retval = -ENOMEM;
+               goto error;
+       }
+
+       /* initialize device spinlock */
+       spin_lock_init(&dev->lock);
+
+       dev->pdev = pdev;
+       DBG(dev, "---> %s()\n", __func__);
+
+#ifdef OTG_TRANSCEIVER
+       /* PCI device is already enabled by otg_transceiver driver */
+       dev->enabled = 1;
+
+       /* mem region and register base */
+       dev->region = 1;
+       dev->transceiver = otg_get_transceiver();
+       dev->lotg = otg_to_langwell(dev->transceiver);
+       base = dev->lotg->regs;
+#else
+       pci_set_drvdata(pdev, dev);
+
+       /* now all the pci goodies ... */
+       if (pci_enable_device(pdev) < 0) {
+               retval = -ENODEV;
+               goto error;
+       }
+       dev->enabled = 1;
+
+       /* control register: BAR 0 */
+       resource = pci_resource_start(pdev, 0);
+       len = pci_resource_len(pdev, 0);
+       if (!request_mem_region(resource, len, driver_name)) {
+               ERROR(dev, "controller already in use\n");
+               retval = -EBUSY;
+               goto error;
+       }
+       dev->region = 1;
+
+       base = ioremap_nocache(resource, len);
+#endif
+       if (base == NULL) {
+               ERROR(dev, "can't map memory\n");
+               retval = -EFAULT;
+               goto error;
+       }
+
+       dev->cap_regs = (struct langwell_cap_regs __iomem *) base;
+       VDBG(dev, "dev->cap_regs: %p\n", dev->cap_regs);
+       dev->op_regs = (struct langwell_op_regs __iomem *)
+               (base + OP_REG_OFFSET);
+       VDBG(dev, "dev->op_regs: %p\n", dev->op_regs);
+
+       /* irq setup after old hardware is cleaned up */
+       if (!pdev->irq) {
+               ERROR(dev, "No IRQ. Check PCI setup!\n");
+               retval = -ENODEV;
+               goto error;
+       }
+
+#ifndef        OTG_TRANSCEIVER
+       INFO(dev, "irq %d, io mem: 0x%08lx, len: 0x%08lx, pci mem 0x%p\n",
+                       pdev->irq, resource, len, base);
+       /* enables bus-mastering for device dev */
+       pci_set_master(pdev);
+
+       if (request_irq(pdev->irq, langwell_irq, IRQF_SHARED,
+                               driver_name, dev) != 0) {
+               ERROR(dev, "request interrupt %d failed\n", pdev->irq);
+               retval = -EBUSY;
+               goto error;
+       }
+       dev->got_irq = 1;
+#endif
+
+       /* set stopped bit */
+       dev->stopped = 1;
+
+       /* capabilities and endpoint number */
+       dev->lpm = (readl(&dev->cap_regs->hccparams) & HCC_LEN) ? 1 : 0;
+       dev->dciversion = readw(&dev->cap_regs->dciversion);
+       dev->devcap = (readl(&dev->cap_regs->dccparams) & DEVCAP) ? 1 : 0;
+       VDBG(dev, "dev->lpm: %d\n", dev->lpm);
+       VDBG(dev, "dev->dciversion: 0x%04x\n", dev->dciversion);
+       VDBG(dev, "dccparams: 0x%08x\n", readl(&dev->cap_regs->dccparams));
+       VDBG(dev, "dev->devcap: %d\n", dev->devcap);
+       if (!dev->devcap) {
+               ERROR(dev, "can't support device mode\n");
+               retval = -ENODEV;
+               goto error;
+       }
+
+       /* a pair of endpoints (out/in) for each address */
+       dev->ep_max = DEN(readl(&dev->cap_regs->dccparams)) * 2;
+       VDBG(dev, "dev->ep_max: %d\n", dev->ep_max);
+
+       /* allocate endpoints memory */
+       dev->ep = kzalloc(sizeof(struct langwell_ep) * dev->ep_max,
+                       GFP_KERNEL);
+       if (!dev->ep) {
+               ERROR(dev, "allocate endpoints memory failed\n");
+               retval = -ENOMEM;
+               goto error;
+       }
+
+       /* allocate device dQH memory */
+       size = dev->ep_max * sizeof(struct langwell_dqh);
+       VDBG(dev, "orig size = %d\n", size);
+       if (size < DQH_ALIGNMENT)
+               size = DQH_ALIGNMENT;
+       else if ((size % DQH_ALIGNMENT) != 0) {
+               size += DQH_ALIGNMENT + 1;
+               size &= ~(DQH_ALIGNMENT - 1);
+       }
+       dev->ep_dqh = dma_alloc_coherent(&pdev->dev, size,
+                                       &dev->ep_dqh_dma, GFP_KERNEL);
+       if (!dev->ep_dqh) {
+               ERROR(dev, "allocate dQH memory failed\n");
+               retval = -ENOMEM;
+               goto error;
+       }
+       dev->ep_dqh_size = size;
+       VDBG(dev, "ep_dqh_size = %d\n", dev->ep_dqh_size);
+
+       /* initialize ep0 status request structure */
+       dev->status_req = kzalloc(sizeof(struct langwell_request), GFP_KERNEL);
+       if (!dev->status_req) {
+               ERROR(dev, "allocate status_req memory failed\n");
+               retval = -ENOMEM;
+               goto error;
+       }
+       INIT_LIST_HEAD(&dev->status_req->queue);
+
+       /* allocate a small amount of memory to get valid address */
+       dev->status_req->req.buf = kmalloc(8, GFP_KERNEL);
+       dev->status_req->req.dma = virt_to_phys(dev->status_req->req.buf);
+
+       dev->resume_state = USB_STATE_NOTATTACHED;
+       dev->usb_state = USB_STATE_POWERED;
+       dev->ep0_dir = USB_DIR_OUT;
+       dev->remote_wakeup = 0; /* default to 0 on reset */
+
+#ifndef        OTG_TRANSCEIVER
+       /* reset device controller */
+       langwell_udc_reset(dev);
+#endif
+
+       /* initialize gadget structure */
+       dev->gadget.ops = &langwell_ops;        /* usb_gadget_ops */
+       dev->gadget.ep0 = &dev->ep[0].ep;       /* gadget ep0 */
+       INIT_LIST_HEAD(&dev->gadget.ep_list);   /* ep_list */
+       dev->gadget.speed = USB_SPEED_UNKNOWN;  /* speed */
+       dev->gadget.is_dualspeed = 1;           /* support dual speed */
+#ifdef OTG_TRANSCEIVER
+       dev->gadget.is_otg = 1;                 /* support otg mode */
+#endif
+
+       /* the "gadget" abstracts/virtualizes the controller */
+       dev_set_name(&dev->gadget.dev, "gadget");
+       dev->gadget.dev.parent = &pdev->dev;
+       dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
+       dev->gadget.dev.release = gadget_release;
+       dev->gadget.name = driver_name;         /* gadget name */
+
+       /* controller endpoints reinit */
+       eps_reinit(dev);
+
+#ifndef        OTG_TRANSCEIVER
+       /* reset ep0 dQH and endptctrl */
+       ep0_reset(dev);
+#endif
+
+       /* create dTD dma_pool resource */
+       dev->dtd_pool = dma_pool_create("langwell_dtd",
+                       &dev->pdev->dev,
+                       sizeof(struct langwell_dtd),
+                       DTD_ALIGNMENT,
+                       DMA_BOUNDARY);
+
+       if (!dev->dtd_pool) {
+               retval = -ENOMEM;
+               goto error;
+       }
+
+       /* done */
+       INFO(dev, "%s\n", driver_desc);
+       INFO(dev, "irq %d, pci mem %p\n", pdev->irq, base);
+       INFO(dev, "Driver version: " DRIVER_VERSION "\n");
+       INFO(dev, "Support (max) %d endpoints\n", dev->ep_max);
+       INFO(dev, "Device interface version: 0x%04x\n", dev->dciversion);
+       INFO(dev, "Controller mode: %s\n", dev->devcap ? "Device" : "Host");
+       INFO(dev, "Support USB LPM: %s\n", dev->lpm ? "Yes" : "No");
+
+       VDBG(dev, "After langwell_udc_probe(), print all registers:\n");
+#ifdef VERBOSE
+       print_all_registers(dev);
+#endif
+
+       the_controller = dev;
+
+       retval = device_register(&dev->gadget.dev);
+       if (retval)
+               goto error;
+
+       retval = device_create_file(&pdev->dev, &dev_attr_langwell_udc);
+       if (retval)
+               goto error;
+
+       VDBG(dev, "<--- %s()\n", __func__);
+       return 0;
+
+error:
+       if (dev) {
+               DBG(dev, "<--- %s()\n", __func__);
+               langwell_udc_remove(pdev);
+       }
+
+       return retval;
+}
+
+
+/* device controller suspend */
+static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct langwell_udc     *dev = the_controller;
+       u32                     devlc;
+
+       DBG(dev, "---> %s()\n", __func__);
+
+       /* disable interrupt and set controller to stop state */
+       langwell_udc_stop(dev);
+
+       /* diable IRQ handler */
+       if (dev->got_irq)
+               free_irq(pdev->irq, dev);
+       dev->got_irq = 0;
+
+
+       /* save PCI state */
+       pci_save_state(pdev);
+
+       /* set device power state */
+       pci_set_power_state(pdev, PCI_D3hot);
+
+       /* enter PHY low power suspend */
+       devlc = readl(&dev->op_regs->devlc);
+       VDBG(dev, "devlc = 0x%08x\n", devlc);
+       devlc |= LPM_PHCD;
+       writel(devlc, &dev->op_regs->devlc);
+
+       DBG(dev, "<--- %s()\n", __func__);
+       return 0;
+}
+
+
+/* device controller resume */
+static int langwell_udc_resume(struct pci_dev *pdev)
+{
+       struct langwell_udc     *dev = the_controller;
+       u32                     devlc;
+
+       DBG(dev, "---> %s()\n", __func__);
+
+       /* exit PHY low power suspend */
+       devlc = readl(&dev->op_regs->devlc);
+       VDBG(dev, "devlc = 0x%08x\n", devlc);
+       devlc &= ~LPM_PHCD;
+       writel(devlc, &dev->op_regs->devlc);
+
+       /* set device D0 power state */
+       pci_set_power_state(pdev, PCI_D0);
+
+       /* restore PCI state */
+       pci_restore_state(pdev);
+
+       /* enable IRQ handler */
+       if (request_irq(pdev->irq, langwell_irq, IRQF_SHARED, driver_name, dev)
+                       != 0) {
+               ERROR(dev, "request interrupt %d failed\n", pdev->irq);
+               return -1;
+       }
+       dev->got_irq = 1;
+
+       /* reset and start controller to run state */
+       if (dev->stopped) {
+               /* reset device controller */
+               langwell_udc_reset(dev);
+
+               /* reset ep0 dQH and endptctrl */
+               ep0_reset(dev);
+
+               /* start device if gadget is loaded */
+               if (dev->driver)
+                       langwell_udc_start(dev);
+       }
+
+       /* reset USB status */
+       dev->usb_state = USB_STATE_ATTACHED;
+       dev->ep0_state = WAIT_FOR_SETUP;
+       dev->ep0_dir = USB_DIR_OUT;
+
+       DBG(dev, "<--- %s()\n", __func__);
+       return 0;
+}
+
+
+/* pci driver shutdown */
+static void langwell_udc_shutdown(struct pci_dev *pdev)
+{
+       struct langwell_udc     *dev = the_controller;
+       u32                     usbmode;
+
+       DBG(dev, "---> %s()\n", __func__);
+
+       /* reset controller mode to IDLE */
+       usbmode = readl(&dev->op_regs->usbmode);
+       DBG(dev, "usbmode = 0x%08x\n", usbmode);
+       usbmode &= (~3 | MODE_IDLE);
+       writel(usbmode, &dev->op_regs->usbmode);
+
+       DBG(dev, "<--- %s()\n", __func__);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct pci_device_id pci_ids[] = { {
+       .class =        ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+       .class_mask =   ~0,
+       .vendor =       0x8086,
+       .device =       0x0811,
+       .subvendor =    PCI_ANY_ID,
+       .subdevice =    PCI_ANY_ID,
+}, { /* end: all zeroes */ }
+};
+
+
+MODULE_DEVICE_TABLE(pci, pci_ids);
+
+
+static struct pci_driver langwell_pci_driver = {
+       .name =         (char *) driver_name,
+       .id_table =     pci_ids,
+
+       .probe =        langwell_udc_probe,
+       .remove =       langwell_udc_remove,
+
+       /* device controller suspend/resume */
+       .suspend =      langwell_udc_suspend,
+       .resume =       langwell_udc_resume,
+
+       .shutdown =     langwell_udc_shutdown,
+};
+
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Xiaochen Shen <xiaochen.shen@intel.com>");
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
+
+static int __init init(void)
+{
+#ifdef OTG_TRANSCEIVER
+       return langwell_register_peripheral(&langwell_pci_driver);
+#else
+       return pci_register_driver(&langwell_pci_driver);
+#endif
+}
+module_init(init);
+
+
+static void __exit cleanup(void)
+{
+#ifdef OTG_TRANSCEIVER
+       return langwell_unregister_peripheral(&langwell_pci_driver);
+#else
+       pci_unregister_driver(&langwell_pci_driver);
+#endif
+}
+module_exit(cleanup);
+
diff --git a/drivers/usb/gadget/langwell_udc.h b/drivers/usb/gadget/langwell_udc.h
new file mode 100644 (file)
index 0000000..9719934
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Intel Langwell USB Device Controller driver
+ * Copyright (C) 2008-2009, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/usb/langwell_udc.h>
+
+#if defined(CONFIG_USB_LANGWELL_OTG)
+#include <linux/usb/langwell_otg.h>
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+
+/* driver data structures and utilities */
+
+/*
+ * dTD: Device Endpoint Transfer Descriptor
+ * describe to the device controller the location and quantity of
+ * data to be send/received for given transfer
+ */
+struct langwell_dtd {
+       u32     dtd_next;
+/* bits 31:5, next transfer element pointer */
+#define        DTD_NEXT(d)     (((d)>>5)&0x7ffffff)
+#define        DTD_NEXT_MASK   (0x7ffffff << 5)
+/* terminate */
+#define        DTD_TERM        BIT(0)
+       /* bits 7:0, execution back states */
+       u32     dtd_status:8;
+#define        DTD_STATUS(d)   (((d)>>0)&0xff)
+#define        DTD_STS_ACTIVE  BIT(7)  /* active */
+#define        DTD_STS_HALTED  BIT(6)  /* halted */
+#define        DTD_STS_DBE     BIT(5)  /* data buffer error */
+#define        DTD_STS_TRE     BIT(3)  /* transaction error  */
+       /* bits 9:8 */
+       u32     dtd_res0:2;
+       /* bits 11:10, multipier override */
+       u32     dtd_multo:2;
+#define        DTD_MULTO       (BIT(11) | BIT(10))
+       /* bits 14:12 */
+       u32     dtd_res1:3;
+       /* bit 15, interrupt on complete */
+       u32     dtd_ioc:1;
+#define        DTD_IOC         BIT(15)
+       /* bits 30:16, total bytes */
+       u32     dtd_total:15;
+#define        DTD_TOTAL(d)    (((d)>>16)&0x7fff)
+#define        DTD_MAX_TRANSFER_LENGTH 0x4000
+       /* bit 31 */
+       u32     dtd_res2:1;
+       /* dTD buffer pointer page 0 to 4 */
+       u32     dtd_buf[5];
+#define        DTD_OFFSET_MASK 0xfff
+/* bits 31:12, buffer pointer */
+#define        DTD_BUFFER(d)   (((d)>>12)&0x3ff)
+/* bits 11:0, current offset */
+#define        DTD_C_OFFSET(d) (((d)>>0)&0xfff)
+/* bits 10:0, frame number */
+#define        DTD_FRAME(d)    (((d)>>0)&0x7ff)
+
+       /* driver-private parts */
+
+       /* dtd dma address */
+       dma_addr_t              dtd_dma;
+       /* next dtd virtual address */
+       struct langwell_dtd     *next_dtd_virt;
+};
+
+
+/*
+ * dQH: Device Endpoint Queue Head
+ * describe where all transfers are managed
+ * 48-byte data structure, aligned on 64-byte boundary
+ *
+ * These are associated with dTD structure
+ */
+struct langwell_dqh {
+       /* endpoint capabilities and characteristics */
+       u32     dqh_res0:15;    /* bits 14:0 */
+       u32     dqh_ios:1;      /* bit 15, interrupt on setup */
+#define        DQH_IOS         BIT(15)
+       u32     dqh_mpl:11;     /* bits 26:16, maximum packet length */
+#define        DQH_MPL         (0x7ff << 16)
+       u32     dqh_res1:2;     /* bits 28:27 */
+       u32     dqh_zlt:1;      /* bit 29, zero length termination */
+#define        DQH_ZLT         BIT(29)
+       u32     dqh_mult:2;     /* bits 31:30 */
+#define        DQH_MULT        (BIT(30) | BIT(31))
+
+       /* current dTD pointer */
+       u32     dqh_current;    /* locate the transfer in progress */
+#define DQH_C_DTD(e)   \
+       (((e)>>5)&0x7ffffff)    /* bits 31:5, current dTD pointer */
+
+       /* transfer overlay, hardware parts of a struct langwell_dtd */
+       u32     dtd_next;
+       u32     dtd_status:8;   /* bits 7:0, execution back states */
+       u32     dtd_res0:2;     /* bits 9:8 */
+       u32     dtd_multo:2;    /* bits 11:10, multipier override */
+       u32     dtd_res1:3;     /* bits 14:12 */
+       u32     dtd_ioc:1;      /* bit 15, interrupt on complete */
+       u32     dtd_total:15;   /* bits 30:16, total bytes */
+       u32     dtd_res2:1;     /* bit 31 */
+       u32     dtd_buf[5];     /* dTD buffer pointer page 0 to 4 */
+
+       u32     dqh_res2;
+       struct usb_ctrlrequest  dqh_setup;      /* setup packet buffer */
+} __attribute__ ((aligned(64)));
+
+
+/* endpoint data structure */
+struct langwell_ep {
+       struct usb_ep           ep;
+       dma_addr_t              dma;
+       struct langwell_udc     *dev;
+       unsigned long           irqs;
+       struct list_head        queue;
+       struct langwell_dqh     *dqh;
+       const struct usb_endpoint_descriptor    *desc;
+       char                    name[14];
+       unsigned                stopped:1,
+                               ep_type:2,
+                               ep_num:8;
+};
+
+
+/* request data structure */
+struct langwell_request {
+       struct usb_request      req;
+       struct langwell_dtd     *dtd, *head, *tail;
+       struct langwell_ep      *ep;
+       dma_addr_t              dtd_dma;
+       struct list_head        queue;
+       unsigned                dtd_count;
+       unsigned                mapped:1;
+};
+
+
+/* ep0 transfer state */
+enum ep0_state {
+       WAIT_FOR_SETUP,
+       DATA_STATE_XMIT,
+       DATA_STATE_NEED_ZLP,
+       WAIT_FOR_OUT_STATUS,
+       DATA_STATE_RECV,
+};
+
+
+/* device suspend state */
+enum lpm_state {
+       LPM_L0, /* on */
+       LPM_L1, /* LPM L1 sleep */
+       LPM_L2, /* suspend */
+       LPM_L3, /* off */
+};
+
+
+/* device data structure */
+struct langwell_udc {
+       /* each pci device provides one gadget, several endpoints */
+       struct usb_gadget       gadget;
+       spinlock_t              lock;   /* device lock */
+       struct langwell_ep      *ep;
+       struct usb_gadget_driver        *driver;
+       struct otg_transceiver  *transceiver;
+       u8                      dev_addr;
+       u32                     usb_state;
+       u32                     resume_state;
+       u32                     bus_reset;
+       enum lpm_state          lpm_state;
+       enum ep0_state          ep0_state;
+       u32                     ep0_dir;
+       u16                     dciversion;
+       unsigned                ep_max;
+       unsigned                devcap:1,
+                               enabled:1,
+                               region:1,
+                               got_irq:1,
+                               powered:1,
+                               remote_wakeup:1,
+                               rate:1,
+                               is_reset:1,
+                               softconnected:1,
+                               vbus_active:1,
+                               suspended:1,
+                               stopped:1,
+                               lpm:1;  /* LPM capability */
+
+       /* pci state used to access those endpoints */
+       struct pci_dev          *pdev;
+
+       /* Langwell otg transceiver */
+       struct langwell_otg     *lotg;
+
+       /* control registers */
+       struct langwell_cap_regs        __iomem *cap_regs;
+       struct langwell_op_regs         __iomem *op_regs;
+
+       struct usb_ctrlrequest  local_setup_buff;
+       struct langwell_dqh     *ep_dqh;
+       size_t                  ep_dqh_size;
+       dma_addr_t              ep_dqh_dma;
+
+       /* ep0 status request */
+       struct langwell_request *status_req;
+
+       /* dma pool */
+       struct dma_pool         *dtd_pool;
+
+       /* make sure release() is done */
+       struct completion       *done;
+};
+
index 8cc676ecbb23ca28f2200575271be80e7b83faee..1937d8c7b433201dc0d31474f99014fc25ce2f04 100644 (file)
@@ -38,7 +38,6 @@
 #include <linux/usb.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
-#include <mach/pxa2xx-regs.h> /* FIXME: for PSSR */
 #include <mach/udc.h>
 
 #include "pxa27x_udc.h"
@@ -473,6 +472,23 @@ static inline void udc_clear_mask_UDCCR(struct pxa_udc *udc, int mask)
                        (udccr & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS));
 }
 
+/**
+ * ep_write_UDCCSR - set bits in UDCCSR
+ * @udc: udc device
+ * @mask: bits to set in UDCCR
+ *
+ * Sets bits in UDCCSR (UDCCSR0 and UDCCSR*).
+ *
+ * A specific case is applied to ep0 : the ACM bit is always set to 1, for
+ * SET_INTERFACE and SET_CONFIGURATION.
+ */
+static inline void ep_write_UDCCSR(struct pxa_ep *ep, int mask)
+{
+       if (is_ep0(ep))
+               mask |= UDCCSR0_ACM;
+       udc_ep_writel(ep, UDCCSR, mask);
+}
+
 /**
  * ep_count_bytes_remain - get how many bytes in udc endpoint
  * @ep: udc endpoint
@@ -861,7 +877,7 @@ static int read_packet(struct pxa_ep *ep, struct pxa27x_request *req)
                *buf++ = udc_ep_readl(ep, UDCDR);
        req->req.actual += count;
 
-       udc_ep_writel(ep, UDCCSR, UDCCSR_PC);
+       ep_write_UDCCSR(ep, UDCCSR_PC);
 
        return count;
 }
@@ -969,12 +985,12 @@ static int write_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
                if (udccsr & UDCCSR_PC) {
                        ep_vdbg(ep, "Clearing Transmit Complete, udccsr=%x\n",
                                udccsr);
-                       udc_ep_writel(ep, UDCCSR, UDCCSR_PC);
+                       ep_write_UDCCSR(ep, UDCCSR_PC);
                }
                if (udccsr & UDCCSR_TRN) {
                        ep_vdbg(ep, "Clearing Underrun on, udccsr=%x\n",
                                udccsr);
-                       udc_ep_writel(ep, UDCCSR, UDCCSR_TRN);
+                       ep_write_UDCCSR(ep, UDCCSR_TRN);
                }
 
                count = write_packet(ep, req, max);
@@ -996,7 +1012,7 @@ static int write_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
                }
 
                if (is_short)
-                       udc_ep_writel(ep, UDCCSR, UDCCSR_SP);
+                       ep_write_UDCCSR(ep, UDCCSR_SP);
 
                /* requests complete when all IN data is in the FIFO */
                if (is_last) {
@@ -1029,7 +1045,7 @@ static int read_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
 
        while (epout_has_pkt(ep)) {
                count = read_packet(ep, req);
-               udc_ep_writel(ep, UDCCSR, UDCCSR0_OPC);
+               ep_write_UDCCSR(ep, UDCCSR0_OPC);
                inc_ep_stats_bytes(ep, count, !USB_DIR_IN);
 
                is_short = (count < ep->fifo_size);
@@ -1074,7 +1090,7 @@ static int write_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
 
        /* Sends either a short packet or a 0 length packet */
        if (unlikely(is_short))
-               udc_ep_writel(ep, UDCCSR, UDCCSR0_IPR);
+               ep_write_UDCCSR(ep, UDCCSR0_IPR);
 
        ep_dbg(ep, "in %d bytes%s%s, %d left, req=%p, udccsr0=0x%03x\n",
                count, is_short ? "/S" : "", is_last ? "/L" : "",
@@ -1277,7 +1293,7 @@ static int pxa_ep_set_halt(struct usb_ep *_ep, int value)
 
        /* FST, FEF bits are the same for control and non control endpoints */
        rc = 0;
-       udc_ep_writel(ep, UDCCSR, UDCCSR_FST | UDCCSR_FEF);
+       ep_write_UDCCSR(ep, UDCCSR_FST | UDCCSR_FEF);
        if (is_ep0(ep))
                set_ep0state(ep->dev, STALL);
 
@@ -1343,7 +1359,7 @@ static void pxa_ep_fifo_flush(struct usb_ep *_ep)
                        udc_ep_readl(ep, UDCDR);
        } else {
                /* most IN status is the same, but ISO can't stall */
-               udc_ep_writel(ep, UDCCSR,
+               ep_write_UDCCSR(ep,
                                UDCCSR_PC | UDCCSR_FEF | UDCCSR_TRN
                                | (EPXFERTYPE_is_ISO(ep) ? 0 : UDCCSR_SST));
        }
@@ -1728,6 +1744,7 @@ static void udc_enable(struct pxa_udc *udc)
        memset(&udc->stats, 0, sizeof(udc->stats));
 
        udc_set_mask_UDCCR(udc, UDCCR_UDE);
+       ep_write_UDCCSR(&udc->pxa_ep[0], UDCCSR0_ACM);
        udelay(2);
        if (udc_readl(udc, UDCCR) & UDCCR_EMCE)
                dev_err(udc->dev, "Configuration errors, udc disabled\n");
@@ -1893,6 +1910,15 @@ static void handle_ep0_ctrl_req(struct pxa_udc *udc,
 
        nuke(ep, -EPROTO);
 
+       /*
+        * In the PXA320 manual, in the section about Back-to-Back setup
+        * packets, it describes this situation.  The solution is to set OPC to
+        * get rid of the status packet, and then continue with the setup
+        * packet. Generalize to pxa27x CPUs.
+        */
+       if (epout_has_pkt(ep) && (ep_count_bytes_remain(ep) == 0))
+               ep_write_UDCCSR(ep, UDCCSR0_OPC);
+
        /* read SETUP packet */
        for (i = 0; i < 2; i++) {
                if (unlikely(ep_is_empty(ep)))
@@ -1919,7 +1945,7 @@ static void handle_ep0_ctrl_req(struct pxa_udc *udc,
                set_ep0state(udc, OUT_DATA_STAGE);
 
        /* Tell UDC to enter Data Stage */
-       udc_ep_writel(ep, UDCCSR, UDCCSR0_SA | UDCCSR0_OPC);
+       ep_write_UDCCSR(ep, UDCCSR0_SA | UDCCSR0_OPC);
 
        i = udc->driver->setup(&udc->gadget, &u.r);
        if (i < 0)
@@ -1929,7 +1955,7 @@ out:
 stall:
        ep_dbg(ep, "protocol STALL, udccsr0=%03x err %d\n",
                udc_ep_readl(ep, UDCCSR), i);
-       udc_ep_writel(ep, UDCCSR, UDCCSR0_FST | UDCCSR0_FTF);
+       ep_write_UDCCSR(ep, UDCCSR0_FST | UDCCSR0_FTF);
        set_ep0state(udc, STALL);
        goto out;
 }
@@ -1966,6 +1992,8 @@ stall:
  *     cleared by software.
  *   - clearing UDCCSR0_OPC always flushes ep0. If in setup stage, never do it
  *     before reading ep0.
+ *     This is true only for PXA27x. This is not true anymore for PXA3xx family
+ *     (check Back-to-Back setup packet in developers guide).
  *   - irq can be called on a "packet complete" event (opc_irq=1), while
  *     UDCCSR0_OPC is not yet raised (delta can be as big as 100ms
  *     from experimentation).
@@ -1998,7 +2026,7 @@ static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq)
        if (udccsr0 & UDCCSR0_SST) {
                ep_dbg(ep, "clearing stall status\n");
                nuke(ep, -EPIPE);
-               udc_ep_writel(ep, UDCCSR, UDCCSR0_SST);
+               ep_write_UDCCSR(ep, UDCCSR0_SST);
                ep0_idle(udc);
        }
 
@@ -2023,7 +2051,7 @@ static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq)
                break;
        case IN_DATA_STAGE:                     /* GET_DESCRIPTOR */
                if (epout_has_pkt(ep))
-                       udc_ep_writel(ep, UDCCSR, UDCCSR0_OPC);
+                       ep_write_UDCCSR(ep, UDCCSR0_OPC);
                if (req && !ep_is_full(ep))
                        completed = write_ep0_fifo(ep, req);
                if (completed)
@@ -2036,7 +2064,7 @@ static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq)
                        ep0_end_out_req(ep, req);
                break;
        case STALL:
-               udc_ep_writel(ep, UDCCSR, UDCCSR0_FST);
+               ep_write_UDCCSR(ep, UDCCSR0_FST);
                break;
        case IN_STATUS_STAGE:
                /*
@@ -2131,6 +2159,7 @@ static void pxa27x_change_configuration(struct pxa_udc *udc, int config)
 
        set_ep0state(udc, WAIT_ACK_SET_CONF_INTERF);
        udc->driver->setup(&udc->gadget, &req);
+       ep_write_UDCCSR(&udc->pxa_ep[0], UDCCSR0_AREN);
 }
 
 /**
@@ -2159,6 +2188,7 @@ static void pxa27x_change_interface(struct pxa_udc *udc, int iface, int alt)
 
        set_ep0state(udc, WAIT_ACK_SET_CONF_INTERF);
        udc->driver->setup(&udc->gadget, &req);
+       ep_write_UDCCSR(&udc->pxa_ep[0], UDCCSR0_AREN);
 }
 
 /*
@@ -2280,7 +2310,7 @@ static void irq_udc_reset(struct pxa_udc *udc)
        memset(&udc->stats, 0, sizeof udc->stats);
 
        nuke(ep, -EPROTO);
-       udc_ep_writel(ep, UDCCSR, UDCCSR0_FTF | UDCCSR0_OPC);
+       ep_write_UDCCSR(ep, UDCCSR0_FTF | UDCCSR0_OPC);
        ep0_idle(udc);
 }
 
@@ -2479,6 +2509,12 @@ static void pxa_udc_shutdown(struct platform_device *_dev)
                udc_disable(udc);
 }
 
+#ifdef CONFIG_CPU_PXA27x
+extern void pxa27x_clear_otgph(void);
+#else
+#define pxa27x_clear_otgph()   do {} while (0)
+#endif
+
 #ifdef CONFIG_PM
 /**
  * pxa_udc_suspend - Suspend udc device
@@ -2546,8 +2582,7 @@ static int pxa_udc_resume(struct platform_device *_dev)
         * Software must configure the USB OTG pad, UDC, and UHC
         * to the state they were in before entering sleep mode.
         */
-       if (cpu_is_pxa27x())
-               PSSR |= PSSR_OTGPH;
+       pxa27x_clear_otgph();
 
        return 0;
 }
@@ -2571,7 +2606,7 @@ static struct platform_driver udc_driver = {
 
 static int __init udc_init(void)
 {
-       if (!cpu_is_pxa27x())
+       if (!cpu_is_pxa27x() && !cpu_is_pxa3xx())
                return -ENODEV;
 
        printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION);
index db58125331dad5d3788d5b3774a34f1637c893df..e25225e26586698ea1ac7ceb5e042b38c4245574 100644 (file)
 #define UP2OCR_HXOE    (1 << 17)       /* Transceiver Output Enable */
 #define UP2OCR_SEOS    (1 << 24)       /* Single-Ended Output Select */
 
+#define UDCCSR0_ACM    (1 << 9)        /* Ack Control Mode */
+#define UDCCSR0_AREN   (1 << 8)        /* Ack Response Enable */
 #define UDCCSR0_SA     (1 << 7)        /* Setup Active */
 #define UDCCSR0_RNE    (1 << 6)        /* Receive FIFO Not Empty */
 #define UDCCSR0_FST    (1 << 5)        /* Force Stall */
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
new file mode 100644 (file)
index 0000000..50c71aa
--- /dev/null
@@ -0,0 +1,3269 @@
+/* linux/drivers/usb/gadget/s3c-hsotg.c
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *      Ben Dooks <ben@simtec.co.uk>
+ *      http://armlinux.simtec.co.uk/
+ *
+ * S3C USB2.0 High-speed / OtG driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <mach/map.h>
+
+#include <plat/regs-usb-hsotg-phy.h>
+#include <plat/regs-usb-hsotg.h>
+#include <plat/regs-sys.h>
+#include <plat/udc-hs.h>
+
+#define DMA_ADDR_INVALID (~((dma_addr_t)0))
+
+/* EP0_MPS_LIMIT
+ *
+ * Unfortunately there seems to be a limit of the amount of data that can
+ * be transfered by IN transactions on EP0. This is either 127 bytes or 3
+ * packets (which practially means 1 packet and 63 bytes of data) when the
+ * MPS is set to 64.
+ *
+ * This means if we are wanting to move >127 bytes of data, we need to
+ * split the transactions up, but just doing one packet at a time does
+ * not work (this may be an implicit DATA0 PID on first packet of the
+ * transaction) and doing 2 packets is outside the controller's limits.
+ *
+ * If we try to lower the MPS size for EP0, then no transfers work properly
+ * for EP0, and the system will fail basic enumeration. As no cause for this
+ * has currently been found, we cannot support any large IN transfers for
+ * EP0.
+ */
+#define EP0_MPS_LIMIT  64
+
+struct s3c_hsotg;
+struct s3c_hsotg_req;
+
+/**
+ * struct s3c_hsotg_ep - driver endpoint definition.
+ * @ep: The gadget layer representation of the endpoint.
+ * @name: The driver generated name for the endpoint.
+ * @queue: Queue of requests for this endpoint.
+ * @parent: Reference back to the parent device structure.
+ * @req: The current request that the endpoint is processing. This is
+ *       used to indicate an request has been loaded onto the endpoint
+ *       and has yet to be completed (maybe due to data move, or simply
+ *      awaiting an ack from the core all the data has been completed).
+ * @debugfs: File entry for debugfs file for this endpoint.
+ * @lock: State lock to protect contents of endpoint.
+ * @dir_in: Set to true if this endpoint is of the IN direction, which
+ *         means that it is sending data to the Host.
+ * @index: The index for the endpoint registers.
+ * @name: The name array passed to the USB core.
+ * @halted: Set if the endpoint has been halted.
+ * @periodic: Set if this is a periodic ep, such as Interrupt
+ * @sent_zlp: Set if we've sent a zero-length packet.
+ * @total_data: The total number of data bytes done.
+ * @fifo_size: The size of the FIFO (for periodic IN endpoints)
+ * @fifo_load: The amount of data loaded into the FIFO (periodic IN)
+ * @last_load: The offset of data for the last start of request.
+ * @size_loaded: The last loaded size for DxEPTSIZE for periodic IN
+ *
+ * This is the driver's state for each registered enpoint, allowing it
+ * to keep track of transactions that need doing. Each endpoint has a
+ * lock to protect the state, to try and avoid using an overall lock
+ * for the host controller as much as possible.
+ *
+ * For periodic IN endpoints, we have fifo_size and fifo_load to try
+ * and keep track of the amount of data in the periodic FIFO for each
+ * of these as we don't have a status register that tells us how much
+ * is in each of them.
+ */
+struct s3c_hsotg_ep {
+       struct usb_ep           ep;
+       struct list_head        queue;
+       struct s3c_hsotg        *parent;
+       struct s3c_hsotg_req    *req;
+       struct dentry           *debugfs;
+
+       spinlock_t              lock;
+
+       unsigned long           total_data;
+       unsigned int            size_loaded;
+       unsigned int            last_load;
+       unsigned int            fifo_load;
+       unsigned short          fifo_size;
+
+       unsigned char           dir_in;
+       unsigned char           index;
+
+       unsigned int            halted:1;
+       unsigned int            periodic:1;
+       unsigned int            sent_zlp:1;
+
+       char                    name[10];
+};
+
+#define S3C_HSOTG_EPS  (8+1)   /* limit to 9 for the moment */
+
+/**
+ * struct s3c_hsotg - driver state.
+ * @dev: The parent device supplied to the probe function
+ * @driver: USB gadget driver
+ * @plat: The platform specific configuration data.
+ * @regs: The memory area mapped for accessing registers.
+ * @regs_res: The resource that was allocated when claiming register space.
+ * @irq: The IRQ number we are using
+ * @debug_root: root directrory for debugfs.
+ * @debug_file: main status file for debugfs.
+ * @debug_fifo: FIFO status file for debugfs.
+ * @ep0_reply: Request used for ep0 reply.
+ * @ep0_buff: Buffer for EP0 reply data, if needed.
+ * @ctrl_buff: Buffer for EP0 control requests.
+ * @ctrl_req: Request for EP0 control packets.
+ * @eps: The endpoints being supplied to the gadget framework
+ */
+struct s3c_hsotg {
+       struct device            *dev;
+       struct usb_gadget_driver *driver;
+       struct s3c_hsotg_plat    *plat;
+
+       void __iomem            *regs;
+       struct resource         *regs_res;
+       int                     irq;
+
+       struct dentry           *debug_root;
+       struct dentry           *debug_file;
+       struct dentry           *debug_fifo;
+
+       struct usb_request      *ep0_reply;
+       struct usb_request      *ctrl_req;
+       u8                      ep0_buff[8];
+       u8                      ctrl_buff[8];
+
+       struct usb_gadget       gadget;
+       struct s3c_hsotg_ep     eps[];
+};
+
+/**
+ * struct s3c_hsotg_req - data transfer request
+ * @req: The USB gadget request
+ * @queue: The list of requests for the endpoint this is queued for.
+ * @in_progress: Has already had size/packets written to core
+ * @mapped: DMA buffer for this request has been mapped via dma_map_single().
+ */
+struct s3c_hsotg_req {
+       struct usb_request      req;
+       struct list_head        queue;
+       unsigned char           in_progress;
+       unsigned char           mapped;
+};
+
+/* conversion functions */
+static inline struct s3c_hsotg_req *our_req(struct usb_request *req)
+{
+       return container_of(req, struct s3c_hsotg_req, req);
+}
+
+static inline struct s3c_hsotg_ep *our_ep(struct usb_ep *ep)
+{
+       return container_of(ep, struct s3c_hsotg_ep, ep);
+}
+
+static inline struct s3c_hsotg *to_hsotg(struct usb_gadget *gadget)
+{
+       return container_of(gadget, struct s3c_hsotg, gadget);
+}
+
+static inline void __orr32(void __iomem *ptr, u32 val)
+{
+       writel(readl(ptr) | val, ptr);
+}
+
+static inline void __bic32(void __iomem *ptr, u32 val)
+{
+       writel(readl(ptr) & ~val, ptr);
+}
+
+/* forward decleration of functions */
+static void s3c_hsotg_dump(struct s3c_hsotg *hsotg);
+
+/**
+ * using_dma - return the DMA status of the driver.
+ * @hsotg: The driver state.
+ *
+ * Return true if we're using DMA.
+ *
+ * Currently, we have the DMA support code worked into everywhere
+ * that needs it, but the AMBA DMA implementation in the hardware can
+ * only DMA from 32bit aligned addresses. This means that gadgets such
+ * as the CDC Ethernet cannot work as they often pass packets which are
+ * not 32bit aligned.
+ *
+ * Unfortunately the choice to use DMA or not is global to the controller
+ * and seems to be only settable when the controller is being put through
+ * a core reset. This means we either need to fix the gadgets to take
+ * account of DMA alignment, or add bounce buffers (yuerk).
+ *
+ * Until this issue is sorted out, we always return 'false'.
+ */
+static inline bool using_dma(struct s3c_hsotg *hsotg)
+{
+       return false;   /* support is not complete */
+}
+
+/**
+ * s3c_hsotg_en_gsint - enable one or more of the general interrupt
+ * @hsotg: The device state
+ * @ints: A bitmask of the interrupts to enable
+ */
+static void s3c_hsotg_en_gsint(struct s3c_hsotg *hsotg, u32 ints)
+{
+       u32 gsintmsk = readl(hsotg->regs + S3C_GINTMSK);
+       u32 new_gsintmsk;
+
+       new_gsintmsk = gsintmsk | ints;
+
+       if (new_gsintmsk != gsintmsk) {
+               dev_dbg(hsotg->dev, "gsintmsk now 0x%08x\n", new_gsintmsk);
+               writel(new_gsintmsk, hsotg->regs + S3C_GINTMSK);
+       }
+}
+
+/**
+ * s3c_hsotg_disable_gsint - disable one or more of the general interrupt
+ * @hsotg: The device state
+ * @ints: A bitmask of the interrupts to enable
+ */
+static void s3c_hsotg_disable_gsint(struct s3c_hsotg *hsotg, u32 ints)
+{
+       u32 gsintmsk = readl(hsotg->regs + S3C_GINTMSK);
+       u32 new_gsintmsk;
+
+       new_gsintmsk = gsintmsk & ~ints;
+
+       if (new_gsintmsk != gsintmsk)
+               writel(new_gsintmsk, hsotg->regs + S3C_GINTMSK);
+}
+
+/**
+ * s3c_hsotg_ctrl_epint - enable/disable an endpoint irq
+ * @hsotg: The device state
+ * @ep: The endpoint index
+ * @dir_in: True if direction is in.
+ * @en: The enable value, true to enable
+ *
+ * Set or clear the mask for an individual endpoint's interrupt
+ * request.
+ */
+static void s3c_hsotg_ctrl_epint(struct s3c_hsotg *hsotg,
+                                unsigned int ep, unsigned int dir_in,
+                                unsigned int en)
+{
+       unsigned long flags;
+       u32 bit = 1 << ep;
+       u32 daint;
+
+       if (!dir_in)
+               bit <<= 16;
+
+       local_irq_save(flags);
+       daint = readl(hsotg->regs + S3C_DAINTMSK);
+       if (en)
+               daint |= bit;
+       else
+               daint &= ~bit;
+       writel(daint, hsotg->regs + S3C_DAINTMSK);
+       local_irq_restore(flags);
+}
+
+/**
+ * s3c_hsotg_init_fifo - initialise non-periodic FIFOs
+ * @hsotg: The device instance.
+ */
+static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg)
+{
+       /* the ryu 2.6.24 release ahs
+          writel(0x1C0, hsotg->regs + S3C_GRXFSIZ);
+          writel(S3C_GNPTXFSIZ_NPTxFStAddr(0x200) |
+               S3C_GNPTXFSIZ_NPTxFDep(0x1C0),
+               hsotg->regs + S3C_GNPTXFSIZ);
+       */
+
+       /* set FIFO sizes to 2048/0x1C0 */
+
+       writel(2048, hsotg->regs + S3C_GRXFSIZ);
+       writel(S3C_GNPTXFSIZ_NPTxFStAddr(2048) |
+              S3C_GNPTXFSIZ_NPTxFDep(0x1C0),
+              hsotg->regs + S3C_GNPTXFSIZ);
+}
+
+/**
+ * @ep: USB endpoint to allocate request for.
+ * @flags: Allocation flags
+ *
+ * Allocate a new USB request structure appropriate for the specified endpoint
+ */
+struct usb_request *s3c_hsotg_ep_alloc_request(struct usb_ep *ep, gfp_t flags)
+{
+       struct s3c_hsotg_req *req;
+
+       req = kzalloc(sizeof(struct s3c_hsotg_req), flags);
+       if (!req)
+               return NULL;
+
+       INIT_LIST_HEAD(&req->queue);
+
+       req->req.dma = DMA_ADDR_INVALID;
+       return &req->req;
+}
+
+/**
+ * is_ep_periodic - return true if the endpoint is in periodic mode.
+ * @hs_ep: The endpoint to query.
+ *
+ * Returns true if the endpoint is in periodic mode, meaning it is being
+ * used for an Interrupt or ISO transfer.
+ */
+static inline int is_ep_periodic(struct s3c_hsotg_ep *hs_ep)
+{
+       return hs_ep->periodic;
+}
+
+/**
+ * s3c_hsotg_unmap_dma - unmap the DMA memory being used for the request
+ * @hsotg: The device state.
+ * @hs_ep: The endpoint for the request
+ * @hs_req: The request being processed.
+ *
+ * This is the reverse of s3c_hsotg_map_dma(), called for the completion
+ * of a request to ensure the buffer is ready for access by the caller.
+*/
+static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg,
+                               struct s3c_hsotg_ep *hs_ep,
+                               struct s3c_hsotg_req *hs_req)
+{
+       struct usb_request *req = &hs_req->req;
+       enum dma_data_direction dir;
+
+       dir = hs_ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+
+       /* ignore this if we're not moving any data */
+       if (hs_req->req.length == 0)
+               return;
+
+       if (hs_req->mapped) {
+               /* we mapped this, so unmap and remove the dma */
+
+               dma_unmap_single(hsotg->dev, req->dma, req->length, dir);
+
+               req->dma = DMA_ADDR_INVALID;
+               hs_req->mapped = 0;
+       } else {
+               dma_sync_single(hsotg->dev, req->dma, req->length, dir);
+       }
+}
+
+/**
+ * s3c_hsotg_write_fifo - write packet Data to the TxFIFO
+ * @hsotg: The controller state.
+ * @hs_ep: The endpoint we're going to write for.
+ * @hs_req: The request to write data for.
+ *
+ * This is called when the TxFIFO has some space in it to hold a new
+ * transmission and we have something to give it. The actual setup of
+ * the data size is done elsewhere, so all we have to do is to actually
+ * write the data.
+ *
+ * The return value is zero if there is more space (or nothing was done)
+ * otherwise -ENOSPC is returned if the FIFO space was used up.
+ *
+ * This routine is only needed for PIO
+*/
+static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
+                               struct s3c_hsotg_ep *hs_ep,
+                               struct s3c_hsotg_req *hs_req)
+{
+       bool periodic = is_ep_periodic(hs_ep);
+       u32 gnptxsts = readl(hsotg->regs + S3C_GNPTXSTS);
+       int buf_pos = hs_req->req.actual;
+       int to_write = hs_ep->size_loaded;
+       void *data;
+       int can_write;
+       int pkt_round;
+
+       to_write -= (buf_pos - hs_ep->last_load);
+
+       /* if there's nothing to write, get out early */
+       if (to_write == 0)
+               return 0;
+
+       if (periodic) {
+               u32 epsize = readl(hsotg->regs + S3C_DIEPTSIZ(hs_ep->index));
+               int size_left;
+               int size_done;
+
+               /* work out how much data was loaded so we can calculate
+                * how much data is left in the fifo. */
+
+               size_left = S3C_DxEPTSIZ_XferSize_GET(epsize);
+
+               dev_dbg(hsotg->dev, "%s: left=%d, load=%d, fifo=%d, size %d\n",
+                       __func__, size_left,
+                       hs_ep->size_loaded, hs_ep->fifo_load, hs_ep->fifo_size);
+
+               /* how much of the data has moved */
+               size_done = hs_ep->size_loaded - size_left;
+
+               /* how much data is left in the fifo */
+               can_write = hs_ep->fifo_load - size_done;
+               dev_dbg(hsotg->dev, "%s: => can_write1=%d\n",
+                       __func__, can_write);
+
+               can_write = hs_ep->fifo_size - can_write;
+               dev_dbg(hsotg->dev, "%s: => can_write2=%d\n",
+                       __func__, can_write);
+
+               if (can_write <= 0) {
+                       s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_PTxFEmp);
+                       return -ENOSPC;
+               }
+       } else {
+               if (S3C_GNPTXSTS_NPTxQSpcAvail_GET(gnptxsts) == 0) {
+                       dev_dbg(hsotg->dev,
+                               "%s: no queue slots available (0x%08x)\n",
+                               __func__, gnptxsts);
+
+                       s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_NPTxFEmp);
+                       return -ENOSPC;
+               }
+
+               can_write = S3C_GNPTXSTS_NPTxFSpcAvail_GET(gnptxsts);
+       }
+
+       dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, mps %d\n",
+                __func__, gnptxsts, can_write, to_write, hs_ep->ep.maxpacket);
+
+       /* limit to 512 bytes of data, it seems at least on the non-periodic
+        * FIFO, requests of >512 cause the endpoint to get stuck with a
+        * fragment of the end of the transfer in it.
+        */
+       if (can_write > 512)
+               can_write = 512;
+
+       /* see if we can write data */
+
+       if (to_write > can_write) {
+               to_write = can_write;
+               pkt_round = to_write % hs_ep->ep.maxpacket;
+
+               /* Not sure, but we probably shouldn't be writing partial
+                * packets into the FIFO, so round the write down to an
+                * exact number of packets.
+                *
+                * Note, we do not currently check to see if we can ever
+                * write a full packet or not to the FIFO.
+                */
+
+               if (pkt_round)
+                       to_write -= pkt_round;
+
+               /* enable correct FIFO interrupt to alert us when there
+                * is more room left. */
+
+               s3c_hsotg_en_gsint(hsotg,
+                                  periodic ? S3C_GINTSTS_PTxFEmp :
+                                  S3C_GINTSTS_NPTxFEmp);
+       }
+
+       dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n",
+                to_write, hs_req->req.length, can_write, buf_pos);
+
+       if (to_write <= 0)
+               return -ENOSPC;
+
+       hs_req->req.actual = buf_pos + to_write;
+       hs_ep->total_data += to_write;
+
+       if (periodic)
+               hs_ep->fifo_load += to_write;
+
+       to_write = DIV_ROUND_UP(to_write, 4);
+       data = hs_req->req.buf + buf_pos;
+
+       writesl(hsotg->regs + S3C_EPFIFO(hs_ep->index), data, to_write);
+
+       return (to_write >= can_write) ? -ENOSPC : 0;
+}
+
+/**
+ * get_ep_limit - get the maximum data legnth for this endpoint
+ * @hs_ep: The endpoint
+ *
+ * Return the maximum data that can be queued in one go on a given endpoint
+ * so that transfers that are too long can be split.
+ */
+static unsigned get_ep_limit(struct s3c_hsotg_ep *hs_ep)
+{
+       int index = hs_ep->index;
+       unsigned maxsize;
+       unsigned maxpkt;
+
+       if (index != 0) {
+               maxsize = S3C_DxEPTSIZ_XferSize_LIMIT + 1;
+               maxpkt = S3C_DxEPTSIZ_PktCnt_LIMIT + 1;
+       } else {
+               if (hs_ep->dir_in) {
+                       /* maxsize = S3C_DIEPTSIZ0_XferSize_LIMIT + 1; */
+                       maxsize = 64+64+1;
+                       maxpkt = S3C_DIEPTSIZ0_PktCnt_LIMIT + 1;
+               } else {
+                       maxsize = 0x3f;
+                       maxpkt = 2;
+               }
+       }
+
+       /* we made the constant loading easier above by using +1 */
+       maxpkt--;
+       maxsize--;
+
+       /* constrain by packet count if maxpkts*pktsize is greater
+        * than the length register size. */
+
+       if ((maxpkt * hs_ep->ep.maxpacket) < maxsize)
+               maxsize = maxpkt * hs_ep->ep.maxpacket;
+
+       return maxsize;
+}
+
+/**
+ * s3c_hsotg_start_req - start a USB request from an endpoint's queue
+ * @hsotg: The controller state.
+ * @hs_ep: The endpoint to process a request for
+ * @hs_req: The request to start.
+ * @continuing: True if we are doing more for the current request.
+ *
+ * Start the given request running by setting the endpoint registers
+ * appropriately, and writing any data to the FIFOs.
+ */
+static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,
+                               struct s3c_hsotg_ep *hs_ep,
+                               struct s3c_hsotg_req *hs_req,
+                               bool continuing)
+{
+       struct usb_request *ureq = &hs_req->req;
+       int index = hs_ep->index;
+       int dir_in = hs_ep->dir_in;
+       u32 epctrl_reg;
+       u32 epsize_reg;
+       u32 epsize;
+       u32 ctrl;
+       unsigned length;
+       unsigned packets;
+       unsigned maxreq;
+
+       if (index != 0) {
+               if (hs_ep->req && !continuing) {
+                       dev_err(hsotg->dev, "%s: active request\n", __func__);
+                       WARN_ON(1);
+                       return;
+               } else if (hs_ep->req != hs_req && continuing) {
+                       dev_err(hsotg->dev,
+                               "%s: continue different req\n", __func__);
+                       WARN_ON(1);
+                       return;
+               }
+       }
+
+       epctrl_reg = dir_in ? S3C_DIEPCTL(index) : S3C_DOEPCTL(index);
+       epsize_reg = dir_in ? S3C_DIEPTSIZ(index) : S3C_DOEPTSIZ(index);
+
+       dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x, ep %d, dir %s\n",
+               __func__, readl(hsotg->regs + epctrl_reg), index,
+               hs_ep->dir_in ? "in" : "out");
+
+       length = ureq->length - ureq->actual;
+
+       if (0)
+               dev_dbg(hsotg->dev,
+                       "REQ buf %p len %d dma 0x%08x noi=%d zp=%d snok=%d\n",
+                       ureq->buf, length, ureq->dma,
+                       ureq->no_interrupt, ureq->zero, ureq->short_not_ok);
+
+       maxreq = get_ep_limit(hs_ep);
+       if (length > maxreq) {
+               int round = maxreq % hs_ep->ep.maxpacket;
+
+               dev_dbg(hsotg->dev, "%s: length %d, max-req %d, r %d\n",
+                       __func__, length, maxreq, round);
+
+               /* round down to multiple of packets */
+               if (round)
+                       maxreq -= round;
+
+               length = maxreq;
+       }
+
+       if (length)
+               packets = DIV_ROUND_UP(length, hs_ep->ep.maxpacket);
+       else
+               packets = 1;    /* send one packet if length is zero. */
+
+       if (dir_in && index != 0)
+               epsize = S3C_DxEPTSIZ_MC(1);
+       else
+               epsize = 0;
+
+       if (index != 0 && ureq->zero) {
+               /* test for the packets being exactly right for the
+                * transfer */
+
+               if (length == (packets * hs_ep->ep.maxpacket))
+                       packets++;
+       }
+
+       epsize |= S3C_DxEPTSIZ_PktCnt(packets);
+       epsize |= S3C_DxEPTSIZ_XferSize(length);
+
+       dev_dbg(hsotg->dev, "%s: %d@%d/%d, 0x%08x => 0x%08x\n",
+               __func__, packets, length, ureq->length, epsize, epsize_reg);
+
+       /* store the request as the current one we're doing */
+       hs_ep->req = hs_req;
+
+       /* write size / packets */
+       writel(epsize, hsotg->regs + epsize_reg);
+
+       ctrl = readl(hsotg->regs + epctrl_reg);
+
+       if (ctrl & S3C_DxEPCTL_Stall) {
+               dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index);
+
+               /* not sure what we can do here, if it is EP0 then we should
+                * get this cleared once the endpoint has transmitted the
+                * STALL packet, otherwise it needs to be cleared by the
+                * host.
+                */
+       }
+
+       if (using_dma(hsotg)) {
+               unsigned int dma_reg;
+
+               /* write DMA address to control register, buffer already
+                * synced by s3c_hsotg_ep_queue().  */
+
+               dma_reg = dir_in ? S3C_DIEPDMA(index) : S3C_DOEPDMA(index);
+               writel(ureq->dma, hsotg->regs + dma_reg);
+
+               dev_dbg(hsotg->dev, "%s: 0x%08x => 0x%08x\n",
+                       __func__, ureq->dma, dma_reg);
+       }
+
+       ctrl |= S3C_DxEPCTL_EPEna;      /* ensure ep enabled */
+       ctrl |= S3C_DxEPCTL_USBActEp;
+       ctrl |= S3C_DxEPCTL_CNAK;       /* clear NAK set by core */
+
+       dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl);
+       writel(ctrl, hsotg->regs + epctrl_reg);
+
+       /* set these, it seems that DMA support increments past the end
+        * of the packet buffer so we need to calculate the length from
+        * this information. */
+       hs_ep->size_loaded = length;
+       hs_ep->last_load = ureq->actual;
+
+       if (dir_in && !using_dma(hsotg)) {
+               /* set these anyway, we may need them for non-periodic in */
+               hs_ep->fifo_load = 0;
+
+               s3c_hsotg_write_fifo(hsotg, hs_ep, hs_req);
+       }
+
+       /* clear the INTknTXFEmpMsk when we start request, more as a aide
+        * to debugging to see what is going on. */
+       if (dir_in)
+               writel(S3C_DIEPMSK_INTknTXFEmpMsk,
+                      hsotg->regs + S3C_DIEPINT(index));
+
+       /* Note, trying to clear the NAK here causes problems with transmit
+        * on the S3C6400 ending up with the TXFIFO becomming full. */
+
+       /* check ep is enabled */
+       if (!(readl(hsotg->regs + epctrl_reg) & S3C_DxEPCTL_EPEna))
+               dev_warn(hsotg->dev,
+                        "ep%d: failed to become enabled (DxEPCTL=0x%08x)?\n",
+                        index, readl(hsotg->regs + epctrl_reg));
+
+       dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n",
+               __func__, readl(hsotg->regs + epctrl_reg));
+}
+
+/**
+ * s3c_hsotg_map_dma - map the DMA memory being used for the request
+ * @hsotg: The device state.
+ * @hs_ep: The endpoint the request is on.
+ * @req: The request being processed.
+ *
+ * We've been asked to queue a request, so ensure that the memory buffer
+ * is correctly setup for DMA. If we've been passed an extant DMA address
+ * then ensure the buffer has been synced to memory. If our buffer has no
+ * DMA memory, then we map the memory and mark our request to allow us to
+ * cleanup on completion.
+*/
+static int s3c_hsotg_map_dma(struct s3c_hsotg *hsotg,
+                            struct s3c_hsotg_ep *hs_ep,
+                            struct usb_request *req)
+{
+       enum dma_data_direction dir;
+       struct s3c_hsotg_req *hs_req = our_req(req);
+
+       dir = hs_ep->dir_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+
+       /* if the length is zero, ignore the DMA data */
+       if (hs_req->req.length == 0)
+               return 0;
+
+       if (req->dma == DMA_ADDR_INVALID) {
+               dma_addr_t dma;
+
+               dma = dma_map_single(hsotg->dev, req->buf, req->length, dir);
+
+               if (unlikely(dma_mapping_error(hsotg->dev, dma)))
+                       goto dma_error;
+
+               if (dma & 3) {
+                       dev_err(hsotg->dev, "%s: unaligned dma buffer\n",
+                               __func__);
+
+                       dma_unmap_single(hsotg->dev, dma, req->length, dir);
+                       return -EINVAL;
+               }
+
+               hs_req->mapped = 1;
+               req->dma = dma;
+       } else {
+               dma_sync_single(hsotg->dev, req->dma, req->length, dir);
+               hs_req->mapped = 0;
+       }
+
+       return 0;
+
+dma_error:
+       dev_err(hsotg->dev, "%s: failed to map buffer %p, %d bytes\n",
+               __func__, req->buf, req->length);
+
+       return -EIO;
+}
+
+static int s3c_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
+                             gfp_t gfp_flags)
+{
+       struct s3c_hsotg_req *hs_req = our_req(req);
+       struct s3c_hsotg_ep *hs_ep = our_ep(ep);
+       struct s3c_hsotg *hs = hs_ep->parent;
+       unsigned long irqflags;
+       bool first;
+
+       dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d, snok=%d\n",
+               ep->name, req, req->length, req->buf, req->no_interrupt,
+               req->zero, req->short_not_ok);
+
+       /* initialise status of the request */
+       INIT_LIST_HEAD(&hs_req->queue);
+       req->actual = 0;
+       req->status = -EINPROGRESS;
+
+       /* if we're using DMA, sync the buffers as necessary */
+       if (using_dma(hs)) {
+               int ret = s3c_hsotg_map_dma(hs, hs_ep, req);
+               if (ret)
+                       return ret;
+       }
+
+       spin_lock_irqsave(&hs_ep->lock, irqflags);
+
+       first = list_empty(&hs_ep->queue);
+       list_add_tail(&hs_req->queue, &hs_ep->queue);
+
+       if (first)
+               s3c_hsotg_start_req(hs, hs_ep, hs_req, false);
+
+       spin_unlock_irqrestore(&hs_ep->lock, irqflags);
+
+       return 0;
+}
+
+static void s3c_hsotg_ep_free_request(struct usb_ep *ep,
+                                     struct usb_request *req)
+{
+       struct s3c_hsotg_req *hs_req = our_req(req);
+
+       kfree(hs_req);
+}
+
+/**
+ * s3c_hsotg_complete_oursetup - setup completion callback
+ * @ep: The endpoint the request was on.
+ * @req: The request completed.
+ *
+ * Called on completion of any requests the driver itself
+ * submitted that need cleaning up.
+ */
+static void s3c_hsotg_complete_oursetup(struct usb_ep *ep,
+                                       struct usb_request *req)
+{
+       struct s3c_hsotg_ep *hs_ep = our_ep(ep);
+       struct s3c_hsotg *hsotg = hs_ep->parent;
+
+       dev_dbg(hsotg->dev, "%s: ep %p, req %p\n", __func__, ep, req);
+
+       s3c_hsotg_ep_free_request(ep, req);
+}
+
+/**
+ * ep_from_windex - convert control wIndex value to endpoint
+ * @hsotg: The driver state.
+ * @windex: The control request wIndex field (in host order).
+ *
+ * Convert the given wIndex into a pointer to an driver endpoint
+ * structure, or return NULL if it is not a valid endpoint.
+*/
+static struct s3c_hsotg_ep *ep_from_windex(struct s3c_hsotg *hsotg,
+                                          u32 windex)
+{
+       struct s3c_hsotg_ep *ep = &hsotg->eps[windex & 0x7F];
+       int dir = (windex & USB_DIR_IN) ? 1 : 0;
+       int idx = windex & 0x7F;
+
+       if (windex >= 0x100)
+               return NULL;
+
+       if (idx > S3C_HSOTG_EPS)
+               return NULL;
+
+       if (idx && ep->dir_in != dir)
+               return NULL;
+
+       return ep;
+}
+
+/**
+ * s3c_hsotg_send_reply - send reply to control request
+ * @hsotg: The device state
+ * @ep: Endpoint 0
+ * @buff: Buffer for request
+ * @length: Length of reply.
+ *
+ * Create a request and queue it on the given endpoint. This is useful as
+ * an internal method of sending replies to certain control requests, etc.
+ */
+static int s3c_hsotg_send_reply(struct s3c_hsotg *hsotg,
+                               struct s3c_hsotg_ep *ep,
+                               void *buff,
+                               int length)
+{
+       struct usb_request *req;
+       int ret;
+
+       dev_dbg(hsotg->dev, "%s: buff %p, len %d\n", __func__, buff, length);
+
+       req = s3c_hsotg_ep_alloc_request(&ep->ep, GFP_ATOMIC);
+       hsotg->ep0_reply = req;
+       if (!req) {
+               dev_warn(hsotg->dev, "%s: cannot alloc req\n", __func__);
+               return -ENOMEM;
+       }
+
+       req->buf = hsotg->ep0_buff;
+       req->length = length;
+       req->zero = 1; /* always do zero-length final transfer */
+       req->complete = s3c_hsotg_complete_oursetup;
+
+       if (length)
+               memcpy(req->buf, buff, length);
+       else
+               ep->sent_zlp = 1;
+
+       ret = s3c_hsotg_ep_queue(&ep->ep, req, GFP_ATOMIC);
+       if (ret) {
+               dev_warn(hsotg->dev, "%s: cannot queue req\n", __func__);
+               return ret;
+       }
+
+       return 0;
+}
+
+/**
+ * s3c_hsotg_process_req_status - process request GET_STATUS
+ * @hsotg: The device state
+ * @ctrl: USB control request
+ */
+static int s3c_hsotg_process_req_status(struct s3c_hsotg *hsotg,
+                                       struct usb_ctrlrequest *ctrl)
+{
+       struct s3c_hsotg_ep *ep0 = &hsotg->eps[0];
+       struct s3c_hsotg_ep *ep;
+       __le16 reply;
+       int ret;
+
+       dev_dbg(hsotg->dev, "%s: USB_REQ_GET_STATUS\n", __func__);
+
+       if (!ep0->dir_in) {
+               dev_warn(hsotg->dev, "%s: direction out?\n", __func__);
+               return -EINVAL;
+       }
+
+       switch (ctrl->bRequestType & USB_RECIP_MASK) {
+       case USB_RECIP_DEVICE:
+               reply = cpu_to_le16(0); /* bit 0 => self powered,
+                                        * bit 1 => remote wakeup */
+               break;
+
+       case USB_RECIP_INTERFACE:
+               /* currently, the data result should be zero */
+               reply = cpu_to_le16(0);
+               break;
+
+       case USB_RECIP_ENDPOINT:
+               ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex));
+               if (!ep)
+                       return -ENOENT;
+
+               reply = cpu_to_le16(ep->halted ? 1 : 0);
+               break;
+
+       default:
+               return 0;
+       }
+
+       if (le16_to_cpu(ctrl->wLength) != 2)
+               return -EINVAL;
+
+       ret = s3c_hsotg_send_reply(hsotg, ep0, &reply, 2);
+       if (ret) {
+               dev_err(hsotg->dev, "%s: failed to send reply\n", __func__);
+               return ret;
+       }
+
+       return 1;
+}
+
+static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value);
+
+/**
+ * s3c_hsotg_process_req_featire - process request {SET,CLEAR}_FEATURE
+ * @hsotg: The device state
+ * @ctrl: USB control request
+ */
+static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg,
+                                        struct usb_ctrlrequest *ctrl)
+{
+       bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE);
+       struct s3c_hsotg_ep *ep;
+
+       dev_dbg(hsotg->dev, "%s: %s_FEATURE\n",
+               __func__, set ? "SET" : "CLEAR");
+
+       if (ctrl->bRequestType == USB_RECIP_ENDPOINT) {
+               ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex));
+               if (!ep) {
+                       dev_dbg(hsotg->dev, "%s: no endpoint for 0x%04x\n",
+                               __func__, le16_to_cpu(ctrl->wIndex));
+                       return -ENOENT;
+               }
+
+               switch (le16_to_cpu(ctrl->wValue)) {
+               case USB_ENDPOINT_HALT:
+                       s3c_hsotg_ep_sethalt(&ep->ep, set);
+                       break;
+
+               default:
+                       return -ENOENT;
+               }
+       } else
+               return -ENOENT;  /* currently only deal with endpoint */
+
+       return 1;
+}
+
+/**
+ * s3c_hsotg_process_control - process a control request
+ * @hsotg: The device state
+ * @ctrl: The control request received
+ *
+ * The controller has received the SETUP phase of a control request, and
+ * needs to work out what to do next (and whether to pass it on to the
+ * gadget driver).
+ */
+static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg,
+                                     struct usb_ctrlrequest *ctrl)
+{
+       struct s3c_hsotg_ep *ep0 = &hsotg->eps[0];
+       int ret = 0;
+       u32 dcfg;
+
+       ep0->sent_zlp = 0;
+
+       dev_dbg(hsotg->dev, "ctrl Req=%02x, Type=%02x, V=%04x, L=%04x\n",
+                ctrl->bRequest, ctrl->bRequestType,
+                ctrl->wValue, ctrl->wLength);
+
+       /* record the direction of the request, for later use when enquing
+        * packets onto EP0. */
+
+       ep0->dir_in = (ctrl->bRequestType & USB_DIR_IN) ? 1 : 0;
+       dev_dbg(hsotg->dev, "ctrl: dir_in=%d\n", ep0->dir_in);
+
+       /* if we've no data with this request, then the last part of the
+        * transaction is going to implicitly be IN. */
+       if (ctrl->wLength == 0)
+               ep0->dir_in = 1;
+
+       if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+               switch (ctrl->bRequest) {
+               case USB_REQ_SET_ADDRESS:
+                       dcfg = readl(hsotg->regs + S3C_DCFG);
+                       dcfg &= ~S3C_DCFG_DevAddr_MASK;
+                       dcfg |= ctrl->wValue << S3C_DCFG_DevAddr_SHIFT;
+                       writel(dcfg, hsotg->regs + S3C_DCFG);
+
+                       dev_info(hsotg->dev, "new address %d\n", ctrl->wValue);
+
+                       ret = s3c_hsotg_send_reply(hsotg, ep0, NULL, 0);
+                       return;
+
+               case USB_REQ_GET_STATUS:
+                       ret = s3c_hsotg_process_req_status(hsotg, ctrl);
+                       break;
+
+               case USB_REQ_CLEAR_FEATURE:
+               case USB_REQ_SET_FEATURE:
+                       ret = s3c_hsotg_process_req_feature(hsotg, ctrl);
+                       break;
+               }
+       }
+
+       /* as a fallback, try delivering it to the driver to deal with */
+
+       if (ret == 0 && hsotg->driver) {
+               ret = hsotg->driver->setup(&hsotg->gadget, ctrl);
+               if (ret < 0)
+                       dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret);
+       }
+
+       if (ret > 0) {
+               if (!ep0->dir_in) {
+                       /* need to generate zlp in reply or take data */
+                       /* todo - deal with any data we might be sent? */
+                       ret = s3c_hsotg_send_reply(hsotg, ep0, NULL, 0);
+               }
+       }
+
+       /* the request is either unhandlable, or is not formatted correctly
+        * so respond with a STALL for the status stage to indicate failure.
+        */
+
+       if (ret < 0) {
+               u32 reg;
+               u32 ctrl;
+
+               dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in);
+               reg = (ep0->dir_in) ? S3C_DIEPCTL0 : S3C_DOEPCTL0;
+
+               /* S3C_DxEPCTL_Stall will be cleared by EP once it has
+                * taken effect, so no need to clear later. */
+
+               ctrl = readl(hsotg->regs + reg);
+               ctrl |= S3C_DxEPCTL_Stall;
+               ctrl |= S3C_DxEPCTL_CNAK;
+               writel(ctrl, hsotg->regs + reg);
+
+               dev_dbg(hsotg->dev,
+                       "writen DxEPCTL=0x%08x to %08x (DxEPCTL=0x%08x)\n",
+                       ctrl, reg, readl(hsotg->regs + reg));
+
+               /* don't belive we need to anything more to get the EP
+                * to reply with a STALL packet */
+       }
+}
+
+static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg);
+
+/**
+ * s3c_hsotg_complete_setup - completion of a setup transfer
+ * @ep: The endpoint the request was on.
+ * @req: The request completed.
+ *
+ * Called on completion of any requests the driver itself submitted for
+ * EP0 setup packets
+ */
+static void s3c_hsotg_complete_setup(struct usb_ep *ep,
+                                    struct usb_request *req)
+{
+       struct s3c_hsotg_ep *hs_ep = our_ep(ep);
+       struct s3c_hsotg *hsotg = hs_ep->parent;
+
+       if (req->status < 0) {
+               dev_dbg(hsotg->dev, "%s: failed %d\n", __func__, req->status);
+               return;
+       }
+
+       if (req->actual == 0)
+               s3c_hsotg_enqueue_setup(hsotg);
+       else
+               s3c_hsotg_process_control(hsotg, req->buf);
+}
+
+/**
+ * s3c_hsotg_enqueue_setup - start a request for EP0 packets
+ * @hsotg: The device state.
+ *
+ * Enqueue a request on EP0 if necessary to received any SETUP packets
+ * received from the host.
+ */
+static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg)
+{
+       struct usb_request *req = hsotg->ctrl_req;
+       struct s3c_hsotg_req *hs_req = our_req(req);
+       int ret;
+
+       dev_dbg(hsotg->dev, "%s: queueing setup request\n", __func__);
+
+       req->zero = 0;
+       req->length = 8;
+       req->buf = hsotg->ctrl_buff;
+       req->complete = s3c_hsotg_complete_setup;
+
+       if (!list_empty(&hs_req->queue)) {
+               dev_dbg(hsotg->dev, "%s already queued???\n", __func__);
+               return;
+       }
+
+       hsotg->eps[0].dir_in = 0;
+
+       ret = s3c_hsotg_ep_queue(&hsotg->eps[0].ep, req, GFP_ATOMIC);
+       if (ret < 0) {
+               dev_err(hsotg->dev, "%s: failed queue (%d)\n", __func__, ret);
+               /* Don't think there's much we can do other than watch the
+                * driver fail. */
+       }
+}
+
+/**
+ * get_ep_head - return the first request on the endpoint
+ * @hs_ep: The controller endpoint to get
+ *
+ * Get the first request on the endpoint.
+*/
+static struct s3c_hsotg_req *get_ep_head(struct s3c_hsotg_ep *hs_ep)
+{
+       if (list_empty(&hs_ep->queue))
+               return NULL;
+
+       return list_first_entry(&hs_ep->queue, struct s3c_hsotg_req, queue);
+}
+
+/**
+ * s3c_hsotg_complete_request - complete a request given to us
+ * @hsotg: The device state.
+ * @hs_ep: The endpoint the request was on.
+ * @hs_req: The request to complete.
+ * @result: The result code (0 => Ok, otherwise errno)
+ *
+ * The given request has finished, so call the necessary completion
+ * if it has one and then look to see if we can start a new request
+ * on the endpoint.
+ *
+ * Note, expects the ep to already be locked as appropriate.
+*/
+static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg,
+                                      struct s3c_hsotg_ep *hs_ep,
+                                      struct s3c_hsotg_req *hs_req,
+                                      int result)
+{
+       bool restart;
+
+       if (!hs_req) {
+               dev_dbg(hsotg->dev, "%s: nothing to complete?\n", __func__);
+               return;
+       }
+
+       dev_dbg(hsotg->dev, "complete: ep %p %s, req %p, %d => %p\n",
+               hs_ep, hs_ep->ep.name, hs_req, result, hs_req->req.complete);
+
+       /* only replace the status if we've not already set an error
+        * from a previous transaction */
+
+       if (hs_req->req.status == -EINPROGRESS)
+               hs_req->req.status = result;
+
+       hs_ep->req = NULL;
+       list_del_init(&hs_req->queue);
+
+       if (using_dma(hsotg))
+               s3c_hsotg_unmap_dma(hsotg, hs_ep, hs_req);
+
+       /* call the complete request with the locks off, just in case the
+        * request tries to queue more work for this endpoint. */
+
+       if (hs_req->req.complete) {
+               spin_unlock(&hs_ep->lock);
+               hs_req->req.complete(&hs_ep->ep, &hs_req->req);
+               spin_lock(&hs_ep->lock);
+       }
+
+       /* Look to see if there is anything else to do. Note, the completion
+        * of the previous request may have caused a new request to be started
+        * so be careful when doing this. */
+
+       if (!hs_ep->req && result >= 0) {
+               restart = !list_empty(&hs_ep->queue);
+               if (restart) {
+                       hs_req = get_ep_head(hs_ep);
+                       s3c_hsotg_start_req(hsotg, hs_ep, hs_req, false);
+               }
+       }
+}
+
+/**
+ * s3c_hsotg_complete_request_lock - complete a request given to us (locked)
+ * @hsotg: The device state.
+ * @hs_ep: The endpoint the request was on.
+ * @hs_req: The request to complete.
+ * @result: The result code (0 => Ok, otherwise errno)
+ *
+ * See s3c_hsotg_complete_request(), but called with the endpoint's
+ * lock held.
+*/
+static void s3c_hsotg_complete_request_lock(struct s3c_hsotg *hsotg,
+                                           struct s3c_hsotg_ep *hs_ep,
+                                           struct s3c_hsotg_req *hs_req,
+                                           int result)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&hs_ep->lock, flags);
+       s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, result);
+       spin_unlock_irqrestore(&hs_ep->lock, flags);
+}
+
+/**
+ * s3c_hsotg_rx_data - receive data from the FIFO for an endpoint
+ * @hsotg: The device state.
+ * @ep_idx: The endpoint index for the data
+ * @size: The size of data in the fifo, in bytes
+ *
+ * The FIFO status shows there is data to read from the FIFO for a given
+ * endpoint, so sort out whether we need to read the data into a request
+ * that has been made for that endpoint.
+ */
+static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size)
+{
+       struct s3c_hsotg_ep *hs_ep = &hsotg->eps[ep_idx];
+       struct s3c_hsotg_req *hs_req = hs_ep->req;
+       void __iomem *fifo = hsotg->regs + S3C_EPFIFO(ep_idx);
+       int to_read;
+       int max_req;
+       int read_ptr;
+
+       if (!hs_req) {
+               u32 epctl = readl(hsotg->regs + S3C_DOEPCTL(ep_idx));
+               int ptr;
+
+               dev_warn(hsotg->dev,
+                        "%s: FIFO %d bytes on ep%d but no req (DxEPCTl=0x%08x)\n",
+                        __func__, size, ep_idx, epctl);
+
+               /* dump the data from the FIFO, we've nothing we can do */
+               for (ptr = 0; ptr < size; ptr += 4)
+                       (void)readl(fifo);
+
+               return;
+       }
+
+       spin_lock(&hs_ep->lock);
+
+       to_read = size;
+       read_ptr = hs_req->req.actual;
+       max_req = hs_req->req.length - read_ptr;
+
+       if (to_read > max_req) {
+               /* more data appeared than we where willing
+                * to deal with in this request.
+                */
+
+               /* currently we don't deal this */
+               WARN_ON_ONCE(1);
+       }
+
+       dev_dbg(hsotg->dev, "%s: read %d/%d, done %d/%d\n",
+               __func__, to_read, max_req, read_ptr, hs_req->req.length);
+
+       hs_ep->total_data += to_read;
+       hs_req->req.actual += to_read;
+       to_read = DIV_ROUND_UP(to_read, 4);
+
+       /* note, we might over-write the buffer end by 3 bytes depending on
+        * alignment of the data. */
+       readsl(fifo, hs_req->req.buf + read_ptr, to_read);
+
+       spin_unlock(&hs_ep->lock);
+}
+
+/**
+ * s3c_hsotg_send_zlp - send zero-length packet on control endpoint
+ * @hsotg: The device instance
+ * @req: The request currently on this endpoint
+ *
+ * Generate a zero-length IN packet request for terminating a SETUP
+ * transaction.
+ *
+ * Note, since we don't write any data to the TxFIFO, then it is
+ * currently belived that we do not need to wait for any space in
+ * the TxFIFO.
+ */
+static void s3c_hsotg_send_zlp(struct s3c_hsotg *hsotg,
+                              struct s3c_hsotg_req *req)
+{
+       u32 ctrl;
+
+       if (!req) {
+               dev_warn(hsotg->dev, "%s: no request?\n", __func__);
+               return;
+       }
+
+       if (req->req.length == 0) {
+               hsotg->eps[0].sent_zlp = 1;
+               s3c_hsotg_enqueue_setup(hsotg);
+               return;
+       }
+
+       hsotg->eps[0].dir_in = 1;
+       hsotg->eps[0].sent_zlp = 1;
+
+       dev_dbg(hsotg->dev, "sending zero-length packet\n");
+
+       /* issue a zero-sized packet to terminate this */
+       writel(S3C_DxEPTSIZ_MC(1) | S3C_DxEPTSIZ_PktCnt(1) |
+              S3C_DxEPTSIZ_XferSize(0), hsotg->regs + S3C_DIEPTSIZ(0));
+
+       ctrl = readl(hsotg->regs + S3C_DIEPCTL0);
+       ctrl |= S3C_DxEPCTL_CNAK;  /* clear NAK set by core */
+       ctrl |= S3C_DxEPCTL_EPEna; /* ensure ep enabled */
+       ctrl |= S3C_DxEPCTL_USBActEp;
+       writel(ctrl, hsotg->regs + S3C_DIEPCTL0);
+}
+
+/**
+ * s3c_hsotg_handle_outdone - handle receiving OutDone/SetupDone from RXFIFO
+ * @hsotg: The device instance
+ * @epnum: The endpoint received from
+ * @was_setup: Set if processing a SetupDone event.
+ *
+ * The RXFIFO has delivered an OutDone event, which means that the data
+ * transfer for an OUT endpoint has been completed, either by a short
+ * packet or by the finish of a transfer.
+*/
+static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg,
+                                    int epnum, bool was_setup)
+{
+       struct s3c_hsotg_ep *hs_ep = &hsotg->eps[epnum];
+       struct s3c_hsotg_req *hs_req = hs_ep->req;
+       struct usb_request *req = &hs_req->req;
+       int result = 0;
+
+       if (!hs_req) {
+               dev_dbg(hsotg->dev, "%s: no request active\n", __func__);
+               return;
+       }
+
+       if (using_dma(hsotg)) {
+               u32 epsize = readl(hsotg->regs + S3C_DOEPTSIZ(epnum));
+               unsigned size_done;
+               unsigned size_left;
+
+               /* Calculate the size of the transfer by checking how much
+                * is left in the endpoint size register and then working it
+                * out from the amount we loaded for the transfer.
+                *
+                * We need to do this as DMA pointers are always 32bit aligned
+                * so may overshoot/undershoot the transfer.
+                */
+
+               size_left = S3C_DxEPTSIZ_XferSize_GET(epsize);
+
+               size_done = hs_ep->size_loaded - size_left;
+               size_done += hs_ep->last_load;
+
+               req->actual = size_done;
+       }
+
+       if (req->actual < req->length && req->short_not_ok) {
+               dev_dbg(hsotg->dev, "%s: got %d/%d (short not ok) => error\n",
+                       __func__, req->actual, req->length);
+
+               /* todo - what should we return here? there's no one else
+                * even bothering to check the status. */
+       }
+
+       if (epnum == 0) {
+               if (!was_setup && req->complete != s3c_hsotg_complete_setup)
+                       s3c_hsotg_send_zlp(hsotg, hs_req);
+       }
+
+       s3c_hsotg_complete_request_lock(hsotg, hs_ep, hs_req, result);
+}
+
+/**
+ * s3c_hsotg_read_frameno - read current frame number
+ * @hsotg: The device instance
+ *
+ * Return the current frame number
+*/
+static u32 s3c_hsotg_read_frameno(struct s3c_hsotg *hsotg)
+{
+       u32 dsts;
+
+       dsts = readl(hsotg->regs + S3C_DSTS);
+       dsts &= S3C_DSTS_SOFFN_MASK;
+       dsts >>= S3C_DSTS_SOFFN_SHIFT;
+
+       return dsts;
+}
+
+/**
+ * s3c_hsotg_handle_rx - RX FIFO has data
+ * @hsotg: The device instance
+ *
+ * The IRQ handler has detected that the RX FIFO has some data in it
+ * that requires processing, so find out what is in there and do the
+ * appropriate read.
+ *
+ * The RXFIFO is a true FIFO, the packets comming out are still in packet
+ * chunks, so if you have x packets received on an endpoint you'll get x
+ * FIFO events delivered, each with a packet's worth of data in it.
+ *
+ * When using DMA, we should not be processing events from the RXFIFO
+ * as the actual data should be sent to the memory directly and we turn
+ * on the completion interrupts to get notifications of transfer completion.
+ */
+void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg)
+{
+       u32 grxstsr = readl(hsotg->regs + S3C_GRXSTSP);
+       u32 epnum, status, size;
+
+       WARN_ON(using_dma(hsotg));
+
+       epnum = grxstsr & S3C_GRXSTS_EPNum_MASK;
+       status = grxstsr & S3C_GRXSTS_PktSts_MASK;
+
+       size = grxstsr & S3C_GRXSTS_ByteCnt_MASK;
+       size >>= S3C_GRXSTS_ByteCnt_SHIFT;
+
+       if (1)
+               dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n",
+                       __func__, grxstsr, size, epnum);
+
+#define __status(x) ((x) >> S3C_GRXSTS_PktSts_SHIFT)
+
+       switch (status >> S3C_GRXSTS_PktSts_SHIFT) {
+       case __status(S3C_GRXSTS_PktSts_GlobalOutNAK):
+               dev_dbg(hsotg->dev, "GlobalOutNAK\n");
+               break;
+
+       case __status(S3C_GRXSTS_PktSts_OutDone):
+               dev_dbg(hsotg->dev, "OutDone (Frame=0x%08x)\n",
+                       s3c_hsotg_read_frameno(hsotg));
+
+               if (!using_dma(hsotg))
+                       s3c_hsotg_handle_outdone(hsotg, epnum, false);
+               break;
+
+       case __status(S3C_GRXSTS_PktSts_SetupDone):
+               dev_dbg(hsotg->dev,
+                       "SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n",
+                       s3c_hsotg_read_frameno(hsotg),
+                       readl(hsotg->regs + S3C_DOEPCTL(0)));
+
+               s3c_hsotg_handle_outdone(hsotg, epnum, true);
+               break;
+
+       case __status(S3C_GRXSTS_PktSts_OutRX):
+               s3c_hsotg_rx_data(hsotg, epnum, size);
+               break;
+
+       case __status(S3C_GRXSTS_PktSts_SetupRX):
+               dev_dbg(hsotg->dev,
+                       "SetupRX (Frame=0x%08x, DOPEPCTL=0x%08x)\n",
+                       s3c_hsotg_read_frameno(hsotg),
+                       readl(hsotg->regs + S3C_DOEPCTL(0)));
+
+               s3c_hsotg_rx_data(hsotg, epnum, size);
+               break;
+
+       default:
+               dev_warn(hsotg->dev, "%s: unknown status %08x\n",
+                        __func__, grxstsr);
+
+               s3c_hsotg_dump(hsotg);
+               break;
+       }
+}
+
+/**
+ * s3c_hsotg_ep0_mps - turn max packet size into register setting
+ * @mps: The maximum packet size in bytes.
+*/
+static u32 s3c_hsotg_ep0_mps(unsigned int mps)
+{
+       switch (mps) {
+       case 64:
+               return S3C_D0EPCTL_MPS_64;
+       case 32:
+               return S3C_D0EPCTL_MPS_32;
+       case 16:
+               return S3C_D0EPCTL_MPS_16;
+       case 8:
+               return S3C_D0EPCTL_MPS_8;
+       }
+
+       /* bad max packet size, warn and return invalid result */
+       WARN_ON(1);
+       return (u32)-1;
+}
+
+/**
+ * s3c_hsotg_set_ep_maxpacket - set endpoint's max-packet field
+ * @hsotg: The driver state.
+ * @ep: The index number of the endpoint
+ * @mps: The maximum packet size in bytes
+ *
+ * Configure the maximum packet size for the given endpoint, updating
+ * the hardware control registers to reflect this.
+ */
+static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg,
+                                      unsigned int ep, unsigned int mps)
+{
+       struct s3c_hsotg_ep *hs_ep = &hsotg->eps[ep];
+       void __iomem *regs = hsotg->regs;
+       u32 mpsval;
+       u32 reg;
+
+       if (ep == 0) {
+               /* EP0 is a special case */
+               mpsval = s3c_hsotg_ep0_mps(mps);
+               if (mpsval > 3)
+                       goto bad_mps;
+       } else {
+               if (mps >= S3C_DxEPCTL_MPS_LIMIT+1)
+                       goto bad_mps;
+
+               mpsval = mps;
+       }
+
+       hs_ep->ep.maxpacket = mps;
+
+       /* update both the in and out endpoint controldir_ registers, even
+        * if one of the directions may not be in use. */
+
+       reg = readl(regs + S3C_DIEPCTL(ep));
+       reg &= ~S3C_DxEPCTL_MPS_MASK;
+       reg |= mpsval;
+       writel(reg, regs + S3C_DIEPCTL(ep));
+
+       reg = readl(regs + S3C_DOEPCTL(ep));
+       reg &= ~S3C_DxEPCTL_MPS_MASK;
+       reg |= mpsval;
+       writel(reg, regs + S3C_DOEPCTL(ep));
+
+       return;
+
+bad_mps:
+       dev_err(hsotg->dev, "ep%d: bad mps of %d\n", ep, mps);
+}
+
+
+/**
+ * s3c_hsotg_trytx - check to see if anything needs transmitting
+ * @hsotg: The driver state
+ * @hs_ep: The driver endpoint to check.
+ *
+ * Check to see if there is a request that has data to send, and if so
+ * make an attempt to write data into the FIFO.
+ */
+static int s3c_hsotg_trytx(struct s3c_hsotg *hsotg,
+                          struct s3c_hsotg_ep *hs_ep)
+{
+       struct s3c_hsotg_req *hs_req = hs_ep->req;
+
+       if (!hs_ep->dir_in || !hs_req)
+               return 0;
+
+       if (hs_req->req.actual < hs_req->req.length) {
+               dev_dbg(hsotg->dev, "trying to write more for ep%d\n",
+                       hs_ep->index);
+               return s3c_hsotg_write_fifo(hsotg, hs_ep, hs_req);
+       }
+
+       return 0;
+}
+
+/**
+ * s3c_hsotg_complete_in - complete IN transfer
+ * @hsotg: The device state.
+ * @hs_ep: The endpoint that has just completed.
+ *
+ * An IN transfer has been completed, update the transfer's state and then
+ * call the relevant completion routines.
+ */
+static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg,
+                                 struct s3c_hsotg_ep *hs_ep)
+{
+       struct s3c_hsotg_req *hs_req = hs_ep->req;
+       u32 epsize = readl(hsotg->regs + S3C_DIEPTSIZ(hs_ep->index));
+       int size_left, size_done;
+
+       if (!hs_req) {
+               dev_dbg(hsotg->dev, "XferCompl but no req\n");
+               return;
+       }
+
+       /* Calculate the size of the transfer by checking how much is left
+        * in the endpoint size register and then working it out from
+        * the amount we loaded for the transfer.
+        *
+        * We do this even for DMA, as the transfer may have incremented
+        * past the end of the buffer (DMA transfers are always 32bit
+        * aligned).
+        */
+
+       size_left = S3C_DxEPTSIZ_XferSize_GET(epsize);
+
+       size_done = hs_ep->size_loaded - size_left;
+       size_done += hs_ep->last_load;
+
+       if (hs_req->req.actual != size_done)
+               dev_dbg(hsotg->dev, "%s: adjusting size done %d => %d\n",
+                       __func__, hs_req->req.actual, size_done);
+
+       hs_req->req.actual = size_done;
+
+       /* if we did all of the transfer, and there is more data left
+        * around, then try restarting the rest of the request */
+
+       if (!size_left && hs_req->req.actual < hs_req->req.length) {
+               dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__);
+               s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true);
+       } else
+               s3c_hsotg_complete_request_lock(hsotg, hs_ep, hs_req, 0);
+}
+
+/**
+ * s3c_hsotg_epint - handle an in/out endpoint interrupt
+ * @hsotg: The driver state
+ * @idx: The index for the endpoint (0..15)
+ * @dir_in: Set if this is an IN endpoint
+ *
+ * Process and clear any interrupt pending for an individual endpoint
+*/
+static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
+                           int dir_in)
+{
+       struct s3c_hsotg_ep *hs_ep = &hsotg->eps[idx];
+       u32 epint_reg = dir_in ? S3C_DIEPINT(idx) : S3C_DOEPINT(idx);
+       u32 epctl_reg = dir_in ? S3C_DIEPCTL(idx) : S3C_DOEPCTL(idx);
+       u32 epsiz_reg = dir_in ? S3C_DIEPTSIZ(idx) : S3C_DOEPTSIZ(idx);
+       u32 ints;
+       u32 clear = 0;
+
+       ints = readl(hsotg->regs + epint_reg);
+
+       dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n",
+               __func__, idx, dir_in ? "in" : "out", ints);
+
+       if (ints & S3C_DxEPINT_XferCompl) {
+               dev_dbg(hsotg->dev,
+                       "%s: XferCompl: DxEPCTL=0x%08x, DxEPTSIZ=%08x\n",
+                       __func__, readl(hsotg->regs + epctl_reg),
+                       readl(hsotg->regs + epsiz_reg));
+
+               /* we get OutDone from the FIFO, so we only need to look
+                * at completing IN requests here */
+               if (dir_in) {
+                       s3c_hsotg_complete_in(hsotg, hs_ep);
+
+                       if (idx == 0)
+                               s3c_hsotg_enqueue_setup(hsotg);
+               } else if (using_dma(hsotg)) {
+                       /* We're using DMA, we need to fire an OutDone here
+                        * as we ignore the RXFIFO. */
+
+                       s3c_hsotg_handle_outdone(hsotg, idx, false);
+               }
+
+               clear |= S3C_DxEPINT_XferCompl;
+       }
+
+       if (ints & S3C_DxEPINT_EPDisbld) {
+               dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__);
+               clear |= S3C_DxEPINT_EPDisbld;
+       }
+
+       if (ints & S3C_DxEPINT_AHBErr) {
+               dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__);
+               clear |= S3C_DxEPINT_AHBErr;
+       }
+
+       if (ints & S3C_DxEPINT_Setup) {  /* Setup or Timeout */
+               dev_dbg(hsotg->dev, "%s: Setup/Timeout\n",  __func__);
+
+               if (using_dma(hsotg) && idx == 0) {
+                       /* this is the notification we've received a
+                        * setup packet. In non-DMA mode we'd get this
+                        * from the RXFIFO, instead we need to process
+                        * the setup here. */
+
+                       if (dir_in)
+                               WARN_ON_ONCE(1);
+                       else
+                               s3c_hsotg_handle_outdone(hsotg, 0, true);
+               }
+
+               clear |= S3C_DxEPINT_Setup;
+       }
+
+       if (ints & S3C_DxEPINT_Back2BackSetup) {
+               dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__);
+               clear |= S3C_DxEPINT_Back2BackSetup;
+       }
+
+       if (dir_in) {
+               /* not sure if this is important, but we'll clear it anyway
+                */
+               if (ints & S3C_DIEPMSK_INTknTXFEmpMsk) {
+                       dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n",
+                               __func__, idx);
+                       clear |= S3C_DIEPMSK_INTknTXFEmpMsk;
+               }
+
+               /* this probably means something bad is happening */
+               if (ints & S3C_DIEPMSK_INTknEPMisMsk) {
+                       dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n",
+                                __func__, idx);
+                       clear |= S3C_DIEPMSK_INTknEPMisMsk;
+               }
+       }
+
+       writel(clear, hsotg->regs + epint_reg);
+}
+
+/**
+ * s3c_hsotg_irq_enumdone - Handle EnumDone interrupt (enumeration done)
+ * @hsotg: The device state.
+ *
+ * Handle updating the device settings after the enumeration phase has
+ * been completed.
+*/
+static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg)
+{
+       u32 dsts = readl(hsotg->regs + S3C_DSTS);
+       int ep0_mps = 0, ep_mps;
+
+       /* This should signal the finish of the enumeration phase
+        * of the USB handshaking, so we should now know what rate
+        * we connected at. */
+
+       dev_dbg(hsotg->dev, "EnumDone (DSTS=0x%08x)\n", dsts);
+
+       /* note, since we're limited by the size of transfer on EP0, and
+        * it seems IN transfers must be a even number of packets we do
+        * not advertise a 64byte MPS on EP0. */
+
+       /* catch both EnumSpd_FS and EnumSpd_FS48 */
+       switch (dsts & S3C_DSTS_EnumSpd_MASK) {
+       case S3C_DSTS_EnumSpd_FS:
+       case S3C_DSTS_EnumSpd_FS48:
+               hsotg->gadget.speed = USB_SPEED_FULL;
+               dev_info(hsotg->dev, "new device is full-speed\n");
+
+               ep0_mps = EP0_MPS_LIMIT;
+               ep_mps = 64;
+               break;
+
+       case S3C_DSTS_EnumSpd_HS:
+               dev_info(hsotg->dev, "new device is high-speed\n");
+               hsotg->gadget.speed = USB_SPEED_HIGH;
+
+               ep0_mps = EP0_MPS_LIMIT;
+               ep_mps = 512;
+               break;
+
+       case S3C_DSTS_EnumSpd_LS:
+               hsotg->gadget.speed = USB_SPEED_LOW;
+               dev_info(hsotg->dev, "new device is low-speed\n");
+
+               /* note, we don't actually support LS in this driver at the
+                * moment, and the documentation seems to imply that it isn't
+                * supported by the PHYs on some of the devices.
+                */
+               break;
+       }
+
+       /* we should now know the maximum packet size for an
+        * endpoint, so set the endpoints to a default value. */
+
+       if (ep0_mps) {
+               int i;
+               s3c_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps);
+               for (i = 1; i < S3C_HSOTG_EPS; i++)
+                       s3c_hsotg_set_ep_maxpacket(hsotg, i, ep_mps);
+       }
+
+       /* ensure after enumeration our EP0 is active */
+
+       s3c_hsotg_enqueue_setup(hsotg);
+
+       dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
+               readl(hsotg->regs + S3C_DIEPCTL0),
+               readl(hsotg->regs + S3C_DOEPCTL0));
+}
+
+/**
+ * kill_all_requests - remove all requests from the endpoint's queue
+ * @hsotg: The device state.
+ * @ep: The endpoint the requests may be on.
+ * @result: The result code to use.
+ * @force: Force removal of any current requests
+ *
+ * Go through the requests on the given endpoint and mark them
+ * completed with the given result code.
+ */
+static void kill_all_requests(struct s3c_hsotg *hsotg,
+                             struct s3c_hsotg_ep *ep,
+                             int result, bool force)
+{
+       struct s3c_hsotg_req *req, *treq;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ep->lock, flags);
+
+       list_for_each_entry_safe(req, treq, &ep->queue, queue) {
+               /* currently, we can't do much about an already
+                * running request on an in endpoint */
+
+               if (ep->req == req && ep->dir_in && !force)
+                       continue;
+
+               s3c_hsotg_complete_request(hsotg, ep, req,
+                                          result);
+       }
+
+       spin_unlock_irqrestore(&ep->lock, flags);
+}
+
+#define call_gadget(_hs, _entry) \
+       if ((_hs)->gadget.speed != USB_SPEED_UNKNOWN && \
+           (_hs)->driver && (_hs)->driver->_entry)     \
+               (_hs)->driver->_entry(&(_hs)->gadget);
+
+/**
+ * s3c_hsotg_disconnect_irq - disconnect irq service
+ * @hsotg: The device state.
+ *
+ * A disconnect IRQ has been received, meaning that the host has
+ * lost contact with the bus. Remove all current transactions
+ * and signal the gadget driver that this has happened.
+*/
+static void s3c_hsotg_disconnect_irq(struct s3c_hsotg *hsotg)
+{
+       unsigned ep;
+
+       for (ep = 0; ep < S3C_HSOTG_EPS; ep++)
+               kill_all_requests(hsotg, &hsotg->eps[ep], -ESHUTDOWN, true);
+
+       call_gadget(hsotg, disconnect);
+}
+
+/**
+ * s3c_hsotg_irq_fifoempty - TX FIFO empty interrupt handler
+ * @hsotg: The device state:
+ * @periodic: True if this is a periodic FIFO interrupt
+ */
+static void s3c_hsotg_irq_fifoempty(struct s3c_hsotg *hsotg, bool periodic)
+{
+       struct s3c_hsotg_ep *ep;
+       int epno, ret;
+
+       /* look through for any more data to transmit */
+
+       for (epno = 0; epno < S3C_HSOTG_EPS; epno++) {
+               ep = &hsotg->eps[epno];
+
+               if (!ep->dir_in)
+                       continue;
+
+               if ((periodic && !ep->periodic) ||
+                   (!periodic && ep->periodic))
+                       continue;
+
+               ret = s3c_hsotg_trytx(hsotg, ep);
+               if (ret < 0)
+                       break;
+       }
+}
+
+static struct s3c_hsotg *our_hsotg;
+
+/* IRQ flags which will trigger a retry around the IRQ loop */
+#define IRQ_RETRY_MASK (S3C_GINTSTS_NPTxFEmp | \
+                       S3C_GINTSTS_PTxFEmp |  \
+                       S3C_GINTSTS_RxFLvl)
+
+/**
+ * s3c_hsotg_irq - handle device interrupt
+ * @irq: The IRQ number triggered
+ * @pw: The pw value when registered the handler.
+ */
+static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
+{
+       struct s3c_hsotg *hsotg = pw;
+       int retry_count = 8;
+       u32 gintsts;
+       u32 gintmsk;
+
+irq_retry:
+       gintsts = readl(hsotg->regs + S3C_GINTSTS);
+       gintmsk = readl(hsotg->regs + S3C_GINTMSK);
+
+       dev_dbg(hsotg->dev, "%s: %08x %08x (%08x) retry %d\n",
+               __func__, gintsts, gintsts & gintmsk, gintmsk, retry_count);
+
+       gintsts &= gintmsk;
+
+       if (gintsts & S3C_GINTSTS_OTGInt) {
+               u32 otgint = readl(hsotg->regs + S3C_GOTGINT);
+
+               dev_info(hsotg->dev, "OTGInt: %08x\n", otgint);
+
+               writel(otgint, hsotg->regs + S3C_GOTGINT);
+               writel(S3C_GINTSTS_OTGInt, hsotg->regs + S3C_GINTSTS);
+       }
+
+       if (gintsts & S3C_GINTSTS_DisconnInt) {
+               dev_dbg(hsotg->dev, "%s: DisconnInt\n", __func__);
+               writel(S3C_GINTSTS_DisconnInt, hsotg->regs + S3C_GINTSTS);
+
+               s3c_hsotg_disconnect_irq(hsotg);
+       }
+
+       if (gintsts & S3C_GINTSTS_SessReqInt) {
+               dev_dbg(hsotg->dev, "%s: SessReqInt\n", __func__);
+               writel(S3C_GINTSTS_SessReqInt, hsotg->regs + S3C_GINTSTS);
+       }
+
+       if (gintsts & S3C_GINTSTS_EnumDone) {
+               s3c_hsotg_irq_enumdone(hsotg);
+               writel(S3C_GINTSTS_EnumDone, hsotg->regs + S3C_GINTSTS);
+       }
+
+       if (gintsts & S3C_GINTSTS_ConIDStsChng) {
+               dev_dbg(hsotg->dev, "ConIDStsChg (DSTS=0x%08x, GOTCTL=%08x)\n",
+                       readl(hsotg->regs + S3C_DSTS),
+                       readl(hsotg->regs + S3C_GOTGCTL));
+
+               writel(S3C_GINTSTS_ConIDStsChng, hsotg->regs + S3C_GINTSTS);
+       }
+
+       if (gintsts & (S3C_GINTSTS_OEPInt | S3C_GINTSTS_IEPInt)) {
+               u32 daint = readl(hsotg->regs + S3C_DAINT);
+               u32 daint_out = daint >> S3C_DAINT_OutEP_SHIFT;
+               u32 daint_in = daint & ~(daint_out << S3C_DAINT_OutEP_SHIFT);
+               int ep;
+
+               dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint);
+
+               for (ep = 0; ep < 15 && daint_out; ep++, daint_out >>= 1) {
+                       if (daint_out & 1)
+                               s3c_hsotg_epint(hsotg, ep, 0);
+               }
+
+               for (ep = 0; ep < 15 && daint_in; ep++, daint_in >>= 1) {
+                       if (daint_in & 1)
+                               s3c_hsotg_epint(hsotg, ep, 1);
+               }
+
+               writel(daint, hsotg->regs + S3C_DAINT);
+               writel(gintsts & (S3C_GINTSTS_OEPInt | S3C_GINTSTS_IEPInt),
+                      hsotg->regs + S3C_GINTSTS);
+       }
+
+       if (gintsts & S3C_GINTSTS_USBRst) {
+               dev_info(hsotg->dev, "%s: USBRst\n", __func__);
+               dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n",
+                       readl(hsotg->regs + S3C_GNPTXSTS));
+
+               kill_all_requests(hsotg, &hsotg->eps[0], -ECONNRESET, true);
+
+               /* it seems after a reset we can end up with a situation
+                * where the TXFIFO still has data in it... try flushing
+                * it to remove anything that may still be in it.
+                */
+
+               if (1) {
+                       writel(S3C_GRSTCTL_TxFNum(0) | S3C_GRSTCTL_TxFFlsh,
+                              hsotg->regs + S3C_GRSTCTL);
+
+                       dev_info(hsotg->dev, "GNPTXSTS=%08x\n",
+                                readl(hsotg->regs + S3C_GNPTXSTS));
+               }
+
+               s3c_hsotg_enqueue_setup(hsotg);
+
+               writel(S3C_GINTSTS_USBRst, hsotg->regs + S3C_GINTSTS);
+       }
+
+       /* check both FIFOs */
+
+       if (gintsts & S3C_GINTSTS_NPTxFEmp) {
+               dev_dbg(hsotg->dev, "NPTxFEmp\n");
+
+               /* Disable the interrupt to stop it happening again
+                * unless one of these endpoint routines decides that
+                * it needs re-enabling */
+
+               s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_NPTxFEmp);
+               s3c_hsotg_irq_fifoempty(hsotg, false);
+
+               writel(S3C_GINTSTS_NPTxFEmp, hsotg->regs + S3C_GINTSTS);
+       }
+
+       if (gintsts & S3C_GINTSTS_PTxFEmp) {
+               dev_dbg(hsotg->dev, "PTxFEmp\n");
+
+               /* See note in S3C_GINTSTS_NPTxFEmp */
+
+               s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_PTxFEmp);
+               s3c_hsotg_irq_fifoempty(hsotg, true);
+
+               writel(S3C_GINTSTS_PTxFEmp, hsotg->regs + S3C_GINTSTS);
+       }
+
+       if (gintsts & S3C_GINTSTS_RxFLvl) {
+               /* note, since GINTSTS_RxFLvl doubles as FIFO-not-empty,
+                * we need to retry s3c_hsotg_handle_rx if this is still
+                * set. */
+
+               s3c_hsotg_handle_rx(hsotg);
+               writel(S3C_GINTSTS_RxFLvl, hsotg->regs + S3C_GINTSTS);
+       }
+
+       if (gintsts & S3C_GINTSTS_ModeMis) {
+               dev_warn(hsotg->dev, "warning, mode mismatch triggered\n");
+               writel(S3C_GINTSTS_ModeMis, hsotg->regs + S3C_GINTSTS);
+       }
+
+       if (gintsts & S3C_GINTSTS_USBSusp) {
+               dev_info(hsotg->dev, "S3C_GINTSTS_USBSusp\n");
+               writel(S3C_GINTSTS_USBSusp, hsotg->regs + S3C_GINTSTS);
+
+               call_gadget(hsotg, suspend);
+       }
+
+       if (gintsts & S3C_GINTSTS_WkUpInt) {
+               dev_info(hsotg->dev, "S3C_GINTSTS_WkUpIn\n");
+               writel(S3C_GINTSTS_WkUpInt, hsotg->regs + S3C_GINTSTS);
+
+               call_gadget(hsotg, resume);
+       }
+
+       if (gintsts & S3C_GINTSTS_ErlySusp) {
+               dev_dbg(hsotg->dev, "S3C_GINTSTS_ErlySusp\n");
+               writel(S3C_GINTSTS_ErlySusp, hsotg->regs + S3C_GINTSTS);
+       }
+
+       /* these next two seem to crop-up occasionally causing the core
+        * to shutdown the USB transfer, so try clearing them and logging
+        * the occurence. */
+
+       if (gintsts & S3C_GINTSTS_GOUTNakEff) {
+               dev_info(hsotg->dev, "GOUTNakEff triggered\n");
+
+               s3c_hsotg_dump(hsotg);
+
+               writel(S3C_DCTL_CGOUTNak, hsotg->regs + S3C_DCTL);
+               writel(S3C_GINTSTS_GOUTNakEff, hsotg->regs + S3C_GINTSTS);
+       }
+
+       if (gintsts & S3C_GINTSTS_GINNakEff) {
+               dev_info(hsotg->dev, "GINNakEff triggered\n");
+
+               s3c_hsotg_dump(hsotg);
+
+               writel(S3C_DCTL_CGNPInNAK, hsotg->regs + S3C_DCTL);
+               writel(S3C_GINTSTS_GINNakEff, hsotg->regs + S3C_GINTSTS);
+       }
+
+       /* if we've had fifo events, we should try and go around the
+        * loop again to see if there's any point in returning yet. */
+
+       if (gintsts & IRQ_RETRY_MASK && --retry_count > 0)
+                       goto irq_retry;
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * s3c_hsotg_ep_enable - enable the given endpoint
+ * @ep: The USB endpint to configure
+ * @desc: The USB endpoint descriptor to configure with.
+ *
+ * This is called from the USB gadget code's usb_ep_enable().
+*/
+static int s3c_hsotg_ep_enable(struct usb_ep *ep,
+                              const struct usb_endpoint_descriptor *desc)
+{
+       struct s3c_hsotg_ep *hs_ep = our_ep(ep);
+       struct s3c_hsotg *hsotg = hs_ep->parent;
+       unsigned long flags;
+       int index = hs_ep->index;
+       u32 epctrl_reg;
+       u32 epctrl;
+       u32 mps;
+       int dir_in;
+
+       dev_dbg(hsotg->dev,
+               "%s: ep %s: a 0x%02x, attr 0x%02x, mps 0x%04x, intr %d\n",
+               __func__, ep->name, desc->bEndpointAddress, desc->bmAttributes,
+               desc->wMaxPacketSize, desc->bInterval);
+
+       /* not to be called for EP0 */
+       WARN_ON(index == 0);
+
+       dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0;
+       if (dir_in != hs_ep->dir_in) {
+               dev_err(hsotg->dev, "%s: direction mismatch!\n", __func__);
+               return -EINVAL;
+       }
+
+       mps = le16_to_cpu(desc->wMaxPacketSize);
+
+       /* note, we handle this here instead of s3c_hsotg_set_ep_maxpacket */
+
+       epctrl_reg = dir_in ? S3C_DIEPCTL(index) : S3C_DOEPCTL(index);
+       epctrl = readl(hsotg->regs + epctrl_reg);
+
+       dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n",
+               __func__, epctrl, epctrl_reg);
+
+       spin_lock_irqsave(&hs_ep->lock, flags);
+
+       epctrl &= ~(S3C_DxEPCTL_EPType_MASK | S3C_DxEPCTL_MPS_MASK);
+       epctrl |= S3C_DxEPCTL_MPS(mps);
+
+       /* mark the endpoint as active, otherwise the core may ignore
+        * transactions entirely for this endpoint */
+       epctrl |= S3C_DxEPCTL_USBActEp;
+
+       /* set the NAK status on the endpoint, otherwise we might try and
+        * do something with data that we've yet got a request to process
+        * since the RXFIFO will take data for an endpoint even if the
+        * size register hasn't been set.
+        */
+
+       epctrl |= S3C_DxEPCTL_SNAK;
+
+       /* update the endpoint state */
+       hs_ep->ep.maxpacket = mps;
+
+       /* default, set to non-periodic */
+       hs_ep->periodic = 0;
+
+       switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+       case USB_ENDPOINT_XFER_ISOC:
+               dev_err(hsotg->dev, "no current ISOC support\n");
+               return -EINVAL;
+
+       case USB_ENDPOINT_XFER_BULK:
+               epctrl |= S3C_DxEPCTL_EPType_Bulk;
+               break;
+
+       case USB_ENDPOINT_XFER_INT:
+               if (dir_in) {
+                       /* Allocate our TxFNum by simply using the index
+                        * of the endpoint for the moment. We could do
+                        * something better if the host indicates how
+                        * many FIFOs we are expecting to use. */
+
+                       hs_ep->periodic = 1;
+                       epctrl |= S3C_DxEPCTL_TxFNum(index);
+               }
+
+               epctrl |= S3C_DxEPCTL_EPType_Intterupt;
+               break;
+
+       case USB_ENDPOINT_XFER_CONTROL:
+               epctrl |= S3C_DxEPCTL_EPType_Control;
+               break;
+       }
+
+       /* for non control endpoints, set PID to D0 */
+       if (index)
+               epctrl |= S3C_DxEPCTL_SetD0PID;
+
+       dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n",
+               __func__, epctrl);
+
+       writel(epctrl, hsotg->regs + epctrl_reg);
+       dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x\n",
+               __func__, readl(hsotg->regs + epctrl_reg));
+
+       /* enable the endpoint interrupt */
+       s3c_hsotg_ctrl_epint(hsotg, index, dir_in, 1);
+
+       spin_unlock_irqrestore(&hs_ep->lock, flags);
+       return 0;
+}
+
+static int s3c_hsotg_ep_disable(struct usb_ep *ep)
+{
+       struct s3c_hsotg_ep *hs_ep = our_ep(ep);
+       struct s3c_hsotg *hsotg = hs_ep->parent;
+       int dir_in = hs_ep->dir_in;
+       int index = hs_ep->index;
+       unsigned long flags;
+       u32 epctrl_reg;
+       u32 ctrl;
+
+       dev_info(hsotg->dev, "%s(ep %p)\n", __func__, ep);
+
+       if (ep == &hsotg->eps[0].ep) {
+               dev_err(hsotg->dev, "%s: called for ep0\n", __func__);
+               return -EINVAL;
+       }
+
+       epctrl_reg = dir_in ? S3C_DIEPCTL(index) : S3C_DOEPCTL(index);
+
+       /* terminate all requests with shutdown */
+       kill_all_requests(hsotg, hs_ep, -ESHUTDOWN, false);
+
+       spin_lock_irqsave(&hs_ep->lock, flags);
+
+       ctrl = readl(hsotg->regs + epctrl_reg);
+       ctrl &= ~S3C_DxEPCTL_EPEna;
+       ctrl &= ~S3C_DxEPCTL_USBActEp;
+       ctrl |= S3C_DxEPCTL_SNAK;
+
+       dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl);
+       writel(ctrl, hsotg->regs + epctrl_reg);
+
+       /* disable endpoint interrupts */
+       s3c_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 0);
+
+       spin_unlock_irqrestore(&hs_ep->lock, flags);
+       return 0;
+}
+
+/**
+ * on_list - check request is on the given endpoint
+ * @ep: The endpoint to check.
+ * @test: The request to test if it is on the endpoint.
+*/
+static bool on_list(struct s3c_hsotg_ep *ep, struct s3c_hsotg_req *test)
+{
+       struct s3c_hsotg_req *req, *treq;
+
+       list_for_each_entry_safe(req, treq, &ep->queue, queue) {
+               if (req == test)
+                       return true;
+       }
+
+       return false;
+}
+
+static int s3c_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
+{
+       struct s3c_hsotg_req *hs_req = our_req(req);
+       struct s3c_hsotg_ep *hs_ep = our_ep(ep);
+       struct s3c_hsotg *hs = hs_ep->parent;
+       unsigned long flags;
+
+       dev_info(hs->dev, "ep_dequeue(%p,%p)\n", ep, req);
+
+       if (hs_req == hs_ep->req) {
+               dev_dbg(hs->dev, "%s: already in progress\n", __func__);
+               return -EINPROGRESS;
+       }
+
+       spin_lock_irqsave(&hs_ep->lock, flags);
+
+       if (!on_list(hs_ep, hs_req)) {
+               spin_unlock_irqrestore(&hs_ep->lock, flags);
+               return -EINVAL;
+       }
+
+       s3c_hsotg_complete_request(hs, hs_ep, hs_req, -ECONNRESET);
+       spin_unlock_irqrestore(&hs_ep->lock, flags);
+
+       return 0;
+}
+
+static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value)
+{
+       struct s3c_hsotg_ep *hs_ep = our_ep(ep);
+       struct s3c_hsotg *hs = hs_ep->parent;
+       int index = hs_ep->index;
+       unsigned long irqflags;
+       u32 epreg;
+       u32 epctl;
+
+       dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value);
+
+       spin_lock_irqsave(&hs_ep->lock, irqflags);
+
+       /* write both IN and OUT control registers */
+
+       epreg = S3C_DIEPCTL(index);
+       epctl = readl(hs->regs + epreg);
+
+       if (value)
+               epctl |= S3C_DxEPCTL_Stall;
+       else
+               epctl &= ~S3C_DxEPCTL_Stall;
+
+       writel(epctl, hs->regs + epreg);
+
+       epreg = S3C_DOEPCTL(index);
+       epctl = readl(hs->regs + epreg);
+
+       if (value)
+               epctl |= S3C_DxEPCTL_Stall;
+       else
+               epctl &= ~S3C_DxEPCTL_Stall;
+
+       writel(epctl, hs->regs + epreg);
+
+       spin_unlock_irqrestore(&hs_ep->lock, irqflags);
+
+       return 0;
+}
+
+static struct usb_ep_ops s3c_hsotg_ep_ops = {
+       .enable         = s3c_hsotg_ep_enable,
+       .disable        = s3c_hsotg_ep_disable,
+       .alloc_request  = s3c_hsotg_ep_alloc_request,
+       .free_request   = s3c_hsotg_ep_free_request,
+       .queue          = s3c_hsotg_ep_queue,
+       .dequeue        = s3c_hsotg_ep_dequeue,
+       .set_halt       = s3c_hsotg_ep_sethalt,
+       /* note, don't belive we have any call for the fifo routines */
+};
+
+/**
+ * s3c_hsotg_corereset - issue softreset to the core
+ * @hsotg: The device state
+ *
+ * Issue a soft reset to the core, and await the core finishing it.
+*/
+static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg)
+{
+       int timeout;
+       u32 grstctl;
+
+       dev_dbg(hsotg->dev, "resetting core\n");
+
+       /* issue soft reset */
+       writel(S3C_GRSTCTL_CSftRst, hsotg->regs + S3C_GRSTCTL);
+
+       timeout = 1000;
+       do {
+               grstctl = readl(hsotg->regs + S3C_GRSTCTL);
+       } while (!(grstctl & S3C_GRSTCTL_CSftRst) && timeout-- > 0);
+
+       if (!grstctl & S3C_GRSTCTL_CSftRst) {
+               dev_err(hsotg->dev, "Failed to get CSftRst asserted\n");
+               return -EINVAL;
+       }
+
+       timeout = 1000;
+
+       while (1) {
+               u32 grstctl = readl(hsotg->regs + S3C_GRSTCTL);
+
+               if (timeout-- < 0) {
+                       dev_info(hsotg->dev,
+                                "%s: reset failed, GRSTCTL=%08x\n",
+                                __func__, grstctl);
+                       return -ETIMEDOUT;
+               }
+
+               if (grstctl & S3C_GRSTCTL_CSftRst)
+                       continue;
+
+               if (!(grstctl & S3C_GRSTCTL_AHBIdle))
+                       continue;
+
+               break;          /* reset done */
+       }
+
+       dev_dbg(hsotg->dev, "reset successful\n");
+       return 0;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+       struct s3c_hsotg *hsotg = our_hsotg;
+       int ret;
+
+       if (!hsotg) {
+               printk(KERN_ERR "%s: called with no device\n", __func__);
+               return -ENODEV;
+       }
+
+       if (!driver) {
+               dev_err(hsotg->dev, "%s: no driver\n", __func__);
+               return -EINVAL;
+       }
+
+       if (driver->speed != USB_SPEED_HIGH &&
+           driver->speed != USB_SPEED_FULL) {
+               dev_err(hsotg->dev, "%s: bad speed\n", __func__);
+       }
+
+       if (!driver->bind || !driver->setup) {
+               dev_err(hsotg->dev, "%s: missing entry points\n", __func__);
+               return -EINVAL;
+       }
+
+       WARN_ON(hsotg->driver);
+
+       driver->driver.bus = NULL;
+       hsotg->driver = driver;
+       hsotg->gadget.dev.driver = &driver->driver;
+       hsotg->gadget.dev.dma_mask = hsotg->dev->dma_mask;
+       hsotg->gadget.speed = USB_SPEED_UNKNOWN;
+
+       ret = device_add(&hsotg->gadget.dev);
+       if (ret) {
+               dev_err(hsotg->dev, "failed to register gadget device\n");
+               goto err;
+       }
+
+       ret = driver->bind(&hsotg->gadget);
+       if (ret) {
+               dev_err(hsotg->dev, "failed bind %s\n", driver->driver.name);
+
+               hsotg->gadget.dev.driver = NULL;
+               hsotg->driver = NULL;
+               goto err;
+       }
+
+       /* we must now enable ep0 ready for host detection and then
+        * set configuration. */
+
+       s3c_hsotg_corereset(hsotg);
+
+       /* set the PLL on, remove the HNP/SRP and set the PHY */
+       writel(S3C_GUSBCFG_PHYIf16 | S3C_GUSBCFG_TOutCal(7) |
+              (0x5 << 10), hsotg->regs + S3C_GUSBCFG);
+
+       /* looks like soft-reset changes state of FIFOs */
+       s3c_hsotg_init_fifo(hsotg);
+
+       __orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon);
+
+       writel(1 << 18 | S3C_DCFG_DevSpd_HS,  hsotg->regs + S3C_DCFG);
+
+       writel(S3C_GINTSTS_DisconnInt | S3C_GINTSTS_SessReqInt |
+              S3C_GINTSTS_ConIDStsChng | S3C_GINTSTS_USBRst |
+              S3C_GINTSTS_EnumDone | S3C_GINTSTS_OTGInt |
+              S3C_GINTSTS_USBSusp | S3C_GINTSTS_WkUpInt |
+              S3C_GINTSTS_GOUTNakEff | S3C_GINTSTS_GINNakEff |
+              S3C_GINTSTS_ErlySusp,
+              hsotg->regs + S3C_GINTMSK);
+
+       if (using_dma(hsotg))
+               writel(S3C_GAHBCFG_GlblIntrEn | S3C_GAHBCFG_DMAEn |
+                      S3C_GAHBCFG_HBstLen_Incr4,
+                      hsotg->regs + S3C_GAHBCFG);
+       else
+               writel(S3C_GAHBCFG_GlblIntrEn, hsotg->regs + S3C_GAHBCFG);
+
+       /* Enabling INTknTXFEmpMsk here seems to be a big mistake, we end
+        * up being flooded with interrupts if the host is polling the
+        * endpoint to try and read data. */
+
+       writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk |
+              S3C_DIEPMSK_INTknEPMisMsk |
+              S3C_DIEPMSK_EPDisbldMsk | S3C_DIEPMSK_XferComplMsk,
+              hsotg->regs + S3C_DIEPMSK);
+
+       /* don't need XferCompl, we get that from RXFIFO in slave mode. In
+        * DMA mode we may need this. */
+       writel(S3C_DOEPMSK_SetupMsk | S3C_DOEPMSK_AHBErrMsk |
+              S3C_DOEPMSK_EPDisbldMsk |
+              using_dma(hsotg) ? (S3C_DIEPMSK_XferComplMsk |
+                                  S3C_DIEPMSK_TimeOUTMsk) : 0,
+              hsotg->regs + S3C_DOEPMSK);
+
+       writel(0, hsotg->regs + S3C_DAINTMSK);
+
+       dev_info(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
+                readl(hsotg->regs + S3C_DIEPCTL0),
+                readl(hsotg->regs + S3C_DOEPCTL0));
+
+       /* enable in and out endpoint interrupts */
+       s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_OEPInt | S3C_GINTSTS_IEPInt);
+
+       /* Enable the RXFIFO when in slave mode, as this is how we collect
+        * the data. In DMA mode, we get events from the FIFO but also
+        * things we cannot process, so do not use it. */
+       if (!using_dma(hsotg))
+               s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_RxFLvl);
+
+       /* Enable interrupts for EP0 in and out */
+       s3c_hsotg_ctrl_epint(hsotg, 0, 0, 1);
+       s3c_hsotg_ctrl_epint(hsotg, 0, 1, 1);
+
+       __orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_PWROnPrgDone);
+       udelay(10);  /* see openiboot */
+       __bic32(hsotg->regs + S3C_DCTL, S3C_DCTL_PWROnPrgDone);
+
+       dev_info(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + S3C_DCTL));
+
+       /* S3C_DxEPCTL_USBActEp says RO in manual, but seems to be set by
+          writing to the EPCTL register.. */
+
+       /* set to read 1 8byte packet */
+       writel(S3C_DxEPTSIZ_MC(1) | S3C_DxEPTSIZ_PktCnt(1) |
+              S3C_DxEPTSIZ_XferSize(8), hsotg->regs + DOEPTSIZ0);
+
+       writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) |
+              S3C_DxEPCTL_CNAK | S3C_DxEPCTL_EPEna |
+              S3C_DxEPCTL_USBActEp,
+              hsotg->regs + S3C_DOEPCTL0);
+
+       /* enable, but don't activate EP0in */
+       writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) |
+              S3C_DxEPCTL_USBActEp, hsotg->regs + S3C_DIEPCTL0);
+
+       s3c_hsotg_enqueue_setup(hsotg);
+
+       dev_info(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
+                readl(hsotg->regs + S3C_DIEPCTL0),
+                readl(hsotg->regs + S3C_DOEPCTL0));
+
+       /* clear global NAKs */
+       writel(S3C_DCTL_CGOUTNak | S3C_DCTL_CGNPInNAK,
+              hsotg->regs + S3C_DCTL);
+
+       /* remove the soft-disconnect and let's go */
+       __bic32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon);
+
+       /* report to the user, and return */
+
+       dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name);
+       return 0;
+
+err:
+       hsotg->driver = NULL;
+       hsotg->gadget.dev.driver = NULL;
+       return ret;
+}
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+       struct s3c_hsotg *hsotg = our_hsotg;
+       int ep;
+
+       if (!hsotg)
+               return -ENODEV;
+
+       if (!driver || driver != hsotg->driver || !driver->unbind)
+               return -EINVAL;
+
+       /* all endpoints should be shutdown */
+       for (ep = 0; ep < S3C_HSOTG_EPS; ep++)
+               s3c_hsotg_ep_disable(&hsotg->eps[ep].ep);
+
+       call_gadget(hsotg, disconnect);
+
+       driver->unbind(&hsotg->gadget);
+       hsotg->driver = NULL;
+       hsotg->gadget.speed = USB_SPEED_UNKNOWN;
+
+       device_del(&hsotg->gadget.dev);
+
+       dev_info(hsotg->dev, "unregistered gadget driver '%s'\n",
+                driver->driver.name);
+
+       return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget)
+{
+       return s3c_hsotg_read_frameno(to_hsotg(gadget));
+}
+
+static struct usb_gadget_ops s3c_hsotg_gadget_ops = {
+       .get_frame      = s3c_hsotg_gadget_getframe,
+};
+
+/**
+ * s3c_hsotg_initep - initialise a single endpoint
+ * @hsotg: The device state.
+ * @hs_ep: The endpoint to be initialised.
+ * @epnum: The endpoint number
+ *
+ * Initialise the given endpoint (as part of the probe and device state
+ * creation) to give to the gadget driver. Setup the endpoint name, any
+ * direction information and other state that may be required.
+ */
+static void __devinit s3c_hsotg_initep(struct s3c_hsotg *hsotg,
+                                      struct s3c_hsotg_ep *hs_ep,
+                                      int epnum)
+{
+       u32 ptxfifo;
+       char *dir;
+
+       if (epnum == 0)
+               dir = "";
+       else if ((epnum % 2) == 0) {
+               dir = "out";
+       } else {
+               dir = "in";
+               hs_ep->dir_in = 1;
+       }
+
+       hs_ep->index = epnum;
+
+       snprintf(hs_ep->name, sizeof(hs_ep->name), "ep%d%s", epnum, dir);
+
+       INIT_LIST_HEAD(&hs_ep->queue);
+       INIT_LIST_HEAD(&hs_ep->ep.ep_list);
+
+       spin_lock_init(&hs_ep->lock);
+
+       /* add to the list of endpoints known by the gadget driver */
+       if (epnum)
+               list_add_tail(&hs_ep->ep.ep_list, &hsotg->gadget.ep_list);
+
+       hs_ep->parent = hsotg;
+       hs_ep->ep.name = hs_ep->name;
+       hs_ep->ep.maxpacket = epnum ? 512 : EP0_MPS_LIMIT;
+       hs_ep->ep.ops = &s3c_hsotg_ep_ops;
+
+       /* Read the FIFO size for the Periodic TX FIFO, even if we're
+        * an OUT endpoint, we may as well do this if in future the
+        * code is changed to make each endpoint's direction changeable.
+        */
+
+       ptxfifo = readl(hsotg->regs + S3C_DPTXFSIZn(epnum));
+       hs_ep->fifo_size = S3C_DPTXFSIZn_DPTxFSize_GET(ptxfifo);
+
+       /* if we're using dma, we need to set the next-endpoint pointer
+        * to be something valid.
+        */
+
+       if (using_dma(hsotg)) {
+               u32 next = S3C_DxEPCTL_NextEp((epnum + 1) % 15);
+               writel(next, hsotg->regs + S3C_DIEPCTL(epnum));
+               writel(next, hsotg->regs + S3C_DOEPCTL(epnum));
+       }
+}
+
+/**
+ * s3c_hsotg_otgreset - reset the OtG phy block
+ * @hsotg: The host state.
+ *
+ * Power up the phy, set the basic configuration and start the PHY.
+ */
+static void s3c_hsotg_otgreset(struct s3c_hsotg *hsotg)
+{
+       u32 osc;
+
+       writel(0, S3C_PHYPWR);
+       mdelay(1);
+
+       osc = hsotg->plat->is_osc ? S3C_PHYCLK_EXT_OSC : 0;
+
+       writel(osc | 0x10, S3C_PHYCLK);
+
+       /* issue a full set of resets to the otg and core */
+
+       writel(S3C_RSTCON_PHY, S3C_RSTCON);
+       udelay(20);     /* at-least 10uS */
+       writel(0, S3C_RSTCON);
+}
+
+
+static void s3c_hsotg_init(struct s3c_hsotg *hsotg)
+{
+       /* unmask subset of endpoint interrupts */
+
+       writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk |
+              S3C_DIEPMSK_EPDisbldMsk | S3C_DIEPMSK_XferComplMsk,
+              hsotg->regs + S3C_DIEPMSK);
+
+       writel(S3C_DOEPMSK_SetupMsk | S3C_DOEPMSK_AHBErrMsk |
+              S3C_DOEPMSK_EPDisbldMsk | S3C_DOEPMSK_XferComplMsk,
+              hsotg->regs + S3C_DOEPMSK);
+
+       writel(0, hsotg->regs + S3C_DAINTMSK);
+
+       if (0) {
+               /* post global nak until we're ready */
+               writel(S3C_DCTL_SGNPInNAK | S3C_DCTL_SGOUTNak,
+                      hsotg->regs + S3C_DCTL);
+       }
+
+       /* setup fifos */
+
+       dev_info(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n",
+                readl(hsotg->regs + S3C_GRXFSIZ),
+                readl(hsotg->regs + S3C_GNPTXFSIZ));
+
+       s3c_hsotg_init_fifo(hsotg);
+
+       /* set the PLL on, remove the HNP/SRP and set the PHY */
+       writel(S3C_GUSBCFG_PHYIf16 | S3C_GUSBCFG_TOutCal(7) | (0x5 << 10),
+              hsotg->regs + S3C_GUSBCFG);
+
+       writel(using_dma(hsotg) ? S3C_GAHBCFG_DMAEn : 0x0,
+              hsotg->regs + S3C_GAHBCFG);
+}
+
+static void s3c_hsotg_dump(struct s3c_hsotg *hsotg)
+{
+       struct device *dev = hsotg->dev;
+       void __iomem *regs = hsotg->regs;
+       u32 val;
+       int idx;
+
+       dev_info(dev, "DCFG=0x%08x, DCTL=0x%08x, DIEPMSK=%08x\n",
+                readl(regs + S3C_DCFG), readl(regs + S3C_DCTL),
+                readl(regs + S3C_DIEPMSK));
+
+       dev_info(dev, "GAHBCFG=0x%08x, 0x44=0x%08x\n",
+                readl(regs + S3C_GAHBCFG), readl(regs + 0x44));
+
+       dev_info(dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n",
+                readl(regs + S3C_GRXFSIZ), readl(regs + S3C_GNPTXFSIZ));
+
+       /* show periodic fifo settings */
+
+       for (idx = 1; idx <= 15; idx++) {
+               val = readl(regs + S3C_DPTXFSIZn(idx));
+               dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx,
+                        val >> S3C_DPTXFSIZn_DPTxFSize_SHIFT,
+                        val & S3C_DPTXFSIZn_DPTxFStAddr_MASK);
+       }
+
+       for (idx = 0; idx < 15; idx++) {
+               dev_info(dev,
+                        "ep%d-in: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", idx,
+                        readl(regs + S3C_DIEPCTL(idx)),
+                        readl(regs + S3C_DIEPTSIZ(idx)),
+                        readl(regs + S3C_DIEPDMA(idx)));
+
+               val = readl(regs + S3C_DOEPCTL(idx));
+               dev_info(dev,
+                        "ep%d-out: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n",
+                        idx, readl(regs + S3C_DOEPCTL(idx)),
+                        readl(regs + S3C_DOEPTSIZ(idx)),
+                        readl(regs + S3C_DOEPDMA(idx)));
+
+       }
+
+       dev_info(dev, "DVBUSDIS=0x%08x, DVBUSPULSE=%08x\n",
+                readl(regs + S3C_DVBUSDIS), readl(regs + S3C_DVBUSPULSE));
+}
+
+
+/**
+ * state_show - debugfs: show overall driver and device state.
+ * @seq: The seq file to write to.
+ * @v: Unused parameter.
+ *
+ * This debugfs entry shows the overall state of the hardware and
+ * some general information about each of the endpoints available
+ * to the system.
+ */
+static int state_show(struct seq_file *seq, void *v)
+{
+       struct s3c_hsotg *hsotg = seq->private;
+       void __iomem *regs = hsotg->regs;
+       int idx;
+
+       seq_printf(seq, "DCFG=0x%08x, DCTL=0x%08x, DSTS=0x%08x\n",
+                readl(regs + S3C_DCFG),
+                readl(regs + S3C_DCTL),
+                readl(regs + S3C_DSTS));
+
+       seq_printf(seq, "DIEPMSK=0x%08x, DOEPMASK=0x%08x\n",
+                  readl(regs + S3C_DIEPMSK), readl(regs + S3C_DOEPMSK));
+
+       seq_printf(seq, "GINTMSK=0x%08x, GINTSTS=0x%08x\n",
+                  readl(regs + S3C_GINTMSK),
+                  readl(regs + S3C_GINTSTS));
+
+       seq_printf(seq, "DAINTMSK=0x%08x, DAINT=0x%08x\n",
+                  readl(regs + S3C_DAINTMSK),
+                  readl(regs + S3C_DAINT));
+
+       seq_printf(seq, "GNPTXSTS=0x%08x, GRXSTSR=%08x\n",
+                  readl(regs + S3C_GNPTXSTS),
+                  readl(regs + S3C_GRXSTSR));
+
+       seq_printf(seq, "\nEndpoint status:\n");
+
+       for (idx = 0; idx < 15; idx++) {
+               u32 in, out;
+
+               in = readl(regs + S3C_DIEPCTL(idx));
+               out = readl(regs + S3C_DOEPCTL(idx));
+
+               seq_printf(seq, "ep%d: DIEPCTL=0x%08x, DOEPCTL=0x%08x",
+                          idx, in, out);
+
+               in = readl(regs + S3C_DIEPTSIZ(idx));
+               out = readl(regs + S3C_DOEPTSIZ(idx));
+
+               seq_printf(seq, ", DIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x",
+                          in, out);
+
+               seq_printf(seq, "\n");
+       }
+
+       return 0;
+}
+
+static int state_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, state_show, inode->i_private);
+}
+
+static const struct file_operations state_fops = {
+       .owner          = THIS_MODULE,
+       .open           = state_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+/**
+ * fifo_show - debugfs: show the fifo information
+ * @seq: The seq_file to write data to.
+ * @v: Unused parameter.
+ *
+ * Show the FIFO information for the overall fifo and all the
+ * periodic transmission FIFOs.
+*/
+static int fifo_show(struct seq_file *seq, void *v)
+{
+       struct s3c_hsotg *hsotg = seq->private;
+       void __iomem *regs = hsotg->regs;
+       u32 val;
+       int idx;
+
+       seq_printf(seq, "Non-periodic FIFOs:\n");
+       seq_printf(seq, "RXFIFO: Size %d\n", readl(regs + S3C_GRXFSIZ));
+
+       val = readl(regs + S3C_GNPTXFSIZ);
+       seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n",
+                  val >> S3C_GNPTXFSIZ_NPTxFDep_SHIFT,
+                  val & S3C_GNPTXFSIZ_NPTxFStAddr_MASK);
+
+       seq_printf(seq, "\nPeriodic TXFIFOs:\n");
+
+       for (idx = 1; idx <= 15; idx++) {
+               val = readl(regs + S3C_DPTXFSIZn(idx));
+
+               seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx,
+                          val >> S3C_DPTXFSIZn_DPTxFSize_SHIFT,
+                          val & S3C_DPTXFSIZn_DPTxFStAddr_MASK);
+       }
+
+       return 0;
+}
+
+static int fifo_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, fifo_show, inode->i_private);
+}
+
+static const struct file_operations fifo_fops = {
+       .owner          = THIS_MODULE,
+       .open           = fifo_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+
+static const char *decode_direction(int is_in)
+{
+       return is_in ? "in" : "out";
+}
+
+/**
+ * ep_show - debugfs: show the state of an endpoint.
+ * @seq: The seq_file to write data to.
+ * @v: Unused parameter.
+ *
+ * This debugfs entry shows the state of the given endpoint (one is
+ * registered for each available).
+*/
+static int ep_show(struct seq_file *seq, void *v)
+{
+       struct s3c_hsotg_ep *ep = seq->private;
+       struct s3c_hsotg *hsotg = ep->parent;
+       struct s3c_hsotg_req *req;
+       void __iomem *regs = hsotg->regs;
+       int index = ep->index;
+       int show_limit = 15;
+       unsigned long flags;
+
+       seq_printf(seq, "Endpoint index %d, named %s,  dir %s:\n",
+                  ep->index, ep->ep.name, decode_direction(ep->dir_in));
+
+       /* first show the register state */
+
+       seq_printf(seq, "\tDIEPCTL=0x%08x, DOEPCTL=0x%08x\n",
+                  readl(regs + S3C_DIEPCTL(index)),
+                  readl(regs + S3C_DOEPCTL(index)));
+
+       seq_printf(seq, "\tDIEPDMA=0x%08x, DOEPDMA=0x%08x\n",
+                  readl(regs + S3C_DIEPDMA(index)),
+                  readl(regs + S3C_DOEPDMA(index)));
+
+       seq_printf(seq, "\tDIEPINT=0x%08x, DOEPINT=0x%08x\n",
+                  readl(regs + S3C_DIEPINT(index)),
+                  readl(regs + S3C_DOEPINT(index)));
+
+       seq_printf(seq, "\tDIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x\n",
+                  readl(regs + S3C_DIEPTSIZ(index)),
+                  readl(regs + S3C_DOEPTSIZ(index)));
+
+       seq_printf(seq, "\n");
+       seq_printf(seq, "mps %d\n", ep->ep.maxpacket);
+       seq_printf(seq, "total_data=%ld\n", ep->total_data);
+
+       seq_printf(seq, "request list (%p,%p):\n",
+                  ep->queue.next, ep->queue.prev);
+
+       spin_lock_irqsave(&ep->lock, flags);
+
+       list_for_each_entry(req, &ep->queue, queue) {
+               if (--show_limit < 0) {
+                       seq_printf(seq, "not showing more requests...\n");
+                       break;
+               }
+
+               seq_printf(seq, "%c req %p: %d bytes @%p, ",
+                          req == ep->req ? '*' : ' ',
+                          req, req->req.length, req->req.buf);
+               seq_printf(seq, "%d done, res %d\n",
+                          req->req.actual, req->req.status);
+       }
+
+       spin_unlock_irqrestore(&ep->lock, flags);
+
+       return 0;
+}
+
+static int ep_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ep_show, inode->i_private);
+}
+
+static const struct file_operations ep_fops = {
+       .owner          = THIS_MODULE,
+       .open           = ep_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+/**
+ * s3c_hsotg_create_debug - create debugfs directory and files
+ * @hsotg: The driver state
+ *
+ * Create the debugfs files to allow the user to get information
+ * about the state of the system. The directory name is created
+ * with the same name as the device itself, in case we end up
+ * with multiple blocks in future systems.
+*/
+static void __devinit s3c_hsotg_create_debug(struct s3c_hsotg *hsotg)
+{
+       struct dentry *root;
+       unsigned epidx;
+
+       root = debugfs_create_dir(dev_name(hsotg->dev), NULL);
+       hsotg->debug_root = root;
+       if (IS_ERR(root)) {
+               dev_err(hsotg->dev, "cannot create debug root\n");
+               return;
+       }
+
+       /* create general state file */
+
+       hsotg->debug_file = debugfs_create_file("state", 0444, root,
+                                               hsotg, &state_fops);
+
+       if (IS_ERR(hsotg->debug_file))
+               dev_err(hsotg->dev, "%s: failed to create state\n", __func__);
+
+       hsotg->debug_fifo = debugfs_create_file("fifo", 0444, root,
+                                               hsotg, &fifo_fops);
+
+       if (IS_ERR(hsotg->debug_fifo))
+               dev_err(hsotg->dev, "%s: failed to create fifo\n", __func__);
+
+       /* create one file for each endpoint */
+
+       for (epidx = 0; epidx < S3C_HSOTG_EPS; epidx++) {
+               struct s3c_hsotg_ep *ep = &hsotg->eps[epidx];
+
+               ep->debugfs = debugfs_create_file(ep->name, 0444,
+                                                 root, ep, &ep_fops);
+
+               if (IS_ERR(ep->debugfs))
+                       dev_err(hsotg->dev, "failed to create %s debug file\n",
+                               ep->name);
+       }
+}
+
+/**
+ * s3c_hsotg_delete_debug - cleanup debugfs entries
+ * @hsotg: The driver state
+ *
+ * Cleanup (remove) the debugfs files for use on module exit.
+*/
+static void __devexit s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
+{
+       unsigned epidx;
+
+       for (epidx = 0; epidx < S3C_HSOTG_EPS; epidx++) {
+               struct s3c_hsotg_ep *ep = &hsotg->eps[epidx];
+               debugfs_remove(ep->debugfs);
+       }
+
+       debugfs_remove(hsotg->debug_file);
+       debugfs_remove(hsotg->debug_fifo);
+       debugfs_remove(hsotg->debug_root);
+}
+
+/**
+ * s3c_hsotg_gate - set the hardware gate for the block
+ * @pdev: The device we bound to
+ * @on: On or off.
+ *
+ * Set the hardware gate setting into the block. If we end up on
+ * something other than an S3C64XX, then we might need to change this
+ * to using a platform data callback, or some other mechanism.
+ */
+static void s3c_hsotg_gate(struct platform_device *pdev, bool on)
+{
+       unsigned long flags;
+       u32 others;
+
+       local_irq_save(flags);
+
+       others = __raw_readl(S3C64XX_OTHERS);
+       if (on)
+               others |= S3C64XX_OTHERS_USBMASK;
+       else
+               others &= ~S3C64XX_OTHERS_USBMASK;
+       __raw_writel(others, S3C64XX_OTHERS);
+
+       local_irq_restore(flags);
+}
+
+struct s3c_hsotg_plat s3c_hsotg_default_pdata;
+
+static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
+{
+       struct s3c_hsotg_plat *plat = pdev->dev.platform_data;
+       struct device *dev = &pdev->dev;
+       struct s3c_hsotg *hsotg;
+       struct resource *res;
+       int epnum;
+       int ret;
+
+       if (!plat)
+               plat = &s3c_hsotg_default_pdata;
+
+       hsotg = kzalloc(sizeof(struct s3c_hsotg) +
+                       sizeof(struct s3c_hsotg_ep) * S3C_HSOTG_EPS,
+                       GFP_KERNEL);
+       if (!hsotg) {
+               dev_err(dev, "cannot get memory\n");
+               return -ENOMEM;
+       }
+
+       hsotg->dev = dev;
+       hsotg->plat = plat;
+
+       platform_set_drvdata(pdev, hsotg);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev, "cannot find register resource 0\n");
+               ret = -EINVAL;
+               goto err_mem;
+       }
+
+       hsotg->regs_res = request_mem_region(res->start, resource_size(res),
+                                            dev_name(dev));
+       if (!hsotg->regs_res) {
+               dev_err(dev, "cannot reserve registers\n");
+               ret = -ENOENT;
+               goto err_mem;
+       }
+
+       hsotg->regs = ioremap(res->start, resource_size(res));
+       if (!hsotg->regs) {
+               dev_err(dev, "cannot map registers\n");
+               ret = -ENXIO;
+               goto err_regs_res;
+       }
+
+       ret = platform_get_irq(pdev, 0);
+       if (ret < 0) {
+               dev_err(dev, "cannot find IRQ\n");
+               goto err_regs;
+       }
+
+       hsotg->irq = ret;
+
+       ret = request_irq(ret, s3c_hsotg_irq, 0, dev_name(dev), hsotg);
+       if (ret < 0) {
+               dev_err(dev, "cannot claim IRQ\n");
+               goto err_regs;
+       }
+
+       dev_info(dev, "regs %p, irq %d\n", hsotg->regs, hsotg->irq);
+
+       device_initialize(&hsotg->gadget.dev);
+
+       dev_set_name(&hsotg->gadget.dev, "gadget");
+
+       hsotg->gadget.is_dualspeed = 1;
+       hsotg->gadget.ops = &s3c_hsotg_gadget_ops;
+       hsotg->gadget.name = dev_name(dev);
+
+       hsotg->gadget.dev.parent = dev;
+       hsotg->gadget.dev.dma_mask = dev->dma_mask;
+
+       /* setup endpoint information */
+
+       INIT_LIST_HEAD(&hsotg->gadget.ep_list);
+       hsotg->gadget.ep0 = &hsotg->eps[0].ep;
+
+       /* allocate EP0 request */
+
+       hsotg->ctrl_req = s3c_hsotg_ep_alloc_request(&hsotg->eps[0].ep,
+                                                    GFP_KERNEL);
+       if (!hsotg->ctrl_req) {
+               dev_err(dev, "failed to allocate ctrl req\n");
+               goto err_regs;
+       }
+
+       /* reset the system */
+
+       s3c_hsotg_gate(pdev, true);
+
+       s3c_hsotg_otgreset(hsotg);
+       s3c_hsotg_corereset(hsotg);
+       s3c_hsotg_init(hsotg);
+
+       /* initialise the endpoints now the core has been initialised */
+       for (epnum = 0; epnum < S3C_HSOTG_EPS; epnum++)
+               s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum);
+
+       s3c_hsotg_create_debug(hsotg);
+
+       s3c_hsotg_dump(hsotg);
+
+       our_hsotg = hsotg;
+       return 0;
+
+err_regs:
+       iounmap(hsotg->regs);
+
+err_regs_res:
+       release_resource(hsotg->regs_res);
+       kfree(hsotg->regs_res);
+
+err_mem:
+       kfree(hsotg);
+       return ret;
+}
+
+static int __devexit s3c_hsotg_remove(struct platform_device *pdev)
+{
+       struct s3c_hsotg *hsotg = platform_get_drvdata(pdev);
+
+       s3c_hsotg_delete_debug(hsotg);
+
+       usb_gadget_unregister_driver(hsotg->driver);
+
+       free_irq(hsotg->irq, hsotg);
+       iounmap(hsotg->regs);
+
+       release_resource(hsotg->regs_res);
+       kfree(hsotg->regs_res);
+
+       s3c_hsotg_gate(pdev, false);
+
+       kfree(hsotg);
+       return 0;
+}
+
+#if 1
+#define s3c_hsotg_suspend NULL
+#define s3c_hsotg_resume NULL
+#endif
+
+static struct platform_driver s3c_hsotg_driver = {
+       .driver         = {
+               .name   = "s3c-hsotg",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = s3c_hsotg_probe,
+       .remove         = __devexit_p(s3c_hsotg_remove),
+       .suspend        = s3c_hsotg_suspend,
+       .resume         = s3c_hsotg_resume,
+};
+
+static int __init s3c_hsotg_modinit(void)
+{
+       return platform_driver_register(&s3c_hsotg_driver);
+}
+
+static void __exit s3c_hsotg_modexit(void)
+{
+       platform_driver_unregister(&s3c_hsotg_driver);
+}
+
+module_init(s3c_hsotg_modinit);
+module_exit(s3c_hsotg_modexit);
+
+MODULE_DESCRIPTION("Samsung S3C USB High-speed/OtG device");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c-hsotg");
diff --git a/drivers/usb/gadget/u_audio.c b/drivers/usb/gadget/u_audio.c
new file mode 100644 (file)
index 0000000..0f3d22f
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * u_audio.c -- ALSA audio utilities for Gadget stack
+ *
+ * Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
+ * Copyright (C) 2008 Analog Devices, Inc
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/kernel.h>
+#include <linux/utsname.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/random.h>
+#include <linux/syscalls.h>
+
+#include "u_audio.h"
+
+/*
+ * This component encapsulates the ALSA devices for USB audio gadget
+ */
+
+#define FILE_PCM_PLAYBACK      "/dev/snd/pcmC0D0p"
+#define FILE_PCM_CAPTURE       "/dev/snd/pcmC0D0c"
+#define FILE_CONTROL           "/dev/snd/controlC0"
+
+static char *fn_play = FILE_PCM_PLAYBACK;
+module_param(fn_play, charp, S_IRUGO);
+MODULE_PARM_DESC(fn_play, "Playback PCM device file name");
+
+static char *fn_cap = FILE_PCM_CAPTURE;
+module_param(fn_cap, charp, S_IRUGO);
+MODULE_PARM_DESC(fn_cap, "Capture PCM device file name");
+
+static char *fn_cntl = FILE_CONTROL;
+module_param(fn_cntl, charp, S_IRUGO);
+MODULE_PARM_DESC(fn_cntl, "Control device file name");
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * Some ALSA internal helper functions
+ */
+static int snd_interval_refine_set(struct snd_interval *i, unsigned int val)
+{
+       struct snd_interval t;
+       t.empty = 0;
+       t.min = t.max = val;
+       t.openmin = t.openmax = 0;
+       t.integer = 1;
+       return snd_interval_refine(i, &t);
+}
+
+static int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params,
+                                snd_pcm_hw_param_t var, unsigned int val,
+                                int dir)
+{
+       int changed;
+       if (hw_is_mask(var)) {
+               struct snd_mask *m = hw_param_mask(params, var);
+               if (val == 0 && dir < 0) {
+                       changed = -EINVAL;
+                       snd_mask_none(m);
+               } else {
+                       if (dir > 0)
+                               val++;
+                       else if (dir < 0)
+                               val--;
+                       changed = snd_mask_refine_set(
+                                       hw_param_mask(params, var), val);
+               }
+       } else if (hw_is_interval(var)) {
+               struct snd_interval *i = hw_param_interval(params, var);
+               if (val == 0 && dir < 0) {
+                       changed = -EINVAL;
+                       snd_interval_none(i);
+               } else if (dir == 0)
+                       changed = snd_interval_refine_set(i, val);
+               else {
+                       struct snd_interval t;
+                       t.openmin = 1;
+                       t.openmax = 1;
+                       t.empty = 0;
+                       t.integer = 0;
+                       if (dir < 0) {
+                               t.min = val - 1;
+                               t.max = val;
+                       } else {
+                               t.min = val;
+                               t.max = val+1;
+                       }
+                       changed = snd_interval_refine(i, &t);
+               }
+       } else
+               return -EINVAL;
+       if (changed) {
+               params->cmask |= 1 << var;
+               params->rmask |= 1 << var;
+       }
+       return changed;
+}
+/*-------------------------------------------------------------------------*/
+
+/**
+ * Set default hardware params
+ */
+static int playback_default_hw_params(struct gaudio_snd_dev *snd)
+{
+       struct snd_pcm_substream *substream = snd->substream;
+       struct snd_pcm_hw_params *params;
+       snd_pcm_sframes_t result;
+
+       /*
+       * SNDRV_PCM_ACCESS_RW_INTERLEAVED,
+       * SNDRV_PCM_FORMAT_S16_LE
+       * CHANNELS: 2
+       * RATE: 48000
+       */
+       snd->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
+       snd->format = SNDRV_PCM_FORMAT_S16_LE;
+       snd->channels = 2;
+       snd->rate = 48000;
+
+       params = kzalloc(sizeof(*params), GFP_KERNEL);
+       if (!params)
+               return -ENOMEM;
+
+       _snd_pcm_hw_params_any(params);
+       _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS,
+                       snd->access, 0);
+       _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT,
+                       snd->format, 0);
+       _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS,
+                       snd->channels, 0);
+       _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE,
+                       snd->rate, 0);
+
+       snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
+       snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, params);
+
+       result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL);
+       if (result < 0) {
+               ERROR(snd->card,
+                       "Preparing sound card failed: %d\n", (int)result);
+               kfree(params);
+               return result;
+       }
+
+       /* Store the hardware parameters */
+       snd->access = params_access(params);
+       snd->format = params_format(params);
+       snd->channels = params_channels(params);
+       snd->rate = params_rate(params);
+
+       kfree(params);
+
+       INFO(snd->card,
+               "Hardware params: access %x, format %x, channels %d, rate %d\n",
+               snd->access, snd->format, snd->channels, snd->rate);
+
+       return 0;
+}
+
+/**
+ * Playback audio buffer data by ALSA PCM device
+ */
+static size_t u_audio_playback(struct gaudio *card, void *buf, size_t count)
+{
+       struct gaudio_snd_dev   *snd = &card->playback;
+       struct snd_pcm_substream *substream = snd->substream;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       mm_segment_t old_fs;
+       ssize_t result;
+       snd_pcm_sframes_t frames;
+
+try_again:
+       if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
+               runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
+               result = snd_pcm_kernel_ioctl(substream,
+                               SNDRV_PCM_IOCTL_PREPARE, NULL);
+               if (result < 0) {
+                       ERROR(card, "Preparing sound card failed: %d\n",
+                                       (int)result);
+                       return result;
+               }
+       }
+
+       frames = bytes_to_frames(runtime, count);
+       old_fs = get_fs();
+       set_fs(KERNEL_DS);
+       result = snd_pcm_lib_write(snd->substream, buf, frames);
+       if (result != frames) {
+               ERROR(card, "Playback error: %d\n", (int)result);
+               set_fs(old_fs);
+               goto try_again;
+       }
+       set_fs(old_fs);
+
+       return 0;
+}
+
+static int u_audio_get_playback_channels(struct gaudio *card)
+{
+       return card->playback.channels;
+}
+
+static int u_audio_get_playback_rate(struct gaudio *card)
+{
+       return card->playback.rate;
+}
+
+/**
+ * Open ALSA PCM and control device files
+ * Initial the PCM or control device
+ */
+static int gaudio_open_snd_dev(struct gaudio *card)
+{
+       struct snd_pcm_file *pcm_file;
+       struct gaudio_snd_dev *snd;
+
+       if (!card)
+               return -ENODEV;
+
+       /* Open control device */
+       snd = &card->control;
+       snd->filp = filp_open(fn_cntl, O_RDWR, 0);
+       if (IS_ERR(snd->filp)) {
+               int ret = PTR_ERR(snd->filp);
+               ERROR(card, "unable to open sound control device file: %s\n",
+                               fn_cntl);
+               snd->filp = NULL;
+               return ret;
+       }
+       snd->card = card;
+
+       /* Open PCM playback device and setup substream */
+       snd = &card->playback;
+       snd->filp = filp_open(fn_play, O_WRONLY, 0);
+       if (IS_ERR(snd->filp)) {
+               ERROR(card, "No such PCM playback device: %s\n", fn_play);
+               snd->filp = NULL;
+       }
+       pcm_file = snd->filp->private_data;
+       snd->substream = pcm_file->substream;
+       snd->card = card;
+       playback_default_hw_params(snd);
+
+       /* Open PCM capture device and setup substream */
+       snd = &card->capture;
+       snd->filp = filp_open(fn_cap, O_RDONLY, 0);
+       if (IS_ERR(snd->filp)) {
+               ERROR(card, "No such PCM capture device: %s\n", fn_cap);
+               snd->filp = NULL;
+       }
+       pcm_file = snd->filp->private_data;
+       snd->substream = pcm_file->substream;
+       snd->card = card;
+
+       return 0;
+}
+
+/**
+ * Close ALSA PCM and control device files
+ */
+static int gaudio_close_snd_dev(struct gaudio *gau)
+{
+       struct gaudio_snd_dev   *snd;
+
+       /* Close control device */
+       snd = &gau->control;
+       if (!IS_ERR(snd->filp))
+               filp_close(snd->filp, current->files);
+
+       /* Close PCM playback device and setup substream */
+       snd = &gau->playback;
+       if (!IS_ERR(snd->filp))
+               filp_close(snd->filp, current->files);
+
+       /* Close PCM capture device and setup substream */
+       snd = &gau->capture;
+       if (!IS_ERR(snd->filp))
+               filp_close(snd->filp, current->files);
+
+       return 0;
+}
+
+/**
+ * gaudio_setup - setup ALSA interface and preparing for USB transfer
+ *
+ * This sets up PCM, mixer or MIDI ALSA devices fore USB gadget using.
+ *
+ * Returns negative errno, or zero on success
+ */
+int __init gaudio_setup(struct gaudio *card)
+{
+       int     ret;
+
+       ret = gaudio_open_snd_dev(card);
+       if (ret)
+               ERROR(card, "we need at least one control device\n");
+
+       return ret;
+
+}
+
+/**
+ * gaudio_cleanup - remove ALSA device interface
+ *
+ * This is called to free all resources allocated by @gaudio_setup().
+ */
+void gaudio_cleanup(struct gaudio *card)
+{
+       if (card)
+               gaudio_close_snd_dev(card);
+}
+
diff --git a/drivers/usb/gadget/u_audio.h b/drivers/usb/gadget/u_audio.h
new file mode 100644 (file)
index 0000000..cc8d159
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * u_audio.h -- interface to USB gadget "ALSA AUDIO" utilities
+ *
+ * Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
+ * Copyright (C) 2008 Analog Devices, Inc
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __U_AUDIO_H
+#define __U_AUDIO_H
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/usb/audio.h>
+#include <linux/usb/composite.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include "gadget_chips.h"
+
+/*
+ * This represents the USB side of an audio card device, managed by a USB
+ * function which provides control and stream interfaces.
+ */
+
+struct gaudio_snd_dev {
+       struct gaudio                   *card;
+       struct file                     *filp;
+       struct snd_pcm_substream        *substream;
+       int                             access;
+       int                             format;
+       int                             channels;
+       int                             rate;
+};
+
+struct gaudio {
+       struct usb_function             func;
+       struct usb_gadget               *gadget;
+
+       /* ALSA sound device interfaces */
+       struct gaudio_snd_dev           control;
+       struct gaudio_snd_dev           playback;
+       struct gaudio_snd_dev           capture;
+
+       /* TODO */
+};
+
+int gaudio_setup(struct gaudio *card);
+void gaudio_cleanup(struct gaudio *card);
+
+#endif /* __U_AUDIO_H */
index 0a4d99ab40d8c0c224a78d060e93574b63fcbd2e..fc6e709f45b1b184891b0201cffcbeef17daf09f 100644 (file)
@@ -371,6 +371,7 @@ __acquires(&port->port_lock)
 
                req->length = len;
                list_del(&req->list);
+               req->zero = (gs_buf_data_avail(&port->port_write_buf) == 0);
 
                pr_vdebug(PREFIX "%d: tx len=%d, 0x%02x 0x%02x 0x%02x ...\n",
                                port->port_num, len, *((u8 *)req->buf),
index 845479f7c70773cacff061d3a04c0f3ca0b21d86..1576a0520adf35ba813ef9ebd30cd8fb28f16e62 100644 (file)
@@ -17,6 +17,26 @@ config USB_C67X00_HCD
          To compile this driver as a module, choose M here: the
          module will be called c67x00.
 
+config USB_XHCI_HCD
+       tristate "xHCI HCD (USB 3.0) support (EXPERIMENTAL)"
+       depends on USB && PCI && EXPERIMENTAL
+       ---help---
+         The eXtensible Host Controller Interface (xHCI) is standard for USB 3.0
+         "SuperSpeed" host controller hardware.
+
+         To compile this driver as a module, choose M here: the
+         module will be called xhci-hcd.
+
+config USB_XHCI_HCD_DEBUGGING
+       bool "Debugging for the xHCI host controller"
+       depends on USB_XHCI_HCD
+       ---help---
+         Say 'Y' to turn on debugging for the xHCI host controller driver.
+         This will spew debugging output, even in interrupt context.
+         This should only be used for debugging xHCI driver bugs.
+
+         If unsure, say N.
+
 config USB_EHCI_HCD
        tristate "EHCI HCD (USB 2.0) support"
        depends on USB && USB_ARCH_HAS_EHCI
index f163571e33d8dc0e61f10ec1addf50d4956baf39..289d748bb41422ae6d607130a09fe3c410037049 100644 (file)
@@ -12,6 +12,7 @@ fhci-objs := fhci-hcd.o fhci-hub.o fhci-q.o fhci-mem.o \
 ifeq ($(CONFIG_FHCI_DEBUG),y)
 fhci-objs += fhci-dbg.o
 endif
+xhci-objs := xhci-hcd.o xhci-mem.o xhci-pci.o xhci-ring.o xhci-hub.o xhci-dbg.o
 
 obj-$(CONFIG_USB_WHCI_HCD)     += whci/
 
@@ -23,6 +24,7 @@ obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o
 obj-$(CONFIG_USB_OHCI_HCD)     += ohci-hcd.o
 obj-$(CONFIG_USB_UHCI_HCD)     += uhci-hcd.o
 obj-$(CONFIG_USB_FHCI_HCD)     += fhci.o
+obj-$(CONFIG_USB_XHCI_HCD)     += xhci.o
 obj-$(CONFIG_USB_SL811_HCD)    += sl811-hcd.o
 obj-$(CONFIG_USB_SL811_CS)     += sl811_cs.o
 obj-$(CONFIG_USB_U132_HCD)     += u132-hcd.o
index bf69f473910785465c8c20ef4be46ea7acab2946..c3a778bd359c9b883bd6e361e78951818fd3a280 100644 (file)
@@ -97,6 +97,7 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
        .urb_enqueue            = ehci_urb_enqueue,
        .urb_dequeue            = ehci_urb_dequeue,
        .endpoint_disable       = ehci_endpoint_disable,
+       .endpoint_reset         = ehci_endpoint_reset,
 
        /*
         * scheduling support
index 01c3da34f678e4a52107f64bca1674bb7e64c807..bf86809c5120795eac8521b68e2159d2fef37127 100644 (file)
@@ -309,6 +309,7 @@ static const struct hc_driver ehci_fsl_hc_driver = {
        .urb_enqueue = ehci_urb_enqueue,
        .urb_dequeue = ehci_urb_dequeue,
        .endpoint_disable = ehci_endpoint_disable,
+       .endpoint_reset = ehci_endpoint_reset,
 
        /*
         * scheduling support
index c637207a1c80b63eab4bfa5587d4250bfe0d3c86..2b72473544d31d798034ed5aa92cb555384a8055 100644 (file)
@@ -1024,6 +1024,51 @@ done:
        return;
 }
 
+static void
+ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
+{
+       struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
+       struct ehci_qh          *qh;
+       int                     eptype = usb_endpoint_type(&ep->desc);
+
+       if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT)
+               return;
+
+ rescan:
+       spin_lock_irq(&ehci->lock);
+       qh = ep->hcpriv;
+
+       /* For Bulk and Interrupt endpoints we maintain the toggle state
+        * in the hardware; the toggle bits in udev aren't used at all.
+        * When an endpoint is reset by usb_clear_halt() we must reset
+        * the toggle bit in the QH.
+        */
+       if (qh) {
+               if (!list_empty(&qh->qtd_list)) {
+                       WARN_ONCE(1, "clear_halt for a busy endpoint\n");
+               } else if (qh->qh_state == QH_STATE_IDLE) {
+                       qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
+               } else {
+                       /* It's not safe to write into the overlay area
+                        * while the QH is active.  Unlink it first and
+                        * wait for the unlink to complete.
+                        */
+                       if (qh->qh_state == QH_STATE_LINKED) {
+                               if (eptype == USB_ENDPOINT_XFER_BULK) {
+                                       unlink_async(ehci, qh);
+                               } else {
+                                       intr_deschedule(ehci, qh);
+                                       (void) qh_schedule(ehci, qh);
+                               }
+                       }
+                       spin_unlock_irq(&ehci->lock);
+                       schedule_timeout_uninterruptible(1);
+                       goto rescan;
+               }
+       }
+       spin_unlock_irq(&ehci->lock);
+}
+
 static int ehci_get_frame (struct usb_hcd *hcd)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
@@ -1097,7 +1142,7 @@ static int __init ehci_hcd_init(void)
                 sizeof(struct ehci_itd), sizeof(struct ehci_sitd));
 
 #ifdef DEBUG
-       ehci_debug_root = debugfs_create_dir("ehci", NULL);
+       ehci_debug_root = debugfs_create_dir("ehci", usb_debug_root);
        if (!ehci_debug_root) {
                retval = -ENOENT;
                goto err_debug;
index 97a53a48a3d8e24383e5f14cc2590bc36b0408a9..f46ad27c9a90e2cda2e8bbb8b9b45c861af765c5 100644 (file)
@@ -391,7 +391,7 @@ static inline void create_companion_file(struct ehci_hcd *ehci)
 
        /* with integrated TT there is no companion! */
        if (!ehci_is_TDI(ehci))
-               i = device_create_file(ehci_to_hcd(ehci)->self.dev,
+               i = device_create_file(ehci_to_hcd(ehci)->self.controller,
                                       &dev_attr_companion);
 }
 
@@ -399,7 +399,7 @@ static inline void remove_companion_file(struct ehci_hcd *ehci)
 {
        /* with integrated TT there is no companion! */
        if (!ehci_is_TDI(ehci))
-               device_remove_file(ehci_to_hcd(ehci)->self.dev,
+               device_remove_file(ehci_to_hcd(ehci)->self.controller,
                                   &dev_attr_companion);
 }
 
index 9c32063a0c2f6611fc938760ea84906d1f3f9666..a44bb4a949543d797f336827edb8ac6fa088d8ac 100644 (file)
@@ -51,6 +51,7 @@ static const struct hc_driver ixp4xx_ehci_hc_driver = {
        .urb_enqueue            = ehci_urb_enqueue,
        .urb_dequeue            = ehci_urb_dequeue,
        .endpoint_disable       = ehci_endpoint_disable,
+       .endpoint_reset         = ehci_endpoint_reset,
        .get_frame_number       = ehci_get_frame,
        .hub_status_data        = ehci_hub_status_data,
        .hub_control            = ehci_hub_control,
index 9d487908012e56fb515d82576ccdbd5db71fa480..770dd9aba62a9f07aabd9863e59fc4acae6a81dd 100644 (file)
@@ -149,6 +149,7 @@ static const struct hc_driver ehci_orion_hc_driver = {
        .urb_enqueue = ehci_urb_enqueue,
        .urb_dequeue = ehci_urb_dequeue,
        .endpoint_disable = ehci_endpoint_disable,
+       .endpoint_reset = ehci_endpoint_reset,
 
        /*
         * scheduling support
@@ -187,7 +188,7 @@ ehci_orion_conf_mbus_windows(struct usb_hcd *hcd,
        }
 }
 
-static int __init ehci_orion_drv_probe(struct platform_device *pdev)
+static int __devinit ehci_orion_drv_probe(struct platform_device *pdev)
 {
        struct orion_ehci_data *pd = pdev->dev.platform_data;
        struct resource *res;
index 5aa8bce90e1f3856d7195db5614394a6c709ba9f..f3683e1da16134b3c20a6239b5edfd406af923aa 100644 (file)
@@ -268,7 +268,7 @@ done:
  * Also they depend on separate root hub suspend/resume.
  */
 
-static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
+static int ehci_pci_suspend(struct usb_hcd *hcd)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
        unsigned long           flags;
@@ -293,12 +293,6 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
        ehci_writel(ehci, 0, &ehci->regs->intr_enable);
        (void)ehci_readl(ehci, &ehci->regs->intr_enable);
 
-       /* make sure snapshot being resumed re-enumerates everything */
-       if (message.event == PM_EVENT_PRETHAW) {
-               ehci_halt(ehci);
-               ehci_reset(ehci);
-       }
-
        clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
  bail:
        spin_unlock_irqrestore (&ehci->lock, flags);
@@ -309,7 +303,7 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
        return rc;
 }
 
-static int ehci_pci_resume(struct usb_hcd *hcd)
+static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
        struct pci_dev          *pdev = to_pci_dev(hcd->self.controller);
@@ -322,10 +316,12 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
        /* Mark hardware accessible again as we are out of D3 state by now */
        set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
 
-       /* If CF is still set, we maintained PCI Vaux power.
+       /* If CF is still set and we aren't resuming from hibernation
+        * then we maintained PCI Vaux power.
         * Just undo the effect of ehci_pci_suspend().
         */
-       if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
+       if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF &&
+                               !hibernated) {
                int     mask = INTR_MASK;
 
                if (!hcd->self.root_hub->do_remote_wakeup)
@@ -335,7 +331,6 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
                return 0;
        }
 
-       ehci_dbg(ehci, "lost power, restarting\n");
        usb_root_hub_lost_power(hcd->self.root_hub);
 
        /* Else reset, to cope with power loss or flush-to-storage
@@ -393,6 +388,7 @@ static const struct hc_driver ehci_pci_hc_driver = {
        .urb_enqueue =          ehci_urb_enqueue,
        .urb_dequeue =          ehci_urb_dequeue,
        .endpoint_disable =     ehci_endpoint_disable,
+       .endpoint_reset =       ehci_endpoint_reset,
 
        /*
         * scheduling support
@@ -429,10 +425,11 @@ static struct pci_driver ehci_pci_driver = {
 
        .probe =        usb_hcd_pci_probe,
        .remove =       usb_hcd_pci_remove,
+       .shutdown =     usb_hcd_pci_shutdown,
 
-#ifdef CONFIG_PM
-       .suspend =      usb_hcd_pci_suspend,
-       .resume =       usb_hcd_pci_resume,
+#ifdef CONFIG_PM_SLEEP
+       .driver =       {
+               .pm =   &usb_hcd_pci_pm_ops
+       },
 #endif
-       .shutdown =     usb_hcd_pci_shutdown,
 };
index ef732b704f53d996aed213bc1563c10063e89978..fbd272288fc2cf799ef1d075adea282dd01aa863 100644 (file)
@@ -61,6 +61,7 @@ static const struct hc_driver ehci_ppc_of_hc_driver = {
        .urb_enqueue            = ehci_urb_enqueue,
        .urb_dequeue            = ehci_urb_dequeue,
        .endpoint_disable       = ehci_endpoint_disable,
+       .endpoint_reset         = ehci_endpoint_reset,
 
        /*
         * scheduling support
index 1ba9f9a8c3088bd607fb95b5599e0982c6c8c9d2..eecd2a0680a216bd68a26a3eba3459cd16037ac3 100644 (file)
@@ -65,6 +65,7 @@ static const struct hc_driver ps3_ehci_hc_driver = {
        .urb_enqueue            = ehci_urb_enqueue,
        .urb_dequeue            = ehci_urb_dequeue,
        .endpoint_disable       = ehci_endpoint_disable,
+       .endpoint_reset         = ehci_endpoint_reset,
        .get_frame_number       = ehci_get_frame,
        .hub_status_data        = ehci_hub_status_data,
        .hub_control            = ehci_hub_control,
@@ -162,7 +163,7 @@ static int ps3_ehci_probe(struct ps3_system_bus_device *dev)
        dev_dbg(&dev->core, "%s:%d: virq            %lu\n", __func__, __LINE__,
                (unsigned long)virq);
 
-       ps3_system_bus_set_driver_data(dev, hcd);
+       ps3_system_bus_set_drvdata(dev, hcd);
 
        result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
 
@@ -195,8 +196,7 @@ fail_start:
 static int ps3_ehci_remove(struct ps3_system_bus_device *dev)
 {
        unsigned int tmp;
-       struct usb_hcd *hcd =
-               (struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
+       struct usb_hcd *hcd = ps3_system_bus_get_drvdata(dev);
 
        BUG_ON(!hcd);
 
@@ -208,7 +208,7 @@ static int ps3_ehci_remove(struct ps3_system_bus_device *dev)
        ehci_shutdown(hcd);
        usb_remove_hcd(hcd);
 
-       ps3_system_bus_set_driver_data(dev, NULL);
+       ps3_system_bus_set_drvdata(dev, NULL);
 
        BUG_ON(!hcd->regs);
        iounmap(hcd->regs);
index 1976b1b3778cd3de2d7946733fbda37edb6a7108..3192f683f8073293a6366b532ced3ff0dd5007f1 100644 (file)
@@ -93,22 +93,6 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
        qh->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma);
        qh->hw_alt_next = EHCI_LIST_END(ehci);
 
-       /* Except for control endpoints, we make hardware maintain data
-        * toggle (like OHCI) ... here (re)initialize the toggle in the QH,
-        * and set the pseudo-toggle in udev. Only usb_clear_halt() will
-        * ever clear it.
-        */
-       if (!(qh->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) {
-               unsigned        is_out, epnum;
-
-               is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8));
-               epnum = (hc32_to_cpup(ehci, &qh->hw_info1) >> 8) & 0x0f;
-               if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) {
-                       qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
-                       usb_settoggle (qh->dev, epnum, is_out, 1);
-               }
-       }
-
        /* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
        wmb ();
        qh->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING);
@@ -850,7 +834,6 @@ done:
        qh->qh_state = QH_STATE_IDLE;
        qh->hw_info1 = cpu_to_hc32(ehci, info1);
        qh->hw_info2 = cpu_to_hc32(ehci, info2);
-       usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
        qh_refresh (ehci, qh);
        return qh;
 }
@@ -881,7 +864,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
                }
        }
 
-       /* clear halt and/or toggle; and maybe recover from silicon quirk */
+       /* clear halt and maybe recover from silicon quirk */
        if (qh->qh_state == QH_STATE_IDLE)
                qh_refresh (ehci, qh);
 
index 556d0ec0c1f81048044a7b6e51019a5a1d4443e5..9d1babc7ff6553c64de8cec32fcfcff3f5ce5967 100644 (file)
@@ -760,8 +760,10 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
        if (status) {
                /* "normal" case, uframing flexible except with splits */
                if (qh->period) {
-                       frame = qh->period - 1;
-                       do {
+                       int             i;
+
+                       for (i = qh->period; status && i > 0; --i) {
+                               frame = ++ehci->random_frame % qh->period;
                                for (uframe = 0; uframe < 8; uframe++) {
                                        status = check_intr_schedule (ehci,
                                                        frame, uframe, qh,
@@ -769,7 +771,7 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
                                        if (status == 0)
                                                break;
                                }
-                       } while (status && frame--);
+                       }
 
                /* qh->period == 0 means every uframe */
                } else {
index 6cff195e1a365e46d739bc42263b57381365bb3b..90ad3395bb21f0f96923ab21431dc7c44165badb 100644 (file)
@@ -116,6 +116,7 @@ struct ehci_hcd {                   /* one per controller */
        struct timer_list       watchdog;
        unsigned long           actions;
        unsigned                stamp;
+       unsigned                random_frame;
        unsigned long           next_statechange;
        u32                     command;
 
index ea8a4255c5da25b29136da57b8849c7bdd3f4285..e799f86dab1169c3542dc4c7c8eb5411feb2c2c8 100644 (file)
@@ -108,7 +108,7 @@ void fhci_dfs_create(struct fhci_hcd *fhci)
 {
        struct device *dev = fhci_to_hcd(fhci)->self.controller;
 
-       fhci->dfs_root = debugfs_create_dir(dev_name(dev), NULL);
+       fhci->dfs_root = debugfs_create_dir(dev_name(dev), usb_debug_root);
        if (!fhci->dfs_root) {
                WARN_ON(1);
                return;
index cbf30e515f29f2e7f7668f1143c8f09d02a45738..88b03214622b96683f3c0f6d9b5db73e8d98f2d5 100644 (file)
@@ -172,25 +172,6 @@ error_cluster_id_get:
 
 }
 
-static int hwahc_op_suspend(struct usb_hcd *usb_hcd, pm_message_t msg)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-       dev_err(wusbhc->dev, "%s (%p [%p], 0x%lx) UNIMPLEMENTED\n", __func__,
-               usb_hcd, hwahc, *(unsigned long *) &msg);
-       return -ENOSYS;
-}
-
-static int hwahc_op_resume(struct usb_hcd *usb_hcd)
-{
-       struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
-       struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
-
-       dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__,
-               usb_hcd, hwahc);
-       return -ENOSYS;
-}
-
 /*
  * No need to abort pipes, as when this is called, all the children
  * has been disconnected and that has done it [through
@@ -598,8 +579,6 @@ static struct hc_driver hwahc_hc_driver = {
        .flags = HCD_USB2,              /* FIXME */
        .reset = hwahc_op_reset,
        .start = hwahc_op_start,
-       .pci_suspend = hwahc_op_suspend,
-       .pci_resume = hwahc_op_resume,
        .stop = hwahc_op_stop,
        .get_frame_number = hwahc_op_get_frame_number,
        .urb_enqueue = hwahc_op_urb_enqueue,
index d3269656aa4d8c81036b6e5880123c42a254c821..811f5dfdc582447c18716a79e1bb055735975fff 100644 (file)
@@ -431,7 +431,7 @@ static struct dentry *ohci_debug_root;
 
 struct debug_buffer {
        ssize_t (*fill_func)(struct debug_buffer *);    /* fill method */
-       struct device *dev;
+       struct ohci_hcd *ohci;
        struct mutex mutex;     /* protect filling of buffer */
        size_t count;           /* number of characters filled into buffer */
        char *page;
@@ -505,15 +505,11 @@ show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed)
 
 static ssize_t fill_async_buffer(struct debug_buffer *buf)
 {
-       struct usb_bus          *bus;
-       struct usb_hcd          *hcd;
        struct ohci_hcd         *ohci;
        size_t                  temp;
        unsigned long           flags;
 
-       bus = dev_get_drvdata(buf->dev);
-       hcd = bus_to_hcd(bus);
-       ohci = hcd_to_ohci(hcd);
+       ohci = buf->ohci;
 
        /* display control and bulk lists together, for simplicity */
        spin_lock_irqsave (&ohci->lock, flags);
@@ -529,8 +525,6 @@ static ssize_t fill_async_buffer(struct debug_buffer *buf)
 
 static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
 {
-       struct usb_bus          *bus;
-       struct usb_hcd          *hcd;
        struct ohci_hcd         *ohci;
        struct ed               **seen, *ed;
        unsigned long           flags;
@@ -542,9 +536,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
                return 0;
        seen_count = 0;
 
-       bus = (struct usb_bus *)dev_get_drvdata(buf->dev);
-       hcd = bus_to_hcd(bus);
-       ohci = hcd_to_ohci(hcd);
+       ohci = buf->ohci;
        next = buf->page;
        size = PAGE_SIZE;
 
@@ -626,7 +618,6 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
 
 static ssize_t fill_registers_buffer(struct debug_buffer *buf)
 {
-       struct usb_bus          *bus;
        struct usb_hcd          *hcd;
        struct ohci_hcd         *ohci;
        struct ohci_regs __iomem *regs;
@@ -635,9 +626,8 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
        char                    *next;
        u32                     rdata;
 
-       bus = (struct usb_bus *)dev_get_drvdata(buf->dev);
-       hcd = bus_to_hcd(bus);
-       ohci = hcd_to_ohci(hcd);
+       ohci = buf->ohci;
+       hcd = ohci_to_hcd(ohci);
        regs = ohci->regs;
        next = buf->page;
        size = PAGE_SIZE;
@@ -710,7 +700,7 @@ done:
        return PAGE_SIZE - size;
 }
 
-static struct debug_buffer *alloc_buffer(struct device *dev,
+static struct debug_buffer *alloc_buffer(struct ohci_hcd *ohci,
                                ssize_t (*fill_func)(struct debug_buffer *))
 {
        struct debug_buffer *buf;
@@ -718,7 +708,7 @@ static struct debug_buffer *alloc_buffer(struct device *dev,
        buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL);
 
        if (buf) {
-               buf->dev = dev;
+               buf->ohci = ohci;
                buf->fill_func = fill_func;
                mutex_init(&buf->mutex);
        }
@@ -810,26 +800,25 @@ static int debug_registers_open(struct inode *inode, struct file *file)
 static inline void create_debug_files (struct ohci_hcd *ohci)
 {
        struct usb_bus *bus = &ohci_to_hcd(ohci)->self;
-       struct device *dev = bus->dev;
 
        ohci->debug_dir = debugfs_create_dir(bus->bus_name, ohci_debug_root);
        if (!ohci->debug_dir)
                goto dir_error;
 
        ohci->debug_async = debugfs_create_file("async", S_IRUGO,
-                                               ohci->debug_dir, dev,
+                                               ohci->debug_dir, ohci,
                                                &debug_async_fops);
        if (!ohci->debug_async)
                goto async_error;
 
        ohci->debug_periodic = debugfs_create_file("periodic", S_IRUGO,
-                                                  ohci->debug_dir, dev,
+                                                  ohci->debug_dir, ohci,
                                                   &debug_periodic_fops);
        if (!ohci->debug_periodic)
                goto periodic_error;
 
        ohci->debug_registers = debugfs_create_file("registers", S_IRUGO,
-                                                   ohci->debug_dir, dev,
+                                                   ohci->debug_dir, ohci,
                                                    &debug_registers_fops);
        if (!ohci->debug_registers)
                goto registers_error;
index 25db704f3a2aa8c7d60ae1c48eab54270abab45e..58151687d3518ef8da2938ae1fb34babe1a3caca 100644 (file)
@@ -571,7 +571,7 @@ static int ohci_init (struct ohci_hcd *ohci)
  */
 static int ohci_run (struct ohci_hcd *ohci)
 {
-       u32                     mask, temp;
+       u32                     mask, val;
        int                     first = ohci->fminterval == 0;
        struct usb_hcd          *hcd = ohci_to_hcd(ohci);
 
@@ -580,8 +580,8 @@ static int ohci_run (struct ohci_hcd *ohci)
        /* boot firmware should have set this up (5.1.1.3.1) */
        if (first) {
 
-               temp = ohci_readl (ohci, &ohci->regs->fminterval);
-               ohci->fminterval = temp & 0x3fff;
+               val = ohci_readl (ohci, &ohci->regs->fminterval);
+               ohci->fminterval = val & 0x3fff;
                if (ohci->fminterval != FI)
                        ohci_dbg (ohci, "fminterval delta %d\n",
                                ohci->fminterval - FI);
@@ -600,25 +600,25 @@ static int ohci_run (struct ohci_hcd *ohci)
 
        switch (ohci->hc_control & OHCI_CTRL_HCFS) {
        case OHCI_USB_OPER:
-               temp = 0;
+               val = 0;
                break;
        case OHCI_USB_SUSPEND:
        case OHCI_USB_RESUME:
                ohci->hc_control &= OHCI_CTRL_RWC;
                ohci->hc_control |= OHCI_USB_RESUME;
-               temp = 10 /* msec wait */;
+               val = 10 /* msec wait */;
                break;
        // case OHCI_USB_RESET:
        default:
                ohci->hc_control &= OHCI_CTRL_RWC;
                ohci->hc_control |= OHCI_USB_RESET;
-               temp = 50 /* msec wait */;
+               val = 50 /* msec wait */;
                break;
        }
        ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
        // flush the writes
        (void) ohci_readl (ohci, &ohci->regs->control);
-       msleep(temp);
+       msleep(val);
 
        memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
 
@@ -628,9 +628,9 @@ static int ohci_run (struct ohci_hcd *ohci)
 retry:
        /* HC Reset requires max 10 us delay */
        ohci_writel (ohci, OHCI_HCR,  &ohci->regs->cmdstatus);
-       temp = 30;      /* ... allow extra time */
+       val = 30;       /* ... allow extra time */
        while ((ohci_readl (ohci, &ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
-               if (--temp == 0) {
+               if (--val == 0) {
                        spin_unlock_irq (&ohci->lock);
                        ohci_err (ohci, "USB HC reset timed out!\n");
                        return -1;
@@ -699,23 +699,23 @@ retry:
        ohci_writel (ohci, mask, &ohci->regs->intrenable);
 
        /* handle root hub init quirks ... */
-       temp = roothub_a (ohci);
-       temp &= ~(RH_A_PSM | RH_A_OCPM);
+       val = roothub_a (ohci);
+       val &= ~(RH_A_PSM | RH_A_OCPM);
        if (ohci->flags & OHCI_QUIRK_SUPERIO) {
                /* NSC 87560 and maybe others */
-               temp |= RH_A_NOCP;
-               temp &= ~(RH_A_POTPGT | RH_A_NPS);
-               ohci_writel (ohci, temp, &ohci->regs->roothub.a);
+               val |= RH_A_NOCP;
+               val &= ~(RH_A_POTPGT | RH_A_NPS);
+               ohci_writel (ohci, val, &ohci->regs->roothub.a);
        } else if ((ohci->flags & OHCI_QUIRK_AMD756) ||
                        (ohci->flags & OHCI_QUIRK_HUB_POWER)) {
                /* hub power always on; required for AMD-756 and some
                 * Mac platforms.  ganged overcurrent reporting, if any.
                 */
-               temp |= RH_A_NPS;
-               ohci_writel (ohci, temp, &ohci->regs->roothub.a);
+               val |= RH_A_NPS;
+               ohci_writel (ohci, val, &ohci->regs->roothub.a);
        }
        ohci_writel (ohci, RH_HS_LPSC, &ohci->regs->roothub.status);
-       ohci_writel (ohci, (temp & RH_A_NPS) ? 0 : RH_B_PPCM,
+       ohci_writel (ohci, (val & RH_A_NPS) ? 0 : RH_B_PPCM,
                                                &ohci->regs->roothub.b);
        // flush those writes
        (void) ohci_readl (ohci, &ohci->regs->control);
@@ -724,7 +724,7 @@ retry:
        spin_unlock_irq (&ohci->lock);
 
        // POTPGT delay is bits 24-31, in 2 ms units.
-       mdelay ((temp >> 23) & 0x1fe);
+       mdelay ((val >> 23) & 0x1fe);
        hcd->state = HC_STATE_RUNNING;
 
        if (quirk_zfmicro(ohci)) {
@@ -1105,7 +1105,7 @@ static int __init ohci_hcd_mod_init(void)
        set_bit(USB_OHCI_LOADED, &usb_hcds_loaded);
 
 #ifdef DEBUG
-       ohci_debug_root = debugfs_create_dir("ohci", NULL);
+       ohci_debug_root = debugfs_create_dir("ohci", usb_debug_root);
        if (!ohci_debug_root) {
                retval = -ENOENT;
                goto error_debug;
index f9961b4c0da3e5065f054aa7dc34a619e00b8187..d2ba04dd785e4942d69ad28f4b2a3a727d3efd54 100644 (file)
@@ -372,7 +372,7 @@ static int __devinit ohci_pci_start (struct usb_hcd *hcd)
 
 #ifdef CONFIG_PM
 
-static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
+static int ohci_pci_suspend(struct usb_hcd *hcd)
 {
        struct ohci_hcd *ohci = hcd_to_ohci (hcd);
        unsigned long   flags;
@@ -394,10 +394,6 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
        ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
        (void)ohci_readl(ohci, &ohci->regs->intrdisable);
 
-       /* make sure snapshot being resumed re-enumerates everything */
-       if (message.event == PM_EVENT_PRETHAW)
-               ohci_usb_reset(ohci);
-
        clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
  bail:
        spin_unlock_irqrestore (&ohci->lock, flags);
@@ -406,9 +402,14 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
 }
 
 
-static int ohci_pci_resume (struct usb_hcd *hcd)
+static int ohci_pci_resume(struct usb_hcd *hcd, bool hibernated)
 {
        set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+       /* Make sure resume from hibernation re-enumerates everything */
+       if (hibernated)
+               ohci_usb_reset(hcd_to_ohci(hcd));
+
        ohci_finish_controller_resume(hcd);
        return 0;
 }
@@ -484,12 +485,11 @@ static struct pci_driver ohci_pci_driver = {
 
        .probe =        usb_hcd_pci_probe,
        .remove =       usb_hcd_pci_remove,
+       .shutdown =     usb_hcd_pci_shutdown,
 
-#ifdef CONFIG_PM
-       .suspend =      usb_hcd_pci_suspend,
-       .resume =       usb_hcd_pci_resume,
+#ifdef CONFIG_PM_SLEEP
+       .driver =       {
+               .pm =   &usb_hcd_pci_pm_ops
+       },
 #endif
-
-       .shutdown =     usb_hcd_pci_shutdown,
 };
-
index 3d19103173286e849e54a21ede9012b04426ee24..1d56259c5db1650bb610e3318aa3a969a381f4cb 100644 (file)
@@ -162,7 +162,7 @@ static int ps3_ohci_probe(struct ps3_system_bus_device *dev)
        dev_dbg(&dev->core, "%s:%d: virq            %lu\n", __func__, __LINE__,
                (unsigned long)virq);
 
-       ps3_system_bus_set_driver_data(dev, hcd);
+       ps3_system_bus_set_drvdata(dev, hcd);
 
        result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
 
@@ -195,8 +195,7 @@ fail_start:
 static int ps3_ohci_remove(struct ps3_system_bus_device *dev)
 {
        unsigned int tmp;
-       struct usb_hcd *hcd =
-               (struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
+       struct usb_hcd *hcd = ps3_system_bus_get_drvdata(dev);
 
        BUG_ON(!hcd);
 
@@ -208,7 +207,7 @@ static int ps3_ohci_remove(struct ps3_system_bus_device *dev)
        ohci_shutdown(hcd);
        usb_remove_hcd(hcd);
 
-       ps3_system_bus_set_driver_data(dev, NULL);
+       ps3_system_bus_set_drvdata(dev, NULL);
 
        BUG_ON(!hcd->regs);
        iounmap(hcd->regs);
index 033c2846ce5923e05f0805bff889ab45268ea056..83b5f9cea85ac9f43af8d3b1eb87a259517cc05c 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/delay.h>
 #include <linux/acpi.h>
 #include "pci-quirks.h"
+#include "xhci-ext-caps.h"
 
 
 #define UHCI_USBLEGSUP         0xc0            /* legacy support */
@@ -341,7 +342,127 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
        return;
 }
 
+/*
+ * handshake - spin reading a register until handshake completes
+ * @ptr: address of hc register to be read
+ * @mask: bits to look at in result of read
+ * @done: value of those bits when handshake succeeds
+ * @wait_usec: timeout in microseconds
+ * @delay_usec: delay in microseconds to wait between polling
+ *
+ * Polls a register every delay_usec microseconds.
+ * Returns 0 when the mask bits have the value done.
+ * Returns -ETIMEDOUT if this condition is not true after
+ * wait_usec microseconds have passed.
+ */
+static int handshake(void __iomem *ptr, u32 mask, u32 done,
+               int wait_usec, int delay_usec)
+{
+       u32     result;
+
+       do {
+               result = readl(ptr);
+               result &= mask;
+               if (result == done)
+                       return 0;
+               udelay(delay_usec);
+               wait_usec -= delay_usec;
+       } while (wait_usec > 0);
+       return -ETIMEDOUT;
+}
+
+/**
+ * PCI Quirks for xHCI.
+ *
+ * Takes care of the handoff between the Pre-OS (i.e. BIOS) and the OS.
+ * It signals to the BIOS that the OS wants control of the host controller,
+ * and then waits 5 seconds for the BIOS to hand over control.
+ * If we timeout, assume the BIOS is broken and take control anyway.
+ */
+static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
+{
+       void __iomem *base;
+       int ext_cap_offset;
+       void __iomem *op_reg_base;
+       u32 val;
+       int timeout;
+
+       if (!mmio_resource_enabled(pdev, 0))
+               return;
+
+       base = ioremap_nocache(pci_resource_start(pdev, 0),
+                               pci_resource_len(pdev, 0));
+       if (base == NULL)
+               return;
 
+       /*
+        * Find the Legacy Support Capability register -
+        * this is optional for xHCI host controllers.
+        */
+       ext_cap_offset = xhci_find_next_cap_offset(base, XHCI_HCC_PARAMS_OFFSET);
+       do {
+               if (!ext_cap_offset)
+                       /* We've reached the end of the extended capabilities */
+                       goto hc_init;
+               val = readl(base + ext_cap_offset);
+               if (XHCI_EXT_CAPS_ID(val) == XHCI_EXT_CAPS_LEGACY)
+                       break;
+               ext_cap_offset = xhci_find_next_cap_offset(base, ext_cap_offset);
+       } while (1);
+
+       /* If the BIOS owns the HC, signal that the OS wants it, and wait */
+       if (val & XHCI_HC_BIOS_OWNED) {
+               writel(val & XHCI_HC_OS_OWNED, base + ext_cap_offset);
+
+               /* Wait for 5 seconds with 10 microsecond polling interval */
+               timeout = handshake(base + ext_cap_offset, XHCI_HC_BIOS_OWNED,
+                               0, 5000, 10);
+
+               /* Assume a buggy BIOS and take HC ownership anyway */
+               if (timeout) {
+                       dev_warn(&pdev->dev, "xHCI BIOS handoff failed"
+                                       " (BIOS bug ?) %08x\n", val);
+                       writel(val & ~XHCI_HC_BIOS_OWNED, base + ext_cap_offset);
+               }
+       }
+
+       /* Disable any BIOS SMIs */
+       writel(XHCI_LEGACY_DISABLE_SMI,
+                       base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
+
+hc_init:
+       op_reg_base = base + XHCI_HC_LENGTH(readl(base));
+
+       /* Wait for the host controller to be ready before writing any
+        * operational or runtime registers.  Wait 5 seconds and no more.
+        */
+       timeout = handshake(op_reg_base + XHCI_STS_OFFSET, XHCI_STS_CNR, 0,
+                       5000, 10);
+       /* Assume a buggy HC and start HC initialization anyway */
+       if (timeout) {
+               val = readl(op_reg_base + XHCI_STS_OFFSET);
+               dev_warn(&pdev->dev,
+                               "xHCI HW not ready after 5 sec (HC bug?) "
+                               "status = 0x%x\n", val);
+       }
+
+       /* Send the halt and disable interrupts command */
+       val = readl(op_reg_base + XHCI_CMD_OFFSET);
+       val &= ~(XHCI_CMD_RUN | XHCI_IRQS);
+       writel(val, op_reg_base + XHCI_CMD_OFFSET);
+
+       /* Wait for the HC to halt - poll every 125 usec (one microframe). */
+       timeout = handshake(op_reg_base + XHCI_STS_OFFSET, XHCI_STS_HALT, 1,
+                       XHCI_MAX_HALT_USEC, 125);
+       if (timeout) {
+               val = readl(op_reg_base + XHCI_STS_OFFSET);
+               dev_warn(&pdev->dev,
+                               "xHCI HW did not halt within %d usec "
+                               "status = 0x%x\n", XHCI_MAX_HALT_USEC, val);
+       }
+
+       iounmap(base);
+}
 
 static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
 {
@@ -351,5 +472,7 @@ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
                quirk_usb_handoff_ohci(pdev);
        else if (pdev->class == PCI_CLASS_SERIAL_USB_EHCI)
                quirk_usb_disable_ehci(pdev);
+       else if (pdev->class == PCI_CLASS_SERIAL_USB_XHCI)
+               quirk_usb_handoff_xhci(pdev);
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);
index f1626e58c141ff207fac18c57d3ce58212f86b72..56976cc0352a9ae9e87a0a1cb681135410e0e581 100644 (file)
@@ -46,31 +46,10 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Yoshihiro Shimoda");
 MODULE_ALIAS("platform:r8a66597_hcd");
 
-#define DRIVER_VERSION "10 Apr 2008"
+#define DRIVER_VERSION "2009-05-26"
 
 static const char hcd_name[] = "r8a66597_hcd";
 
-/* module parameters */
-#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
-static unsigned short clock = XTAL12;
-module_param(clock, ushort, 0644);
-MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
-               "(default=0)");
-#endif
-
-static unsigned short vif = LDRV;
-module_param(vif, ushort, 0644);
-MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0(default=32768)");
-
-static unsigned short endian;
-module_param(endian, ushort, 0644);
-MODULE_PARM_DESC(endian, "data endian: big=256, little=0 (default=0)");
-
-static unsigned short irq_sense = 0xff;
-module_param(irq_sense, ushort, 0644);
-MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=32, falling edge=0 "
-               "(default=32)");
-
 static void packet_write(struct r8a66597 *r8a66597, u16 pipenum);
 static int r8a66597_get_frame(struct usb_hcd *hcd);
 
@@ -136,7 +115,8 @@ static int r8a66597_clock_enable(struct r8a66597 *r8a66597)
                }
        } while ((tmp & USBE) != USBE);
        r8a66597_bclr(r8a66597, USBE, SYSCFG0);
-       r8a66597_mdfy(r8a66597, clock, XTAL, SYSCFG0);
+       r8a66597_mdfy(r8a66597, get_xtal_from_pdata(r8a66597->pdata), XTAL,
+                       SYSCFG0);
 
        i = 0;
        r8a66597_bset(r8a66597, XCKE, SYSCFG0);
@@ -203,6 +183,9 @@ static void r8a66597_disable_port(struct r8a66597 *r8a66597, int port)
 static int enable_controller(struct r8a66597 *r8a66597)
 {
        int ret, port;
+       u16 vif = r8a66597->pdata->vif ? LDRV : 0;
+       u16 irq_sense = r8a66597->irq_sense_low ? INTL : 0;
+       u16 endian = r8a66597->pdata->endian ? BIGEND : 0;
 
        ret = r8a66597_clock_enable(r8a66597);
        if (ret < 0)
@@ -2373,7 +2356,7 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev)
        return 0;
 }
 
-static int __init r8a66597_probe(struct platform_device *pdev)
+static int __devinit r8a66597_probe(struct platform_device *pdev)
 {
 #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
        char clk_name[8];
@@ -2418,6 +2401,12 @@ static int __init r8a66597_probe(struct platform_device *pdev)
                goto clean_up;
        }
 
+       if (pdev->dev.platform_data == NULL) {
+               dev_err(&pdev->dev, "no platform data\n");
+               ret = -ENODEV;
+               goto clean_up;
+       }
+
        /* initialize hcd */
        hcd = usb_create_hcd(&r8a66597_hc_driver, &pdev->dev, (char *)hcd_name);
        if (!hcd) {
@@ -2428,6 +2417,8 @@ static int __init r8a66597_probe(struct platform_device *pdev)
        r8a66597 = hcd_to_r8a66597(hcd);
        memset(r8a66597, 0, sizeof(struct r8a66597));
        dev_set_drvdata(&pdev->dev, r8a66597);
+       r8a66597->pdata = pdev->dev.platform_data;
+       r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW;
 
 #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
        snprintf(clk_name, sizeof(clk_name), "usb%d", pdev->id);
@@ -2458,29 +2449,6 @@ static int __init r8a66597_probe(struct platform_device *pdev)
 
        hcd->rsrc_start = res->start;
 
-       /* irq_sense setting on cmdline takes precedence over resource
-        * settings, so the introduction of irqflags in IRQ resourse
-        * won't disturb existing setups */
-       switch (irq_sense) {
-               case INTL:
-                       irq_trigger = IRQF_TRIGGER_LOW;
-                       break;
-               case 0:
-                       irq_trigger = IRQF_TRIGGER_FALLING;
-                       break;
-               case 0xff:
-                       if (irq_trigger)
-                               irq_sense = (irq_trigger & IRQF_TRIGGER_LOW) ?
-                                           INTL : 0;
-                       else {
-                               irq_sense = INTL;
-                               irq_trigger = IRQF_TRIGGER_LOW;
-                       }
-                       break;
-               default:
-                       dev_err(&pdev->dev, "Unknown irq_sense value.\n");
-       }
-
        ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | irq_trigger);
        if (ret != 0) {
                dev_err(&pdev->dev, "Failed to add hcd\n");
index f49208f1bb74d80003c9a79b1e87090d298ac5f4..d72680b433f93c2309d7c17acbee40cab8281c45 100644 (file)
@@ -30,6 +30,8 @@
 #include <linux/clk.h>
 #endif
 
+#include <linux/usb/r8a66597.h>
+
 #define SYSCFG0                0x00
 #define SYSCFG1                0x02
 #define SYSSTS0                0x04
@@ -488,6 +490,7 @@ struct r8a66597 {
 #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
        struct clk *clk;
 #endif
+       struct r8a66597_platdata        *pdata;
        struct r8a66597_device          device0;
        struct r8a66597_root_hub        root_hub[R8A66597_MAX_ROOT_HUB];
        struct list_head                pipe_queue[R8A66597_MAX_NUM_PIPE];
@@ -506,6 +509,7 @@ struct r8a66597 {
        unsigned long child_connect_map[4];
 
        unsigned bus_suspended:1;
+       unsigned irq_sense_low:1;
 };
 
 static inline struct r8a66597 *hcd_to_r8a66597(struct usb_hcd *hcd)
@@ -660,10 +664,36 @@ static inline void r8a66597_port_power(struct r8a66597 *r8a66597, int port,
 {
        unsigned long dvstctr_reg = get_dvstctr_reg(port);
 
-       if (power)
-               r8a66597_bset(r8a66597, VBOUT, dvstctr_reg);
-       else
-               r8a66597_bclr(r8a66597, VBOUT, dvstctr_reg);
+       if (r8a66597->pdata->port_power) {
+               r8a66597->pdata->port_power(port, power);
+       } else {
+               if (power)
+                       r8a66597_bset(r8a66597, VBOUT, dvstctr_reg);
+               else
+                       r8a66597_bclr(r8a66597, VBOUT, dvstctr_reg);
+       }
+}
+
+static inline u16 get_xtal_from_pdata(struct r8a66597_platdata *pdata)
+{
+       u16 clock = 0;
+
+       switch (pdata->xtal) {
+       case R8A66597_PLATDATA_XTAL_12MHZ:
+               clock = XTAL12;
+               break;
+       case R8A66597_PLATDATA_XTAL_24MHZ:
+               clock = XTAL24;
+               break;
+       case R8A66597_PLATDATA_XTAL_48MHZ:
+               clock = XTAL48;
+               break;
+       default:
+               printk(KERN_ERR "r8a66597: platdata clock is wrong.\n");
+               break;
+       }
+
+       return clock;
 }
 
 #define get_pipectr_addr(pipenum)      (PIPE1CTR + (pipenum - 1) * 2)
index cf5e4cf7ea425828ca099af27dc6d2639ded8f9a..274751b4409c2bc2f71b7ea17a49a374d4494190 100644 (file)
@@ -769,7 +769,7 @@ static int uhci_rh_resume(struct usb_hcd *hcd)
        return rc;
 }
 
-static int uhci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
+static int uhci_pci_suspend(struct usb_hcd *hcd)
 {
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
        int rc = 0;
@@ -795,10 +795,6 @@ static int uhci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
 
        /* FIXME: Enable non-PME# remote wakeup? */
 
-       /* make sure snapshot being resumed re-enumerates everything */
-       if (message.event == PM_EVENT_PRETHAW)
-               uhci_hc_died(uhci);
-
 done_okay:
        clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
 done:
@@ -806,7 +802,7 @@ done:
        return rc;
 }
 
-static int uhci_pci_resume(struct usb_hcd *hcd)
+static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
 {
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 
@@ -820,6 +816,10 @@ static int uhci_pci_resume(struct usb_hcd *hcd)
 
        spin_lock_irq(&uhci->lock);
 
+       /* Make sure resume from hibernation re-enumerates everything */
+       if (hibernated)
+               uhci_hc_died(uhci);
+
        /* FIXME: Disable non-PME# remote wakeup? */
 
        /* The firmware or a boot kernel may have changed the controller
@@ -940,10 +940,11 @@ static struct pci_driver uhci_pci_driver = {
        .remove =       usb_hcd_pci_remove,
        .shutdown =     uhci_shutdown,
 
-#ifdef CONFIG_PM
-       .suspend =      usb_hcd_pci_suspend,
-       .resume =       usb_hcd_pci_resume,
-#endif /* PM */
+#ifdef CONFIG_PM_SLEEP
+       .driver =       {
+               .pm =   &usb_hcd_pci_pm_ops
+       },
+#endif
 };
  
 static int __init uhci_hcd_init(void)
@@ -961,7 +962,7 @@ static int __init uhci_hcd_init(void)
                errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
                if (!errbuf)
                        goto errbuf_failed;
-               uhci_debugfs_root = debugfs_create_dir("uhci", NULL);
+               uhci_debugfs_root = debugfs_create_dir("uhci", usb_debug_root);
                if (!uhci_debugfs_root)
                        goto debug_failed;
        }
index 3e5807d14ffb5ed89d765b9b82087cb2e2d5fb30..64e57bfe236ba89019c0884432cb44e9f2d72fd8 100644 (file)
@@ -260,7 +260,7 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
        INIT_LIST_HEAD(&qh->node);
 
        if (udev) {             /* Normal QH */
-               qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+               qh->type = usb_endpoint_type(&hep->desc);
                if (qh->type != USB_ENDPOINT_XFER_ISOC) {
                        qh->dummy_td = uhci_alloc_td(uhci);
                        if (!qh->dummy_td) {
diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c
new file mode 100644 (file)
index 0000000..2501c57
--- /dev/null
@@ -0,0 +1,485 @@
+/*
+ * xHCI host controller driver
+ *
+ * Copyright (C) 2008 Intel Corp.
+ *
+ * Author: Sarah Sharp
+ * Some code borrowed from the Linux EHCI driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 "xhci.h"
+
+#define XHCI_INIT_VALUE 0x0
+
+/* Add verbose debugging later, just print everything for now */
+
+void xhci_dbg_regs(struct xhci_hcd *xhci)
+{
+       u32 temp;
+
+       xhci_dbg(xhci, "// xHCI capability registers at %p:\n",
+                       xhci->cap_regs);
+       temp = xhci_readl(xhci, &xhci->cap_regs->hc_capbase);
+       xhci_dbg(xhci, "// @%p = 0x%x (CAPLENGTH AND HCIVERSION)\n",
+                       &xhci->cap_regs->hc_capbase, temp);
+       xhci_dbg(xhci, "//   CAPLENGTH: 0x%x\n",
+                       (unsigned int) HC_LENGTH(temp));
+#if 0
+       xhci_dbg(xhci, "//   HCIVERSION: 0x%x\n",
+                       (unsigned int) HC_VERSION(temp));
+#endif
+
+       xhci_dbg(xhci, "// xHCI operational registers at %p:\n", xhci->op_regs);
+
+       temp = xhci_readl(xhci, &xhci->cap_regs->run_regs_off);
+       xhci_dbg(xhci, "// @%p = 0x%x RTSOFF\n",
+                       &xhci->cap_regs->run_regs_off,
+                       (unsigned int) temp & RTSOFF_MASK);
+       xhci_dbg(xhci, "// xHCI runtime registers at %p:\n", xhci->run_regs);
+
+       temp = xhci_readl(xhci, &xhci->cap_regs->db_off);
+       xhci_dbg(xhci, "// @%p = 0x%x DBOFF\n", &xhci->cap_regs->db_off, temp);
+       xhci_dbg(xhci, "// Doorbell array at %p:\n", xhci->dba);
+}
+
+static void xhci_print_cap_regs(struct xhci_hcd *xhci)
+{
+       u32 temp;
+
+       xhci_dbg(xhci, "xHCI capability registers at %p:\n", xhci->cap_regs);
+
+       temp = xhci_readl(xhci, &xhci->cap_regs->hc_capbase);
+       xhci_dbg(xhci, "CAPLENGTH AND HCIVERSION 0x%x:\n",
+                       (unsigned int) temp);
+       xhci_dbg(xhci, "CAPLENGTH: 0x%x\n",
+                       (unsigned int) HC_LENGTH(temp));
+       xhci_dbg(xhci, "HCIVERSION: 0x%x\n",
+                       (unsigned int) HC_VERSION(temp));
+
+       temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params1);
+       xhci_dbg(xhci, "HCSPARAMS 1: 0x%x\n",
+                       (unsigned int) temp);
+       xhci_dbg(xhci, "  Max device slots: %u\n",
+                       (unsigned int) HCS_MAX_SLOTS(temp));
+       xhci_dbg(xhci, "  Max interrupters: %u\n",
+                       (unsigned int) HCS_MAX_INTRS(temp));
+       xhci_dbg(xhci, "  Max ports: %u\n",
+                       (unsigned int) HCS_MAX_PORTS(temp));
+
+       temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params2);
+       xhci_dbg(xhci, "HCSPARAMS 2: 0x%x\n",
+                       (unsigned int) temp);
+       xhci_dbg(xhci, "  Isoc scheduling threshold: %u\n",
+                       (unsigned int) HCS_IST(temp));
+       xhci_dbg(xhci, "  Maximum allowed segments in event ring: %u\n",
+                       (unsigned int) HCS_ERST_MAX(temp));
+
+       temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params3);
+       xhci_dbg(xhci, "HCSPARAMS 3 0x%x:\n",
+                       (unsigned int) temp);
+       xhci_dbg(xhci, "  Worst case U1 device exit latency: %u\n",
+                       (unsigned int) HCS_U1_LATENCY(temp));
+       xhci_dbg(xhci, "  Worst case U2 device exit latency: %u\n",
+                       (unsigned int) HCS_U2_LATENCY(temp));
+
+       temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
+       xhci_dbg(xhci, "HCC PARAMS 0x%x:\n", (unsigned int) temp);
+       xhci_dbg(xhci, "  HC generates %s bit addresses\n",
+                       HCC_64BIT_ADDR(temp) ? "64" : "32");
+       /* FIXME */
+       xhci_dbg(xhci, "  FIXME: more HCCPARAMS debugging\n");
+
+       temp = xhci_readl(xhci, &xhci->cap_regs->run_regs_off);
+       xhci_dbg(xhci, "RTSOFF 0x%x:\n", temp & RTSOFF_MASK);
+}
+
+static void xhci_print_command_reg(struct xhci_hcd *xhci)
+{
+       u32 temp;
+
+       temp = xhci_readl(xhci, &xhci->op_regs->command);
+       xhci_dbg(xhci, "USBCMD 0x%x:\n", temp);
+       xhci_dbg(xhci, "  HC is %s\n",
+                       (temp & CMD_RUN) ? "running" : "being stopped");
+       xhci_dbg(xhci, "  HC has %sfinished hard reset\n",
+                       (temp & CMD_RESET) ? "not " : "");
+       xhci_dbg(xhci, "  Event Interrupts %s\n",
+                       (temp & CMD_EIE) ? "enabled " : "disabled");
+       xhci_dbg(xhci, "  Host System Error Interrupts %s\n",
+                       (temp & CMD_EIE) ? "enabled " : "disabled");
+       xhci_dbg(xhci, "  HC has %sfinished light reset\n",
+                       (temp & CMD_LRESET) ? "not " : "");
+}
+
+static void xhci_print_status(struct xhci_hcd *xhci)
+{
+       u32 temp;
+
+       temp = xhci_readl(xhci, &xhci->op_regs->status);
+       xhci_dbg(xhci, "USBSTS 0x%x:\n", temp);
+       xhci_dbg(xhci, "  Event ring is %sempty\n",
+                       (temp & STS_EINT) ? "not " : "");
+       xhci_dbg(xhci, "  %sHost System Error\n",
+                       (temp & STS_FATAL) ? "WARNING: " : "No ");
+       xhci_dbg(xhci, "  HC is %s\n",
+                       (temp & STS_HALT) ? "halted" : "running");
+}
+
+static void xhci_print_op_regs(struct xhci_hcd *xhci)
+{
+       xhci_dbg(xhci, "xHCI operational registers at %p:\n", xhci->op_regs);
+       xhci_print_command_reg(xhci);
+       xhci_print_status(xhci);
+}
+
+static void xhci_print_ports(struct xhci_hcd *xhci)
+{
+       u32 __iomem *addr;
+       int i, j;
+       int ports;
+       char *names[NUM_PORT_REGS] = {
+               "status",
+               "power",
+               "link",
+               "reserved",
+       };
+
+       ports = HCS_MAX_PORTS(xhci->hcs_params1);
+       addr = &xhci->op_regs->port_status_base;
+       for (i = 0; i < ports; i++) {
+               for (j = 0; j < NUM_PORT_REGS; ++j) {
+                       xhci_dbg(xhci, "%p port %s reg = 0x%x\n",
+                                       addr, names[j],
+                                       (unsigned int) xhci_readl(xhci, addr));
+                       addr++;
+               }
+       }
+}
+
+void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int set_num)
+{
+       void *addr;
+       u32 temp;
+
+       addr = &ir_set->irq_pending;
+       temp = xhci_readl(xhci, addr);
+       if (temp == XHCI_INIT_VALUE)
+               return;
+
+       xhci_dbg(xhci, "  %p: ir_set[%i]\n", ir_set, set_num);
+
+       xhci_dbg(xhci, "  %p: ir_set.pending = 0x%x\n", addr,
+                       (unsigned int)temp);
+
+       addr = &ir_set->irq_control;
+       temp = xhci_readl(xhci, addr);
+       xhci_dbg(xhci, "  %p: ir_set.control = 0x%x\n", addr,
+                       (unsigned int)temp);
+
+       addr = &ir_set->erst_size;
+       temp = xhci_readl(xhci, addr);
+       xhci_dbg(xhci, "  %p: ir_set.erst_size = 0x%x\n", addr,
+                       (unsigned int)temp);
+
+       addr = &ir_set->rsvd;
+       temp = xhci_readl(xhci, addr);
+       if (temp != XHCI_INIT_VALUE)
+               xhci_dbg(xhci, "  WARN: %p: ir_set.rsvd = 0x%x\n",
+                               addr, (unsigned int)temp);
+
+       addr = &ir_set->erst_base[0];
+       temp = xhci_readl(xhci, addr);
+       xhci_dbg(xhci, "  %p: ir_set.erst_base[0] = 0x%x\n",
+                       addr, (unsigned int) temp);
+
+       addr = &ir_set->erst_base[1];
+       temp = xhci_readl(xhci, addr);
+       xhci_dbg(xhci, "  %p: ir_set.erst_base[1] = 0x%x\n",
+                       addr, (unsigned int) temp);
+
+       addr = &ir_set->erst_dequeue[0];
+       temp = xhci_readl(xhci, addr);
+       xhci_dbg(xhci, "  %p: ir_set.erst_dequeue[0] = 0x%x\n",
+                       addr, (unsigned int) temp);
+
+       addr = &ir_set->erst_dequeue[1];
+       temp = xhci_readl(xhci, addr);
+       xhci_dbg(xhci, "  %p: ir_set.erst_dequeue[1] = 0x%x\n",
+                       addr, (unsigned int) temp);
+}
+
+void xhci_print_run_regs(struct xhci_hcd *xhci)
+{
+       u32 temp;
+       int i;
+
+       xhci_dbg(xhci, "xHCI runtime registers at %p:\n", xhci->run_regs);
+       temp = xhci_readl(xhci, &xhci->run_regs->microframe_index);
+       xhci_dbg(xhci, "  %p: Microframe index = 0x%x\n",
+                       &xhci->run_regs->microframe_index,
+                       (unsigned int) temp);
+       for (i = 0; i < 7; ++i) {
+               temp = xhci_readl(xhci, &xhci->run_regs->rsvd[i]);
+               if (temp != XHCI_INIT_VALUE)
+                       xhci_dbg(xhci, "  WARN: %p: Rsvd[%i] = 0x%x\n",
+                                       &xhci->run_regs->rsvd[i],
+                                       i, (unsigned int) temp);
+       }
+}
+
+void xhci_print_registers(struct xhci_hcd *xhci)
+{
+       xhci_print_cap_regs(xhci);
+       xhci_print_op_regs(xhci);
+       xhci_print_ports(xhci);
+}
+
+void xhci_print_trb_offsets(struct xhci_hcd *xhci, union xhci_trb *trb)
+{
+       int i;
+       for (i = 0; i < 4; ++i)
+               xhci_dbg(xhci, "Offset 0x%x = 0x%x\n",
+                               i*4, trb->generic.field[i]);
+}
+
+/**
+ * Debug a transfer request block (TRB).
+ */
+void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)
+{
+       u64     address;
+       u32     type = xhci_readl(xhci, &trb->link.control) & TRB_TYPE_BITMASK;
+
+       switch (type) {
+       case TRB_TYPE(TRB_LINK):
+               xhci_dbg(xhci, "Link TRB:\n");
+               xhci_print_trb_offsets(xhci, trb);
+
+               address = trb->link.segment_ptr[0] +
+                       (((u64) trb->link.segment_ptr[1]) << 32);
+               xhci_dbg(xhci, "Next ring segment DMA address = 0x%llx\n", address);
+
+               xhci_dbg(xhci, "Interrupter target = 0x%x\n",
+                               GET_INTR_TARGET(trb->link.intr_target));
+               xhci_dbg(xhci, "Cycle bit = %u\n",
+                               (unsigned int) (trb->link.control & TRB_CYCLE));
+               xhci_dbg(xhci, "Toggle cycle bit = %u\n",
+                               (unsigned int) (trb->link.control & LINK_TOGGLE));
+               xhci_dbg(xhci, "No Snoop bit = %u\n",
+                               (unsigned int) (trb->link.control & TRB_NO_SNOOP));
+               break;
+       case TRB_TYPE(TRB_TRANSFER):
+               address = trb->trans_event.buffer[0] +
+                       (((u64) trb->trans_event.buffer[1]) << 32);
+               /*
+                * FIXME: look at flags to figure out if it's an address or if
+                * the data is directly in the buffer field.
+                */
+               xhci_dbg(xhci, "DMA address or buffer contents= %llu\n", address);
+               break;
+       case TRB_TYPE(TRB_COMPLETION):
+               address = trb->event_cmd.cmd_trb[0] +
+                       (((u64) trb->event_cmd.cmd_trb[1]) << 32);
+               xhci_dbg(xhci, "Command TRB pointer = %llu\n", address);
+               xhci_dbg(xhci, "Completion status = %u\n",
+                               (unsigned int) GET_COMP_CODE(trb->event_cmd.status));
+               xhci_dbg(xhci, "Flags = 0x%x\n", (unsigned int) trb->event_cmd.flags);
+               break;
+       default:
+               xhci_dbg(xhci, "Unknown TRB with TRB type ID %u\n",
+                               (unsigned int) type>>10);
+               xhci_print_trb_offsets(xhci, trb);
+               break;
+       }
+}
+
+/**
+ * Debug a segment with an xHCI ring.
+ *
+ * @return The Link TRB of the segment, or NULL if there is no Link TRB
+ * (which is a bug, since all segments must have a Link TRB).
+ *
+ * Prints out all TRBs in the segment, even those after the Link TRB.
+ *
+ * XXX: should we print out TRBs that the HC owns?  As long as we don't
+ * write, that should be fine...  We shouldn't expect that the memory pointed to
+ * by the TRB is valid at all.  Do we care about ones the HC owns?  Probably,
+ * for HC debugging.
+ */
+void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg)
+{
+       int i;
+       u32 addr = (u32) seg->dma;
+       union xhci_trb *trb = seg->trbs;
+
+       for (i = 0; i < TRBS_PER_SEGMENT; ++i) {
+               trb = &seg->trbs[i];
+               xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n", addr,
+                               (unsigned int) trb->link.segment_ptr[0],
+                               (unsigned int) trb->link.segment_ptr[1],
+                               (unsigned int) trb->link.intr_target,
+                               (unsigned int) trb->link.control);
+               addr += sizeof(*trb);
+       }
+}
+
+void xhci_dbg_ring_ptrs(struct xhci_hcd *xhci, struct xhci_ring *ring)
+{
+       xhci_dbg(xhci, "Ring deq = %p (virt), 0x%llx (dma)\n",
+                       ring->dequeue,
+                       (unsigned long long)xhci_trb_virt_to_dma(ring->deq_seg,
+                                                           ring->dequeue));
+       xhci_dbg(xhci, "Ring deq updated %u times\n",
+                       ring->deq_updates);
+       xhci_dbg(xhci, "Ring enq = %p (virt), 0x%llx (dma)\n",
+                       ring->enqueue,
+                       (unsigned long long)xhci_trb_virt_to_dma(ring->enq_seg,
+                                                           ring->enqueue));
+       xhci_dbg(xhci, "Ring enq updated %u times\n",
+                       ring->enq_updates);
+}
+
+/**
+ * Debugging for an xHCI ring, which is a queue broken into multiple segments.
+ *
+ * Print out each segment in the ring.  Check that the DMA address in
+ * each link segment actually matches the segment's stored DMA address.
+ * Check that the link end bit is only set at the end of the ring.
+ * Check that the dequeue and enqueue pointers point to real data in this ring
+ * (not some other ring).
+ */
+void xhci_debug_ring(struct xhci_hcd *xhci, struct xhci_ring *ring)
+{
+       /* FIXME: Throw an error if any segment doesn't have a Link TRB */
+       struct xhci_segment *seg;
+       struct xhci_segment *first_seg = ring->first_seg;
+       xhci_debug_segment(xhci, first_seg);
+
+       if (!ring->enq_updates && !ring->deq_updates) {
+               xhci_dbg(xhci, "  Ring has not been updated\n");
+               return;
+       }
+       for (seg = first_seg->next; seg != first_seg; seg = seg->next)
+               xhci_debug_segment(xhci, seg);
+}
+
+void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst)
+{
+       u32 addr = (u32) erst->erst_dma_addr;
+       int i;
+       struct xhci_erst_entry *entry;
+
+       for (i = 0; i < erst->num_entries; ++i) {
+               entry = &erst->entries[i];
+               xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n",
+                               (unsigned int) addr,
+                               (unsigned int) entry->seg_addr[0],
+                               (unsigned int) entry->seg_addr[1],
+                               (unsigned int) entry->seg_size,
+                               (unsigned int) entry->rsvd);
+               addr += sizeof(*entry);
+       }
+}
+
+void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci)
+{
+       u32 val;
+
+       val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[0]);
+       xhci_dbg(xhci, "// xHC command ring deq ptr low bits + flags = 0x%x\n", val);
+       val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[1]);
+       xhci_dbg(xhci, "// xHC command ring deq ptr high bits = 0x%x\n", val);
+}
+
+void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep)
+{
+       int i, j;
+       int last_ep_ctx = 31;
+       /* Fields are 32 bits wide, DMA addresses are in bytes */
+       int field_size = 32 / 8;
+
+       xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - drop flags\n",
+                       &ctx->drop_flags, (unsigned long long)dma,
+                       ctx->drop_flags);
+       dma += field_size;
+       xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - add flags\n",
+                       &ctx->add_flags, (unsigned long long)dma,
+                       ctx->add_flags);
+       dma += field_size;
+       for (i = 0; i > 6; ++i) {
+               xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n",
+                               &ctx->rsvd[i], (unsigned long long)dma,
+                               ctx->rsvd[i], i);
+               dma += field_size;
+       }
+
+       xhci_dbg(xhci, "Slot Context:\n");
+       xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info\n",
+                       &ctx->slot.dev_info,
+                       (unsigned long long)dma, ctx->slot.dev_info);
+       dma += field_size;
+       xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info2\n",
+                       &ctx->slot.dev_info2,
+                       (unsigned long long)dma, ctx->slot.dev_info2);
+       dma += field_size;
+       xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tt_info\n",
+                       &ctx->slot.tt_info,
+                       (unsigned long long)dma, ctx->slot.tt_info);
+       dma += field_size;
+       xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_state\n",
+                       &ctx->slot.dev_state,
+                       (unsigned long long)dma, ctx->slot.dev_state);
+       dma += field_size;
+       for (i = 0; i > 4; ++i) {
+               xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n",
+                               &ctx->slot.reserved[i], (unsigned long long)dma,
+                               ctx->slot.reserved[i], i);
+               dma += field_size;
+       }
+
+       if (last_ep < 31)
+               last_ep_ctx = last_ep + 1;
+       for (i = 0; i < last_ep_ctx; ++i) {
+               xhci_dbg(xhci, "Endpoint %02d Context:\n", i);
+               xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info\n",
+                               &ctx->ep[i].ep_info,
+                               (unsigned long long)dma, ctx->ep[i].ep_info);
+               dma += field_size;
+               xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info2\n",
+                               &ctx->ep[i].ep_info2,
+                               (unsigned long long)dma, ctx->ep[i].ep_info2);
+               dma += field_size;
+               xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - deq[0]\n",
+                               &ctx->ep[i].deq[0],
+                               (unsigned long long)dma, ctx->ep[i].deq[0]);
+               dma += field_size;
+               xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - deq[1]\n",
+                               &ctx->ep[i].deq[1],
+                               (unsigned long long)dma, ctx->ep[i].deq[1]);
+               dma += field_size;
+               xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tx_info\n",
+                               &ctx->ep[i].tx_info,
+                               (unsigned long long)dma, ctx->ep[i].tx_info);
+               dma += field_size;
+               for (j = 0; j < 3; ++j) {
+                       xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n",
+                                       &ctx->ep[i].reserved[j],
+                                       (unsigned long long)dma,
+                                       ctx->ep[i].reserved[j], j);
+                       dma += field_size;
+               }
+       }
+}
diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h
new file mode 100644 (file)
index 0000000..ecc131c
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * xHCI host controller driver
+ *
+ * Copyright (C) 2008 Intel Corp.
+ *
+ * Author: Sarah Sharp
+ * Some code borrowed from the Linux EHCI driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+/* Up to 16 microframes to halt an HC - one microframe is 125 microsectonds */
+#define XHCI_MAX_HALT_USEC     (16*125)
+/* HC not running - set to 1 when run/stop bit is cleared. */
+#define XHCI_STS_HALT          (1<<0)
+
+/* HCCPARAMS offset from PCI base address */
+#define XHCI_HCC_PARAMS_OFFSET 0x10
+/* HCCPARAMS contains the first extended capability pointer */
+#define XHCI_HCC_EXT_CAPS(p)   (((p)>>16)&0xffff)
+
+/* Command and Status registers offset from the Operational Registers address */
+#define XHCI_CMD_OFFSET                0x00
+#define XHCI_STS_OFFSET                0x04
+
+#define XHCI_MAX_EXT_CAPS              50
+
+/* Capability Register */
+/* bits 7:0 - how long is the Capabilities register */
+#define XHCI_HC_LENGTH(p)      (((p)>>00)&0x00ff)
+
+/* Extended capability register fields */
+#define XHCI_EXT_CAPS_ID(p)    (((p)>>0)&0xff)
+#define XHCI_EXT_CAPS_NEXT(p)  (((p)>>8)&0xff)
+#define        XHCI_EXT_CAPS_VAL(p)    ((p)>>16)
+/* Extended capability IDs - ID 0 reserved */
+#define XHCI_EXT_CAPS_LEGACY   1
+#define XHCI_EXT_CAPS_PROTOCOL 2
+#define XHCI_EXT_CAPS_PM       3
+#define XHCI_EXT_CAPS_VIRT     4
+#define XHCI_EXT_CAPS_ROUTE    5
+/* IDs 6-9 reserved */
+#define XHCI_EXT_CAPS_DEBUG    10
+/* USB Legacy Support Capability - section 7.1.1 */
+#define XHCI_HC_BIOS_OWNED     (1 << 16)
+#define XHCI_HC_OS_OWNED       (1 << 24)
+
+/* USB Legacy Support Capability - section 7.1.1 */
+/* Add this offset, plus the value of xECP in HCCPARAMS to the base address */
+#define XHCI_LEGACY_SUPPORT_OFFSET     (0x00)
+
+/* USB Legacy Support Control and Status Register  - section 7.1.2 */
+/* Add this offset, plus the value of xECP in HCCPARAMS to the base address */
+#define XHCI_LEGACY_CONTROL_OFFSET     (0x04)
+/* bits 1:2, 5:12, and 17:19 need to be preserved; bits 21:28 should be zero */
+#define        XHCI_LEGACY_DISABLE_SMI         ((0x3 << 1) + (0xff << 5) + (0x7 << 17))
+
+/* command register values to disable interrupts and halt the HC */
+/* start/stop HC execution - do not write unless HC is halted*/
+#define XHCI_CMD_RUN           (1 << 0)
+/* Event Interrupt Enable - get irq when EINT bit is set in USBSTS register */
+#define XHCI_CMD_EIE           (1 << 2)
+/* Host System Error Interrupt Enable - get irq when HSEIE bit set in USBSTS */
+#define XHCI_CMD_HSEIE         (1 << 3)
+/* Enable Wrap Event - '1' means xHC generates an event when MFINDEX wraps. */
+#define XHCI_CMD_EWE           (1 << 10)
+
+#define XHCI_IRQS              (XHCI_CMD_EIE | XHCI_CMD_HSEIE | XHCI_CMD_EWE)
+
+/* true: Controller Not Ready to accept doorbell or op reg writes after reset */
+#define XHCI_STS_CNR           (1 << 11)
+
+#include <linux/io.h>
+
+/**
+ * Return the next extended capability pointer register.
+ *
+ * @base       PCI register base address.
+ *
+ * @ext_offset Offset of the 32-bit register that contains the extended
+ * capabilites pointer.  If searching for the first extended capability, pass
+ * in XHCI_HCC_PARAMS_OFFSET.  If searching for the next extended capability,
+ * pass in the offset of the current extended capability register.
+ *
+ * Returns 0 if there is no next extended capability register or returns the register offset
+ * from the PCI registers base address.
+ */
+static inline int xhci_find_next_cap_offset(void __iomem *base, int ext_offset)
+{
+       u32 next;
+
+       next = readl(base + ext_offset);
+
+       if (ext_offset == XHCI_HCC_PARAMS_OFFSET)
+               /* Find the first extended capability */
+               next = XHCI_HCC_EXT_CAPS(next);
+       else
+               /* Find the next extended capability */
+               next = XHCI_EXT_CAPS_NEXT(next);
+       if (!next)
+               return 0;
+       /*
+        * Address calculation from offset of extended capabilities
+        * (or HCCPARAMS) register - see section 5.3.6 and section 7.
+        */
+       return ext_offset + (next << 2);
+}
+
+/**
+ * Find the offset of the extended capabilities with capability ID id.
+ *
+ * @base PCI MMIO registers base address.
+ * @ext_offset Offset from base of the first extended capability to look at,
+ *             or the address of HCCPARAMS.
+ * @id Extended capability ID to search for.
+ *
+ * This uses an arbitrary limit of XHCI_MAX_EXT_CAPS extended capabilities
+ * to make sure that the list doesn't contain a loop.
+ */
+static inline int xhci_find_ext_cap_by_id(void __iomem *base, int ext_offset, int id)
+{
+       u32 val;
+       int limit = XHCI_MAX_EXT_CAPS;
+
+       while (ext_offset && limit > 0) {
+               val = readl(base + ext_offset);
+               if (XHCI_EXT_CAPS_ID(val) == id)
+                       break;
+               ext_offset = xhci_find_next_cap_offset(base, ext_offset);
+               limit--;
+       }
+       if (limit > 0)
+               return ext_offset;
+       return 0;
+}
diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
new file mode 100644 (file)
index 0000000..dba3e07
--- /dev/null
@@ -0,0 +1,1274 @@
+/*
+ * xHCI host controller driver
+ *
+ * Copyright (C) 2008 Intel Corp.
+ *
+ * Author: Sarah Sharp
+ * Some code borrowed from the Linux EHCI driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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/irq.h>
+#include <linux/module.h>
+
+#include "xhci.h"
+
+#define DRIVER_AUTHOR "Sarah Sharp"
+#define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver"
+
+/* TODO: copied from ehci-hcd.c - can this be refactored? */
+/*
+ * handshake - spin reading hc until handshake completes or fails
+ * @ptr: address of hc register to be read
+ * @mask: bits to look at in result of read
+ * @done: value of those bits when handshake succeeds
+ * @usec: timeout in microseconds
+ *
+ * Returns negative errno, or zero on success
+ *
+ * Success happens when the "mask" bits have the specified value (hardware
+ * handshake done).  There are two failure modes:  "usec" have passed (major
+ * hardware flakeout), or the register reads as all-ones (hardware removed).
+ */
+static int handshake(struct xhci_hcd *xhci, void __iomem *ptr,
+                     u32 mask, u32 done, int usec)
+{
+       u32     result;
+
+       do {
+               result = xhci_readl(xhci, ptr);
+               if (result == ~(u32)0)          /* card removed */
+                       return -ENODEV;
+               result &= mask;
+               if (result == done)
+                       return 0;
+               udelay(1);
+               usec--;
+       } while (usec > 0);
+       return -ETIMEDOUT;
+}
+
+/*
+ * Force HC into halt state.
+ *
+ * Disable any IRQs and clear the run/stop bit.
+ * HC will complete any current and actively pipelined transactions, and
+ * should halt within 16 microframes of the run/stop bit being cleared.
+ * Read HC Halted bit in the status register to see when the HC is finished.
+ * XXX: shouldn't we set HC_STATE_HALT here somewhere?
+ */
+int xhci_halt(struct xhci_hcd *xhci)
+{
+       u32 halted;
+       u32 cmd;
+       u32 mask;
+
+       xhci_dbg(xhci, "// Halt the HC\n");
+       /* Disable all interrupts from the host controller */
+       mask = ~(XHCI_IRQS);
+       halted = xhci_readl(xhci, &xhci->op_regs->status) & STS_HALT;
+       if (!halted)
+               mask &= ~CMD_RUN;
+
+       cmd = xhci_readl(xhci, &xhci->op_regs->command);
+       cmd &= mask;
+       xhci_writel(xhci, cmd, &xhci->op_regs->command);
+
+       return handshake(xhci, &xhci->op_regs->status,
+                       STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC);
+}
+
+/*
+ * Reset a halted HC, and set the internal HC state to HC_STATE_HALT.
+ *
+ * This resets pipelines, timers, counters, state machines, etc.
+ * Transactions will be terminated immediately, and operational registers
+ * will be set to their defaults.
+ */
+int xhci_reset(struct xhci_hcd *xhci)
+{
+       u32 command;
+       u32 state;
+
+       state = xhci_readl(xhci, &xhci->op_regs->status);
+       BUG_ON((state & STS_HALT) == 0);
+
+       xhci_dbg(xhci, "// Reset the HC\n");
+       command = xhci_readl(xhci, &xhci->op_regs->command);
+       command |= CMD_RESET;
+       xhci_writel(xhci, command, &xhci->op_regs->command);
+       /* XXX: Why does EHCI set this here?  Shouldn't other code do this? */
+       xhci_to_hcd(xhci)->state = HC_STATE_HALT;
+
+       return handshake(xhci, &xhci->op_regs->command, CMD_RESET, 0, 250 * 1000);
+}
+
+/*
+ * Stop the HC from processing the endpoint queues.
+ */
+static void xhci_quiesce(struct xhci_hcd *xhci)
+{
+       /*
+        * Queues are per endpoint, so we need to disable an endpoint or slot.
+        *
+        * To disable a slot, we need to insert a disable slot command on the
+        * command ring and ring the doorbell.  This will also free any internal
+        * resources associated with the slot (which might not be what we want).
+        *
+        * A Release Endpoint command sounds better - doesn't free internal HC
+        * memory, but removes the endpoints from the schedule and releases the
+        * bandwidth, disables the doorbells, and clears the endpoint enable
+        * flag.  Usually used prior to a set interface command.
+        *
+        * TODO: Implement after command ring code is done.
+        */
+       BUG_ON(!HC_IS_RUNNING(xhci_to_hcd(xhci)->state));
+       xhci_dbg(xhci, "Finished quiescing -- code not written yet\n");
+}
+
+#if 0
+/* Set up MSI-X table for entry 0 (may claim other entries later) */
+static int xhci_setup_msix(struct xhci_hcd *xhci)
+{
+       int ret;
+       struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
+
+       xhci->msix_count = 0;
+       /* XXX: did I do this right?  ixgbe does kcalloc for more than one */
+       xhci->msix_entries = kmalloc(sizeof(struct msix_entry), GFP_KERNEL);
+       if (!xhci->msix_entries) {
+               xhci_err(xhci, "Failed to allocate MSI-X entries\n");
+               return -ENOMEM;
+       }
+       xhci->msix_entries[0].entry = 0;
+
+       ret = pci_enable_msix(pdev, xhci->msix_entries, xhci->msix_count);
+       if (ret) {
+               xhci_err(xhci, "Failed to enable MSI-X\n");
+               goto free_entries;
+       }
+
+       /*
+        * Pass the xhci pointer value as the request_irq "cookie".
+        * If more irqs are added, this will need to be unique for each one.
+        */
+       ret = request_irq(xhci->msix_entries[0].vector, &xhci_irq, 0,
+                       "xHCI", xhci_to_hcd(xhci));
+       if (ret) {
+               xhci_err(xhci, "Failed to allocate MSI-X interrupt\n");
+               goto disable_msix;
+       }
+       xhci_dbg(xhci, "Finished setting up MSI-X\n");
+       return 0;
+
+disable_msix:
+       pci_disable_msix(pdev);
+free_entries:
+       kfree(xhci->msix_entries);
+       xhci->msix_entries = NULL;
+       return ret;
+}
+
+/* XXX: code duplication; can xhci_setup_msix call this? */
+/* Free any IRQs and disable MSI-X */
+static void xhci_cleanup_msix(struct xhci_hcd *xhci)
+{
+       struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
+       if (!xhci->msix_entries)
+               return;
+
+       free_irq(xhci->msix_entries[0].vector, xhci);
+       pci_disable_msix(pdev);
+       kfree(xhci->msix_entries);
+       xhci->msix_entries = NULL;
+       xhci_dbg(xhci, "Finished cleaning up MSI-X\n");
+}
+#endif
+
+/*
+ * Initialize memory for HCD and xHC (one-time init).
+ *
+ * Program the PAGESIZE register, initialize the device context array, create
+ * device contexts (?), set up a command ring segment (or two?), create event
+ * ring (one for now).
+ */
+int xhci_init(struct usb_hcd *hcd)
+{
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       int retval = 0;
+
+       xhci_dbg(xhci, "xhci_init\n");
+       spin_lock_init(&xhci->lock);
+       retval = xhci_mem_init(xhci, GFP_KERNEL);
+       xhci_dbg(xhci, "Finished xhci_init\n");
+
+       return retval;
+}
+
+/*
+ * Called in interrupt context when there might be work
+ * queued on the event ring
+ *
+ * xhci->lock must be held by caller.
+ */
+static void xhci_work(struct xhci_hcd *xhci)
+{
+       u32 temp;
+
+       /*
+        * Clear the op reg interrupt status first,
+        * so we can receive interrupts from other MSI-X interrupters.
+        * Write 1 to clear the interrupt status.
+        */
+       temp = xhci_readl(xhci, &xhci->op_regs->status);
+       temp |= STS_EINT;
+       xhci_writel(xhci, temp, &xhci->op_regs->status);
+       /* FIXME when MSI-X is supported and there are multiple vectors */
+       /* Clear the MSI-X event interrupt status */
+
+       /* Acknowledge the interrupt */
+       temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
+       temp |= 0x3;
+       xhci_writel(xhci, temp, &xhci->ir_set->irq_pending);
+       /* Flush posted writes */
+       xhci_readl(xhci, &xhci->ir_set->irq_pending);
+
+       /* FIXME this should be a delayed service routine that clears the EHB */
+       xhci_handle_event(xhci);
+
+       /* Clear the event handler busy flag; the event ring should be empty. */
+       temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]);
+       xhci_writel(xhci, temp & ~ERST_EHB, &xhci->ir_set->erst_dequeue[0]);
+       /* Flush posted writes -- FIXME is this necessary? */
+       xhci_readl(xhci, &xhci->ir_set->irq_pending);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * xHCI spec says we can get an interrupt, and if the HC has an error condition,
+ * we might get bad data out of the event ring.  Section 4.10.2.7 has a list of
+ * indicators of an event TRB error, but we check the status *first* to be safe.
+ */
+irqreturn_t xhci_irq(struct usb_hcd *hcd)
+{
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       u32 temp, temp2;
+
+       spin_lock(&xhci->lock);
+       /* Check if the xHC generated the interrupt, or the irq is shared */
+       temp = xhci_readl(xhci, &xhci->op_regs->status);
+       temp2 = xhci_readl(xhci, &xhci->ir_set->irq_pending);
+       if (!(temp & STS_EINT) && !ER_IRQ_PENDING(temp2)) {
+               spin_unlock(&xhci->lock);
+               return IRQ_NONE;
+       }
+
+       if (temp & STS_FATAL) {
+               xhci_warn(xhci, "WARNING: Host System Error\n");
+               xhci_halt(xhci);
+               xhci_to_hcd(xhci)->state = HC_STATE_HALT;
+               spin_unlock(&xhci->lock);
+               return -ESHUTDOWN;
+       }
+
+       xhci_work(xhci);
+       spin_unlock(&xhci->lock);
+
+       return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
+void xhci_event_ring_work(unsigned long arg)
+{
+       unsigned long flags;
+       int temp;
+       struct xhci_hcd *xhci = (struct xhci_hcd *) arg;
+       int i, j;
+
+       xhci_dbg(xhci, "Poll event ring: %lu\n", jiffies);
+
+       spin_lock_irqsave(&xhci->lock, flags);
+       temp = xhci_readl(xhci, &xhci->op_regs->status);
+       xhci_dbg(xhci, "op reg status = 0x%x\n", temp);
+       temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
+       xhci_dbg(xhci, "ir_set 0 pending = 0x%x\n", temp);
+       xhci_dbg(xhci, "No-op commands handled = %d\n", xhci->noops_handled);
+       xhci_dbg(xhci, "HC error bitmask = 0x%x\n", xhci->error_bitmask);
+       xhci->error_bitmask = 0;
+       xhci_dbg(xhci, "Event ring:\n");
+       xhci_debug_segment(xhci, xhci->event_ring->deq_seg);
+       xhci_dbg_ring_ptrs(xhci, xhci->event_ring);
+       temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]);
+       temp &= ERST_PTR_MASK;
+       xhci_dbg(xhci, "ERST deq = 0x%x\n", temp);
+       xhci_dbg(xhci, "Command ring:\n");
+       xhci_debug_segment(xhci, xhci->cmd_ring->deq_seg);
+       xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring);
+       xhci_dbg_cmd_ptrs(xhci);
+       for (i = 0; i < MAX_HC_SLOTS; ++i) {
+               if (xhci->devs[i]) {
+                       for (j = 0; j < 31; ++j) {
+                               if (xhci->devs[i]->ep_rings[j]) {
+                                       xhci_dbg(xhci, "Dev %d endpoint ring %d:\n", i, j);
+                                       xhci_debug_segment(xhci, xhci->devs[i]->ep_rings[j]->deq_seg);
+                               }
+                       }
+               }
+       }
+
+       if (xhci->noops_submitted != NUM_TEST_NOOPS)
+               if (xhci_setup_one_noop(xhci))
+                       xhci_ring_cmd_db(xhci);
+       spin_unlock_irqrestore(&xhci->lock, flags);
+
+       if (!xhci->zombie)
+               mod_timer(&xhci->event_ring_timer, jiffies + POLL_TIMEOUT * HZ);
+       else
+               xhci_dbg(xhci, "Quit polling the event ring.\n");
+}
+#endif
+
+/*
+ * Start the HC after it was halted.
+ *
+ * This function is called by the USB core when the HC driver is added.
+ * Its opposite is xhci_stop().
+ *
+ * xhci_init() must be called once before this function can be called.
+ * Reset the HC, enable device slot contexts, program DCBAAP, and
+ * set command ring pointer and event ring pointer.
+ *
+ * Setup MSI-X vectors and enable interrupts.
+ */
+int xhci_run(struct usb_hcd *hcd)
+{
+       u32 temp;
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       void (*doorbell)(struct xhci_hcd *) = NULL;
+
+       hcd->uses_new_polling = 1;
+       hcd->poll_rh = 0;
+
+       xhci_dbg(xhci, "xhci_run\n");
+#if 0  /* FIXME: MSI not setup yet */
+       /* Do this at the very last minute */
+       ret = xhci_setup_msix(xhci);
+       if (!ret)
+               return ret;
+
+       return -ENOSYS;
+#endif
+#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
+       init_timer(&xhci->event_ring_timer);
+       xhci->event_ring_timer.data = (unsigned long) xhci;
+       xhci->event_ring_timer.function = xhci_event_ring_work;
+       /* Poll the event ring */
+       xhci->event_ring_timer.expires = jiffies + POLL_TIMEOUT * HZ;
+       xhci->zombie = 0;
+       xhci_dbg(xhci, "Setting event ring polling timer\n");
+       add_timer(&xhci->event_ring_timer);
+#endif
+
+       xhci_dbg(xhci, "// Set the interrupt modulation register\n");
+       temp = xhci_readl(xhci, &xhci->ir_set->irq_control);
+       temp &= ~ER_IRQ_INTERVAL_MASK;
+       temp |= (u32) 160;
+       xhci_writel(xhci, temp, &xhci->ir_set->irq_control);
+
+       /* Set the HCD state before we enable the irqs */
+       hcd->state = HC_STATE_RUNNING;
+       temp = xhci_readl(xhci, &xhci->op_regs->command);
+       temp |= (CMD_EIE);
+       xhci_dbg(xhci, "// Enable interrupts, cmd = 0x%x.\n",
+                       temp);
+       xhci_writel(xhci, temp, &xhci->op_regs->command);
+
+       temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
+       xhci_dbg(xhci, "// Enabling event ring interrupter %p by writing 0x%x to irq_pending\n",
+                       xhci->ir_set, (unsigned int) ER_IRQ_ENABLE(temp));
+       xhci_writel(xhci, ER_IRQ_ENABLE(temp),
+                       &xhci->ir_set->irq_pending);
+       xhci_print_ir_set(xhci, xhci->ir_set, 0);
+
+       if (NUM_TEST_NOOPS > 0)
+               doorbell = xhci_setup_one_noop(xhci);
+
+       xhci_dbg(xhci, "Command ring memory map follows:\n");
+       xhci_debug_ring(xhci, xhci->cmd_ring);
+       xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring);
+       xhci_dbg_cmd_ptrs(xhci);
+
+       xhci_dbg(xhci, "ERST memory map follows:\n");
+       xhci_dbg_erst(xhci, &xhci->erst);
+       xhci_dbg(xhci, "Event ring:\n");
+       xhci_debug_ring(xhci, xhci->event_ring);
+       xhci_dbg_ring_ptrs(xhci, xhci->event_ring);
+       temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]);
+       temp &= ERST_PTR_MASK;
+       xhci_dbg(xhci, "ERST deq = 0x%x\n", temp);
+       temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[1]);
+       xhci_dbg(xhci, "ERST deq upper = 0x%x\n", temp);
+
+       temp = xhci_readl(xhci, &xhci->op_regs->command);
+       temp |= (CMD_RUN);
+       xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n",
+                       temp);
+       xhci_writel(xhci, temp, &xhci->op_regs->command);
+       /* Flush PCI posted writes */
+       temp = xhci_readl(xhci, &xhci->op_regs->command);
+       xhci_dbg(xhci, "// @%p = 0x%x\n", &xhci->op_regs->command, temp);
+       if (doorbell)
+               (*doorbell)(xhci);
+
+       xhci_dbg(xhci, "Finished xhci_run\n");
+       return 0;
+}
+
+/*
+ * Stop xHCI driver.
+ *
+ * This function is called by the USB core when the HC driver is removed.
+ * Its opposite is xhci_run().
+ *
+ * Disable device contexts, disable IRQs, and quiesce the HC.
+ * Reset the HC, finish any completed transactions, and cleanup memory.
+ */
+void xhci_stop(struct usb_hcd *hcd)
+{
+       u32 temp;
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+       spin_lock_irq(&xhci->lock);
+       if (HC_IS_RUNNING(hcd->state))
+               xhci_quiesce(xhci);
+       xhci_halt(xhci);
+       xhci_reset(xhci);
+       spin_unlock_irq(&xhci->lock);
+
+#if 0  /* No MSI yet */
+       xhci_cleanup_msix(xhci);
+#endif
+#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
+       /* Tell the event ring poll function not to reschedule */
+       xhci->zombie = 1;
+       del_timer_sync(&xhci->event_ring_timer);
+#endif
+
+       xhci_dbg(xhci, "// Disabling event ring interrupts\n");
+       temp = xhci_readl(xhci, &xhci->op_regs->status);
+       xhci_writel(xhci, temp & ~STS_EINT, &xhci->op_regs->status);
+       temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
+       xhci_writel(xhci, ER_IRQ_DISABLE(temp),
+                       &xhci->ir_set->irq_pending);
+       xhci_print_ir_set(xhci, xhci->ir_set, 0);
+
+       xhci_dbg(xhci, "cleaning up memory\n");
+       xhci_mem_cleanup(xhci);
+       xhci_dbg(xhci, "xhci_stop completed - status = %x\n",
+                   xhci_readl(xhci, &xhci->op_regs->status));
+}
+
+/*
+ * Shutdown HC (not bus-specific)
+ *
+ * This is called when the machine is rebooting or halting.  We assume that the
+ * machine will be powered off, and the HC's internal state will be reset.
+ * Don't bother to free memory.
+ */
+void xhci_shutdown(struct usb_hcd *hcd)
+{
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+       spin_lock_irq(&xhci->lock);
+       xhci_halt(xhci);
+       spin_unlock_irq(&xhci->lock);
+
+#if 0
+       xhci_cleanup_msix(xhci);
+#endif
+
+       xhci_dbg(xhci, "xhci_shutdown completed - status = %x\n",
+                   xhci_readl(xhci, &xhci->op_regs->status));
+}
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * xhci_get_endpoint_index - Used for passing endpoint bitmasks between the core and
+ * HCDs.  Find the index for an endpoint given its descriptor.  Use the return
+ * value to right shift 1 for the bitmask.
+ *
+ * Index  = (epnum * 2) + direction - 1,
+ * where direction = 0 for OUT, 1 for IN.
+ * For control endpoints, the IN index is used (OUT index is unused), so
+ * index = (epnum * 2) + direction - 1 = (epnum * 2) + 1 - 1 = (epnum * 2)
+ */
+unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc)
+{
+       unsigned int index;
+       if (usb_endpoint_xfer_control(desc))
+               index = (unsigned int) (usb_endpoint_num(desc)*2);
+       else
+               index = (unsigned int) (usb_endpoint_num(desc)*2) +
+                       (usb_endpoint_dir_in(desc) ? 1 : 0) - 1;
+       return index;
+}
+
+/* Find the flag for this endpoint (for use in the control context).  Use the
+ * endpoint index to create a bitmask.  The slot context is bit 0, endpoint 0 is
+ * bit 1, etc.
+ */
+unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc)
+{
+       return 1 << (xhci_get_endpoint_index(desc) + 1);
+}
+
+/* Compute the last valid endpoint context index.  Basically, this is the
+ * endpoint index plus one.  For slot contexts with more than valid endpoint,
+ * we find the most significant bit set in the added contexts flags.
+ * e.g. ep 1 IN (with epnum 0x81) => added_ctxs = 0b1000
+ * fls(0b1000) = 4, but the endpoint context index is 3, so subtract one.
+ */
+static inline unsigned int xhci_last_valid_endpoint(u32 added_ctxs)
+{
+       return fls(added_ctxs) - 1;
+}
+
+/* Returns 1 if the arguments are OK;
+ * returns 0 this is a root hub; returns -EINVAL for NULL pointers.
+ */
+int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev,
+               struct usb_host_endpoint *ep, int check_ep, const char *func) {
+       if (!hcd || (check_ep && !ep) || !udev) {
+               printk(KERN_DEBUG "xHCI %s called with invalid args\n",
+                               func);
+               return -EINVAL;
+       }
+       if (!udev->parent) {
+               printk(KERN_DEBUG "xHCI %s called for root hub\n",
+                               func);
+               return 0;
+       }
+       if (!udev->slot_id) {
+               printk(KERN_DEBUG "xHCI %s called with unaddressed device\n",
+                               func);
+               return -EINVAL;
+       }
+       return 1;
+}
+
+/*
+ * non-error returns are a promise to giveback() the urb later
+ * we drop ownership so next owner (or urb unlink) can get it
+ */
+int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
+{
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       unsigned long flags;
+       int ret = 0;
+       unsigned int slot_id, ep_index;
+
+       if (!urb || xhci_check_args(hcd, urb->dev, urb->ep, true, __func__) <= 0)
+               return -EINVAL;
+
+       slot_id = urb->dev->slot_id;
+       ep_index = xhci_get_endpoint_index(&urb->ep->desc);
+
+       spin_lock_irqsave(&xhci->lock, flags);
+       if (!xhci->devs || !xhci->devs[slot_id]) {
+               if (!in_interrupt())
+                       dev_warn(&urb->dev->dev, "WARN: urb submitted for dev with no Slot ID\n");
+               ret = -EINVAL;
+               goto exit;
+       }
+       if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
+               if (!in_interrupt())
+                       xhci_dbg(xhci, "urb submitted during PCI suspend\n");
+               ret = -ESHUTDOWN;
+               goto exit;
+       }
+       if (usb_endpoint_xfer_control(&urb->ep->desc))
+               ret = xhci_queue_ctrl_tx(xhci, mem_flags, urb,
+                               slot_id, ep_index);
+       else if (usb_endpoint_xfer_bulk(&urb->ep->desc))
+               ret = xhci_queue_bulk_tx(xhci, mem_flags, urb,
+                               slot_id, ep_index);
+       else
+               ret = -EINVAL;
+exit:
+       spin_unlock_irqrestore(&xhci->lock, flags);
+       return ret;
+}
+
+/*
+ * Remove the URB's TD from the endpoint ring.  This may cause the HC to stop
+ * USB transfers, potentially stopping in the middle of a TRB buffer.  The HC
+ * should pick up where it left off in the TD, unless a Set Transfer Ring
+ * Dequeue Pointer is issued.
+ *
+ * The TRBs that make up the buffers for the canceled URB will be "removed" from
+ * the ring.  Since the ring is a contiguous structure, they can't be physically
+ * removed.  Instead, there are two options:
+ *
+ *  1) If the HC is in the middle of processing the URB to be canceled, we
+ *     simply move the ring's dequeue pointer past those TRBs using the Set
+ *     Transfer Ring Dequeue Pointer command.  This will be the common case,
+ *     when drivers timeout on the last submitted URB and attempt to cancel.
+ *
+ *  2) If the HC is in the middle of a different TD, we turn the TRBs into a
+ *     series of 1-TRB transfer no-op TDs.  (No-ops shouldn't be chained.)  The
+ *     HC will need to invalidate the any TRBs it has cached after the stop
+ *     endpoint command, as noted in the xHCI 0.95 errata.
+ *
+ *  3) The TD may have completed by the time the Stop Endpoint Command
+ *     completes, so software needs to handle that case too.
+ *
+ * This function should protect against the TD enqueueing code ringing the
+ * doorbell while this code is waiting for a Stop Endpoint command to complete.
+ * It also needs to account for multiple cancellations on happening at the same
+ * time for the same endpoint.
+ *
+ * Note that this function can be called in any context, or so says
+ * usb_hcd_unlink_urb()
+ */
+int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+       unsigned long flags;
+       int ret;
+       struct xhci_hcd *xhci;
+       struct xhci_td *td;
+       unsigned int ep_index;
+       struct xhci_ring *ep_ring;
+
+       xhci = hcd_to_xhci(hcd);
+       spin_lock_irqsave(&xhci->lock, flags);
+       /* Make sure the URB hasn't completed or been unlinked already */
+       ret = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (ret || !urb->hcpriv)
+               goto done;
+
+       xhci_dbg(xhci, "Cancel URB %p\n", urb);
+       ep_index = xhci_get_endpoint_index(&urb->ep->desc);
+       ep_ring = xhci->devs[urb->dev->slot_id]->ep_rings[ep_index];
+       td = (struct xhci_td *) urb->hcpriv;
+
+       ep_ring->cancels_pending++;
+       list_add_tail(&td->cancelled_td_list, &ep_ring->cancelled_td_list);
+       /* Queue a stop endpoint command, but only if this is
+        * the first cancellation to be handled.
+        */
+       if (ep_ring->cancels_pending == 1) {
+               xhci_queue_stop_endpoint(xhci, urb->dev->slot_id, ep_index);
+               xhci_ring_cmd_db(xhci);
+       }
+done:
+       spin_unlock_irqrestore(&xhci->lock, flags);
+       return ret;
+}
+
+/* Drop an endpoint from a new bandwidth configuration for this device.
+ * Only one call to this function is allowed per endpoint before
+ * check_bandwidth() or reset_bandwidth() must be called.
+ * A call to xhci_drop_endpoint() followed by a call to xhci_add_endpoint() will
+ * add the endpoint to the schedule with possibly new parameters denoted by a
+ * different endpoint descriptor in usb_host_endpoint.
+ * A call to xhci_add_endpoint() followed by a call to xhci_drop_endpoint() is
+ * not allowed.
+ *
+ * The USB core will not allow URBs to be queued to an endpoint that is being
+ * disabled, so there's no need for mutual exclusion to protect
+ * the xhci->devs[slot_id] structure.
+ */
+int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
+               struct usb_host_endpoint *ep)
+{
+       struct xhci_hcd *xhci;
+       struct xhci_device_control *in_ctx;
+       unsigned int last_ctx;
+       unsigned int ep_index;
+       struct xhci_ep_ctx *ep_ctx;
+       u32 drop_flag;
+       u32 new_add_flags, new_drop_flags, new_slot_info;
+       int ret;
+
+       ret = xhci_check_args(hcd, udev, ep, 1, __func__);
+       if (ret <= 0)
+               return ret;
+       xhci = hcd_to_xhci(hcd);
+       xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
+
+       drop_flag = xhci_get_endpoint_flag(&ep->desc);
+       if (drop_flag == SLOT_FLAG || drop_flag == EP0_FLAG) {
+               xhci_dbg(xhci, "xHCI %s - can't drop slot or ep 0 %#x\n",
+                               __func__, drop_flag);
+               return 0;
+       }
+
+       if (!xhci->devs || !xhci->devs[udev->slot_id]) {
+               xhci_warn(xhci, "xHCI %s called with unaddressed device\n",
+                               __func__);
+               return -EINVAL;
+       }
+
+       in_ctx = xhci->devs[udev->slot_id]->in_ctx;
+       ep_index = xhci_get_endpoint_index(&ep->desc);
+       ep_ctx = &xhci->devs[udev->slot_id]->out_ctx->ep[ep_index];
+       /* If the HC already knows the endpoint is disabled,
+        * or the HCD has noted it is disabled, ignore this request
+        */
+       if ((ep_ctx->ep_info & EP_STATE_MASK) == EP_STATE_DISABLED ||
+                       in_ctx->drop_flags & xhci_get_endpoint_flag(&ep->desc)) {
+               xhci_warn(xhci, "xHCI %s called with disabled ep %p\n",
+                               __func__, ep);
+               return 0;
+       }
+
+       in_ctx->drop_flags |= drop_flag;
+       new_drop_flags = in_ctx->drop_flags;
+
+       in_ctx->add_flags = ~drop_flag;
+       new_add_flags = in_ctx->add_flags;
+
+       last_ctx = xhci_last_valid_endpoint(in_ctx->add_flags);
+       /* Update the last valid endpoint context, if we deleted the last one */
+       if ((in_ctx->slot.dev_info & LAST_CTX_MASK) > LAST_CTX(last_ctx)) {
+               in_ctx->slot.dev_info &= ~LAST_CTX_MASK;
+               in_ctx->slot.dev_info |= LAST_CTX(last_ctx);
+       }
+       new_slot_info = in_ctx->slot.dev_info;
+
+       xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep);
+
+       xhci_dbg(xhci, "drop ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x, new slot info = %#x\n",
+                       (unsigned int) ep->desc.bEndpointAddress,
+                       udev->slot_id,
+                       (unsigned int) new_drop_flags,
+                       (unsigned int) new_add_flags,
+                       (unsigned int) new_slot_info);
+       return 0;
+}
+
+/* Add an endpoint to a new possible bandwidth configuration for this device.
+ * Only one call to this function is allowed per endpoint before
+ * check_bandwidth() or reset_bandwidth() must be called.
+ * A call to xhci_drop_endpoint() followed by a call to xhci_add_endpoint() will
+ * add the endpoint to the schedule with possibly new parameters denoted by a
+ * different endpoint descriptor in usb_host_endpoint.
+ * A call to xhci_add_endpoint() followed by a call to xhci_drop_endpoint() is
+ * not allowed.
+ *
+ * The USB core will not allow URBs to be queued to an endpoint until the
+ * configuration or alt setting is installed in the device, so there's no need
+ * for mutual exclusion to protect the xhci->devs[slot_id] structure.
+ */
+int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
+               struct usb_host_endpoint *ep)
+{
+       struct xhci_hcd *xhci;
+       struct xhci_device_control *in_ctx;
+       unsigned int ep_index;
+       struct xhci_ep_ctx *ep_ctx;
+       u32 added_ctxs;
+       unsigned int last_ctx;
+       u32 new_add_flags, new_drop_flags, new_slot_info;
+       int ret = 0;
+
+       ret = xhci_check_args(hcd, udev, ep, 1, __func__);
+       if (ret <= 0)
+               return ret;
+       xhci = hcd_to_xhci(hcd);
+
+       added_ctxs = xhci_get_endpoint_flag(&ep->desc);
+       last_ctx = xhci_last_valid_endpoint(added_ctxs);
+       if (added_ctxs == SLOT_FLAG || added_ctxs == EP0_FLAG) {
+               /* FIXME when we have to issue an evaluate endpoint command to
+                * deal with ep0 max packet size changing once we get the
+                * descriptors
+                */
+               xhci_dbg(xhci, "xHCI %s - can't add slot or ep 0 %#x\n",
+                               __func__, added_ctxs);
+               return 0;
+       }
+
+       if (!xhci->devs || !xhci->devs[udev->slot_id]) {
+               xhci_warn(xhci, "xHCI %s called with unaddressed device\n",
+                               __func__);
+               return -EINVAL;
+       }
+
+       in_ctx = xhci->devs[udev->slot_id]->in_ctx;
+       ep_index = xhci_get_endpoint_index(&ep->desc);
+       ep_ctx = &xhci->devs[udev->slot_id]->out_ctx->ep[ep_index];
+       /* If the HCD has already noted the endpoint is enabled,
+        * ignore this request.
+        */
+       if (in_ctx->add_flags & xhci_get_endpoint_flag(&ep->desc)) {
+               xhci_warn(xhci, "xHCI %s called with enabled ep %p\n",
+                               __func__, ep);
+               return 0;
+       }
+
+       /*
+        * Configuration and alternate setting changes must be done in
+        * process context, not interrupt context (or so documenation
+        * for usb_set_interface() and usb_set_configuration() claim).
+        */
+       if (xhci_endpoint_init(xhci, xhci->devs[udev->slot_id],
+                               udev, ep, GFP_KERNEL) < 0) {
+               dev_dbg(&udev->dev, "%s - could not initialize ep %#x\n",
+                               __func__, ep->desc.bEndpointAddress);
+               return -ENOMEM;
+       }
+
+       in_ctx->add_flags |= added_ctxs;
+       new_add_flags = in_ctx->add_flags;
+
+       /* If xhci_endpoint_disable() was called for this endpoint, but the
+        * xHC hasn't been notified yet through the check_bandwidth() call,
+        * this re-adds a new state for the endpoint from the new endpoint
+        * descriptors.  We must drop and re-add this endpoint, so we leave the
+        * drop flags alone.
+        */
+       new_drop_flags = in_ctx->drop_flags;
+
+       /* Update the last valid endpoint context, if we just added one past */
+       if ((in_ctx->slot.dev_info & LAST_CTX_MASK) < LAST_CTX(last_ctx)) {
+               in_ctx->slot.dev_info &= ~LAST_CTX_MASK;
+               in_ctx->slot.dev_info |= LAST_CTX(last_ctx);
+       }
+       new_slot_info = in_ctx->slot.dev_info;
+
+       xhci_dbg(xhci, "add ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x, new slot info = %#x\n",
+                       (unsigned int) ep->desc.bEndpointAddress,
+                       udev->slot_id,
+                       (unsigned int) new_drop_flags,
+                       (unsigned int) new_add_flags,
+                       (unsigned int) new_slot_info);
+       return 0;
+}
+
+static void xhci_zero_in_ctx(struct xhci_virt_device *virt_dev)
+{
+       struct xhci_ep_ctx *ep_ctx;
+       int i;
+
+       /* When a device's add flag and drop flag are zero, any subsequent
+        * configure endpoint command will leave that endpoint's state
+        * untouched.  Make sure we don't leave any old state in the input
+        * endpoint contexts.
+        */
+       virt_dev->in_ctx->drop_flags = 0;
+       virt_dev->in_ctx->add_flags = 0;
+       virt_dev->in_ctx->slot.dev_info &= ~LAST_CTX_MASK;
+       /* Endpoint 0 is always valid */
+       virt_dev->in_ctx->slot.dev_info |= LAST_CTX(1);
+       for (i = 1; i < 31; ++i) {
+               ep_ctx = &virt_dev->in_ctx->ep[i];
+               ep_ctx->ep_info = 0;
+               ep_ctx->ep_info2 = 0;
+               ep_ctx->deq[0] = 0;
+               ep_ctx->deq[1] = 0;
+               ep_ctx->tx_info = 0;
+       }
+}
+
+/* Called after one or more calls to xhci_add_endpoint() or
+ * xhci_drop_endpoint().  If this call fails, the USB core is expected
+ * to call xhci_reset_bandwidth().
+ *
+ * Since we are in the middle of changing either configuration or
+ * installing a new alt setting, the USB core won't allow URBs to be
+ * enqueued for any endpoint on the old config or interface.  Nothing
+ * else should be touching the xhci->devs[slot_id] structure, so we
+ * don't need to take the xhci->lock for manipulating that.
+ */
+int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
+{
+       int i;
+       int ret = 0;
+       int timeleft;
+       unsigned long flags;
+       struct xhci_hcd *xhci;
+       struct xhci_virt_device *virt_dev;
+
+       ret = xhci_check_args(hcd, udev, NULL, 0, __func__);
+       if (ret <= 0)
+               return ret;
+       xhci = hcd_to_xhci(hcd);
+
+       if (!udev->slot_id || !xhci->devs || !xhci->devs[udev->slot_id]) {
+               xhci_warn(xhci, "xHCI %s called with unaddressed device\n",
+                               __func__);
+               return -EINVAL;
+       }
+       xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
+       virt_dev = xhci->devs[udev->slot_id];
+
+       /* See section 4.6.6 - A0 = 1; A1 = D0 = D1 = 0 */
+       virt_dev->in_ctx->add_flags |= SLOT_FLAG;
+       virt_dev->in_ctx->add_flags &= ~EP0_FLAG;
+       virt_dev->in_ctx->drop_flags &= ~SLOT_FLAG;
+       virt_dev->in_ctx->drop_flags &= ~EP0_FLAG;
+       xhci_dbg(xhci, "New Input Control Context:\n");
+       xhci_dbg_ctx(xhci, virt_dev->in_ctx, virt_dev->in_ctx_dma,
+                       LAST_CTX_TO_EP_NUM(virt_dev->in_ctx->slot.dev_info));
+
+       spin_lock_irqsave(&xhci->lock, flags);
+       ret = xhci_queue_configure_endpoint(xhci, virt_dev->in_ctx_dma,
+                       udev->slot_id);
+       if (ret < 0) {
+               spin_unlock_irqrestore(&xhci->lock, flags);
+               xhci_dbg(xhci, "FIXME allocate a new ring segment\n");
+               return -ENOMEM;
+       }
+       xhci_ring_cmd_db(xhci);
+       spin_unlock_irqrestore(&xhci->lock, flags);
+
+       /* Wait for the configure endpoint command to complete */
+       timeleft = wait_for_completion_interruptible_timeout(
+                       &virt_dev->cmd_completion,
+                       USB_CTRL_SET_TIMEOUT);
+       if (timeleft <= 0) {
+               xhci_warn(xhci, "%s while waiting for configure endpoint command\n",
+                               timeleft == 0 ? "Timeout" : "Signal");
+               /* FIXME cancel the configure endpoint command */
+               return -ETIME;
+       }
+
+       switch (virt_dev->cmd_status) {
+       case COMP_ENOMEM:
+               dev_warn(&udev->dev, "Not enough host controller resources "
+                               "for new device state.\n");
+               ret = -ENOMEM;
+               /* FIXME: can we allocate more resources for the HC? */
+               break;
+       case COMP_BW_ERR:
+               dev_warn(&udev->dev, "Not enough bandwidth "
+                               "for new device state.\n");
+               ret = -ENOSPC;
+               /* FIXME: can we go back to the old state? */
+               break;
+       case COMP_TRB_ERR:
+               /* the HCD set up something wrong */
+               dev_warn(&udev->dev, "ERROR: Endpoint drop flag = 0, add flag = 1, "
+                               "and endpoint is not disabled.\n");
+               ret = -EINVAL;
+               break;
+       case COMP_SUCCESS:
+               dev_dbg(&udev->dev, "Successful Endpoint Configure command\n");
+               break;
+       default:
+               xhci_err(xhci, "ERROR: unexpected command completion "
+                               "code 0x%x.\n", virt_dev->cmd_status);
+               ret = -EINVAL;
+               break;
+       }
+       if (ret) {
+               /* Callee should call reset_bandwidth() */
+               return ret;
+       }
+
+       xhci_dbg(xhci, "Output context after successful config ep cmd:\n");
+       xhci_dbg_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma,
+                       LAST_CTX_TO_EP_NUM(virt_dev->in_ctx->slot.dev_info));
+
+       xhci_zero_in_ctx(virt_dev);
+       /* Free any old rings */
+       for (i = 1; i < 31; ++i) {
+               if (virt_dev->new_ep_rings[i]) {
+                       xhci_ring_free(xhci, virt_dev->ep_rings[i]);
+                       virt_dev->ep_rings[i] = virt_dev->new_ep_rings[i];
+                       virt_dev->new_ep_rings[i] = NULL;
+               }
+       }
+
+       return ret;
+}
+
+void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
+{
+       struct xhci_hcd *xhci;
+       struct xhci_virt_device *virt_dev;
+       int i, ret;
+
+       ret = xhci_check_args(hcd, udev, NULL, 0, __func__);
+       if (ret <= 0)
+               return;
+       xhci = hcd_to_xhci(hcd);
+
+       if (!xhci->devs || !xhci->devs[udev->slot_id]) {
+               xhci_warn(xhci, "xHCI %s called with unaddressed device\n",
+                               __func__);
+               return;
+       }
+       xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
+       virt_dev = xhci->devs[udev->slot_id];
+       /* Free any rings allocated for added endpoints */
+       for (i = 0; i < 31; ++i) {
+               if (virt_dev->new_ep_rings[i]) {
+                       xhci_ring_free(xhci, virt_dev->new_ep_rings[i]);
+                       virt_dev->new_ep_rings[i] = NULL;
+               }
+       }
+       xhci_zero_in_ctx(virt_dev);
+}
+
+/*
+ * At this point, the struct usb_device is about to go away, the device has
+ * disconnected, and all traffic has been stopped and the endpoints have been
+ * disabled.  Free any HC data structures associated with that device.
+ */
+void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
+{
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       unsigned long flags;
+
+       if (udev->slot_id == 0)
+               return;
+
+       spin_lock_irqsave(&xhci->lock, flags);
+       if (xhci_queue_slot_control(xhci, TRB_DISABLE_SLOT, udev->slot_id)) {
+               spin_unlock_irqrestore(&xhci->lock, flags);
+               xhci_dbg(xhci, "FIXME: allocate a command ring segment\n");
+               return;
+       }
+       xhci_ring_cmd_db(xhci);
+       spin_unlock_irqrestore(&xhci->lock, flags);
+       /*
+        * Event command completion handler will free any data structures
+        * associated with the slot.  XXX Can free sleep?
+        */
+}
+
+/*
+ * Returns 0 if the xHC ran out of device slots, the Enable Slot command
+ * timed out, or allocating memory failed.  Returns 1 on success.
+ */
+int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)
+{
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       unsigned long flags;
+       int timeleft;
+       int ret;
+
+       spin_lock_irqsave(&xhci->lock, flags);
+       ret = xhci_queue_slot_control(xhci, TRB_ENABLE_SLOT, 0);
+       if (ret) {
+               spin_unlock_irqrestore(&xhci->lock, flags);
+               xhci_dbg(xhci, "FIXME: allocate a command ring segment\n");
+               return 0;
+       }
+       xhci_ring_cmd_db(xhci);
+       spin_unlock_irqrestore(&xhci->lock, flags);
+
+       /* XXX: how much time for xHC slot assignment? */
+       timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev,
+                       USB_CTRL_SET_TIMEOUT);
+       if (timeleft <= 0) {
+               xhci_warn(xhci, "%s while waiting for a slot\n",
+                               timeleft == 0 ? "Timeout" : "Signal");
+               /* FIXME cancel the enable slot request */
+               return 0;
+       }
+
+       if (!xhci->slot_id) {
+               xhci_err(xhci, "Error while assigning device slot ID\n");
+               return 0;
+       }
+       /* xhci_alloc_virt_device() does not touch rings; no need to lock */
+       if (!xhci_alloc_virt_device(xhci, xhci->slot_id, udev, GFP_KERNEL)) {
+               /* Disable slot, if we can do it without mem alloc */
+               xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n");
+               spin_lock_irqsave(&xhci->lock, flags);
+               if (!xhci_queue_slot_control(xhci, TRB_DISABLE_SLOT, udev->slot_id))
+                       xhci_ring_cmd_db(xhci);
+               spin_unlock_irqrestore(&xhci->lock, flags);
+               return 0;
+       }
+       udev->slot_id = xhci->slot_id;
+       /* Is this a LS or FS device under a HS hub? */
+       /* Hub or peripherial? */
+       return 1;
+}
+
+/*
+ * Issue an Address Device command (which will issue a SetAddress request to
+ * the device).
+ * We should be protected by the usb_address0_mutex in khubd's hub_port_init, so
+ * we should only issue and wait on one address command at the same time.
+ *
+ * We add one to the device address issued by the hardware because the USB core
+ * uses address 1 for the root hubs (even though they're not really devices).
+ */
+int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
+{
+       unsigned long flags;
+       int timeleft;
+       struct xhci_virt_device *virt_dev;
+       int ret = 0;
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       u32 temp;
+
+       if (!udev->slot_id) {
+               xhci_dbg(xhci, "Bad Slot ID %d\n", udev->slot_id);
+               return -EINVAL;
+       }
+
+       virt_dev = xhci->devs[udev->slot_id];
+
+       /* If this is a Set Address to an unconfigured device, setup ep 0 */
+       if (!udev->config)
+               xhci_setup_addressable_virt_dev(xhci, udev);
+       /* Otherwise, assume the core has the device configured how it wants */
+
+       spin_lock_irqsave(&xhci->lock, flags);
+       ret = xhci_queue_address_device(xhci, virt_dev->in_ctx_dma,
+                       udev->slot_id);
+       if (ret) {
+               spin_unlock_irqrestore(&xhci->lock, flags);
+               xhci_dbg(xhci, "FIXME: allocate a command ring segment\n");
+               return ret;
+       }
+       xhci_ring_cmd_db(xhci);
+       spin_unlock_irqrestore(&xhci->lock, flags);
+
+       /* ctrl tx can take up to 5 sec; XXX: need more time for xHC? */
+       timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev,
+                       USB_CTRL_SET_TIMEOUT);
+       /* FIXME: From section 4.3.4: "Software shall be responsible for timing
+        * the SetAddress() "recovery interval" required by USB and aborting the
+        * command on a timeout.
+        */
+       if (timeleft <= 0) {
+               xhci_warn(xhci, "%s while waiting for a slot\n",
+                               timeleft == 0 ? "Timeout" : "Signal");
+               /* FIXME cancel the address device command */
+               return -ETIME;
+       }
+
+       switch (virt_dev->cmd_status) {
+       case COMP_CTX_STATE:
+       case COMP_EBADSLT:
+               xhci_err(xhci, "Setup ERROR: address device command for slot %d.\n",
+                               udev->slot_id);
+               ret = -EINVAL;
+               break;
+       case COMP_TX_ERR:
+               dev_warn(&udev->dev, "Device not responding to set address.\n");
+               ret = -EPROTO;
+               break;
+       case COMP_SUCCESS:
+               xhci_dbg(xhci, "Successful Address Device command\n");
+               break;
+       default:
+               xhci_err(xhci, "ERROR: unexpected command completion "
+                               "code 0x%x.\n", virt_dev->cmd_status);
+               ret = -EINVAL;
+               break;
+       }
+       if (ret) {
+               return ret;
+       }
+       temp = xhci_readl(xhci, &xhci->op_regs->dcbaa_ptr[0]);
+       xhci_dbg(xhci, "Op regs DCBAA ptr[0] = %#08x\n", temp);
+       temp = xhci_readl(xhci, &xhci->op_regs->dcbaa_ptr[1]);
+       xhci_dbg(xhci, "Op regs DCBAA ptr[1] = %#08x\n", temp);
+       xhci_dbg(xhci, "Slot ID %d dcbaa entry[0] @%p = %#08x\n",
+                       udev->slot_id,
+                       &xhci->dcbaa->dev_context_ptrs[2*udev->slot_id],
+                       xhci->dcbaa->dev_context_ptrs[2*udev->slot_id]);
+       xhci_dbg(xhci, "Slot ID %d dcbaa entry[1] @%p = %#08x\n",
+                       udev->slot_id,
+                       &xhci->dcbaa->dev_context_ptrs[2*udev->slot_id+1],
+                       xhci->dcbaa->dev_context_ptrs[2*udev->slot_id+1]);
+       xhci_dbg(xhci, "Output Context DMA address = %#08llx\n",
+                       (unsigned long long)virt_dev->out_ctx_dma);
+       xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id);
+       xhci_dbg_ctx(xhci, virt_dev->in_ctx, virt_dev->in_ctx_dma, 2);
+       xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id);
+       xhci_dbg_ctx(xhci, virt_dev->out_ctx, virt_dev->out_ctx_dma, 2);
+       /*
+        * USB core uses address 1 for the roothubs, so we add one to the
+        * address given back to us by the HC.
+        */
+       udev->devnum = (virt_dev->out_ctx->slot.dev_state & DEV_ADDR_MASK) + 1;
+       /* Zero the input context control for later use */
+       virt_dev->in_ctx->add_flags = 0;
+       virt_dev->in_ctx->drop_flags = 0;
+       /* Mirror flags in the output context for future ep enable/disable */
+       virt_dev->out_ctx->add_flags = SLOT_FLAG | EP0_FLAG;
+       virt_dev->out_ctx->drop_flags = 0;
+
+       xhci_dbg(xhci, "Device address = %d\n", udev->devnum);
+       /* XXX Meh, not sure if anyone else but choose_address uses this. */
+       set_bit(udev->devnum, udev->bus->devmap.devicemap);
+
+       return 0;
+}
+
+int xhci_get_frame(struct usb_hcd *hcd)
+{
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       /* EHCI mods by the periodic size.  Why? */
+       return xhci_readl(xhci, &xhci->run_regs->microframe_index) >> 3;
+}
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
+
+static int __init xhci_hcd_init(void)
+{
+#ifdef CONFIG_PCI
+       int retval = 0;
+
+       retval = xhci_register_pci();
+
+       if (retval < 0) {
+               printk(KERN_DEBUG "Problem registering PCI driver.");
+               return retval;
+       }
+#endif
+       /*
+        * Check the compiler generated sizes of structures that must be laid
+        * out in specific ways for hardware access.
+        */
+       BUILD_BUG_ON(sizeof(struct xhci_doorbell_array) != 256*32/8);
+       BUILD_BUG_ON(sizeof(struct xhci_slot_ctx) != 8*32/8);
+       BUILD_BUG_ON(sizeof(struct xhci_ep_ctx) != 8*32/8);
+       /* xhci_device_control has eight fields, and also
+        * embeds one xhci_slot_ctx and 31 xhci_ep_ctx
+        */
+       BUILD_BUG_ON(sizeof(struct xhci_device_control) != (8+8+8*31)*32/8);
+       BUILD_BUG_ON(sizeof(struct xhci_stream_ctx) != 4*32/8);
+       BUILD_BUG_ON(sizeof(union xhci_trb) != 4*32/8);
+       BUILD_BUG_ON(sizeof(struct xhci_erst_entry) != 4*32/8);
+       BUILD_BUG_ON(sizeof(struct xhci_cap_regs) != 7*32/8);
+       BUILD_BUG_ON(sizeof(struct xhci_intr_reg) != 8*32/8);
+       /* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */
+       BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8);
+       BUILD_BUG_ON(sizeof(struct xhci_doorbell_array) != 256*32/8);
+       return 0;
+}
+module_init(xhci_hcd_init);
+
+static void __exit xhci_hcd_cleanup(void)
+{
+#ifdef CONFIG_PCI
+       xhci_unregister_pci();
+#endif
+}
+module_exit(xhci_hcd_cleanup);
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
new file mode 100644 (file)
index 0000000..eac5b53
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * xHCI host controller driver
+ *
+ * Copyright (C) 2008 Intel Corp.
+ *
+ * Author: Sarah Sharp
+ * Some code borrowed from the Linux EHCI driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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 <asm/unaligned.h>
+
+#include "xhci.h"
+
+static void xhci_hub_descriptor(struct xhci_hcd *xhci,
+               struct usb_hub_descriptor *desc)
+{
+       int ports;
+       u16 temp;
+
+       ports = HCS_MAX_PORTS(xhci->hcs_params1);
+
+       /* USB 3.0 hubs have a different descriptor, but we fake this for now */
+       desc->bDescriptorType = 0x29;
+       desc->bPwrOn2PwrGood = 10;      /* xhci section 5.4.9 says 20ms max */
+       desc->bHubContrCurrent = 0;
+
+       desc->bNbrPorts = ports;
+       temp = 1 + (ports / 8);
+       desc->bDescLength = 7 + 2 * temp;
+
+       /* Why does core/hcd.h define bitmap?  It's just confusing. */
+       memset(&desc->DeviceRemovable[0], 0, temp);
+       memset(&desc->DeviceRemovable[temp], 0xff, temp);
+
+       /* Ugh, these should be #defines, FIXME */
+       /* Using table 11-13 in USB 2.0 spec. */
+       temp = 0;
+       /* Bits 1:0 - support port power switching, or power always on */
+       if (HCC_PPC(xhci->hcc_params))
+               temp |= 0x0001;
+       else
+               temp |= 0x0002;
+       /* Bit  2 - root hubs are not part of a compound device */
+       /* Bits 4:3 - individual port over current protection */
+       temp |= 0x0008;
+       /* Bits 6:5 - no TTs in root ports */
+       /* Bit  7 - no port indicators */
+       desc->wHubCharacteristics = (__force __u16) cpu_to_le16(temp);
+}
+
+static unsigned int xhci_port_speed(unsigned int port_status)
+{
+       if (DEV_LOWSPEED(port_status))
+               return 1 << USB_PORT_FEAT_LOWSPEED;
+       if (DEV_HIGHSPEED(port_status))
+               return 1 << USB_PORT_FEAT_HIGHSPEED;
+       if (DEV_SUPERSPEED(port_status))
+               return 1 << USB_PORT_FEAT_SUPERSPEED;
+       /*
+        * FIXME: Yes, we should check for full speed, but the core uses that as
+        * a default in portspeed() in usb/core/hub.c (which is the only place
+        * USB_PORT_FEAT_*SPEED is used).
+        */
+       return 0;
+}
+
+/*
+ * These bits are Read Only (RO) and should be saved and written to the
+ * registers: 0, 3, 10:13, 30
+ * connect status, over-current status, port speed, and device removable.
+ * connect status and port speed are also sticky - meaning they're in
+ * the AUX well and they aren't changed by a hot, warm, or cold reset.
+ */
+#define        XHCI_PORT_RO    ((1<<0) | (1<<3) | (0xf<<10) | (1<<30))
+/*
+ * These bits are RW; writing a 0 clears the bit, writing a 1 sets the bit:
+ * bits 5:8, 9, 14:15, 25:27
+ * link state, port power, port indicator state, "wake on" enable state
+ */
+#define XHCI_PORT_RWS  ((0xf<<5) | (1<<9) | (0x3<<14) | (0x7<<25))
+/*
+ * These bits are RW; writing a 1 sets the bit, writing a 0 has no effect:
+ * bit 4 (port reset)
+ */
+#define        XHCI_PORT_RW1S  ((1<<4))
+/*
+ * These bits are RW; writing a 1 clears the bit, writing a 0 has no effect:
+ * bits 1, 17, 18, 19, 20, 21, 22, 23
+ * port enable/disable, and
+ * change bits: connect, PED, warm port reset changed (reserved zero for USB 2.0 ports),
+ * over-current, reset, link state, and L1 change
+ */
+#define XHCI_PORT_RW1CS        ((1<<1) | (0x7f<<17))
+/*
+ * Bit 16 is RW, and writing a '1' to it causes the link state control to be
+ * latched in
+ */
+#define        XHCI_PORT_RW    ((1<<16))
+/*
+ * These bits are Reserved Zero (RsvdZ) and zero should be written to them:
+ * bits 2, 24, 28:31
+ */
+#define        XHCI_PORT_RZ    ((1<<2) | (1<<24) | (0xf<<28))
+
+/*
+ * Given a port state, this function returns a value that would result in the
+ * port being in the same state, if the value was written to the port status
+ * control register.
+ * Save Read Only (RO) bits and save read/write bits where
+ * writing a 0 clears the bit and writing a 1 sets the bit (RWS).
+ * For all other types (RW1S, RW1CS, RW, and RZ), writing a '0' has no effect.
+ */
+static u32 xhci_port_state_to_neutral(u32 state)
+{
+       /* Save read-only status and port state */
+       return (state & XHCI_PORT_RO) | (state & XHCI_PORT_RWS);
+}
+
+int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+               u16 wIndex, char *buf, u16 wLength)
+{
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       int ports;
+       unsigned long flags;
+       u32 temp, status;
+       int retval = 0;
+       u32 __iomem *addr;
+       char *port_change_bit;
+
+       ports = HCS_MAX_PORTS(xhci->hcs_params1);
+
+       spin_lock_irqsave(&xhci->lock, flags);
+       switch (typeReq) {
+       case GetHubStatus:
+               /* No power source, over-current reported per port */
+               memset(buf, 0, 4);
+               break;
+       case GetHubDescriptor:
+               xhci_hub_descriptor(xhci, (struct usb_hub_descriptor *) buf);
+               break;
+       case GetPortStatus:
+               if (!wIndex || wIndex > ports)
+                       goto error;
+               wIndex--;
+               status = 0;
+               addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS*(wIndex & 0xff);
+               temp = xhci_readl(xhci, addr);
+               xhci_dbg(xhci, "get port status, actual port %d status  = 0x%x\n", wIndex, temp);
+
+               /* wPortChange bits */
+               if (temp & PORT_CSC)
+                       status |= 1 << USB_PORT_FEAT_C_CONNECTION;
+               if (temp & PORT_PEC)
+                       status |= 1 << USB_PORT_FEAT_C_ENABLE;
+               if ((temp & PORT_OCC))
+                       status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
+               /*
+                * FIXME ignoring suspend, reset, and USB 2.1/3.0 specific
+                * changes
+                */
+               if (temp & PORT_CONNECT) {
+                       status |= 1 << USB_PORT_FEAT_CONNECTION;
+                       status |= xhci_port_speed(temp);
+               }
+               if (temp & PORT_PE)
+                       status |= 1 << USB_PORT_FEAT_ENABLE;
+               if (temp & PORT_OC)
+                       status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
+               if (temp & PORT_RESET)
+                       status |= 1 << USB_PORT_FEAT_RESET;
+               if (temp & PORT_POWER)
+                       status |= 1 << USB_PORT_FEAT_POWER;
+               xhci_dbg(xhci, "Get port status returned 0x%x\n", status);
+               put_unaligned(cpu_to_le32(status), (__le32 *) buf);
+               break;
+       case SetPortFeature:
+               wIndex &= 0xff;
+               if (!wIndex || wIndex > ports)
+                       goto error;
+               wIndex--;
+               addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS*(wIndex & 0xff);
+               temp = xhci_readl(xhci, addr);
+               temp = xhci_port_state_to_neutral(temp);
+               switch (wValue) {
+               case USB_PORT_FEAT_POWER:
+                       /*
+                        * Turn on ports, even if there isn't per-port switching.
+                        * HC will report connect events even before this is set.
+                        * However, khubd will ignore the roothub events until
+                        * the roothub is registered.
+                        */
+                       xhci_writel(xhci, temp | PORT_POWER, addr);
+
+                       temp = xhci_readl(xhci, addr);
+                       xhci_dbg(xhci, "set port power, actual port %d status  = 0x%x\n", wIndex, temp);
+                       break;
+               case USB_PORT_FEAT_RESET:
+                       temp = (temp | PORT_RESET);
+                       xhci_writel(xhci, temp, addr);
+
+                       temp = xhci_readl(xhci, addr);
+                       xhci_dbg(xhci, "set port reset, actual port %d status  = 0x%x\n", wIndex, temp);
+                       break;
+               default:
+                       goto error;
+               }
+               temp = xhci_readl(xhci, addr); /* unblock any posted writes */
+               break;
+       case ClearPortFeature:
+               if (!wIndex || wIndex > ports)
+                       goto error;
+               wIndex--;
+               addr = &xhci->op_regs->port_status_base +
+                       NUM_PORT_REGS*(wIndex & 0xff);
+               temp = xhci_readl(xhci, addr);
+               temp = xhci_port_state_to_neutral(temp);
+               switch (wValue) {
+               case USB_PORT_FEAT_C_RESET:
+                       status = PORT_RC;
+                       port_change_bit = "reset";
+                       break;
+               case USB_PORT_FEAT_C_CONNECTION:
+                       status = PORT_CSC;
+                       port_change_bit = "connect";
+                       break;
+               case USB_PORT_FEAT_C_OVER_CURRENT:
+                       status = PORT_OCC;
+                       port_change_bit = "over-current";
+                       break;
+               default:
+                       goto error;
+               }
+               /* Change bits are all write 1 to clear */
+               xhci_writel(xhci, temp | status, addr);
+               temp = xhci_readl(xhci, addr);
+               xhci_dbg(xhci, "clear port %s change, actual port %d status  = 0x%x\n",
+                               port_change_bit, wIndex, temp);
+               temp = xhci_readl(xhci, addr); /* unblock any posted writes */
+               break;
+       default:
+error:
+               /* "stall" on error */
+               retval = -EPIPE;
+       }
+       spin_unlock_irqrestore(&xhci->lock, flags);
+       return retval;
+}
+
+/*
+ * Returns 0 if the status hasn't changed, or the number of bytes in buf.
+ * Ports are 0-indexed from the HCD point of view,
+ * and 1-indexed from the USB core pointer of view.
+ * xHCI instances can have up to 127 ports, so FIXME if you see more than 15.
+ *
+ * Note that the status change bits will be cleared as soon as a port status
+ * change event is generated, so we use the saved status from that event.
+ */
+int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+       unsigned long flags;
+       u32 temp, status;
+       int i, retval;
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       int ports;
+       u32 __iomem *addr;
+
+       ports = HCS_MAX_PORTS(xhci->hcs_params1);
+
+       /* Initial status is no changes */
+       buf[0] = 0;
+       status = 0;
+       if (ports > 7) {
+               buf[1] = 0;
+               retval = 2;
+       } else {
+               retval = 1;
+       }
+
+       spin_lock_irqsave(&xhci->lock, flags);
+       /* For each port, did anything change?  If so, set that bit in buf. */
+       for (i = 0; i < ports; i++) {
+               addr = &xhci->op_regs->port_status_base +
+                       NUM_PORT_REGS*i;
+               temp = xhci_readl(xhci, addr);
+               if (temp & (PORT_CSC | PORT_PEC | PORT_OCC)) {
+                       if (i < 7)
+                               buf[0] |= 1 << (i + 1);
+                       else
+                               buf[1] |= 1 << (i - 7);
+                       status = 1;
+               }
+       }
+       spin_unlock_irqrestore(&xhci->lock, flags);
+       return status ? retval : 0;
+}
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
new file mode 100644 (file)
index 0000000..c8a72de
--- /dev/null
@@ -0,0 +1,769 @@
+/*
+ * xHCI host controller driver
+ *
+ * Copyright (C) 2008 Intel Corp.
+ *
+ * Author: Sarah Sharp
+ * Some code borrowed from the Linux EHCI driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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/usb.h>
+#include <linux/pci.h>
+#include <linux/dmapool.h>
+
+#include "xhci.h"
+
+/*
+ * Allocates a generic ring segment from the ring pool, sets the dma address,
+ * initializes the segment to zero, and sets the private next pointer to NULL.
+ *
+ * Section 4.11.1.1:
+ * "All components of all Command and Transfer TRBs shall be initialized to '0'"
+ */
+static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, gfp_t flags)
+{
+       struct xhci_segment *seg;
+       dma_addr_t      dma;
+
+       seg = kzalloc(sizeof *seg, flags);
+       if (!seg)
+               return 0;
+       xhci_dbg(xhci, "Allocating priv segment structure at %p\n", seg);
+
+       seg->trbs = dma_pool_alloc(xhci->segment_pool, flags, &dma);
+       if (!seg->trbs) {
+               kfree(seg);
+               return 0;
+       }
+       xhci_dbg(xhci, "// Allocating segment at %p (virtual) 0x%llx (DMA)\n",
+                       seg->trbs, (unsigned long long)dma);
+
+       memset(seg->trbs, 0, SEGMENT_SIZE);
+       seg->dma = dma;
+       seg->next = NULL;
+
+       return seg;
+}
+
+static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg)
+{
+       if (!seg)
+               return;
+       if (seg->trbs) {
+               xhci_dbg(xhci, "Freeing DMA segment at %p (virtual) 0x%llx (DMA)\n",
+                               seg->trbs, (unsigned long long)seg->dma);
+               dma_pool_free(xhci->segment_pool, seg->trbs, seg->dma);
+               seg->trbs = NULL;
+       }
+       xhci_dbg(xhci, "Freeing priv segment structure at %p\n", seg);
+       kfree(seg);
+}
+
+/*
+ * Make the prev segment point to the next segment.
+ *
+ * Change the last TRB in the prev segment to be a Link TRB which points to the
+ * DMA address of the next segment.  The caller needs to set any Link TRB
+ * related flags, such as End TRB, Toggle Cycle, and no snoop.
+ */
+static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
+               struct xhci_segment *next, bool link_trbs)
+{
+       u32 val;
+
+       if (!prev || !next)
+               return;
+       prev->next = next;
+       if (link_trbs) {
+               prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr[0] = next->dma;
+
+               /* Set the last TRB in the segment to have a TRB type ID of Link TRB */
+               val = prev->trbs[TRBS_PER_SEGMENT-1].link.control;
+               val &= ~TRB_TYPE_BITMASK;
+               val |= TRB_TYPE(TRB_LINK);
+               prev->trbs[TRBS_PER_SEGMENT-1].link.control = val;
+       }
+       xhci_dbg(xhci, "Linking segment 0x%llx to segment 0x%llx (DMA)\n",
+                       (unsigned long long)prev->dma,
+                       (unsigned long long)next->dma);
+}
+
+/* XXX: Do we need the hcd structure in all these functions? */
+void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring)
+{
+       struct xhci_segment *seg;
+       struct xhci_segment *first_seg;
+
+       if (!ring || !ring->first_seg)
+               return;
+       first_seg = ring->first_seg;
+       seg = first_seg->next;
+       xhci_dbg(xhci, "Freeing ring at %p\n", ring);
+       while (seg != first_seg) {
+               struct xhci_segment *next = seg->next;
+               xhci_segment_free(xhci, seg);
+               seg = next;
+       }
+       xhci_segment_free(xhci, first_seg);
+       ring->first_seg = NULL;
+       kfree(ring);
+}
+
+/**
+ * Create a new ring with zero or more segments.
+ *
+ * Link each segment together into a ring.
+ * Set the end flag and the cycle toggle bit on the last segment.
+ * See section 4.9.1 and figures 15 and 16.
+ */
+static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
+               unsigned int num_segs, bool link_trbs, gfp_t flags)
+{
+       struct xhci_ring        *ring;
+       struct xhci_segment     *prev;
+
+       ring = kzalloc(sizeof *(ring), flags);
+       xhci_dbg(xhci, "Allocating ring at %p\n", ring);
+       if (!ring)
+               return 0;
+
+       INIT_LIST_HEAD(&ring->td_list);
+       INIT_LIST_HEAD(&ring->cancelled_td_list);
+       if (num_segs == 0)
+               return ring;
+
+       ring->first_seg = xhci_segment_alloc(xhci, flags);
+       if (!ring->first_seg)
+               goto fail;
+       num_segs--;
+
+       prev = ring->first_seg;
+       while (num_segs > 0) {
+               struct xhci_segment     *next;
+
+               next = xhci_segment_alloc(xhci, flags);
+               if (!next)
+                       goto fail;
+               xhci_link_segments(xhci, prev, next, link_trbs);
+
+               prev = next;
+               num_segs--;
+       }
+       xhci_link_segments(xhci, prev, ring->first_seg, link_trbs);
+
+       if (link_trbs) {
+               /* See section 4.9.2.1 and 6.4.4.1 */
+               prev->trbs[TRBS_PER_SEGMENT-1].link.control |= (LINK_TOGGLE);
+               xhci_dbg(xhci, "Wrote link toggle flag to"
+                               " segment %p (virtual), 0x%llx (DMA)\n",
+                               prev, (unsigned long long)prev->dma);
+       }
+       /* The ring is empty, so the enqueue pointer == dequeue pointer */
+       ring->enqueue = ring->first_seg->trbs;
+       ring->enq_seg = ring->first_seg;
+       ring->dequeue = ring->enqueue;
+       ring->deq_seg = ring->first_seg;
+       /* The ring is initialized to 0. The producer must write 1 to the cycle
+        * bit to handover ownership of the TRB, so PCS = 1.  The consumer must
+        * compare CCS to the cycle bit to check ownership, so CCS = 1.
+        */
+       ring->cycle_state = 1;
+
+       return ring;
+
+fail:
+       xhci_ring_free(xhci, ring);
+       return 0;
+}
+
+/* All the xhci_tds in the ring's TD list should be freed at this point */
+void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)
+{
+       struct xhci_virt_device *dev;
+       int i;
+
+       /* Slot ID 0 is reserved */
+       if (slot_id == 0 || !xhci->devs[slot_id])
+               return;
+
+       dev = xhci->devs[slot_id];
+       xhci->dcbaa->dev_context_ptrs[2*slot_id] = 0;
+       xhci->dcbaa->dev_context_ptrs[2*slot_id + 1] = 0;
+       if (!dev)
+               return;
+
+       for (i = 0; i < 31; ++i)
+               if (dev->ep_rings[i])
+                       xhci_ring_free(xhci, dev->ep_rings[i]);
+
+       if (dev->in_ctx)
+               dma_pool_free(xhci->device_pool,
+                               dev->in_ctx, dev->in_ctx_dma);
+       if (dev->out_ctx)
+               dma_pool_free(xhci->device_pool,
+                               dev->out_ctx, dev->out_ctx_dma);
+       kfree(xhci->devs[slot_id]);
+       xhci->devs[slot_id] = 0;
+}
+
+int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
+               struct usb_device *udev, gfp_t flags)
+{
+       dma_addr_t      dma;
+       struct xhci_virt_device *dev;
+
+       /* Slot ID 0 is reserved */
+       if (slot_id == 0 || xhci->devs[slot_id]) {
+               xhci_warn(xhci, "Bad Slot ID %d\n", slot_id);
+               return 0;
+       }
+
+       xhci->devs[slot_id] = kzalloc(sizeof(*xhci->devs[slot_id]), flags);
+       if (!xhci->devs[slot_id])
+               return 0;
+       dev = xhci->devs[slot_id];
+
+       /* Allocate the (output) device context that will be used in the HC */
+       dev->out_ctx = dma_pool_alloc(xhci->device_pool, flags, &dma);
+       if (!dev->out_ctx)
+               goto fail;
+       dev->out_ctx_dma = dma;
+       xhci_dbg(xhci, "Slot %d output ctx = 0x%llx (dma)\n", slot_id,
+                       (unsigned long long)dma);
+       memset(dev->out_ctx, 0, sizeof(*dev->out_ctx));
+
+       /* Allocate the (input) device context for address device command */
+       dev->in_ctx = dma_pool_alloc(xhci->device_pool, flags, &dma);
+       if (!dev->in_ctx)
+               goto fail;
+       dev->in_ctx_dma = dma;
+       xhci_dbg(xhci, "Slot %d input ctx = 0x%llx (dma)\n", slot_id,
+                       (unsigned long long)dma);
+       memset(dev->in_ctx, 0, sizeof(*dev->in_ctx));
+
+       /* Allocate endpoint 0 ring */
+       dev->ep_rings[0] = xhci_ring_alloc(xhci, 1, true, flags);
+       if (!dev->ep_rings[0])
+               goto fail;
+
+       init_completion(&dev->cmd_completion);
+
+       /*
+        * Point to output device context in dcbaa; skip the output control
+        * context, which is eight 32 bit fields (or 32 bytes long)
+        */
+       xhci->dcbaa->dev_context_ptrs[2*slot_id] =
+               (u32) dev->out_ctx_dma + (32);
+       xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n",
+                       slot_id,
+                       &xhci->dcbaa->dev_context_ptrs[2*slot_id],
+                       (unsigned long long)dev->out_ctx_dma);
+       xhci->dcbaa->dev_context_ptrs[2*slot_id + 1] = 0;
+
+       return 1;
+fail:
+       xhci_free_virt_device(xhci, slot_id);
+       return 0;
+}
+
+/* Setup an xHCI virtual device for a Set Address command */
+int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev)
+{
+       struct xhci_virt_device *dev;
+       struct xhci_ep_ctx      *ep0_ctx;
+       struct usb_device       *top_dev;
+
+       dev = xhci->devs[udev->slot_id];
+       /* Slot ID 0 is reserved */
+       if (udev->slot_id == 0 || !dev) {
+               xhci_warn(xhci, "Slot ID %d is not assigned to this device\n",
+                               udev->slot_id);
+               return -EINVAL;
+       }
+       ep0_ctx = &dev->in_ctx->ep[0];
+
+       /* 2) New slot context and endpoint 0 context are valid*/
+       dev->in_ctx->add_flags = SLOT_FLAG | EP0_FLAG;
+
+       /* 3) Only the control endpoint is valid - one endpoint context */
+       dev->in_ctx->slot.dev_info |= LAST_CTX(1);
+
+       switch (udev->speed) {
+       case USB_SPEED_SUPER:
+               dev->in_ctx->slot.dev_info |= (u32) udev->route;
+               dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_SS;
+               break;
+       case USB_SPEED_HIGH:
+               dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_HS;
+               break;
+       case USB_SPEED_FULL:
+               dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_FS;
+               break;
+       case USB_SPEED_LOW:
+               dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_LS;
+               break;
+       case USB_SPEED_VARIABLE:
+               xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n");
+               return -EINVAL;
+               break;
+       default:
+               /* Speed was set earlier, this shouldn't happen. */
+               BUG();
+       }
+       /* Find the root hub port this device is under */
+       for (top_dev = udev; top_dev->parent && top_dev->parent->parent;
+                       top_dev = top_dev->parent)
+               /* Found device below root hub */;
+       dev->in_ctx->slot.dev_info2 |= (u32) ROOT_HUB_PORT(top_dev->portnum);
+       xhci_dbg(xhci, "Set root hub portnum to %d\n", top_dev->portnum);
+
+       /* Is this a LS/FS device under a HS hub? */
+       /*
+        * FIXME: I don't think this is right, where does the TT info for the
+        * roothub or parent hub come from?
+        */
+       if ((udev->speed == USB_SPEED_LOW || udev->speed == USB_SPEED_FULL) &&
+                       udev->tt) {
+               dev->in_ctx->slot.tt_info = udev->tt->hub->slot_id;
+               dev->in_ctx->slot.tt_info |= udev->ttport << 8;
+       }
+       xhci_dbg(xhci, "udev->tt = %p\n", udev->tt);
+       xhci_dbg(xhci, "udev->ttport = 0x%x\n", udev->ttport);
+
+       /* Step 4 - ring already allocated */
+       /* Step 5 */
+       ep0_ctx->ep_info2 = EP_TYPE(CTRL_EP);
+       /*
+        * See section 4.3 bullet 6:
+        * The default Max Packet size for ep0 is "8 bytes for a USB2
+        * LS/FS/HS device or 512 bytes for a USB3 SS device"
+        * XXX: Not sure about wireless USB devices.
+        */
+       if (udev->speed == USB_SPEED_SUPER)
+               ep0_ctx->ep_info2 |= MAX_PACKET(512);
+       else
+               ep0_ctx->ep_info2 |= MAX_PACKET(8);
+       /* EP 0 can handle "burst" sizes of 1, so Max Burst Size field is 0 */
+       ep0_ctx->ep_info2 |= MAX_BURST(0);
+       ep0_ctx->ep_info2 |= ERROR_COUNT(3);
+
+       ep0_ctx->deq[0] =
+               dev->ep_rings[0]->first_seg->dma;
+       ep0_ctx->deq[0] |= dev->ep_rings[0]->cycle_state;
+       ep0_ctx->deq[1] = 0;
+
+       /* Steps 7 and 8 were done in xhci_alloc_virt_device() */
+
+       return 0;
+}
+
+/* Return the polling or NAK interval.
+ *
+ * The polling interval is expressed in "microframes".  If xHCI's Interval field
+ * is set to N, it will service the endpoint every 2^(Interval)*125us.
+ *
+ * The NAK interval is one NAK per 1 to 255 microframes, or no NAKs if interval
+ * is set to 0.
+ */
+static inline unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
+               struct usb_host_endpoint *ep)
+{
+       unsigned int interval = 0;
+
+       switch (udev->speed) {
+       case USB_SPEED_HIGH:
+               /* Max NAK rate */
+               if (usb_endpoint_xfer_control(&ep->desc) ||
+                               usb_endpoint_xfer_bulk(&ep->desc))
+                       interval = ep->desc.bInterval;
+               /* Fall through - SS and HS isoc/int have same decoding */
+       case USB_SPEED_SUPER:
+               if (usb_endpoint_xfer_int(&ep->desc) ||
+                               usb_endpoint_xfer_isoc(&ep->desc)) {
+                       if (ep->desc.bInterval == 0)
+                               interval = 0;
+                       else
+                               interval = ep->desc.bInterval - 1;
+                       if (interval > 15)
+                               interval = 15;
+                       if (interval != ep->desc.bInterval + 1)
+                               dev_warn(&udev->dev, "ep %#x - rounding interval to %d microframes\n",
+                                               ep->desc.bEndpointAddress, 1 << interval);
+               }
+               break;
+       /* Convert bInterval (in 1-255 frames) to microframes and round down to
+        * nearest power of 2.
+        */
+       case USB_SPEED_FULL:
+       case USB_SPEED_LOW:
+               if (usb_endpoint_xfer_int(&ep->desc) ||
+                               usb_endpoint_xfer_isoc(&ep->desc)) {
+                       interval = fls(8*ep->desc.bInterval) - 1;
+                       if (interval > 10)
+                               interval = 10;
+                       if (interval < 3)
+                               interval = 3;
+                       if ((1 << interval) != 8*ep->desc.bInterval)
+                               dev_warn(&udev->dev, "ep %#x - rounding interval to %d microframes\n",
+                                               ep->desc.bEndpointAddress, 1 << interval);
+               }
+               break;
+       default:
+               BUG();
+       }
+       return EP_INTERVAL(interval);
+}
+
+static inline u32 xhci_get_endpoint_type(struct usb_device *udev,
+               struct usb_host_endpoint *ep)
+{
+       int in;
+       u32 type;
+
+       in = usb_endpoint_dir_in(&ep->desc);
+       if (usb_endpoint_xfer_control(&ep->desc)) {
+               type = EP_TYPE(CTRL_EP);
+       } else if (usb_endpoint_xfer_bulk(&ep->desc)) {
+               if (in)
+                       type = EP_TYPE(BULK_IN_EP);
+               else
+                       type = EP_TYPE(BULK_OUT_EP);
+       } else if (usb_endpoint_xfer_isoc(&ep->desc)) {
+               if (in)
+                       type = EP_TYPE(ISOC_IN_EP);
+               else
+                       type = EP_TYPE(ISOC_OUT_EP);
+       } else if (usb_endpoint_xfer_int(&ep->desc)) {
+               if (in)
+                       type = EP_TYPE(INT_IN_EP);
+               else
+                       type = EP_TYPE(INT_OUT_EP);
+       } else {
+               BUG();
+       }
+       return type;
+}
+
+int xhci_endpoint_init(struct xhci_hcd *xhci,
+               struct xhci_virt_device *virt_dev,
+               struct usb_device *udev,
+               struct usb_host_endpoint *ep,
+               gfp_t mem_flags)
+{
+       unsigned int ep_index;
+       struct xhci_ep_ctx *ep_ctx;
+       struct xhci_ring *ep_ring;
+       unsigned int max_packet;
+       unsigned int max_burst;
+
+       ep_index = xhci_get_endpoint_index(&ep->desc);
+       ep_ctx = &virt_dev->in_ctx->ep[ep_index];
+
+       /* Set up the endpoint ring */
+       virt_dev->new_ep_rings[ep_index] = xhci_ring_alloc(xhci, 1, true, mem_flags);
+       if (!virt_dev->new_ep_rings[ep_index])
+               return -ENOMEM;
+       ep_ring = virt_dev->new_ep_rings[ep_index];
+       ep_ctx->deq[0] = ep_ring->first_seg->dma | ep_ring->cycle_state;
+       ep_ctx->deq[1] = 0;
+
+       ep_ctx->ep_info = xhci_get_endpoint_interval(udev, ep);
+
+       /* FIXME dig Mult and streams info out of ep companion desc */
+
+       /* Allow 3 retries for everything but isoc */
+       if (!usb_endpoint_xfer_isoc(&ep->desc))
+               ep_ctx->ep_info2 = ERROR_COUNT(3);
+       else
+               ep_ctx->ep_info2 = ERROR_COUNT(0);
+
+       ep_ctx->ep_info2 |= xhci_get_endpoint_type(udev, ep);
+
+       /* Set the max packet size and max burst */
+       switch (udev->speed) {
+       case USB_SPEED_SUPER:
+               max_packet = ep->desc.wMaxPacketSize;
+               ep_ctx->ep_info2 |= MAX_PACKET(max_packet);
+               /* dig out max burst from ep companion desc */
+               max_packet = ep->ss_ep_comp->desc.bMaxBurst;
+               ep_ctx->ep_info2 |= MAX_BURST(max_packet);
+               break;
+       case USB_SPEED_HIGH:
+               /* bits 11:12 specify the number of additional transaction
+                * opportunities per microframe (USB 2.0, section 9.6.6)
+                */
+               if (usb_endpoint_xfer_isoc(&ep->desc) ||
+                               usb_endpoint_xfer_int(&ep->desc)) {
+                       max_burst = (ep->desc.wMaxPacketSize & 0x1800) >> 11;
+                       ep_ctx->ep_info2 |= MAX_BURST(max_burst);
+               }
+               /* Fall through */
+       case USB_SPEED_FULL:
+       case USB_SPEED_LOW:
+               max_packet = ep->desc.wMaxPacketSize & 0x3ff;
+               ep_ctx->ep_info2 |= MAX_PACKET(max_packet);
+               break;
+       default:
+               BUG();
+       }
+       /* FIXME Debug endpoint context */
+       return 0;
+}
+
+void xhci_endpoint_zero(struct xhci_hcd *xhci,
+               struct xhci_virt_device *virt_dev,
+               struct usb_host_endpoint *ep)
+{
+       unsigned int ep_index;
+       struct xhci_ep_ctx *ep_ctx;
+
+       ep_index = xhci_get_endpoint_index(&ep->desc);
+       ep_ctx = &virt_dev->in_ctx->ep[ep_index];
+
+       ep_ctx->ep_info = 0;
+       ep_ctx->ep_info2 = 0;
+       ep_ctx->deq[0] = 0;
+       ep_ctx->deq[1] = 0;
+       ep_ctx->tx_info = 0;
+       /* Don't free the endpoint ring until the set interface or configuration
+        * request succeeds.
+        */
+}
+
+void xhci_mem_cleanup(struct xhci_hcd *xhci)
+{
+       struct pci_dev  *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
+       int size;
+       int i;
+
+       /* Free the Event Ring Segment Table and the actual Event Ring */
+       xhci_writel(xhci, 0, &xhci->ir_set->erst_size);
+       xhci_writel(xhci, 0, &xhci->ir_set->erst_base[0]);
+       xhci_writel(xhci, 0, &xhci->ir_set->erst_base[1]);
+       xhci_writel(xhci, 0, &xhci->ir_set->erst_dequeue[0]);
+       xhci_writel(xhci, 0, &xhci->ir_set->erst_dequeue[1]);
+       size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
+       if (xhci->erst.entries)
+               pci_free_consistent(pdev, size,
+                               xhci->erst.entries, xhci->erst.erst_dma_addr);
+       xhci->erst.entries = NULL;
+       xhci_dbg(xhci, "Freed ERST\n");
+       if (xhci->event_ring)
+               xhci_ring_free(xhci, xhci->event_ring);
+       xhci->event_ring = NULL;
+       xhci_dbg(xhci, "Freed event ring\n");
+
+       xhci_writel(xhci, 0, &xhci->op_regs->cmd_ring[0]);
+       xhci_writel(xhci, 0, &xhci->op_regs->cmd_ring[1]);
+       if (xhci->cmd_ring)
+               xhci_ring_free(xhci, xhci->cmd_ring);
+       xhci->cmd_ring = NULL;
+       xhci_dbg(xhci, "Freed command ring\n");
+
+       for (i = 1; i < MAX_HC_SLOTS; ++i)
+               xhci_free_virt_device(xhci, i);
+
+       if (xhci->segment_pool)
+               dma_pool_destroy(xhci->segment_pool);
+       xhci->segment_pool = NULL;
+       xhci_dbg(xhci, "Freed segment pool\n");
+
+       if (xhci->device_pool)
+               dma_pool_destroy(xhci->device_pool);
+       xhci->device_pool = NULL;
+       xhci_dbg(xhci, "Freed device context pool\n");
+
+       xhci_writel(xhci, 0, &xhci->op_regs->dcbaa_ptr[0]);
+       xhci_writel(xhci, 0, &xhci->op_regs->dcbaa_ptr[1]);
+       if (xhci->dcbaa)
+               pci_free_consistent(pdev, sizeof(*xhci->dcbaa),
+                               xhci->dcbaa, xhci->dcbaa->dma);
+       xhci->dcbaa = NULL;
+
+       xhci->page_size = 0;
+       xhci->page_shift = 0;
+}
+
+int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
+{
+       dma_addr_t      dma;
+       struct device   *dev = xhci_to_hcd(xhci)->self.controller;
+       unsigned int    val, val2;
+       struct xhci_segment     *seg;
+       u32 page_size;
+       int i;
+
+       page_size = xhci_readl(xhci, &xhci->op_regs->page_size);
+       xhci_dbg(xhci, "Supported page size register = 0x%x\n", page_size);
+       for (i = 0; i < 16; i++) {
+               if ((0x1 & page_size) != 0)
+                       break;
+               page_size = page_size >> 1;
+       }
+       if (i < 16)
+               xhci_dbg(xhci, "Supported page size of %iK\n", (1 << (i+12)) / 1024);
+       else
+               xhci_warn(xhci, "WARN: no supported page size\n");
+       /* Use 4K pages, since that's common and the minimum the HC supports */
+       xhci->page_shift = 12;
+       xhci->page_size = 1 << xhci->page_shift;
+       xhci_dbg(xhci, "HCD page size set to %iK\n", xhci->page_size / 1024);
+
+       /*
+        * Program the Number of Device Slots Enabled field in the CONFIG
+        * register with the max value of slots the HC can handle.
+        */
+       val = HCS_MAX_SLOTS(xhci_readl(xhci, &xhci->cap_regs->hcs_params1));
+       xhci_dbg(xhci, "// xHC can handle at most %d device slots.\n",
+                       (unsigned int) val);
+       val2 = xhci_readl(xhci, &xhci->op_regs->config_reg);
+       val |= (val2 & ~HCS_SLOTS_MASK);
+       xhci_dbg(xhci, "// Setting Max device slots reg = 0x%x.\n",
+                       (unsigned int) val);
+       xhci_writel(xhci, val, &xhci->op_regs->config_reg);
+
+       /*
+        * Section 5.4.8 - doorbell array must be
+        * "physically contiguous and 64-byte (cache line) aligned".
+        */
+       xhci->dcbaa = pci_alloc_consistent(to_pci_dev(dev),
+                       sizeof(*xhci->dcbaa), &dma);
+       if (!xhci->dcbaa)
+               goto fail;
+       memset(xhci->dcbaa, 0, sizeof *(xhci->dcbaa));
+       xhci->dcbaa->dma = dma;
+       xhci_dbg(xhci, "// Device context base array address = 0x%llx (DMA), %p (virt)\n",
+                       (unsigned long long)xhci->dcbaa->dma, xhci->dcbaa);
+       xhci_writel(xhci, dma, &xhci->op_regs->dcbaa_ptr[0]);
+       xhci_writel(xhci, (u32) 0, &xhci->op_regs->dcbaa_ptr[1]);
+
+       /*
+        * Initialize the ring segment pool.  The ring must be a contiguous
+        * structure comprised of TRBs.  The TRBs must be 16 byte aligned,
+        * however, the command ring segment needs 64-byte aligned segments,
+        * so we pick the greater alignment need.
+        */
+       xhci->segment_pool = dma_pool_create("xHCI ring segments", dev,
+                       SEGMENT_SIZE, 64, xhci->page_size);
+       /* See Table 46 and Note on Figure 55 */
+       /* FIXME support 64-byte contexts */
+       xhci->device_pool = dma_pool_create("xHCI input/output contexts", dev,
+                       sizeof(struct xhci_device_control),
+                       64, xhci->page_size);
+       if (!xhci->segment_pool || !xhci->device_pool)
+               goto fail;
+
+       /* Set up the command ring to have one segments for now. */
+       xhci->cmd_ring = xhci_ring_alloc(xhci, 1, true, flags);
+       if (!xhci->cmd_ring)
+               goto fail;
+       xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring);
+       xhci_dbg(xhci, "First segment DMA is 0x%llx\n",
+                       (unsigned long long)xhci->cmd_ring->first_seg->dma);
+
+       /* Set the address in the Command Ring Control register */
+       val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[0]);
+       val = (val & ~CMD_RING_ADDR_MASK) |
+               (xhci->cmd_ring->first_seg->dma & CMD_RING_ADDR_MASK) |
+               xhci->cmd_ring->cycle_state;
+       xhci_dbg(xhci, "// Setting command ring address low bits to 0x%x\n", val);
+       xhci_writel(xhci, val, &xhci->op_regs->cmd_ring[0]);
+       xhci_dbg(xhci, "// Setting command ring address high bits to 0x0\n");
+       xhci_writel(xhci, (u32) 0, &xhci->op_regs->cmd_ring[1]);
+       xhci_dbg_cmd_ptrs(xhci);
+
+       val = xhci_readl(xhci, &xhci->cap_regs->db_off);
+       val &= DBOFF_MASK;
+       xhci_dbg(xhci, "// Doorbell array is located at offset 0x%x"
+                       " from cap regs base addr\n", val);
+       xhci->dba = (void *) xhci->cap_regs + val;
+       xhci_dbg_regs(xhci);
+       xhci_print_run_regs(xhci);
+       /* Set ir_set to interrupt register set 0 */
+       xhci->ir_set = (void *) xhci->run_regs->ir_set;
+
+       /*
+        * Event ring setup: Allocate a normal ring, but also setup
+        * the event ring segment table (ERST).  Section 4.9.3.
+        */
+       xhci_dbg(xhci, "// Allocating event ring\n");
+       xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, false, flags);
+       if (!xhci->event_ring)
+               goto fail;
+
+       xhci->erst.entries = pci_alloc_consistent(to_pci_dev(dev),
+                       sizeof(struct xhci_erst_entry)*ERST_NUM_SEGS, &dma);
+       if (!xhci->erst.entries)
+               goto fail;
+       xhci_dbg(xhci, "// Allocated event ring segment table at 0x%llx\n",
+                       (unsigned long long)dma);
+
+       memset(xhci->erst.entries, 0, sizeof(struct xhci_erst_entry)*ERST_NUM_SEGS);
+       xhci->erst.num_entries = ERST_NUM_SEGS;
+       xhci->erst.erst_dma_addr = dma;
+       xhci_dbg(xhci, "Set ERST to 0; private num segs = %i, virt addr = %p, dma addr = 0x%llx\n",
+                       xhci->erst.num_entries,
+                       xhci->erst.entries,
+                       (unsigned long long)xhci->erst.erst_dma_addr);
+
+       /* set ring base address and size for each segment table entry */
+       for (val = 0, seg = xhci->event_ring->first_seg; val < ERST_NUM_SEGS; val++) {
+               struct xhci_erst_entry *entry = &xhci->erst.entries[val];
+               entry->seg_addr[0] = seg->dma;
+               entry->seg_addr[1] = 0;
+               entry->seg_size = TRBS_PER_SEGMENT;
+               entry->rsvd = 0;
+               seg = seg->next;
+       }
+
+       /* set ERST count with the number of entries in the segment table */
+       val = xhci_readl(xhci, &xhci->ir_set->erst_size);
+       val &= ERST_SIZE_MASK;
+       val |= ERST_NUM_SEGS;
+       xhci_dbg(xhci, "// Write ERST size = %i to ir_set 0 (some bits preserved)\n",
+                       val);
+       xhci_writel(xhci, val, &xhci->ir_set->erst_size);
+
+       xhci_dbg(xhci, "// Set ERST entries to point to event ring.\n");
+       /* set the segment table base address */
+       xhci_dbg(xhci, "// Set ERST base address for ir_set 0 = 0x%llx\n",
+                       (unsigned long long)xhci->erst.erst_dma_addr);
+       val = xhci_readl(xhci, &xhci->ir_set->erst_base[0]);
+       val &= ERST_PTR_MASK;
+       val |= (xhci->erst.erst_dma_addr & ~ERST_PTR_MASK);
+       xhci_writel(xhci, val, &xhci->ir_set->erst_base[0]);
+       xhci_writel(xhci, 0, &xhci->ir_set->erst_base[1]);
+
+       /* Set the event ring dequeue address */
+       xhci_set_hc_event_deq(xhci);
+       xhci_dbg(xhci, "Wrote ERST address to ir_set 0.\n");
+       xhci_print_ir_set(xhci, xhci->ir_set, 0);
+
+       /*
+        * XXX: Might need to set the Interrupter Moderation Register to
+        * something other than the default (~1ms minimum between interrupts).
+        * See section 5.5.1.2.
+        */
+       init_completion(&xhci->addr_dev);
+       for (i = 0; i < MAX_HC_SLOTS; ++i)
+               xhci->devs[i] = 0;
+
+       return 0;
+fail:
+       xhci_warn(xhci, "Couldn't initialize memory\n");
+       xhci_mem_cleanup(xhci);
+       return -ENOMEM;
+}
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
new file mode 100644 (file)
index 0000000..1462709
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * xHCI host controller driver PCI Bus Glue.
+ *
+ * Copyright (C) 2008 Intel Corp.
+ *
+ * Author: Sarah Sharp
+ * Some code borrowed from the Linux EHCI driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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/pci.h>
+
+#include "xhci.h"
+
+static const char hcd_name[] = "xhci_hcd";
+
+/* called after powerup, by probe or system-pm "wakeup" */
+static int xhci_pci_reinit(struct xhci_hcd *xhci, struct pci_dev *pdev)
+{
+       /*
+        * TODO: Implement finding debug ports later.
+        * TODO: see if there are any quirks that need to be added to handle
+        * new extended capabilities.
+        */
+
+       /* PCI Memory-Write-Invalidate cycle support is optional (uncommon) */
+       if (!pci_set_mwi(pdev))
+               xhci_dbg(xhci, "MWI active\n");
+
+       xhci_dbg(xhci, "Finished xhci_pci_reinit\n");
+       return 0;
+}
+
+/* called during probe() after chip reset completes */
+static int xhci_pci_setup(struct usb_hcd *hcd)
+{
+       struct xhci_hcd         *xhci = hcd_to_xhci(hcd);
+       struct pci_dev          *pdev = to_pci_dev(hcd->self.controller);
+       int                     retval;
+
+       xhci->cap_regs = hcd->regs;
+       xhci->op_regs = hcd->regs +
+               HC_LENGTH(xhci_readl(xhci, &xhci->cap_regs->hc_capbase));
+       xhci->run_regs = hcd->regs +
+               (xhci_readl(xhci, &xhci->cap_regs->run_regs_off) & RTSOFF_MASK);
+       /* Cache read-only capability registers */
+       xhci->hcs_params1 = xhci_readl(xhci, &xhci->cap_regs->hcs_params1);
+       xhci->hcs_params2 = xhci_readl(xhci, &xhci->cap_regs->hcs_params2);
+       xhci->hcs_params3 = xhci_readl(xhci, &xhci->cap_regs->hcs_params3);
+       xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
+       xhci_print_registers(xhci);
+
+       /* Make sure the HC is halted. */
+       retval = xhci_halt(xhci);
+       if (retval)
+               return retval;
+
+       xhci_dbg(xhci, "Resetting HCD\n");
+       /* Reset the internal HC memory state and registers. */
+       retval = xhci_reset(xhci);
+       if (retval)
+               return retval;
+       xhci_dbg(xhci, "Reset complete\n");
+
+       xhci_dbg(xhci, "Calling HCD init\n");
+       /* Initialize HCD and host controller data structures. */
+       retval = xhci_init(hcd);
+       if (retval)
+               return retval;
+       xhci_dbg(xhci, "Called HCD init\n");
+
+       pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn);
+       xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn);
+
+       /* Find any debug ports */
+       return xhci_pci_reinit(xhci, pdev);
+}
+
+static const struct hc_driver xhci_pci_hc_driver = {
+       .description =          hcd_name,
+       .product_desc =         "xHCI Host Controller",
+       .hcd_priv_size =        sizeof(struct xhci_hcd),
+
+       /*
+        * generic hardware linkage
+        */
+       .irq =                  xhci_irq,
+       .flags =                HCD_MEMORY | HCD_USB3,
+
+       /*
+        * basic lifecycle operations
+        */
+       .reset =                xhci_pci_setup,
+       .start =                xhci_run,
+       /* suspend and resume implemented later */
+       .stop =                 xhci_stop,
+       .shutdown =             xhci_shutdown,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       .urb_enqueue =          xhci_urb_enqueue,
+       .urb_dequeue =          xhci_urb_dequeue,
+       .alloc_dev =            xhci_alloc_dev,
+       .free_dev =             xhci_free_dev,
+       .add_endpoint =         xhci_add_endpoint,
+       .drop_endpoint =        xhci_drop_endpoint,
+       .check_bandwidth =      xhci_check_bandwidth,
+       .reset_bandwidth =      xhci_reset_bandwidth,
+       .address_device =       xhci_address_device,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number =     xhci_get_frame,
+
+       /* Root hub support */
+       .hub_control =          xhci_hub_control,
+       .hub_status_data =      xhci_hub_status_data,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* PCI driver selection metadata; PCI hotplugging uses this */
+static const struct pci_device_id pci_ids[] = { {
+       /* handle any USB 3.0 xHCI controller */
+       PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_XHCI, ~0),
+       .driver_data =  (unsigned long) &xhci_pci_hc_driver,
+       },
+       { /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE(pci, pci_ids);
+
+/* pci driver glue; this is a "new style" PCI driver module */
+static struct pci_driver xhci_pci_driver = {
+       .name =         (char *) hcd_name,
+       .id_table =     pci_ids,
+
+       .probe =        usb_hcd_pci_probe,
+       .remove =       usb_hcd_pci_remove,
+       /* suspend and resume implemented later */
+
+       .shutdown =     usb_hcd_pci_shutdown,
+};
+
+int xhci_register_pci()
+{
+       return pci_register_driver(&xhci_pci_driver);
+}
+
+void xhci_unregister_pci()
+{
+       pci_unregister_driver(&xhci_pci_driver);
+}
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
new file mode 100644 (file)
index 0000000..02d8198
--- /dev/null
@@ -0,0 +1,1648 @@
+/*
+ * xHCI host controller driver
+ *
+ * Copyright (C) 2008 Intel Corp.
+ *
+ * Author: Sarah Sharp
+ * Some code borrowed from the Linux EHCI driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/*
+ * Ring initialization rules:
+ * 1. Each segment is initialized to zero, except for link TRBs.
+ * 2. Ring cycle state = 0.  This represents Producer Cycle State (PCS) or
+ *    Consumer Cycle State (CCS), depending on ring function.
+ * 3. Enqueue pointer = dequeue pointer = address of first TRB in the segment.
+ *
+ * Ring behavior rules:
+ * 1. A ring is empty if enqueue == dequeue.  This means there will always be at
+ *    least one free TRB in the ring.  This is useful if you want to turn that
+ *    into a link TRB and expand the ring.
+ * 2. When incrementing an enqueue or dequeue pointer, if the next TRB is a
+ *    link TRB, then load the pointer with the address in the link TRB.  If the
+ *    link TRB had its toggle bit set, you may need to update the ring cycle
+ *    state (see cycle bit rules).  You may have to do this multiple times
+ *    until you reach a non-link TRB.
+ * 3. A ring is full if enqueue++ (for the definition of increment above)
+ *    equals the dequeue pointer.
+ *
+ * Cycle bit rules:
+ * 1. When a consumer increments a dequeue pointer and encounters a toggle bit
+ *    in a link TRB, it must toggle the ring cycle state.
+ * 2. When a producer increments an enqueue pointer and encounters a toggle bit
+ *    in a link TRB, it must toggle the ring cycle state.
+ *
+ * Producer rules:
+ * 1. Check if ring is full before you enqueue.
+ * 2. Write the ring cycle state to the cycle bit in the TRB you're enqueuing.
+ *    Update enqueue pointer between each write (which may update the ring
+ *    cycle state).
+ * 3. Notify consumer.  If SW is producer, it rings the doorbell for command
+ *    and endpoint rings.  If HC is the producer for the event ring,
+ *    and it generates an interrupt according to interrupt modulation rules.
+ *
+ * Consumer rules:
+ * 1. Check if TRB belongs to you.  If the cycle bit == your ring cycle state,
+ *    the TRB is owned by the consumer.
+ * 2. Update dequeue pointer (which may update the ring cycle state) and
+ *    continue processing TRBs until you reach a TRB which is not owned by you.
+ * 3. Notify the producer.  SW is the consumer for the event ring, and it
+ *   updates event ring dequeue pointer.  HC is the consumer for the command and
+ *   endpoint rings; it generates events on the event ring for these.
+ */
+
+#include <linux/scatterlist.h>
+#include "xhci.h"
+
+/*
+ * Returns zero if the TRB isn't in this segment, otherwise it returns the DMA
+ * address of the TRB.
+ */
+dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg,
+               union xhci_trb *trb)
+{
+       unsigned long segment_offset;
+
+       if (!seg || !trb || trb < seg->trbs)
+               return 0;
+       /* offset in TRBs */
+       segment_offset = trb - seg->trbs;
+       if (segment_offset > TRBS_PER_SEGMENT)
+               return 0;
+       return seg->dma + (segment_offset * sizeof(*trb));
+}
+
+/* Does this link TRB point to the first segment in a ring,
+ * or was the previous TRB the last TRB on the last segment in the ERST?
+ */
+static inline bool last_trb_on_last_seg(struct xhci_hcd *xhci, struct xhci_ring *ring,
+               struct xhci_segment *seg, union xhci_trb *trb)
+{
+       if (ring == xhci->event_ring)
+               return (trb == &seg->trbs[TRBS_PER_SEGMENT]) &&
+                       (seg->next == xhci->event_ring->first_seg);
+       else
+               return trb->link.control & LINK_TOGGLE;
+}
+
+/* Is this TRB a link TRB or was the last TRB the last TRB in this event ring
+ * segment?  I.e. would the updated event TRB pointer step off the end of the
+ * event seg?
+ */
+static inline int last_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
+               struct xhci_segment *seg, union xhci_trb *trb)
+{
+       if (ring == xhci->event_ring)
+               return trb == &seg->trbs[TRBS_PER_SEGMENT];
+       else
+               return (trb->link.control & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK);
+}
+
+/* Updates trb to point to the next TRB in the ring, and updates seg if the next
+ * TRB is in a new segment.  This does not skip over link TRBs, and it does not
+ * effect the ring dequeue or enqueue pointers.
+ */
+static void next_trb(struct xhci_hcd *xhci,
+               struct xhci_ring *ring,
+               struct xhci_segment **seg,
+               union xhci_trb **trb)
+{
+       if (last_trb(xhci, ring, *seg, *trb)) {
+               *seg = (*seg)->next;
+               *trb = ((*seg)->trbs);
+       } else {
+               *trb = (*trb)++;
+       }
+}
+
+/*
+ * See Cycle bit rules. SW is the consumer for the event ring only.
+ * Don't make a ring full of link TRBs.  That would be dumb and this would loop.
+ */
+static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer)
+{
+       union xhci_trb *next = ++(ring->dequeue);
+
+       ring->deq_updates++;
+       /* Update the dequeue pointer further if that was a link TRB or we're at
+        * the end of an event ring segment (which doesn't have link TRBS)
+        */
+       while (last_trb(xhci, ring, ring->deq_seg, next)) {
+               if (consumer && last_trb_on_last_seg(xhci, ring, ring->deq_seg, next)) {
+                       ring->cycle_state = (ring->cycle_state ? 0 : 1);
+                       if (!in_interrupt())
+                               xhci_dbg(xhci, "Toggle cycle state for ring %p = %i\n",
+                                               ring,
+                                               (unsigned int) ring->cycle_state);
+               }
+               ring->deq_seg = ring->deq_seg->next;
+               ring->dequeue = ring->deq_seg->trbs;
+               next = ring->dequeue;
+       }
+}
+
+/*
+ * See Cycle bit rules. SW is the consumer for the event ring only.
+ * Don't make a ring full of link TRBs.  That would be dumb and this would loop.
+ *
+ * If we've just enqueued a TRB that is in the middle of a TD (meaning the
+ * chain bit is set), then set the chain bit in all the following link TRBs.
+ * If we've enqueued the last TRB in a TD, make sure the following link TRBs
+ * have their chain bit cleared (so that each Link TRB is a separate TD).
+ *
+ * Section 6.4.4.1 of the 0.95 spec says link TRBs cannot have the chain bit
+ * set, but other sections talk about dealing with the chain bit set.
+ * Assume section 6.4.4.1 is wrong, and the chain bit can be set in a Link TRB.
+ */
+static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer)
+{
+       u32 chain;
+       union xhci_trb *next;
+
+       chain = ring->enqueue->generic.field[3] & TRB_CHAIN;
+       next = ++(ring->enqueue);
+
+       ring->enq_updates++;
+       /* Update the dequeue pointer further if that was a link TRB or we're at
+        * the end of an event ring segment (which doesn't have link TRBS)
+        */
+       while (last_trb(xhci, ring, ring->enq_seg, next)) {
+               if (!consumer) {
+                       if (ring != xhci->event_ring) {
+                               next->link.control &= ~TRB_CHAIN;
+                               next->link.control |= chain;
+                               /* Give this link TRB to the hardware */
+                               wmb();
+                               if (next->link.control & TRB_CYCLE)
+                                       next->link.control &= (u32) ~TRB_CYCLE;
+                               else
+                                       next->link.control |= (u32) TRB_CYCLE;
+                       }
+                       /* Toggle the cycle bit after the last ring segment. */
+                       if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {
+                               ring->cycle_state = (ring->cycle_state ? 0 : 1);
+                               if (!in_interrupt())
+                                       xhci_dbg(xhci, "Toggle cycle state for ring %p = %i\n",
+                                                       ring,
+                                                       (unsigned int) ring->cycle_state);
+                       }
+               }
+               ring->enq_seg = ring->enq_seg->next;
+               ring->enqueue = ring->enq_seg->trbs;
+               next = ring->enqueue;
+       }
+}
+
+/*
+ * Check to see if there's room to enqueue num_trbs on the ring.  See rules
+ * above.
+ * FIXME: this would be simpler and faster if we just kept track of the number
+ * of free TRBs in a ring.
+ */
+static int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring,
+               unsigned int num_trbs)
+{
+       int i;
+       union xhci_trb *enq = ring->enqueue;
+       struct xhci_segment *enq_seg = ring->enq_seg;
+
+       /* Check if ring is empty */
+       if (enq == ring->dequeue)
+               return 1;
+       /* Make sure there's an extra empty TRB available */
+       for (i = 0; i <= num_trbs; ++i) {
+               if (enq == ring->dequeue)
+                       return 0;
+               enq++;
+               while (last_trb(xhci, ring, enq_seg, enq)) {
+                       enq_seg = enq_seg->next;
+                       enq = enq_seg->trbs;
+               }
+       }
+       return 1;
+}
+
+void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
+{
+       u32 temp;
+       dma_addr_t deq;
+
+       deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg,
+                       xhci->event_ring->dequeue);
+       if (deq == 0 && !in_interrupt())
+               xhci_warn(xhci, "WARN something wrong with SW event ring "
+                               "dequeue ptr.\n");
+       /* Update HC event ring dequeue pointer */
+       temp = xhci_readl(xhci, &xhci->ir_set->erst_dequeue[0]);
+       temp &= ERST_PTR_MASK;
+       if (!in_interrupt())
+               xhci_dbg(xhci, "// Write event ring dequeue pointer\n");
+       xhci_writel(xhci, 0, &xhci->ir_set->erst_dequeue[1]);
+       xhci_writel(xhci, (deq & ~ERST_PTR_MASK) | temp,
+                       &xhci->ir_set->erst_dequeue[0]);
+}
+
+/* Ring the host controller doorbell after placing a command on the ring */
+void xhci_ring_cmd_db(struct xhci_hcd *xhci)
+{
+       u32 temp;
+
+       xhci_dbg(xhci, "// Ding dong!\n");
+       temp = xhci_readl(xhci, &xhci->dba->doorbell[0]) & DB_MASK;
+       xhci_writel(xhci, temp | DB_TARGET_HOST, &xhci->dba->doorbell[0]);
+       /* Flush PCI posted writes */
+       xhci_readl(xhci, &xhci->dba->doorbell[0]);
+}
+
+static void ring_ep_doorbell(struct xhci_hcd *xhci,
+               unsigned int slot_id,
+               unsigned int ep_index)
+{
+       struct xhci_ring *ep_ring;
+       u32 field;
+       __u32 __iomem *db_addr = &xhci->dba->doorbell[slot_id];
+
+       ep_ring = xhci->devs[slot_id]->ep_rings[ep_index];
+       /* Don't ring the doorbell for this endpoint if there are pending
+        * cancellations because the we don't want to interrupt processing.
+        */
+       if (!ep_ring->cancels_pending && !(ep_ring->state & SET_DEQ_PENDING)) {
+               field = xhci_readl(xhci, db_addr) & DB_MASK;
+               xhci_writel(xhci, field | EPI_TO_DB(ep_index), db_addr);
+               /* Flush PCI posted writes - FIXME Matthew Wilcox says this
+                * isn't time-critical and we shouldn't make the CPU wait for
+                * the flush.
+                */
+               xhci_readl(xhci, db_addr);
+       }
+}
+
+/*
+ * Find the segment that trb is in.  Start searching in start_seg.
+ * If we must move past a segment that has a link TRB with a toggle cycle state
+ * bit set, then we will toggle the value pointed at by cycle_state.
+ */
+static struct xhci_segment *find_trb_seg(
+               struct xhci_segment *start_seg,
+               union xhci_trb  *trb, int *cycle_state)
+{
+       struct xhci_segment *cur_seg = start_seg;
+       struct xhci_generic_trb *generic_trb;
+
+       while (cur_seg->trbs > trb ||
+                       &cur_seg->trbs[TRBS_PER_SEGMENT - 1] < trb) {
+               generic_trb = &cur_seg->trbs[TRBS_PER_SEGMENT - 1].generic;
+               if (TRB_TYPE(generic_trb->field[3]) == TRB_LINK &&
+                               (generic_trb->field[3] & LINK_TOGGLE))
+                       *cycle_state = ~(*cycle_state) & 0x1;
+               cur_seg = cur_seg->next;
+               if (cur_seg == start_seg)
+                       /* Looped over the entire list.  Oops! */
+                       return 0;
+       }
+       return cur_seg;
+}
+
+struct dequeue_state {
+       struct xhci_segment *new_deq_seg;
+       union xhci_trb *new_deq_ptr;
+       int new_cycle_state;
+};
+
+/*
+ * Move the xHC's endpoint ring dequeue pointer past cur_td.
+ * Record the new state of the xHC's endpoint ring dequeue segment,
+ * dequeue pointer, and new consumer cycle state in state.
+ * Update our internal representation of the ring's dequeue pointer.
+ *
+ * We do this in three jumps:
+ *  - First we update our new ring state to be the same as when the xHC stopped.
+ *  - Then we traverse the ring to find the segment that contains
+ *    the last TRB in the TD.  We toggle the xHC's new cycle state when we pass
+ *    any link TRBs with the toggle cycle bit set.
+ *  - Finally we move the dequeue state one TRB further, toggling the cycle bit
+ *    if we've moved it past a link TRB with the toggle cycle bit set.
+ */
+static void find_new_dequeue_state(struct xhci_hcd *xhci,
+               unsigned int slot_id, unsigned int ep_index,
+               struct xhci_td *cur_td, struct dequeue_state *state)
+{
+       struct xhci_virt_device *dev = xhci->devs[slot_id];
+       struct xhci_ring *ep_ring = dev->ep_rings[ep_index];
+       struct xhci_generic_trb *trb;
+
+       state->new_cycle_state = 0;
+       state->new_deq_seg = find_trb_seg(cur_td->start_seg,
+                       ep_ring->stopped_trb,
+                       &state->new_cycle_state);
+       if (!state->new_deq_seg)
+               BUG();
+       /* Dig out the cycle state saved by the xHC during the stop ep cmd */
+       state->new_cycle_state = 0x1 & dev->out_ctx->ep[ep_index].deq[0];
+
+       state->new_deq_ptr = cur_td->last_trb;
+       state->new_deq_seg = find_trb_seg(state->new_deq_seg,
+                       state->new_deq_ptr,
+                       &state->new_cycle_state);
+       if (!state->new_deq_seg)
+               BUG();
+
+       trb = &state->new_deq_ptr->generic;
+       if (TRB_TYPE(trb->field[3]) == TRB_LINK &&
+                               (trb->field[3] & LINK_TOGGLE))
+               state->new_cycle_state = ~(state->new_cycle_state) & 0x1;
+       next_trb(xhci, ep_ring, &state->new_deq_seg, &state->new_deq_ptr);
+
+       /* Don't update the ring cycle state for the producer (us). */
+       ep_ring->dequeue = state->new_deq_ptr;
+       ep_ring->deq_seg = state->new_deq_seg;
+}
+
+static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
+               struct xhci_td *cur_td)
+{
+       struct xhci_segment *cur_seg;
+       union xhci_trb *cur_trb;
+
+       for (cur_seg = cur_td->start_seg, cur_trb = cur_td->first_trb;
+                       true;
+                       next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) {
+               if ((cur_trb->generic.field[3] & TRB_TYPE_BITMASK) ==
+                               TRB_TYPE(TRB_LINK)) {
+                       /* Unchain any chained Link TRBs, but
+                        * leave the pointers intact.
+                        */
+                       cur_trb->generic.field[3] &= ~TRB_CHAIN;
+                       xhci_dbg(xhci, "Cancel (unchain) link TRB\n");
+                       xhci_dbg(xhci, "Address = %p (0x%llx dma); "
+                                       "in seg %p (0x%llx dma)\n",
+                                       cur_trb,
+                                       (unsigned long long)xhci_trb_virt_to_dma(cur_seg, cur_trb),
+                                       cur_seg,
+                                       (unsigned long long)cur_seg->dma);
+               } else {
+                       cur_trb->generic.field[0] = 0;
+                       cur_trb->generic.field[1] = 0;
+                       cur_trb->generic.field[2] = 0;
+                       /* Preserve only the cycle bit of this TRB */
+                       cur_trb->generic.field[3] &= TRB_CYCLE;
+                       cur_trb->generic.field[3] |= TRB_TYPE(TRB_TR_NOOP);
+                       xhci_dbg(xhci, "Cancel TRB %p (0x%llx dma) "
+                                       "in seg %p (0x%llx dma)\n",
+                                       cur_trb,
+                                       (unsigned long long)xhci_trb_virt_to_dma(cur_seg, cur_trb),
+                                       cur_seg,
+                                       (unsigned long long)cur_seg->dma);
+               }
+               if (cur_trb == cur_td->last_trb)
+                       break;
+       }
+}
+
+static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id,
+               unsigned int ep_index, struct xhci_segment *deq_seg,
+               union xhci_trb *deq_ptr, u32 cycle_state);
+
+/*
+ * When we get a command completion for a Stop Endpoint Command, we need to
+ * unlink any cancelled TDs from the ring.  There are two ways to do that:
+ *
+ *  1. If the HW was in the middle of processing the TD that needs to be
+ *     cancelled, then we must move the ring's dequeue pointer past the last TRB
+ *     in the TD with a Set Dequeue Pointer Command.
+ *  2. Otherwise, we turn all the TRBs in the TD into No-op TRBs (with the chain
+ *     bit cleared) so that the HW will skip over them.
+ */
+static void handle_stopped_endpoint(struct xhci_hcd *xhci,
+               union xhci_trb *trb)
+{
+       unsigned int slot_id;
+       unsigned int ep_index;
+       struct xhci_ring *ep_ring;
+       struct list_head *entry;
+       struct xhci_td *cur_td = 0;
+       struct xhci_td *last_unlinked_td;
+
+       struct dequeue_state deq_state;
+#ifdef CONFIG_USB_HCD_STAT
+       ktime_t stop_time = ktime_get();
+#endif
+
+       memset(&deq_state, 0, sizeof(deq_state));
+       slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]);
+       ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]);
+       ep_ring = xhci->devs[slot_id]->ep_rings[ep_index];
+
+       if (list_empty(&ep_ring->cancelled_td_list))
+               return;
+
+       /* Fix up the ep ring first, so HW stops executing cancelled TDs.
+        * We have the xHCI lock, so nothing can modify this list until we drop
+        * it.  We're also in the event handler, so we can't get re-interrupted
+        * if another Stop Endpoint command completes
+        */
+       list_for_each(entry, &ep_ring->cancelled_td_list) {
+               cur_td = list_entry(entry, struct xhci_td, cancelled_td_list);
+               xhci_dbg(xhci, "Cancelling TD starting at %p, 0x%llx (dma).\n",
+                               cur_td->first_trb,
+                               (unsigned long long)xhci_trb_virt_to_dma(cur_td->start_seg, cur_td->first_trb));
+               /*
+                * If we stopped on the TD we need to cancel, then we have to
+                * move the xHC endpoint ring dequeue pointer past this TD.
+                */
+               if (cur_td == ep_ring->stopped_td)
+                       find_new_dequeue_state(xhci, slot_id, ep_index, cur_td,
+                                       &deq_state);
+               else
+                       td_to_noop(xhci, ep_ring, cur_td);
+               /*
+                * The event handler won't see a completion for this TD anymore,
+                * so remove it from the endpoint ring's TD list.  Keep it in
+                * the cancelled TD list for URB completion later.
+                */
+               list_del(&cur_td->td_list);
+               ep_ring->cancels_pending--;
+       }
+       last_unlinked_td = cur_td;
+
+       /* If necessary, queue a Set Transfer Ring Dequeue Pointer command */
+       if (deq_state.new_deq_ptr && deq_state.new_deq_seg) {
+               xhci_dbg(xhci, "Set TR Deq Ptr cmd, new deq seg = %p (0x%llx dma), "
+                               "new deq ptr = %p (0x%llx dma), new cycle = %u\n",
+                               deq_state.new_deq_seg,
+                               (unsigned long long)deq_state.new_deq_seg->dma,
+                               deq_state.new_deq_ptr,
+                               (unsigned long long)xhci_trb_virt_to_dma(deq_state.new_deq_seg, deq_state.new_deq_ptr),
+                               deq_state.new_cycle_state);
+               queue_set_tr_deq(xhci, slot_id, ep_index,
+                               deq_state.new_deq_seg,
+                               deq_state.new_deq_ptr,
+                               (u32) deq_state.new_cycle_state);
+               /* Stop the TD queueing code from ringing the doorbell until
+                * this command completes.  The HC won't set the dequeue pointer
+                * if the ring is running, and ringing the doorbell starts the
+                * ring running.
+                */
+               ep_ring->state |= SET_DEQ_PENDING;
+               xhci_ring_cmd_db(xhci);
+       } else {
+               /* Otherwise just ring the doorbell to restart the ring */
+               ring_ep_doorbell(xhci, slot_id, ep_index);
+       }
+
+       /*
+        * Drop the lock and complete the URBs in the cancelled TD list.
+        * New TDs to be cancelled might be added to the end of the list before
+        * we can complete all the URBs for the TDs we already unlinked.
+        * So stop when we've completed the URB for the last TD we unlinked.
+        */
+       do {
+               cur_td = list_entry(ep_ring->cancelled_td_list.next,
+                               struct xhci_td, cancelled_td_list);
+               list_del(&cur_td->cancelled_td_list);
+
+               /* Clean up the cancelled URB */
+#ifdef CONFIG_USB_HCD_STAT
+               hcd_stat_update(xhci->tp_stat, cur_td->urb->actual_length,
+                               ktime_sub(stop_time, cur_td->start_time));
+#endif
+               cur_td->urb->hcpriv = NULL;
+               usb_hcd_unlink_urb_from_ep(xhci_to_hcd(xhci), cur_td->urb);
+
+               xhci_dbg(xhci, "Giveback cancelled URB %p\n", cur_td->urb);
+               spin_unlock(&xhci->lock);
+               /* Doesn't matter what we pass for status, since the core will
+                * just overwrite it (because the URB has been unlinked).
+                */
+               usb_hcd_giveback_urb(xhci_to_hcd(xhci), cur_td->urb, 0);
+               kfree(cur_td);
+
+               spin_lock(&xhci->lock);
+       } while (cur_td != last_unlinked_td);
+
+       /* Return to the event handler with xhci->lock re-acquired */
+}
+
+/*
+ * When we get a completion for a Set Transfer Ring Dequeue Pointer command,
+ * we need to clear the set deq pending flag in the endpoint ring state, so that
+ * the TD queueing code can ring the doorbell again.  We also need to ring the
+ * endpoint doorbell to restart the ring, but only if there aren't more
+ * cancellations pending.
+ */
+static void handle_set_deq_completion(struct xhci_hcd *xhci,
+               struct xhci_event_cmd *event,
+               union xhci_trb *trb)
+{
+       unsigned int slot_id;
+       unsigned int ep_index;
+       struct xhci_ring *ep_ring;
+       struct xhci_virt_device *dev;
+
+       slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]);
+       ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]);
+       dev = xhci->devs[slot_id];
+       ep_ring = dev->ep_rings[ep_index];
+
+       if (GET_COMP_CODE(event->status) != COMP_SUCCESS) {
+               unsigned int ep_state;
+               unsigned int slot_state;
+
+               switch (GET_COMP_CODE(event->status)) {
+               case COMP_TRB_ERR:
+                       xhci_warn(xhci, "WARN Set TR Deq Ptr cmd invalid because "
+                                       "of stream ID configuration\n");
+                       break;
+               case COMP_CTX_STATE:
+                       xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed due "
+                                       "to incorrect slot or ep state.\n");
+                       ep_state = dev->out_ctx->ep[ep_index].ep_info;
+                       ep_state &= EP_STATE_MASK;
+                       slot_state = dev->out_ctx->slot.dev_state;
+                       slot_state = GET_SLOT_STATE(slot_state);
+                       xhci_dbg(xhci, "Slot state = %u, EP state = %u\n",
+                                       slot_state, ep_state);
+                       break;
+               case COMP_EBADSLT:
+                       xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed because "
+                                       "slot %u was not enabled.\n", slot_id);
+                       break;
+               default:
+                       xhci_warn(xhci, "WARN Set TR Deq Ptr cmd with unknown "
+                                       "completion code of %u.\n",
+                                       GET_COMP_CODE(event->status));
+                       break;
+               }
+               /* OK what do we do now?  The endpoint state is hosed, and we
+                * should never get to this point if the synchronization between
+                * queueing, and endpoint state are correct.  This might happen
+                * if the device gets disconnected after we've finished
+                * cancelling URBs, which might not be an error...
+                */
+       } else {
+               xhci_dbg(xhci, "Successful Set TR Deq Ptr cmd, deq[0] = 0x%x, "
+                               "deq[1] = 0x%x.\n",
+                               dev->out_ctx->ep[ep_index].deq[0],
+                               dev->out_ctx->ep[ep_index].deq[1]);
+       }
+
+       ep_ring->state &= ~SET_DEQ_PENDING;
+       ring_ep_doorbell(xhci, slot_id, ep_index);
+}
+
+
+static void handle_cmd_completion(struct xhci_hcd *xhci,
+               struct xhci_event_cmd *event)
+{
+       int slot_id = TRB_TO_SLOT_ID(event->flags);
+       u64 cmd_dma;
+       dma_addr_t cmd_dequeue_dma;
+
+       cmd_dma = (((u64) event->cmd_trb[1]) << 32) + event->cmd_trb[0];
+       cmd_dequeue_dma = xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg,
+                       xhci->cmd_ring->dequeue);
+       /* Is the command ring deq ptr out of sync with the deq seg ptr? */
+       if (cmd_dequeue_dma == 0) {
+               xhci->error_bitmask |= 1 << 4;
+               return;
+       }
+       /* Does the DMA address match our internal dequeue pointer address? */
+       if (cmd_dma != (u64) cmd_dequeue_dma) {
+               xhci->error_bitmask |= 1 << 5;
+               return;
+       }
+       switch (xhci->cmd_ring->dequeue->generic.field[3] & TRB_TYPE_BITMASK) {
+       case TRB_TYPE(TRB_ENABLE_SLOT):
+               if (GET_COMP_CODE(event->status) == COMP_SUCCESS)
+                       xhci->slot_id = slot_id;
+               else
+                       xhci->slot_id = 0;
+               complete(&xhci->addr_dev);
+               break;
+       case TRB_TYPE(TRB_DISABLE_SLOT):
+               if (xhci->devs[slot_id])
+                       xhci_free_virt_device(xhci, slot_id);
+               break;
+       case TRB_TYPE(TRB_CONFIG_EP):
+               xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(event->status);
+               complete(&xhci->devs[slot_id]->cmd_completion);
+               break;
+       case TRB_TYPE(TRB_ADDR_DEV):
+               xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(event->status);
+               complete(&xhci->addr_dev);
+               break;
+       case TRB_TYPE(TRB_STOP_RING):
+               handle_stopped_endpoint(xhci, xhci->cmd_ring->dequeue);
+               break;
+       case TRB_TYPE(TRB_SET_DEQ):
+               handle_set_deq_completion(xhci, event, xhci->cmd_ring->dequeue);
+               break;
+       case TRB_TYPE(TRB_CMD_NOOP):
+               ++xhci->noops_handled;
+               break;
+       default:
+               /* Skip over unknown commands on the event ring */
+               xhci->error_bitmask |= 1 << 6;
+               break;
+       }
+       inc_deq(xhci, xhci->cmd_ring, false);
+}
+
+static void handle_port_status(struct xhci_hcd *xhci,
+               union xhci_trb *event)
+{
+       u32 port_id;
+
+       /* Port status change events always have a successful completion code */
+       if (GET_COMP_CODE(event->generic.field[2]) != COMP_SUCCESS) {
+               xhci_warn(xhci, "WARN: xHC returned failed port status event\n");
+               xhci->error_bitmask |= 1 << 8;
+       }
+       /* FIXME: core doesn't care about all port link state changes yet */
+       port_id = GET_PORT_ID(event->generic.field[0]);
+       xhci_dbg(xhci, "Port Status Change Event for port %d\n", port_id);
+
+       /* Update event ring dequeue pointer before dropping the lock */
+       inc_deq(xhci, xhci->event_ring, true);
+       xhci_set_hc_event_deq(xhci);
+
+       spin_unlock(&xhci->lock);
+       /* Pass this up to the core */
+       usb_hcd_poll_rh_status(xhci_to_hcd(xhci));
+       spin_lock(&xhci->lock);
+}
+
+/*
+ * This TD is defined by the TRBs starting at start_trb in start_seg and ending
+ * at end_trb, which may be in another segment.  If the suspect DMA address is a
+ * TRB in this TD, this function returns that TRB's segment.  Otherwise it
+ * returns 0.
+ */
+static struct xhci_segment *trb_in_td(
+               struct xhci_segment *start_seg,
+               union xhci_trb  *start_trb,
+               union xhci_trb  *end_trb,
+               dma_addr_t      suspect_dma)
+{
+       dma_addr_t start_dma;
+       dma_addr_t end_seg_dma;
+       dma_addr_t end_trb_dma;
+       struct xhci_segment *cur_seg;
+
+       start_dma = xhci_trb_virt_to_dma(start_seg, start_trb);
+       cur_seg = start_seg;
+
+       do {
+               /* We may get an event for a Link TRB in the middle of a TD */
+               end_seg_dma = xhci_trb_virt_to_dma(cur_seg,
+                               &start_seg->trbs[TRBS_PER_SEGMENT - 1]);
+               /* If the end TRB isn't in this segment, this is set to 0 */
+               end_trb_dma = xhci_trb_virt_to_dma(cur_seg, end_trb);
+
+               if (end_trb_dma > 0) {
+                       /* The end TRB is in this segment, so suspect should be here */
+                       if (start_dma <= end_trb_dma) {
+                               if (suspect_dma >= start_dma && suspect_dma <= end_trb_dma)
+                                       return cur_seg;
+                       } else {
+                               /* Case for one segment with
+                                * a TD wrapped around to the top
+                                */
+                               if ((suspect_dma >= start_dma &&
+                                                       suspect_dma <= end_seg_dma) ||
+                                               (suspect_dma >= cur_seg->dma &&
+                                                suspect_dma <= end_trb_dma))
+                                       return cur_seg;
+                       }
+                       return 0;
+               } else {
+                       /* Might still be somewhere in this segment */
+                       if (suspect_dma >= start_dma && suspect_dma <= end_seg_dma)
+                               return cur_seg;
+               }
+               cur_seg = cur_seg->next;
+               start_dma = xhci_trb_virt_to_dma(cur_seg, &cur_seg->trbs[0]);
+       } while (1);
+
+}
+
+/*
+ * If this function returns an error condition, it means it got a Transfer
+ * event with a corrupted Slot ID, Endpoint ID, or TRB DMA address.
+ * At this point, the host controller is probably hosed and should be reset.
+ */
+static int handle_tx_event(struct xhci_hcd *xhci,
+               struct xhci_transfer_event *event)
+{
+       struct xhci_virt_device *xdev;
+       struct xhci_ring *ep_ring;
+       int ep_index;
+       struct xhci_td *td = 0;
+       dma_addr_t event_dma;
+       struct xhci_segment *event_seg;
+       union xhci_trb *event_trb;
+       struct urb *urb = 0;
+       int status = -EINPROGRESS;
+
+       xdev = xhci->devs[TRB_TO_SLOT_ID(event->flags)];
+       if (!xdev) {
+               xhci_err(xhci, "ERROR Transfer event pointed to bad slot\n");
+               return -ENODEV;
+       }
+
+       /* Endpoint ID is 1 based, our index is zero based */
+       ep_index = TRB_TO_EP_ID(event->flags) - 1;
+       ep_ring = xdev->ep_rings[ep_index];
+       if (!ep_ring || (xdev->out_ctx->ep[ep_index].ep_info & EP_STATE_MASK) == EP_STATE_DISABLED) {
+               xhci_err(xhci, "ERROR Transfer event pointed to disabled endpoint\n");
+               return -ENODEV;
+       }
+
+       event_dma = event->buffer[0];
+       if (event->buffer[1] != 0)
+               xhci_warn(xhci, "WARN ignoring upper 32-bits of 64-bit TRB dma address\n");
+
+       /* This TRB should be in the TD at the head of this ring's TD list */
+       if (list_empty(&ep_ring->td_list)) {
+               xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n",
+                               TRB_TO_SLOT_ID(event->flags), ep_index);
+               xhci_dbg(xhci, "Event TRB with TRB type ID %u\n",
+                               (unsigned int) (event->flags & TRB_TYPE_BITMASK)>>10);
+               xhci_print_trb_offsets(xhci, (union xhci_trb *) event);
+               urb = NULL;
+               goto cleanup;
+       }
+       td = list_entry(ep_ring->td_list.next, struct xhci_td, td_list);
+
+       /* Is this a TRB in the currently executing TD? */
+       event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue,
+                       td->last_trb, event_dma);
+       if (!event_seg) {
+               /* HC is busted, give up! */
+               xhci_err(xhci, "ERROR Transfer event TRB DMA ptr not part of current TD\n");
+               return -ESHUTDOWN;
+       }
+       event_trb = &event_seg->trbs[(event_dma - event_seg->dma) / sizeof(*event_trb)];
+       xhci_dbg(xhci, "Event TRB with TRB type ID %u\n",
+                       (unsigned int) (event->flags & TRB_TYPE_BITMASK)>>10);
+       xhci_dbg(xhci, "Offset 0x00 (buffer[0]) = 0x%x\n",
+                       (unsigned int) event->buffer[0]);
+       xhci_dbg(xhci, "Offset 0x04 (buffer[0]) = 0x%x\n",
+                       (unsigned int) event->buffer[1]);
+       xhci_dbg(xhci, "Offset 0x08 (transfer length) = 0x%x\n",
+                       (unsigned int) event->transfer_len);
+       xhci_dbg(xhci, "Offset 0x0C (flags) = 0x%x\n",
+                       (unsigned int) event->flags);
+
+       /* Look for common error cases */
+       switch (GET_COMP_CODE(event->transfer_len)) {
+       /* Skip codes that require special handling depending on
+        * transfer type
+        */
+       case COMP_SUCCESS:
+       case COMP_SHORT_TX:
+               break;
+       case COMP_STOP:
+               xhci_dbg(xhci, "Stopped on Transfer TRB\n");
+               break;
+       case COMP_STOP_INVAL:
+               xhci_dbg(xhci, "Stopped on No-op or Link TRB\n");
+               break;
+       case COMP_STALL:
+               xhci_warn(xhci, "WARN: Stalled endpoint\n");
+               status = -EPIPE;
+               break;
+       case COMP_TRB_ERR:
+               xhci_warn(xhci, "WARN: TRB error on endpoint\n");
+               status = -EILSEQ;
+               break;
+       case COMP_TX_ERR:
+               xhci_warn(xhci, "WARN: transfer error on endpoint\n");
+               status = -EPROTO;
+               break;
+       case COMP_DB_ERR:
+               xhci_warn(xhci, "WARN: HC couldn't access mem fast enough\n");
+               status = -ENOSR;
+               break;
+       default:
+               xhci_warn(xhci, "ERROR Unknown event condition, HC probably busted\n");
+               urb = NULL;
+               goto cleanup;
+       }
+       /* Now update the urb's actual_length and give back to the core */
+       /* Was this a control transfer? */
+       if (usb_endpoint_xfer_control(&td->urb->ep->desc)) {
+               xhci_debug_trb(xhci, xhci->event_ring->dequeue);
+               switch (GET_COMP_CODE(event->transfer_len)) {
+               case COMP_SUCCESS:
+                       if (event_trb == ep_ring->dequeue) {
+                               xhci_warn(xhci, "WARN: Success on ctrl setup TRB without IOC set??\n");
+                               status = -ESHUTDOWN;
+                       } else if (event_trb != td->last_trb) {
+                               xhci_warn(xhci, "WARN: Success on ctrl data TRB without IOC set??\n");
+                               status = -ESHUTDOWN;
+                       } else {
+                               xhci_dbg(xhci, "Successful control transfer!\n");
+                               status = 0;
+                       }
+                       break;
+               case COMP_SHORT_TX:
+                       xhci_warn(xhci, "WARN: short transfer on control ep\n");
+                       status = -EREMOTEIO;
+                       break;
+               default:
+                       /* Others already handled above */
+                       break;
+               }
+               /*
+                * Did we transfer any data, despite the errors that might have
+                * happened?  I.e. did we get past the setup stage?
+                */
+               if (event_trb != ep_ring->dequeue) {
+                       /* The event was for the status stage */
+                       if (event_trb == td->last_trb) {
+                               td->urb->actual_length =
+                                       td->urb->transfer_buffer_length;
+                       } else {
+                       /* Maybe the event was for the data stage? */
+                               if (GET_COMP_CODE(event->transfer_len) != COMP_STOP_INVAL)
+                                       /* We didn't stop on a link TRB in the middle */
+                                       td->urb->actual_length =
+                                               td->urb->transfer_buffer_length -
+                                               TRB_LEN(event->transfer_len);
+                       }
+               }
+       } else {
+               switch (GET_COMP_CODE(event->transfer_len)) {
+               case COMP_SUCCESS:
+                       /* Double check that the HW transferred everything. */
+                       if (event_trb != td->last_trb) {
+                               xhci_warn(xhci, "WARN Successful completion "
+                                               "on short TX\n");
+                               if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
+                                       status = -EREMOTEIO;
+                               else
+                                       status = 0;
+                       } else {
+                               xhci_dbg(xhci, "Successful bulk transfer!\n");
+                               status = 0;
+                       }
+                       break;
+               case COMP_SHORT_TX:
+                       if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
+                               status = -EREMOTEIO;
+                       else
+                               status = 0;
+                       break;
+               default:
+                       /* Others already handled above */
+                       break;
+               }
+               dev_dbg(&td->urb->dev->dev,
+                               "ep %#x - asked for %d bytes, "
+                               "%d bytes untransferred\n",
+                               td->urb->ep->desc.bEndpointAddress,
+                               td->urb->transfer_buffer_length,
+                               TRB_LEN(event->transfer_len));
+               /* Fast path - was this the last TRB in the TD for this URB? */
+               if (event_trb == td->last_trb) {
+                       if (TRB_LEN(event->transfer_len) != 0) {
+                               td->urb->actual_length =
+                                       td->urb->transfer_buffer_length -
+                                       TRB_LEN(event->transfer_len);
+                               if (td->urb->actual_length < 0) {
+                                       xhci_warn(xhci, "HC gave bad length "
+                                                       "of %d bytes left\n",
+                                                       TRB_LEN(event->transfer_len));
+                                       td->urb->actual_length = 0;
+                               }
+                               if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
+                                       status = -EREMOTEIO;
+                               else
+                                       status = 0;
+                       } else {
+                               td->urb->actual_length = td->urb->transfer_buffer_length;
+                               /* Ignore a short packet completion if the
+                                * untransferred length was zero.
+                                */
+                               status = 0;
+                       }
+               } else {
+                       /* Slow path - walk the list, starting from the dequeue
+                        * pointer, to get the actual length transferred.
+                        */
+                       union xhci_trb *cur_trb;
+                       struct xhci_segment *cur_seg;
+
+                       td->urb->actual_length = 0;
+                       for (cur_trb = ep_ring->dequeue, cur_seg = ep_ring->deq_seg;
+                                       cur_trb != event_trb;
+                                       next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) {
+                               if (TRB_TYPE(cur_trb->generic.field[3]) != TRB_TR_NOOP &&
+                                               TRB_TYPE(cur_trb->generic.field[3]) != TRB_LINK)
+                                       td->urb->actual_length +=
+                                               TRB_LEN(cur_trb->generic.field[2]);
+                       }
+                       /* If the ring didn't stop on a Link or No-op TRB, add
+                        * in the actual bytes transferred from the Normal TRB
+                        */
+                       if (GET_COMP_CODE(event->transfer_len) != COMP_STOP_INVAL)
+                               td->urb->actual_length +=
+                                       TRB_LEN(cur_trb->generic.field[2]) -
+                                       TRB_LEN(event->transfer_len);
+               }
+       }
+       /* The Endpoint Stop Command completion will take care of
+        * any stopped TDs.  A stopped TD may be restarted, so don't update the
+        * ring dequeue pointer or take this TD off any lists yet.
+        */
+       if (GET_COMP_CODE(event->transfer_len) == COMP_STOP_INVAL ||
+                       GET_COMP_CODE(event->transfer_len) == COMP_STOP) {
+               ep_ring->stopped_td = td;
+               ep_ring->stopped_trb = event_trb;
+       } else {
+               /* Update ring dequeue pointer */
+               while (ep_ring->dequeue != td->last_trb)
+                       inc_deq(xhci, ep_ring, false);
+               inc_deq(xhci, ep_ring, false);
+
+               /* Clean up the endpoint's TD list */
+               urb = td->urb;
+               list_del(&td->td_list);
+               /* Was this TD slated to be cancelled but completed anyway? */
+               if (!list_empty(&td->cancelled_td_list)) {
+                       list_del(&td->cancelled_td_list);
+                       ep_ring->cancels_pending--;
+               }
+               kfree(td);
+               urb->hcpriv = NULL;
+       }
+cleanup:
+       inc_deq(xhci, xhci->event_ring, true);
+       xhci_set_hc_event_deq(xhci);
+
+       /* FIXME for multi-TD URBs (who have buffers bigger than 64MB) */
+       if (urb) {
+               usb_hcd_unlink_urb_from_ep(xhci_to_hcd(xhci), urb);
+               spin_unlock(&xhci->lock);
+               usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, status);
+               spin_lock(&xhci->lock);
+       }
+       return 0;
+}
+
+/*
+ * This function handles all OS-owned events on the event ring.  It may drop
+ * xhci->lock between event processing (e.g. to pass up port status changes).
+ */
+void xhci_handle_event(struct xhci_hcd *xhci)
+{
+       union xhci_trb *event;
+       int update_ptrs = 1;
+       int ret;
+
+       if (!xhci->event_ring || !xhci->event_ring->dequeue) {
+               xhci->error_bitmask |= 1 << 1;
+               return;
+       }
+
+       event = xhci->event_ring->dequeue;
+       /* Does the HC or OS own the TRB? */
+       if ((event->event_cmd.flags & TRB_CYCLE) !=
+                       xhci->event_ring->cycle_state) {
+               xhci->error_bitmask |= 1 << 2;
+               return;
+       }
+
+       /* FIXME: Handle more event types. */
+       switch ((event->event_cmd.flags & TRB_TYPE_BITMASK)) {
+       case TRB_TYPE(TRB_COMPLETION):
+               handle_cmd_completion(xhci, &event->event_cmd);
+               break;
+       case TRB_TYPE(TRB_PORT_STATUS):
+               handle_port_status(xhci, event);
+               update_ptrs = 0;
+               break;
+       case TRB_TYPE(TRB_TRANSFER):
+               ret = handle_tx_event(xhci, &event->trans_event);
+               if (ret < 0)
+                       xhci->error_bitmask |= 1 << 9;
+               else
+                       update_ptrs = 0;
+               break;
+       default:
+               xhci->error_bitmask |= 1 << 3;
+       }
+
+       if (update_ptrs) {
+               /* Update SW and HC event ring dequeue pointer */
+               inc_deq(xhci, xhci->event_ring, true);
+               xhci_set_hc_event_deq(xhci);
+       }
+       /* Are there more items on the event ring? */
+       xhci_handle_event(xhci);
+}
+
+/****          Endpoint Ring Operations        ****/
+
+/*
+ * Generic function for queueing a TRB on a ring.
+ * The caller must have checked to make sure there's room on the ring.
+ */
+static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
+               bool consumer,
+               u32 field1, u32 field2, u32 field3, u32 field4)
+{
+       struct xhci_generic_trb *trb;
+
+       trb = &ring->enqueue->generic;
+       trb->field[0] = field1;
+       trb->field[1] = field2;
+       trb->field[2] = field3;
+       trb->field[3] = field4;
+       inc_enq(xhci, ring, consumer);
+}
+
+/*
+ * Does various checks on the endpoint ring, and makes it ready to queue num_trbs.
+ * FIXME allocate segments if the ring is full.
+ */
+static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
+               u32 ep_state, unsigned int num_trbs, gfp_t mem_flags)
+{
+       /* Make sure the endpoint has been added to xHC schedule */
+       xhci_dbg(xhci, "Endpoint state = 0x%x\n", ep_state);
+       switch (ep_state) {
+       case EP_STATE_DISABLED:
+               /*
+                * USB core changed config/interfaces without notifying us,
+                * or hardware is reporting the wrong state.
+                */
+               xhci_warn(xhci, "WARN urb submitted to disabled ep\n");
+               return -ENOENT;
+       case EP_STATE_HALTED:
+       case EP_STATE_ERROR:
+               xhci_warn(xhci, "WARN waiting for halt or error on ep "
+                               "to be cleared\n");
+               /* FIXME event handling code for error needs to clear it */
+               /* XXX not sure if this should be -ENOENT or not */
+               return -EINVAL;
+       case EP_STATE_STOPPED:
+       case EP_STATE_RUNNING:
+               break;
+       default:
+               xhci_err(xhci, "ERROR unknown endpoint state for ep\n");
+               /*
+                * FIXME issue Configure Endpoint command to try to get the HC
+                * back into a known state.
+                */
+               return -EINVAL;
+       }
+       if (!room_on_ring(xhci, ep_ring, num_trbs)) {
+               /* FIXME allocate more room */
+               xhci_err(xhci, "ERROR no room on ep ring\n");
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static int prepare_transfer(struct xhci_hcd *xhci,
+               struct xhci_virt_device *xdev,
+               unsigned int ep_index,
+               unsigned int num_trbs,
+               struct urb *urb,
+               struct xhci_td **td,
+               gfp_t mem_flags)
+{
+       int ret;
+
+       ret = prepare_ring(xhci, xdev->ep_rings[ep_index],
+                       xdev->out_ctx->ep[ep_index].ep_info & EP_STATE_MASK,
+                       num_trbs, mem_flags);
+       if (ret)
+               return ret;
+       *td = kzalloc(sizeof(struct xhci_td), mem_flags);
+       if (!*td)
+               return -ENOMEM;
+       INIT_LIST_HEAD(&(*td)->td_list);
+       INIT_LIST_HEAD(&(*td)->cancelled_td_list);
+
+       ret = usb_hcd_link_urb_to_ep(xhci_to_hcd(xhci), urb);
+       if (unlikely(ret)) {
+               kfree(*td);
+               return ret;
+       }
+
+       (*td)->urb = urb;
+       urb->hcpriv = (void *) (*td);
+       /* Add this TD to the tail of the endpoint ring's TD list */
+       list_add_tail(&(*td)->td_list, &xdev->ep_rings[ep_index]->td_list);
+       (*td)->start_seg = xdev->ep_rings[ep_index]->enq_seg;
+       (*td)->first_trb = xdev->ep_rings[ep_index]->enqueue;
+
+       return 0;
+}
+
+static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb *urb)
+{
+       int num_sgs, num_trbs, running_total, temp, i;
+       struct scatterlist *sg;
+
+       sg = NULL;
+       num_sgs = urb->num_sgs;
+       temp = urb->transfer_buffer_length;
+
+       xhci_dbg(xhci, "count sg list trbs: \n");
+       num_trbs = 0;
+       for_each_sg(urb->sg->sg, sg, num_sgs, i) {
+               unsigned int previous_total_trbs = num_trbs;
+               unsigned int len = sg_dma_len(sg);
+
+               /* Scatter gather list entries may cross 64KB boundaries */
+               running_total = TRB_MAX_BUFF_SIZE -
+                       (sg_dma_address(sg) & ((1 << TRB_MAX_BUFF_SHIFT) - 1));
+               if (running_total != 0)
+                       num_trbs++;
+
+               /* How many more 64KB chunks to transfer, how many more TRBs? */
+               while (running_total < sg_dma_len(sg)) {
+                       num_trbs++;
+                       running_total += TRB_MAX_BUFF_SIZE;
+               }
+               xhci_dbg(xhci, " sg #%d: dma = %#llx, len = %#x (%d), num_trbs = %d\n",
+                               i, (unsigned long long)sg_dma_address(sg),
+                               len, len, num_trbs - previous_total_trbs);
+
+               len = min_t(int, len, temp);
+               temp -= len;
+               if (temp == 0)
+                       break;
+       }
+       xhci_dbg(xhci, "\n");
+       if (!in_interrupt())
+               dev_dbg(&urb->dev->dev, "ep %#x - urb len = %d, sglist used, num_trbs = %d\n",
+                               urb->ep->desc.bEndpointAddress,
+                               urb->transfer_buffer_length,
+                               num_trbs);
+       return num_trbs;
+}
+
+static void check_trb_math(struct urb *urb, int num_trbs, int running_total)
+{
+       if (num_trbs != 0)
+               dev_dbg(&urb->dev->dev, "%s - ep %#x - Miscalculated number of "
+                               "TRBs, %d left\n", __func__,
+                               urb->ep->desc.bEndpointAddress, num_trbs);
+       if (running_total != urb->transfer_buffer_length)
+               dev_dbg(&urb->dev->dev, "%s - ep %#x - Miscalculated tx length, "
+                               "queued %#x (%d), asked for %#x (%d)\n",
+                               __func__,
+                               urb->ep->desc.bEndpointAddress,
+                               running_total, running_total,
+                               urb->transfer_buffer_length,
+                               urb->transfer_buffer_length);
+}
+
+static void giveback_first_trb(struct xhci_hcd *xhci, int slot_id,
+               unsigned int ep_index, int start_cycle,
+               struct xhci_generic_trb *start_trb, struct xhci_td *td)
+{
+       /*
+        * Pass all the TRBs to the hardware at once and make sure this write
+        * isn't reordered.
+        */
+       wmb();
+       start_trb->field[3] |= start_cycle;
+       ring_ep_doorbell(xhci, slot_id, ep_index);
+}
+
+static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
+               struct urb *urb, int slot_id, unsigned int ep_index)
+{
+       struct xhci_ring *ep_ring;
+       unsigned int num_trbs;
+       struct xhci_td *td;
+       struct scatterlist *sg;
+       int num_sgs;
+       int trb_buff_len, this_sg_len, running_total;
+       bool first_trb;
+       u64 addr;
+
+       struct xhci_generic_trb *start_trb;
+       int start_cycle;
+
+       ep_ring = xhci->devs[slot_id]->ep_rings[ep_index];
+       num_trbs = count_sg_trbs_needed(xhci, urb);
+       num_sgs = urb->num_sgs;
+
+       trb_buff_len = prepare_transfer(xhci, xhci->devs[slot_id],
+                       ep_index, num_trbs, urb, &td, mem_flags);
+       if (trb_buff_len < 0)
+               return trb_buff_len;
+       /*
+        * Don't give the first TRB to the hardware (by toggling the cycle bit)
+        * until we've finished creating all the other TRBs.  The ring's cycle
+        * state may change as we enqueue the other TRBs, so save it too.
+        */
+       start_trb = &ep_ring->enqueue->generic;
+       start_cycle = ep_ring->cycle_state;
+
+       running_total = 0;
+       /*
+        * How much data is in the first TRB?
+        *
+        * There are three forces at work for TRB buffer pointers and lengths:
+        * 1. We don't want to walk off the end of this sg-list entry buffer.
+        * 2. The transfer length that the driver requested may be smaller than
+        *    the amount of memory allocated for this scatter-gather list.
+        * 3. TRBs buffers can't cross 64KB boundaries.
+        */
+       sg = urb->sg->sg;
+       addr = (u64) sg_dma_address(sg);
+       this_sg_len = sg_dma_len(sg);
+       trb_buff_len = TRB_MAX_BUFF_SIZE -
+               (addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1));
+       trb_buff_len = min_t(int, trb_buff_len, this_sg_len);
+       if (trb_buff_len > urb->transfer_buffer_length)
+               trb_buff_len = urb->transfer_buffer_length;
+       xhci_dbg(xhci, "First length to xfer from 1st sglist entry = %u\n",
+                       trb_buff_len);
+
+       first_trb = true;
+       /* Queue the first TRB, even if it's zero-length */
+       do {
+               u32 field = 0;
+
+               /* Don't change the cycle bit of the first TRB until later */
+               if (first_trb)
+                       first_trb = false;
+               else
+                       field |= ep_ring->cycle_state;
+
+               /* Chain all the TRBs together; clear the chain bit in the last
+                * TRB to indicate it's the last TRB in the chain.
+                */
+               if (num_trbs > 1) {
+                       field |= TRB_CHAIN;
+               } else {
+                       /* FIXME - add check for ZERO_PACKET flag before this */
+                       td->last_trb = ep_ring->enqueue;
+                       field |= TRB_IOC;
+               }
+               xhci_dbg(xhci, " sg entry: dma = %#x, len = %#x (%d), "
+                               "64KB boundary at %#x, end dma = %#x\n",
+                               (unsigned int) addr, trb_buff_len, trb_buff_len,
+                               (unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1),
+                               (unsigned int) addr + trb_buff_len);
+               if (TRB_MAX_BUFF_SIZE -
+                               (addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1)) < trb_buff_len) {
+                       xhci_warn(xhci, "WARN: sg dma xfer crosses 64KB boundaries!\n");
+                       xhci_dbg(xhci, "Next boundary at %#x, end dma = %#x\n",
+                                       (unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1),
+                                       (unsigned int) addr + trb_buff_len);
+               }
+               queue_trb(xhci, ep_ring, false,
+                               (u32) addr,
+                               (u32) ((u64) addr >> 32),
+                               TRB_LEN(trb_buff_len) | TRB_INTR_TARGET(0),
+                               /* We always want to know if the TRB was short,
+                                * or we won't get an event when it completes.
+                                * (Unless we use event data TRBs, which are a
+                                * waste of space and HC resources.)
+                                */
+                               field | TRB_ISP | TRB_TYPE(TRB_NORMAL));
+               --num_trbs;
+               running_total += trb_buff_len;
+
+               /* Calculate length for next transfer --
+                * Are we done queueing all the TRBs for this sg entry?
+                */
+               this_sg_len -= trb_buff_len;
+               if (this_sg_len == 0) {
+                       --num_sgs;
+                       if (num_sgs == 0)
+                               break;
+                       sg = sg_next(sg);
+                       addr = (u64) sg_dma_address(sg);
+                       this_sg_len = sg_dma_len(sg);
+               } else {
+                       addr += trb_buff_len;
+               }
+
+               trb_buff_len = TRB_MAX_BUFF_SIZE -
+                       (addr & ((1 << TRB_MAX_BUFF_SHIFT) - 1));
+               trb_buff_len = min_t(int, trb_buff_len, this_sg_len);
+               if (running_total + trb_buff_len > urb->transfer_buffer_length)
+                       trb_buff_len =
+                               urb->transfer_buffer_length - running_total;
+       } while (running_total < urb->transfer_buffer_length);
+
+       check_trb_math(urb, num_trbs, running_total);
+       giveback_first_trb(xhci, slot_id, ep_index, start_cycle, start_trb, td);
+       return 0;
+}
+
+/* This is very similar to what ehci-q.c qtd_fill() does */
+int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
+               struct urb *urb, int slot_id, unsigned int ep_index)
+{
+       struct xhci_ring *ep_ring;
+       struct xhci_td *td;
+       int num_trbs;
+       struct xhci_generic_trb *start_trb;
+       bool first_trb;
+       int start_cycle;
+       u32 field;
+
+       int running_total, trb_buff_len, ret;
+       u64 addr;
+
+       if (urb->sg)
+               return queue_bulk_sg_tx(xhci, mem_flags, urb, slot_id, ep_index);
+
+       ep_ring = xhci->devs[slot_id]->ep_rings[ep_index];
+
+       num_trbs = 0;
+       /* How much data is (potentially) left before the 64KB boundary? */
+       running_total = TRB_MAX_BUFF_SIZE -
+               (urb->transfer_dma & ((1 << TRB_MAX_BUFF_SHIFT) - 1));
+
+       /* If there's some data on this 64KB chunk, or we have to send a
+        * zero-length transfer, we need at least one TRB
+        */
+       if (running_total != 0 || urb->transfer_buffer_length == 0)
+               num_trbs++;
+       /* How many more 64KB chunks to transfer, how many more TRBs? */
+       while (running_total < urb->transfer_buffer_length) {
+               num_trbs++;
+               running_total += TRB_MAX_BUFF_SIZE;
+       }
+       /* FIXME: this doesn't deal with URB_ZERO_PACKET - need one more */
+
+       if (!in_interrupt())
+               dev_dbg(&urb->dev->dev, "ep %#x - urb len = %#x (%d), addr = %#llx, num_trbs = %d\n",
+                               urb->ep->desc.bEndpointAddress,
+                               urb->transfer_buffer_length,
+                               urb->transfer_buffer_length,
+                               (unsigned long long)urb->transfer_dma,
+                               num_trbs);
+
+       ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index,
+                       num_trbs, urb, &td, mem_flags);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * Don't give the first TRB to the hardware (by toggling the cycle bit)
+        * until we've finished creating all the other TRBs.  The ring's cycle
+        * state may change as we enqueue the other TRBs, so save it too.
+        */
+       start_trb = &ep_ring->enqueue->generic;
+       start_cycle = ep_ring->cycle_state;
+
+       running_total = 0;
+       /* How much data is in the first TRB? */
+       addr = (u64) urb->transfer_dma;
+       trb_buff_len = TRB_MAX_BUFF_SIZE -
+               (urb->transfer_dma & ((1 << TRB_MAX_BUFF_SHIFT) - 1));
+       if (urb->transfer_buffer_length < trb_buff_len)
+               trb_buff_len = urb->transfer_buffer_length;
+
+       first_trb = true;
+
+       /* Queue the first TRB, even if it's zero-length */
+       do {
+               field = 0;
+
+               /* Don't change the cycle bit of the first TRB until later */
+               if (first_trb)
+                       first_trb = false;
+               else
+                       field |= ep_ring->cycle_state;
+
+               /* Chain all the TRBs together; clear the chain bit in the last
+                * TRB to indicate it's the last TRB in the chain.
+                */
+               if (num_trbs > 1) {
+                       field |= TRB_CHAIN;
+               } else {
+                       /* FIXME - add check for ZERO_PACKET flag before this */
+                       td->last_trb = ep_ring->enqueue;
+                       field |= TRB_IOC;
+               }
+               queue_trb(xhci, ep_ring, false,
+                               (u32) addr,
+                               (u32) ((u64) addr >> 32),
+                               TRB_LEN(trb_buff_len) | TRB_INTR_TARGET(0),
+                               /* We always want to know if the TRB was short,
+                                * or we won't get an event when it completes.
+                                * (Unless we use event data TRBs, which are a
+                                * waste of space and HC resources.)
+                                */
+                               field | TRB_ISP | TRB_TYPE(TRB_NORMAL));
+               --num_trbs;
+               running_total += trb_buff_len;
+
+               /* Calculate length for next transfer */
+               addr += trb_buff_len;
+               trb_buff_len = urb->transfer_buffer_length - running_total;
+               if (trb_buff_len > TRB_MAX_BUFF_SIZE)
+                       trb_buff_len = TRB_MAX_BUFF_SIZE;
+       } while (running_total < urb->transfer_buffer_length);
+
+       check_trb_math(urb, num_trbs, running_total);
+       giveback_first_trb(xhci, slot_id, ep_index, start_cycle, start_trb, td);
+       return 0;
+}
+
+/* Caller must have locked xhci->lock */
+int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
+               struct urb *urb, int slot_id, unsigned int ep_index)
+{
+       struct xhci_ring *ep_ring;
+       int num_trbs;
+       int ret;
+       struct usb_ctrlrequest *setup;
+       struct xhci_generic_trb *start_trb;
+       int start_cycle;
+       u32 field;
+       struct xhci_td *td;
+
+       ep_ring = xhci->devs[slot_id]->ep_rings[ep_index];
+
+       /*
+        * Need to copy setup packet into setup TRB, so we can't use the setup
+        * DMA address.
+        */
+       if (!urb->setup_packet)
+               return -EINVAL;
+
+       if (!in_interrupt())
+               xhci_dbg(xhci, "Queueing ctrl tx for slot id %d, ep %d\n",
+                               slot_id, ep_index);
+       /* 1 TRB for setup, 1 for status */
+       num_trbs = 2;
+       /*
+        * Don't need to check if we need additional event data and normal TRBs,
+        * since data in control transfers will never get bigger than 16MB
+        * XXX: can we get a buffer that crosses 64KB boundaries?
+        */
+       if (urb->transfer_buffer_length > 0)
+               num_trbs++;
+       ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, num_trbs,
+                       urb, &td, mem_flags);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * Don't give the first TRB to the hardware (by toggling the cycle bit)
+        * until we've finished creating all the other TRBs.  The ring's cycle
+        * state may change as we enqueue the other TRBs, so save it too.
+        */
+       start_trb = &ep_ring->enqueue->generic;
+       start_cycle = ep_ring->cycle_state;
+
+       /* Queue setup TRB - see section 6.4.1.2.1 */
+       /* FIXME better way to translate setup_packet into two u32 fields? */
+       setup = (struct usb_ctrlrequest *) urb->setup_packet;
+       queue_trb(xhci, ep_ring, false,
+                       /* FIXME endianness is probably going to bite my ass here. */
+                       setup->bRequestType | setup->bRequest << 8 | setup->wValue << 16,
+                       setup->wIndex | setup->wLength << 16,
+                       TRB_LEN(8) | TRB_INTR_TARGET(0),
+                       /* Immediate data in pointer */
+                       TRB_IDT | TRB_TYPE(TRB_SETUP));
+
+       /* If there's data, queue data TRBs */
+       field = 0;
+       if (urb->transfer_buffer_length > 0) {
+               if (setup->bRequestType & USB_DIR_IN)
+                       field |= TRB_DIR_IN;
+               queue_trb(xhci, ep_ring, false,
+                               lower_32_bits(urb->transfer_dma),
+                               upper_32_bits(urb->transfer_dma),
+                               TRB_LEN(urb->transfer_buffer_length) | TRB_INTR_TARGET(0),
+                               /* Event on short tx */
+                               field | TRB_ISP | TRB_TYPE(TRB_DATA) | ep_ring->cycle_state);
+       }
+
+       /* Save the DMA address of the last TRB in the TD */
+       td->last_trb = ep_ring->enqueue;
+
+       /* Queue status TRB - see Table 7 and sections 4.11.2.2 and 6.4.1.2.3 */
+       /* If the device sent data, the status stage is an OUT transfer */
+       if (urb->transfer_buffer_length > 0 && setup->bRequestType & USB_DIR_IN)
+               field = 0;
+       else
+               field = TRB_DIR_IN;
+       queue_trb(xhci, ep_ring, false,
+                       0,
+                       0,
+                       TRB_INTR_TARGET(0),
+                       /* Event on completion */
+                       field | TRB_IOC | TRB_TYPE(TRB_STATUS) | ep_ring->cycle_state);
+
+       giveback_first_trb(xhci, slot_id, ep_index, start_cycle, start_trb, td);
+       return 0;
+}
+
+/****          Command Ring Operations         ****/
+
+/* Generic function for queueing a command TRB on the command ring */
+static int queue_command(struct xhci_hcd *xhci, u32 field1, u32 field2, u32 field3, u32 field4)
+{
+       if (!room_on_ring(xhci, xhci->cmd_ring, 1)) {
+               if (!in_interrupt())
+                       xhci_err(xhci, "ERR: No room for command on command ring\n");
+               return -ENOMEM;
+       }
+       queue_trb(xhci, xhci->cmd_ring, false, field1, field2, field3,
+                       field4 | xhci->cmd_ring->cycle_state);
+       return 0;
+}
+
+/* Queue a no-op command on the command ring */
+static int queue_cmd_noop(struct xhci_hcd *xhci)
+{
+       return queue_command(xhci, 0, 0, 0, TRB_TYPE(TRB_CMD_NOOP));
+}
+
+/*
+ * Place a no-op command on the command ring to test the command and
+ * event ring.
+ */
+void *xhci_setup_one_noop(struct xhci_hcd *xhci)
+{
+       if (queue_cmd_noop(xhci) < 0)
+               return NULL;
+       xhci->noops_submitted++;
+       return xhci_ring_cmd_db;
+}
+
+/* Queue a slot enable or disable request on the command ring */
+int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id)
+{
+       return queue_command(xhci, 0, 0, 0,
+                       TRB_TYPE(trb_type) | SLOT_ID_FOR_TRB(slot_id));
+}
+
+/* Queue an address device command TRB */
+int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
+               u32 slot_id)
+{
+       return queue_command(xhci, in_ctx_ptr, 0, 0,
+                       TRB_TYPE(TRB_ADDR_DEV) | SLOT_ID_FOR_TRB(slot_id));
+}
+
+/* Queue a configure endpoint command TRB */
+int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
+               u32 slot_id)
+{
+       return queue_command(xhci, in_ctx_ptr, 0, 0,
+                       TRB_TYPE(TRB_CONFIG_EP) | SLOT_ID_FOR_TRB(slot_id));
+}
+
+int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id,
+               unsigned int ep_index)
+{
+       u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id);
+       u32 trb_ep_index = EP_ID_FOR_TRB(ep_index);
+       u32 type = TRB_TYPE(TRB_STOP_RING);
+
+       return queue_command(xhci, 0, 0, 0,
+                       trb_slot_id | trb_ep_index | type);
+}
+
+/* Set Transfer Ring Dequeue Pointer command.
+ * This should not be used for endpoints that have streams enabled.
+ */
+static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id,
+               unsigned int ep_index, struct xhci_segment *deq_seg,
+               union xhci_trb *deq_ptr, u32 cycle_state)
+{
+       dma_addr_t addr;
+       u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id);
+       u32 trb_ep_index = EP_ID_FOR_TRB(ep_index);
+       u32 type = TRB_TYPE(TRB_SET_DEQ);
+
+       addr = xhci_trb_virt_to_dma(deq_seg, deq_ptr);
+       if (addr == 0)
+               xhci_warn(xhci, "WARN Cannot submit Set TR Deq Ptr\n");
+               xhci_warn(xhci, "WARN deq seg = %p, deq pt = %p\n",
+                               deq_seg, deq_ptr);
+       return queue_command(xhci, (u32) addr | cycle_state, 0, 0,
+                       trb_slot_id | trb_ep_index | type);
+}
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
new file mode 100644 (file)
index 0000000..8936eeb
--- /dev/null
@@ -0,0 +1,1157 @@
+/*
+ * xHCI host controller driver
+ *
+ * Copyright (C) 2008 Intel Corp.
+ *
+ * Author: Sarah Sharp
+ * Some code borrowed from the Linux EHCI driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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_XHCI_HCD_H
+#define __LINUX_XHCI_HCD_H
+
+#include <linux/usb.h>
+#include <linux/timer.h>
+
+#include "../core/hcd.h"
+/* Code sharing between pci-quirks and xhci hcd */
+#include       "xhci-ext-caps.h"
+
+/* xHCI PCI Configuration Registers */
+#define XHCI_SBRN_OFFSET       (0x60)
+
+/* Max number of USB devices for any host controller - limit in section 6.1 */
+#define MAX_HC_SLOTS           256
+/* Section 5.3.3 - MaxPorts */
+#define MAX_HC_PORTS           127
+
+/*
+ * xHCI register interface.
+ * This corresponds to the eXtensible Host Controller Interface (xHCI)
+ * Revision 0.95 specification
+ *
+ * Registers should always be accessed with double word or quad word accesses.
+ *
+ * Some xHCI implementations may support 64-bit address pointers.  Registers
+ * with 64-bit address pointers should be written to with dword accesses by
+ * writing the low dword first (ptr[0]), then the high dword (ptr[1]) second.
+ * xHCI implementations that do not support 64-bit address pointers will ignore
+ * the high dword, and write order is irrelevant.
+ */
+
+/**
+ * struct xhci_cap_regs - xHCI Host Controller Capability Registers.
+ * @hc_capbase:                length of the capabilities register and HC version number
+ * @hcs_params1:       HCSPARAMS1 - Structural Parameters 1
+ * @hcs_params2:       HCSPARAMS2 - Structural Parameters 2
+ * @hcs_params3:       HCSPARAMS3 - Structural Parameters 3
+ * @hcc_params:                HCCPARAMS - Capability Parameters
+ * @db_off:            DBOFF - Doorbell array offset
+ * @run_regs_off:      RTSOFF - Runtime register space offset
+ */
+struct xhci_cap_regs {
+       u32     hc_capbase;
+       u32     hcs_params1;
+       u32     hcs_params2;
+       u32     hcs_params3;
+       u32     hcc_params;
+       u32     db_off;
+       u32     run_regs_off;
+       /* Reserved up to (CAPLENGTH - 0x1C) */
+};
+
+/* hc_capbase bitmasks */
+/* bits 7:0 - how long is the Capabilities register */
+#define HC_LENGTH(p)           XHCI_HC_LENGTH(p)
+/* bits 31:16  */
+#define HC_VERSION(p)          (((p) >> 16) & 0xffff)
+
+/* HCSPARAMS1 - hcs_params1 - bitmasks */
+/* bits 0:7, Max Device Slots */
+#define HCS_MAX_SLOTS(p)       (((p) >> 0) & 0xff)
+#define HCS_SLOTS_MASK         0xff
+/* bits 8:18, Max Interrupters */
+#define HCS_MAX_INTRS(p)       (((p) >> 8) & 0x7ff)
+/* bits 24:31, Max Ports - max value is 0x7F = 127 ports */
+#define HCS_MAX_PORTS(p)       (((p) >> 24) & 0x7f)
+
+/* HCSPARAMS2 - hcs_params2 - bitmasks */
+/* bits 0:3, frames or uframes that SW needs to queue transactions
+ * ahead of the HW to meet periodic deadlines */
+#define HCS_IST(p)             (((p) >> 0) & 0xf)
+/* bits 4:7, max number of Event Ring segments */
+#define HCS_ERST_MAX(p)                (((p) >> 4) & 0xf)
+/* bit 26 Scratchpad restore - for save/restore HW state - not used yet */
+/* bits 27:31 number of Scratchpad buffers SW must allocate for the HW */
+
+/* HCSPARAMS3 - hcs_params3 - bitmasks */
+/* bits 0:7, Max U1 to U0 latency for the roothub ports */
+#define HCS_U1_LATENCY(p)      (((p) >> 0) & 0xff)
+/* bits 16:31, Max U2 to U0 latency for the roothub ports */
+#define HCS_U2_LATENCY(p)      (((p) >> 16) & 0xffff)
+
+/* HCCPARAMS - hcc_params - bitmasks */
+/* true: HC can use 64-bit address pointers */
+#define HCC_64BIT_ADDR(p)      ((p) & (1 << 0))
+/* true: HC can do bandwidth negotiation */
+#define HCC_BANDWIDTH_NEG(p)   ((p) & (1 << 1))
+/* true: HC uses 64-byte Device Context structures
+ * FIXME 64-byte context structures aren't supported yet.
+ */
+#define HCC_64BYTE_CONTEXT(p)  ((p) & (1 << 2))
+/* true: HC has port power switches */
+#define HCC_PPC(p)             ((p) & (1 << 3))
+/* true: HC has port indicators */
+#define HCS_INDICATOR(p)       ((p) & (1 << 4))
+/* true: HC has Light HC Reset Capability */
+#define HCC_LIGHT_RESET(p)     ((p) & (1 << 5))
+/* true: HC supports latency tolerance messaging */
+#define HCC_LTC(p)             ((p) & (1 << 6))
+/* true: no secondary Stream ID Support */
+#define HCC_NSS(p)             ((p) & (1 << 7))
+/* Max size for Primary Stream Arrays - 2^(n+1), where n is bits 12:15 */
+#define HCC_MAX_PSA            (1 << ((((p) >> 12) & 0xf) + 1))
+/* Extended Capabilities pointer from PCI base - section 5.3.6 */
+#define HCC_EXT_CAPS(p)                XHCI_HCC_EXT_CAPS(p)
+
+/* db_off bitmask - bits 0:1 reserved */
+#define        DBOFF_MASK      (~0x3)
+
+/* run_regs_off bitmask - bits 0:4 reserved */
+#define        RTSOFF_MASK     (~0x1f)
+
+
+/* Number of registers per port */
+#define        NUM_PORT_REGS   4
+
+/**
+ * struct xhci_op_regs - xHCI Host Controller Operational Registers.
+ * @command:           USBCMD - xHC command register
+ * @status:            USBSTS - xHC status register
+ * @page_size:         This indicates the page size that the host controller
+ *                     supports.  If bit n is set, the HC supports a page size
+ *                     of 2^(n+12), up to a 128MB page size.
+ *                     4K is the minimum page size.
+ * @cmd_ring:          CRP - 64-bit Command Ring Pointer
+ * @dcbaa_ptr:         DCBAAP - 64-bit Device Context Base Address Array Pointer
+ * @config_reg:                CONFIG - Configure Register
+ * @port_status_base:  PORTSCn - base address for Port Status and Control
+ *                     Each port has a Port Status and Control register,
+ *                     followed by a Port Power Management Status and Control
+ *                     register, a Port Link Info register, and a reserved
+ *                     register.
+ * @port_power_base:   PORTPMSCn - base address for
+ *                     Port Power Management Status and Control
+ * @port_link_base:    PORTLIn - base address for Port Link Info (current
+ *                     Link PM state and control) for USB 2.1 and USB 3.0
+ *                     devices.
+ */
+struct xhci_op_regs {
+       u32     command;
+       u32     status;
+       u32     page_size;
+       u32     reserved1;
+       u32     reserved2;
+       u32     dev_notification;
+       u32     cmd_ring[2];
+       /* rsvd: offset 0x20-2F */
+       u32     reserved3[4];
+       u32     dcbaa_ptr[2];
+       u32     config_reg;
+       /* rsvd: offset 0x3C-3FF */
+       u32     reserved4[241];
+       /* port 1 registers, which serve as a base address for other ports */
+       u32     port_status_base;
+       u32     port_power_base;
+       u32     port_link_base;
+       u32     reserved5;
+       /* registers for ports 2-255 */
+       u32     reserved6[NUM_PORT_REGS*254];
+};
+
+/* USBCMD - USB command - command bitmasks */
+/* start/stop HC execution - do not write unless HC is halted*/
+#define CMD_RUN                XHCI_CMD_RUN
+/* Reset HC - resets internal HC state machine and all registers (except
+ * PCI config regs).  HC does NOT drive a USB reset on the downstream ports.
+ * The xHCI driver must reinitialize the xHC after setting this bit.
+ */
+#define CMD_RESET      (1 << 1)
+/* Event Interrupt Enable - a '1' allows interrupts from the host controller */
+#define CMD_EIE                XHCI_CMD_EIE
+/* Host System Error Interrupt Enable - get out-of-band signal for HC errors */
+#define CMD_HSEIE      XHCI_CMD_HSEIE
+/* bits 4:6 are reserved (and should be preserved on writes). */
+/* light reset (port status stays unchanged) - reset completed when this is 0 */
+#define CMD_LRESET     (1 << 7)
+/* FIXME: ignoring host controller save/restore state for now. */
+#define CMD_CSS                (1 << 8)
+#define CMD_CRS                (1 << 9)
+/* Enable Wrap Event - '1' means xHC generates an event when MFINDEX wraps. */
+#define CMD_EWE                XHCI_CMD_EWE
+/* MFINDEX power management - '1' means xHC can stop MFINDEX counter if all root
+ * hubs are in U3 (selective suspend), disconnect, disabled, or powered-off.
+ * '0' means the xHC can power it off if all ports are in the disconnect,
+ * disabled, or powered-off state.
+ */
+#define CMD_PM_INDEX   (1 << 11)
+/* bits 12:31 are reserved (and should be preserved on writes). */
+
+/* USBSTS - USB status - status bitmasks */
+/* HC not running - set to 1 when run/stop bit is cleared. */
+#define STS_HALT       XHCI_STS_HALT
+/* serious error, e.g. PCI parity error.  The HC will clear the run/stop bit. */
+#define STS_FATAL      (1 << 2)
+/* event interrupt - clear this prior to clearing any IP flags in IR set*/
+#define STS_EINT       (1 << 3)
+/* port change detect */
+#define STS_PORT       (1 << 4)
+/* bits 5:7 reserved and zeroed */
+/* save state status - '1' means xHC is saving state */
+#define STS_SAVE       (1 << 8)
+/* restore state status - '1' means xHC is restoring state */
+#define STS_RESTORE    (1 << 9)
+/* true: save or restore error */
+#define STS_SRE                (1 << 10)
+/* true: Controller Not Ready to accept doorbell or op reg writes after reset */
+#define STS_CNR                XHCI_STS_CNR
+/* true: internal Host Controller Error - SW needs to reset and reinitialize */
+#define STS_HCE                (1 << 12)
+/* bits 13:31 reserved and should be preserved */
+
+/*
+ * DNCTRL - Device Notification Control Register - dev_notification bitmasks
+ * Generate a device notification event when the HC sees a transaction with a
+ * notification type that matches a bit set in this bit field.
+ */
+#define        DEV_NOTE_MASK           (0xffff)
+#define ENABLE_DEV_NOTE(x)     (1 << x)
+/* Most of the device notification types should only be used for debug.
+ * SW does need to pay attention to function wake notifications.
+ */
+#define        DEV_NOTE_FWAKE          ENABLE_DEV_NOTE(1)
+
+/* CRCR - Command Ring Control Register - cmd_ring bitmasks */
+/* bit 0 is the command ring cycle state */
+/* stop ring operation after completion of the currently executing command */
+#define CMD_RING_PAUSE         (1 << 1)
+/* stop ring immediately - abort the currently executing command */
+#define CMD_RING_ABORT         (1 << 2)
+/* true: command ring is running */
+#define CMD_RING_RUNNING       (1 << 3)
+/* bits 4:5 reserved and should be preserved */
+/* Command Ring pointer - bit mask for the lower 32 bits. */
+#define CMD_RING_ADDR_MASK     (0xffffffc0)
+
+/* CONFIG - Configure Register - config_reg bitmasks */
+/* bits 0:7 - maximum number of device slots enabled (NumSlotsEn) */
+#define MAX_DEVS(p)    ((p) & 0xff)
+/* bits 8:31 - reserved and should be preserved */
+
+/* PORTSC - Port Status and Control Register - port_status_base bitmasks */
+/* true: device connected */
+#define PORT_CONNECT   (1 << 0)
+/* true: port enabled */
+#define PORT_PE                (1 << 1)
+/* bit 2 reserved and zeroed */
+/* true: port has an over-current condition */
+#define PORT_OC                (1 << 3)
+/* true: port reset signaling asserted */
+#define PORT_RESET     (1 << 4)
+/* Port Link State - bits 5:8
+ * A read gives the current link PM state of the port,
+ * a write with Link State Write Strobe set sets the link state.
+ */
+/* true: port has power (see HCC_PPC) */
+#define PORT_POWER     (1 << 9)
+/* bits 10:13 indicate device speed:
+ * 0 - undefined speed - port hasn't be initialized by a reset yet
+ * 1 - full speed
+ * 2 - low speed
+ * 3 - high speed
+ * 4 - super speed
+ * 5-15 reserved
+ */
+#define DEV_SPEED_MASK         (0xf << 10)
+#define        XDEV_FS                 (0x1 << 10)
+#define        XDEV_LS                 (0x2 << 10)
+#define        XDEV_HS                 (0x3 << 10)
+#define        XDEV_SS                 (0x4 << 10)
+#define DEV_UNDEFSPEED(p)      (((p) & DEV_SPEED_MASK) == (0x0<<10))
+#define DEV_FULLSPEED(p)       (((p) & DEV_SPEED_MASK) == XDEV_FS)
+#define DEV_LOWSPEED(p)                (((p) & DEV_SPEED_MASK) == XDEV_LS)
+#define DEV_HIGHSPEED(p)       (((p) & DEV_SPEED_MASK) == XDEV_HS)
+#define DEV_SUPERSPEED(p)      (((p) & DEV_SPEED_MASK) == XDEV_SS)
+/* Bits 20:23 in the Slot Context are the speed for the device */
+#define        SLOT_SPEED_FS           (XDEV_FS << 10)
+#define        SLOT_SPEED_LS           (XDEV_LS << 10)
+#define        SLOT_SPEED_HS           (XDEV_HS << 10)
+#define        SLOT_SPEED_SS           (XDEV_SS << 10)
+/* Port Indicator Control */
+#define PORT_LED_OFF   (0 << 14)
+#define PORT_LED_AMBER (1 << 14)
+#define PORT_LED_GREEN (2 << 14)
+#define PORT_LED_MASK  (3 << 14)
+/* Port Link State Write Strobe - set this when changing link state */
+#define PORT_LINK_STROBE       (1 << 16)
+/* true: connect status change */
+#define PORT_CSC       (1 << 17)
+/* true: port enable change */
+#define PORT_PEC       (1 << 18)
+/* true: warm reset for a USB 3.0 device is done.  A "hot" reset puts the port
+ * into an enabled state, and the device into the default state.  A "warm" reset
+ * also resets the link, forcing the device through the link training sequence.
+ * SW can also look at the Port Reset register to see when warm reset is done.
+ */
+#define PORT_WRC       (1 << 19)
+/* true: over-current change */
+#define PORT_OCC       (1 << 20)
+/* true: reset change - 1 to 0 transition of PORT_RESET */
+#define PORT_RC                (1 << 21)
+/* port link status change - set on some port link state transitions:
+ *  Transition                         Reason
+ *  ------------------------------------------------------------------------------
+ *  - U3 to Resume                     Wakeup signaling from a device
+ *  - Resume to Recovery to U0         USB 3.0 device resume
+ *  - Resume to U0                     USB 2.0 device resume
+ *  - U3 to Recovery to U0             Software resume of USB 3.0 device complete
+ *  - U3 to U0                         Software resume of USB 2.0 device complete
+ *  - U2 to U0                         L1 resume of USB 2.1 device complete
+ *  - U0 to U0 (???)                   L1 entry rejection by USB 2.1 device
+ *  - U0 to disabled                   L1 entry error with USB 2.1 device
+ *  - Any state to inactive            Error on USB 3.0 port
+ */
+#define PORT_PLC       (1 << 22)
+/* port configure error change - port failed to configure its link partner */
+#define PORT_CEC       (1 << 23)
+/* bit 24 reserved */
+/* wake on connect (enable) */
+#define PORT_WKCONN_E  (1 << 25)
+/* wake on disconnect (enable) */
+#define PORT_WKDISC_E  (1 << 26)
+/* wake on over-current (enable) */
+#define PORT_WKOC_E    (1 << 27)
+/* bits 28:29 reserved */
+/* true: device is removable - for USB 3.0 roothub emulation */
+#define PORT_DEV_REMOVE        (1 << 30)
+/* Initiate a warm port reset - complete when PORT_WRC is '1' */
+#define PORT_WR                (1 << 31)
+
+/* Port Power Management Status and Control - port_power_base bitmasks */
+/* Inactivity timer value for transitions into U1, in microseconds.
+ * Timeout can be up to 127us.  0xFF means an infinite timeout.
+ */
+#define PORT_U1_TIMEOUT(p)     ((p) & 0xff)
+/* Inactivity timer value for transitions into U2 */
+#define PORT_U2_TIMEOUT(p)     (((p) & 0xff) << 8)
+/* Bits 24:31 for port testing */
+
+
+/**
+ * struct xhci_intr_reg - Interrupt Register Set
+ * @irq_pending:       IMAN - Interrupt Management Register.  Used to enable
+ *                     interrupts and check for pending interrupts.
+ * @irq_control:       IMOD - Interrupt Moderation Register.
+ *                     Used to throttle interrupts.
+ * @erst_size:         Number of segments in the Event Ring Segment Table (ERST).
+ * @erst_base:         ERST base address.
+ * @erst_dequeue:      Event ring dequeue pointer.
+ *
+ * Each interrupter (defined by a MSI-X vector) has an event ring and an Event
+ * Ring Segment Table (ERST) associated with it.  The event ring is comprised of
+ * multiple segments of the same size.  The HC places events on the ring and
+ * "updates the Cycle bit in the TRBs to indicate to software the current
+ * position of the Enqueue Pointer." The HCD (Linux) processes those events and
+ * updates the dequeue pointer.
+ */
+struct xhci_intr_reg {
+       u32     irq_pending;
+       u32     irq_control;
+       u32     erst_size;
+       u32     rsvd;
+       u32     erst_base[2];
+       u32     erst_dequeue[2];
+};
+
+/* irq_pending bitmasks */
+#define        ER_IRQ_PENDING(p)       ((p) & 0x1)
+/* bits 2:31 need to be preserved */
+/* THIS IS BUGGY - FIXME - IP IS WRITE 1 TO CLEAR */
+#define        ER_IRQ_CLEAR(p)         ((p) & 0xfffffffe)
+#define        ER_IRQ_ENABLE(p)        ((ER_IRQ_CLEAR(p)) | 0x2)
+#define        ER_IRQ_DISABLE(p)       ((ER_IRQ_CLEAR(p)) & ~(0x2))
+
+/* irq_control bitmasks */
+/* Minimum interval between interrupts (in 250ns intervals).  The interval
+ * between interrupts will be longer if there are no events on the event ring.
+ * Default is 4000 (1 ms).
+ */
+#define ER_IRQ_INTERVAL_MASK   (0xffff)
+/* Counter used to count down the time to the next interrupt - HW use only */
+#define ER_IRQ_COUNTER_MASK    (0xffff << 16)
+
+/* erst_size bitmasks */
+/* Preserve bits 16:31 of erst_size */
+#define        ERST_SIZE_MASK          (0xffff << 16)
+
+/* erst_dequeue bitmasks */
+/* Dequeue ERST Segment Index (DESI) - Segment number (or alias)
+ * where the current dequeue pointer lies.  This is an optional HW hint.
+ */
+#define ERST_DESI_MASK         (0x7)
+/* Event Handler Busy (EHB) - is the event ring scheduled to be serviced by
+ * a work queue (or delayed service routine)?
+ */
+#define ERST_EHB               (1 << 3)
+#define ERST_PTR_MASK          (0xf)
+
+/**
+ * struct xhci_run_regs
+ * @microframe_index:
+ *             MFINDEX - current microframe number
+ *
+ * Section 5.5 Host Controller Runtime Registers:
+ * "Software should read and write these registers using only Dword (32 bit)
+ * or larger accesses"
+ */
+struct xhci_run_regs {
+       u32                     microframe_index;
+       u32                     rsvd[7];
+       struct xhci_intr_reg    ir_set[128];
+};
+
+/**
+ * struct doorbell_array
+ *
+ * Section 5.6
+ */
+struct xhci_doorbell_array {
+       u32     doorbell[256];
+};
+
+#define        DB_TARGET_MASK          0xFFFFFF00
+#define        DB_STREAM_ID_MASK       0x0000FFFF
+#define        DB_TARGET_HOST          0x0
+#define        DB_STREAM_ID_HOST       0x0
+#define        DB_MASK                 (0xff << 8)
+
+/* Endpoint Target - bits 0:7 */
+#define EPI_TO_DB(p)           (((p) + 1) & 0xff)
+
+
+/**
+ * struct xhci_slot_ctx
+ * @dev_info:  Route string, device speed, hub info, and last valid endpoint
+ * @dev_info2: Max exit latency for device number, root hub port number
+ * @tt_info:   tt_info is used to construct split transaction tokens
+ * @dev_state: slot state and device address
+ *
+ * Slot Context - section 6.2.1.1.  This assumes the HC uses 32-byte context
+ * structures.  If the HC uses 64-byte contexts, there is an additional 32 bytes
+ * reserved at the end of the slot context for HC internal use.
+ */
+struct xhci_slot_ctx {
+       u32     dev_info;
+       u32     dev_info2;
+       u32     tt_info;
+       u32     dev_state;
+       /* offset 0x10 to 0x1f reserved for HC internal use */
+       u32     reserved[4];
+};
+
+/* dev_info bitmasks */
+/* Route String - 0:19 */
+#define ROUTE_STRING_MASK      (0xfffff)
+/* Device speed - values defined by PORTSC Device Speed field - 20:23 */
+#define DEV_SPEED      (0xf << 20)
+/* bit 24 reserved */
+/* Is this LS/FS device connected through a HS hub? - bit 25 */
+#define DEV_MTT                (0x1 << 25)
+/* Set if the device is a hub - bit 26 */
+#define DEV_HUB                (0x1 << 26)
+/* Index of the last valid endpoint context in this device context - 27:31 */
+#define LAST_CTX_MASK  (0x1f << 27)
+#define LAST_CTX(p)    ((p) << 27)
+#define LAST_CTX_TO_EP_NUM(p)  (((p) >> 27) - 1)
+#define SLOT_FLAG      (1 << 0)
+#define EP0_FLAG       (1 << 1)
+
+/* dev_info2 bitmasks */
+/* Max Exit Latency (ms) - worst case time to wake up all links in dev path */
+#define MAX_EXIT       (0xffff)
+/* Root hub port number that is needed to access the USB device */
+#define ROOT_HUB_PORT(p)       (((p) & 0xff) << 16)
+
+/* tt_info bitmasks */
+/*
+ * TT Hub Slot ID - for low or full speed devices attached to a high-speed hub
+ * The Slot ID of the hub that isolates the high speed signaling from
+ * this low or full-speed device.  '0' if attached to root hub port.
+ */
+#define TT_SLOT                (0xff)
+/*
+ * The number of the downstream facing port of the high-speed hub
+ * '0' if the device is not low or full speed.
+ */
+#define TT_PORT                (0xff << 8)
+
+/* dev_state bitmasks */
+/* USB device address - assigned by the HC */
+#define DEV_ADDR_MASK  (0xff)
+/* bits 8:26 reserved */
+/* Slot state */
+#define SLOT_STATE     (0x1f << 27)
+#define GET_SLOT_STATE(p)      (((p) & (0x1f << 27)) >> 27)
+
+
+/**
+ * struct xhci_ep_ctx
+ * @ep_info:   endpoint state, streams, mult, and interval information.
+ * @ep_info2:  information on endpoint type, max packet size, max burst size,
+ *             error count, and whether the HC will force an event for all
+ *             transactions.
+ * @deq:       64-bit ring dequeue pointer address.  If the endpoint only
+ *             defines one stream, this points to the endpoint transfer ring.
+ *             Otherwise, it points to a stream context array, which has a
+ *             ring pointer for each flow.
+ * @tx_info:
+ *             Average TRB lengths for the endpoint ring and
+ *             max payload within an Endpoint Service Interval Time (ESIT).
+ *
+ * Endpoint Context - section 6.2.1.2.  This assumes the HC uses 32-byte context
+ * structures.  If the HC uses 64-byte contexts, there is an additional 32 bytes
+ * reserved at the end of the endpoint context for HC internal use.
+ */
+struct xhci_ep_ctx {
+       u32     ep_info;
+       u32     ep_info2;
+       u32     deq[2];
+       u32     tx_info;
+       /* offset 0x14 - 0x1f reserved for HC internal use */
+       u32     reserved[3];
+};
+
+/* ep_info bitmasks */
+/*
+ * Endpoint State - bits 0:2
+ * 0 - disabled
+ * 1 - running
+ * 2 - halted due to halt condition - ok to manipulate endpoint ring
+ * 3 - stopped
+ * 4 - TRB error
+ * 5-7 - reserved
+ */
+#define EP_STATE_MASK          (0xf)
+#define EP_STATE_DISABLED      0
+#define EP_STATE_RUNNING       1
+#define EP_STATE_HALTED                2
+#define EP_STATE_STOPPED       3
+#define EP_STATE_ERROR         4
+/* Mult - Max number of burtst within an interval, in EP companion desc. */
+#define EP_MULT(p)             ((p & 0x3) << 8)
+/* bits 10:14 are Max Primary Streams */
+/* bit 15 is Linear Stream Array */
+/* Interval - period between requests to an endpoint - 125u increments. */
+#define EP_INTERVAL(p)         ((p & 0xff) << 16)
+
+/* ep_info2 bitmasks */
+/*
+ * Force Event - generate transfer events for all TRBs for this endpoint
+ * This will tell the HC to ignore the IOC and ISP flags (for debugging only).
+ */
+#define        FORCE_EVENT     (0x1)
+#define ERROR_COUNT(p) (((p) & 0x3) << 1)
+#define EP_TYPE(p)     ((p) << 3)
+#define ISOC_OUT_EP    1
+#define BULK_OUT_EP    2
+#define INT_OUT_EP     3
+#define CTRL_EP                4
+#define ISOC_IN_EP     5
+#define BULK_IN_EP     6
+#define INT_IN_EP      7
+/* bit 6 reserved */
+/* bit 7 is Host Initiate Disable - for disabling stream selection */
+#define MAX_BURST(p)   (((p)&0xff) << 8)
+#define MAX_PACKET(p)  (((p)&0xffff) << 16)
+
+
+/**
+ * struct xhci_device_control
+ * Input/Output context; see section 6.2.5.
+ *
+ * @drop_context:      set the bit of the endpoint context you want to disable
+ * @add_context:       set the bit of the endpoint context you want to enable
+ */
+struct xhci_device_control {
+       u32     drop_flags;
+       u32     add_flags;
+       u32     rsvd[6];
+       struct xhci_slot_ctx    slot;
+       struct xhci_ep_ctx      ep[31];
+};
+
+/* drop context bitmasks */
+#define        DROP_EP(x)      (0x1 << x)
+/* add context bitmasks */
+#define        ADD_EP(x)       (0x1 << x)
+
+
+struct xhci_virt_device {
+       /*
+        * Commands to the hardware are passed an "input context" that
+        * tells the hardware what to change in its data structures.
+        * The hardware will return changes in an "output context" that
+        * software must allocate for the hardware.  We need to keep
+        * track of input and output contexts separately because
+        * these commands might fail and we don't trust the hardware.
+        */
+       struct xhci_device_control      *out_ctx;
+       dma_addr_t                      out_ctx_dma;
+       /* Used for addressing devices and configuration changes */
+       struct xhci_device_control      *in_ctx;
+       dma_addr_t                      in_ctx_dma;
+       /* FIXME when stream support is added */
+       struct xhci_ring                *ep_rings[31];
+       /* Temporary storage in case the configure endpoint command fails and we
+        * have to restore the device state to the previous state
+        */
+       struct xhci_ring                *new_ep_rings[31];
+       struct completion               cmd_completion;
+       /* Status of the last command issued for this device */
+       u32                             cmd_status;
+};
+
+
+/**
+ * struct xhci_device_context_array
+ * @dev_context_ptr    array of 64-bit DMA addresses for device contexts
+ */
+struct xhci_device_context_array {
+       /* 64-bit device addresses; we only write 32-bit addresses */
+       u32                     dev_context_ptrs[2*MAX_HC_SLOTS];
+       /* private xHCD pointers */
+       dma_addr_t      dma;
+};
+/* TODO: write function to set the 64-bit device DMA address */
+/*
+ * TODO: change this to be dynamically sized at HC mem init time since the HC
+ * might not be able to handle the maximum number of devices possible.
+ */
+
+
+struct xhci_stream_ctx {
+       /* 64-bit stream ring address, cycle state, and stream type */
+       u32     stream_ring[2];
+       /* offset 0x14 - 0x1f reserved for HC internal use */
+       u32     reserved[2];
+};
+
+
+struct xhci_transfer_event {
+       /* 64-bit buffer address, or immediate data */
+       u32     buffer[2];
+       u32     transfer_len;
+       /* This field is interpreted differently based on the type of TRB */
+       u32     flags;
+};
+
+/** Transfer Event bit fields **/
+#define        TRB_TO_EP_ID(p) (((p) >> 16) & 0x1f)
+
+/* Completion Code - only applicable for some types of TRBs */
+#define        COMP_CODE_MASK          (0xff << 24)
+#define GET_COMP_CODE(p)       (((p) & COMP_CODE_MASK) >> 24)
+#define COMP_SUCCESS   1
+/* Data Buffer Error */
+#define COMP_DB_ERR    2
+/* Babble Detected Error */
+#define COMP_BABBLE    3
+/* USB Transaction Error */
+#define COMP_TX_ERR    4
+/* TRB Error - some TRB field is invalid */
+#define COMP_TRB_ERR   5
+/* Stall Error - USB device is stalled */
+#define COMP_STALL     6
+/* Resource Error - HC doesn't have memory for that device configuration */
+#define COMP_ENOMEM    7
+/* Bandwidth Error - not enough room in schedule for this dev config */
+#define COMP_BW_ERR    8
+/* No Slots Available Error - HC ran out of device slots */
+#define COMP_ENOSLOTS  9
+/* Invalid Stream Type Error */
+#define COMP_STREAM_ERR        10
+/* Slot Not Enabled Error - doorbell rung for disabled device slot */
+#define COMP_EBADSLT   11
+/* Endpoint Not Enabled Error */
+#define COMP_EBADEP    12
+/* Short Packet */
+#define COMP_SHORT_TX  13
+/* Ring Underrun - doorbell rung for an empty isoc OUT ep ring */
+#define COMP_UNDERRUN  14
+/* Ring Overrun - isoc IN ep ring is empty when ep is scheduled to RX */
+#define COMP_OVERRUN   15
+/* Virtual Function Event Ring Full Error */
+#define COMP_VF_FULL   16
+/* Parameter Error - Context parameter is invalid */
+#define COMP_EINVAL    17
+/* Bandwidth Overrun Error - isoc ep exceeded its allocated bandwidth */
+#define COMP_BW_OVER   18
+/* Context State Error - illegal context state transition requested */
+#define COMP_CTX_STATE 19
+/* No Ping Response Error - HC didn't get PING_RESPONSE in time to TX */
+#define COMP_PING_ERR  20
+/* Event Ring is full */
+#define COMP_ER_FULL   21
+/* Missed Service Error - HC couldn't service an isoc ep within interval */
+#define COMP_MISSED_INT        23
+/* Successfully stopped command ring */
+#define COMP_CMD_STOP  24
+/* Successfully aborted current command and stopped command ring */
+#define COMP_CMD_ABORT 25
+/* Stopped - transfer was terminated by a stop endpoint command */
+#define COMP_STOP      26
+/* Same as COMP_EP_STOPPED, but the transfered length in the event is invalid */
+#define COMP_STOP_INVAL        27
+/* Control Abort Error - Debug Capability - control pipe aborted */
+#define COMP_DBG_ABORT 28
+/* TRB type 29 and 30 reserved */
+/* Isoc Buffer Overrun - an isoc IN ep sent more data than could fit in TD */
+#define COMP_BUFF_OVER 31
+/* Event Lost Error - xHC has an "internal event overrun condition" */
+#define COMP_ISSUES    32
+/* Undefined Error - reported when other error codes don't apply */
+#define COMP_UNKNOWN   33
+/* Invalid Stream ID Error */
+#define COMP_STRID_ERR 34
+/* Secondary Bandwidth Error - may be returned by a Configure Endpoint cmd */
+/* FIXME - check for this */
+#define COMP_2ND_BW_ERR        35
+/* Split Transaction Error */
+#define        COMP_SPLIT_ERR  36
+
+struct xhci_link_trb {
+       /* 64-bit segment pointer*/
+       u32 segment_ptr[2];
+       u32 intr_target;
+       u32 control;
+};
+
+/* control bitfields */
+#define LINK_TOGGLE    (0x1<<1)
+
+/* Command completion event TRB */
+struct xhci_event_cmd {
+       /* Pointer to command TRB, or the value passed by the event data trb */
+       u32 cmd_trb[2];
+       u32 status;
+       u32 flags;
+};
+
+/* flags bitmasks */
+/* bits 16:23 are the virtual function ID */
+/* bits 24:31 are the slot ID */
+#define TRB_TO_SLOT_ID(p)      (((p) & (0xff<<24)) >> 24)
+#define SLOT_ID_FOR_TRB(p)     (((p) & 0xff) << 24)
+
+/* Stop Endpoint TRB - ep_index to endpoint ID for this TRB */
+#define TRB_TO_EP_INDEX(p)             ((((p) & (0x1f << 16)) >> 16) - 1)
+#define        EP_ID_FOR_TRB(p)                ((((p) + 1) & 0x1f) << 16)
+
+
+/* Port Status Change Event TRB fields */
+/* Port ID - bits 31:24 */
+#define GET_PORT_ID(p)         (((p) & (0xff << 24)) >> 24)
+
+/* Normal TRB fields */
+/* transfer_len bitmasks - bits 0:16 */
+#define        TRB_LEN(p)              ((p) & 0x1ffff)
+/* TD size - number of bytes remaining in the TD (including this TRB):
+ * bits 17 - 21.  Shift the number of bytes by 10. */
+#define TD_REMAINDER(p)                ((((p) >> 10) & 0x1f) << 17)
+/* Interrupter Target - which MSI-X vector to target the completion event at */
+#define TRB_INTR_TARGET(p)     (((p) & 0x3ff) << 22)
+#define GET_INTR_TARGET(p)     (((p) >> 22) & 0x3ff)
+
+/* Cycle bit - indicates TRB ownership by HC or HCD */
+#define TRB_CYCLE              (1<<0)
+/*
+ * Force next event data TRB to be evaluated before task switch.
+ * Used to pass OS data back after a TD completes.
+ */
+#define TRB_ENT                        (1<<1)
+/* Interrupt on short packet */
+#define TRB_ISP                        (1<<2)
+/* Set PCIe no snoop attribute */
+#define TRB_NO_SNOOP           (1<<3)
+/* Chain multiple TRBs into a TD */
+#define TRB_CHAIN              (1<<4)
+/* Interrupt on completion */
+#define TRB_IOC                        (1<<5)
+/* The buffer pointer contains immediate data */
+#define TRB_IDT                        (1<<6)
+
+
+/* Control transfer TRB specific fields */
+#define TRB_DIR_IN             (1<<16)
+
+struct xhci_generic_trb {
+       u32 field[4];
+};
+
+union xhci_trb {
+       struct xhci_link_trb            link;
+       struct xhci_transfer_event      trans_event;
+       struct xhci_event_cmd           event_cmd;
+       struct xhci_generic_trb         generic;
+};
+
+/* TRB bit mask */
+#define        TRB_TYPE_BITMASK        (0xfc00)
+#define TRB_TYPE(p)            ((p) << 10)
+/* TRB type IDs */
+/* bulk, interrupt, isoc scatter/gather, and control data stage */
+#define TRB_NORMAL             1
+/* setup stage for control transfers */
+#define TRB_SETUP              2
+/* data stage for control transfers */
+#define TRB_DATA               3
+/* status stage for control transfers */
+#define TRB_STATUS             4
+/* isoc transfers */
+#define TRB_ISOC               5
+/* TRB for linking ring segments */
+#define TRB_LINK               6
+#define TRB_EVENT_DATA         7
+/* Transfer Ring No-op (not for the command ring) */
+#define TRB_TR_NOOP            8
+/* Command TRBs */
+/* Enable Slot Command */
+#define TRB_ENABLE_SLOT                9
+/* Disable Slot Command */
+#define TRB_DISABLE_SLOT       10
+/* Address Device Command */
+#define TRB_ADDR_DEV           11
+/* Configure Endpoint Command */
+#define TRB_CONFIG_EP          12
+/* Evaluate Context Command */
+#define TRB_EVAL_CONTEXT       13
+/* Reset Transfer Ring Command */
+#define TRB_RESET_RING         14
+/* Stop Transfer Ring Command */
+#define TRB_STOP_RING          15
+/* Set Transfer Ring Dequeue Pointer Command */
+#define TRB_SET_DEQ            16
+/* Reset Device Command */
+#define TRB_RESET_DEV          17
+/* Force Event Command (opt) */
+#define TRB_FORCE_EVENT                18
+/* Negotiate Bandwidth Command (opt) */
+#define TRB_NEG_BANDWIDTH      19
+/* Set Latency Tolerance Value Command (opt) */
+#define TRB_SET_LT             20
+/* Get port bandwidth Command */
+#define TRB_GET_BW             21
+/* Force Header Command - generate a transaction or link management packet */
+#define TRB_FORCE_HEADER       22
+/* No-op Command - not for transfer rings */
+#define TRB_CMD_NOOP           23
+/* TRB IDs 24-31 reserved */
+/* Event TRBS */
+/* Transfer Event */
+#define TRB_TRANSFER           32
+/* Command Completion Event */
+#define TRB_COMPLETION         33
+/* Port Status Change Event */
+#define TRB_PORT_STATUS                34
+/* Bandwidth Request Event (opt) */
+#define TRB_BANDWIDTH_EVENT    35
+/* Doorbell Event (opt) */
+#define TRB_DOORBELL           36
+/* Host Controller Event */
+#define TRB_HC_EVENT           37
+/* Device Notification Event - device sent function wake notification */
+#define TRB_DEV_NOTE           38
+/* MFINDEX Wrap Event - microframe counter wrapped */
+#define TRB_MFINDEX_WRAP       39
+/* TRB IDs 40-47 reserved, 48-63 is vendor-defined */
+
+/*
+ * TRBS_PER_SEGMENT must be a multiple of 4,
+ * since the command ring is 64-byte aligned.
+ * It must also be greater than 16.
+ */
+#define TRBS_PER_SEGMENT       64
+#define SEGMENT_SIZE           (TRBS_PER_SEGMENT*16)
+/* TRB buffer pointers can't cross 64KB boundaries */
+#define TRB_MAX_BUFF_SHIFT             16
+#define TRB_MAX_BUFF_SIZE      (1 << TRB_MAX_BUFF_SHIFT)
+
+struct xhci_segment {
+       union xhci_trb          *trbs;
+       /* private to HCD */
+       struct xhci_segment     *next;
+       dma_addr_t              dma;
+};
+
+struct xhci_td {
+       struct list_head        td_list;
+       struct list_head        cancelled_td_list;
+       struct urb              *urb;
+       struct xhci_segment     *start_seg;
+       union xhci_trb          *first_trb;
+       union xhci_trb          *last_trb;
+};
+
+struct xhci_ring {
+       struct xhci_segment     *first_seg;
+       union  xhci_trb         *enqueue;
+       struct xhci_segment     *enq_seg;
+       unsigned int            enq_updates;
+       union  xhci_trb         *dequeue;
+       struct xhci_segment     *deq_seg;
+       unsigned int            deq_updates;
+       struct list_head        td_list;
+       /* ----  Related to URB cancellation ---- */
+       struct list_head        cancelled_td_list;
+       unsigned int            cancels_pending;
+       unsigned int            state;
+#define SET_DEQ_PENDING                (1 << 0)
+       /* The TRB that was last reported in a stopped endpoint ring */
+       union xhci_trb          *stopped_trb;
+       struct xhci_td          *stopped_td;
+       /*
+        * Write the cycle state into the TRB cycle field to give ownership of
+        * the TRB to the host controller (if we are the producer), or to check
+        * if we own the TRB (if we are the consumer).  See section 4.9.1.
+        */
+       u32                     cycle_state;
+};
+
+struct xhci_erst_entry {
+       /* 64-bit event ring segment address */
+       u32     seg_addr[2];
+       u32     seg_size;
+       /* Set to zero */
+       u32     rsvd;
+};
+
+struct xhci_erst {
+       struct xhci_erst_entry  *entries;
+       unsigned int            num_entries;
+       /* xhci->event_ring keeps track of segment dma addresses */
+       dma_addr_t              erst_dma_addr;
+       /* Num entries the ERST can contain */
+       unsigned int            erst_size;
+};
+
+/*
+ * Each segment table entry is 4*32bits long.  1K seems like an ok size:
+ * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table,
+ * meaning 64 ring segments.
+ * Initial allocated size of the ERST, in number of entries */
+#define        ERST_NUM_SEGS   1
+/* Initial allocated size of the ERST, in number of entries */
+#define        ERST_SIZE       64
+/* Initial number of event segment rings allocated */
+#define        ERST_ENTRIES    1
+/* Poll every 60 seconds */
+#define        POLL_TIMEOUT    60
+/* XXX: Make these module parameters */
+
+
+/* There is one ehci_hci structure per controller */
+struct xhci_hcd {
+       /* glue to PCI and HCD framework */
+       struct xhci_cap_regs __iomem *cap_regs;
+       struct xhci_op_regs __iomem *op_regs;
+       struct xhci_run_regs __iomem *run_regs;
+       struct xhci_doorbell_array __iomem *dba;
+       /* Our HCD's current interrupter register set */
+       struct  xhci_intr_reg __iomem *ir_set;
+
+       /* Cached register copies of read-only HC data */
+       __u32           hcs_params1;
+       __u32           hcs_params2;
+       __u32           hcs_params3;
+       __u32           hcc_params;
+
+       spinlock_t      lock;
+
+       /* packed release number */
+       u8              sbrn;
+       u16             hci_version;
+       u8              max_slots;
+       u8              max_interrupters;
+       u8              max_ports;
+       u8              isoc_threshold;
+       int             event_ring_max;
+       int             addr_64;
+       /* 4KB min, 128MB max */
+       int             page_size;
+       /* Valid values are 12 to 20, inclusive */
+       int             page_shift;
+       /* only one MSI vector for now, but might need more later */
+       int             msix_count;
+       struct msix_entry       *msix_entries;
+       /* data structures */
+       struct xhci_device_context_array *dcbaa;
+       struct xhci_ring        *cmd_ring;
+       struct xhci_ring        *event_ring;
+       struct xhci_erst        erst;
+       /* slot enabling and address device helpers */
+       struct completion       addr_dev;
+       int slot_id;
+       /* Internal mirror of the HW's dcbaa */
+       struct xhci_virt_device *devs[MAX_HC_SLOTS];
+
+       /* DMA pools */
+       struct dma_pool *device_pool;
+       struct dma_pool *segment_pool;
+
+#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
+       /* Poll the rings - for debugging */
+       struct timer_list       event_ring_timer;
+       int                     zombie;
+#endif
+       /* Statistics */
+       int                     noops_submitted;
+       int                     noops_handled;
+       int                     error_bitmask;
+};
+
+/* For testing purposes */
+#define NUM_TEST_NOOPS 0
+
+/* convert between an HCD pointer and the corresponding EHCI_HCD */
+static inline struct xhci_hcd *hcd_to_xhci(struct usb_hcd *hcd)
+{
+       return (struct xhci_hcd *) (hcd->hcd_priv);
+}
+
+static inline struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci)
+{
+       return container_of((void *) xhci, struct usb_hcd, hcd_priv);
+}
+
+#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
+#define XHCI_DEBUG     1
+#else
+#define XHCI_DEBUG     0
+#endif
+
+#define xhci_dbg(xhci, fmt, args...) \
+       do { if (XHCI_DEBUG) dev_dbg(xhci_to_hcd(xhci)->self.controller , fmt , ## args); } while (0)
+#define xhci_info(xhci, fmt, args...) \
+       do { if (XHCI_DEBUG) dev_info(xhci_to_hcd(xhci)->self.controller , fmt , ## args); } while (0)
+#define xhci_err(xhci, fmt, args...) \
+       dev_err(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
+#define xhci_warn(xhci, fmt, args...) \
+       dev_warn(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
+
+/* TODO: copied from ehci.h - can be refactored? */
+/* xHCI spec says all registers are little endian */
+static inline unsigned int xhci_readl(const struct xhci_hcd *xhci,
+               __u32 __iomem *regs)
+{
+       return readl(regs);
+}
+static inline void xhci_writel(struct xhci_hcd *xhci,
+               const unsigned int val, __u32 __iomem *regs)
+{
+       if (!in_interrupt())
+               xhci_dbg(xhci,
+                        "`MEM_WRITE_DWORD(3'b000, 32'h%p, 32'h%0x, 4'hf);\n",
+                        regs, val);
+       writel(val, regs);
+}
+
+/* xHCI debugging */
+void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int set_num);
+void xhci_print_registers(struct xhci_hcd *xhci);
+void xhci_dbg_regs(struct xhci_hcd *xhci);
+void xhci_print_run_regs(struct xhci_hcd *xhci);
+void xhci_print_trb_offsets(struct xhci_hcd *xhci, union xhci_trb *trb);
+void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb);
+void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg);
+void xhci_debug_ring(struct xhci_hcd *xhci, struct xhci_ring *ring);
+void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst);
+void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci);
+void xhci_dbg_ring_ptrs(struct xhci_hcd *xhci, struct xhci_ring *ring);
+void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep);
+
+/* xHCI memory managment */
+void xhci_mem_cleanup(struct xhci_hcd *xhci);
+int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags);
+void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id);
+int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, struct usb_device *udev, gfp_t flags);
+int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev);
+unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc);
+unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc);
+void xhci_endpoint_zero(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, struct usb_host_endpoint *ep);
+int xhci_endpoint_init(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev,
+               struct usb_device *udev, struct usb_host_endpoint *ep,
+               gfp_t mem_flags);
+void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring);
+
+#ifdef CONFIG_PCI
+/* xHCI PCI glue */
+int xhci_register_pci(void);
+void xhci_unregister_pci(void);
+#endif
+
+/* xHCI host controller glue */
+int xhci_halt(struct xhci_hcd *xhci);
+int xhci_reset(struct xhci_hcd *xhci);
+int xhci_init(struct usb_hcd *hcd);
+int xhci_run(struct usb_hcd *hcd);
+void xhci_stop(struct usb_hcd *hcd);
+void xhci_shutdown(struct usb_hcd *hcd);
+int xhci_get_frame(struct usb_hcd *hcd);
+irqreturn_t xhci_irq(struct usb_hcd *hcd);
+int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev);
+void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev);
+int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev);
+int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
+int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
+int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep);
+int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep);
+int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
+void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
+
+/* xHCI ring, segment, TRB, and TD functions */
+dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb);
+void xhci_ring_cmd_db(struct xhci_hcd *xhci);
+void *xhci_setup_one_noop(struct xhci_hcd *xhci);
+void xhci_handle_event(struct xhci_hcd *xhci);
+void xhci_set_hc_event_deq(struct xhci_hcd *xhci);
+int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id);
+int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
+               u32 slot_id);
+int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id,
+               unsigned int ep_index);
+int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,
+               int slot_id, unsigned int ep_index);
+int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,
+               int slot_id, unsigned int ep_index);
+int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
+               u32 slot_id);
+
+/* xHCI roothub code */
+int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
+               char *buf, u16 wLength);
+int xhci_hub_status_data(struct usb_hcd *hcd, char *buf);
+
+#endif /* __LINUX_XHCI_HCD_H */
index a4ef77ef917d9bc6be7f2b29bff6a58ba6d105e1..3c5fe5cee05abab286dcc2f00d6cc1f70b031e06 100644 (file)
@@ -726,12 +726,18 @@ static const struct file_operations iowarrior_fops = {
        .poll = iowarrior_poll,
 };
 
+static char *iowarrior_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev));
+}
+
 /*
  * usb class driver info in order to get a minor number from the usb core,
  * and to have the device registered with devfs and the driver core
  */
 static struct usb_class_driver iowarrior_class = {
        .name = "iowarrior%d",
+       .nodename = iowarrior_nodename,
        .fops = &iowarrior_fops,
        .minor_base = IOWARRIOR_MINOR_BASE,
 };
index ab0f3226158b0d6ed735c041931a6b80ae869afb..c1e2433f640d133da219152b7f8ad7389ac51471 100644 (file)
@@ -266,12 +266,18 @@ static const struct file_operations tower_fops = {
        .llseek =       tower_llseek,
 };
 
+static char *legousbtower_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev));
+}
+
 /*
  * usb class driver info in order to get a minor number from the usb core,
  * and to have the device registered with the driver core
  */
 static struct usb_class_driver tower_class = {
        .name =         "legousbtower%d",
+       .nodename =     legousbtower_nodename,
        .fops =         &tower_fops,
        .minor_base =   LEGO_USB_TOWER_MINOR_BASE,
 };
index 7603cbe0865d1268811c717dcaadb0eb7224ce09..30ea7ca6846e2a9cd3c36ecf182b9b934ca2a338 100644 (file)
@@ -1,7 +1,7 @@
 
 config USB_SISUSBVGA
        tristate "USB 2.0 SVGA dongle support (Net2280/SiS315)"
-       depends on USB && USB_EHCI_HCD
+       depends on USB && (USB_MUSB_HDRC || USB_EHCI_HCD)
         ---help---
          Say Y here if you intend to attach a USB2VGA dongle based on a
          Net2280 and a SiS315 chip.
index 5f1a19d1497d108a41a23a7d2d73898bc20cf289..a9f06d76960ffa936858adaf321d5c53d39605dd 100644 (file)
@@ -1072,23 +1072,34 @@ static int unlink1 (struct usbtest_dev *dev, int pipe, int size, int async)
         */
        msleep (jiffies % (2 * INTERRUPT_RATE));
        if (async) {
-retry:
-               retval = usb_unlink_urb (urb);
-               if (retval == -EBUSY || retval == -EIDRM) {
-                       /* we can't unlink urbs while they're completing.
-                        * or if they've completed, and we haven't resubmitted.
-                        * "normal" drivers would prevent resubmission, but
-                        * since we're testing unlink paths, we can't.
-                        */
-                       ERROR(dev,  "unlink retry\n");
-                       goto retry;
+               while (!completion_done(&completion)) {
+                       retval = usb_unlink_urb(urb);
+
+                       switch (retval) {
+                       case -EBUSY:
+                       case -EIDRM:
+                               /* we can't unlink urbs while they're completing
+                                * or if they've completed, and we haven't
+                                * resubmitted. "normal" drivers would prevent
+                                * resubmission, but since we're testing unlink
+                                * paths, we can't.
+                                */
+                               ERROR(dev, "unlink retry\n");
+                               continue;
+                       case 0:
+                       case -EINPROGRESS:
+                               break;
+
+                       default:
+                               dev_err(&dev->intf->dev,
+                                       "unlink fail %d\n", retval);
+                               return retval;
+                       }
+
+                       break;
                }
        } else
                usb_kill_urb (urb);
-       if (!(retval == 0 || retval == -EINPROGRESS)) {
-               dev_err(&dev->intf->dev, "unlink fail %d\n", retval);
-               return retval;
-       }
 
        wait_for_completion (&completion);
        retval = urb->status;
index 1f715436d6d3dec14a96639aa6abde814c9818b4..a7eb4c99342c91d0fabdb8a6d9beab5e09b093b9 100644 (file)
@@ -733,7 +733,7 @@ int __init mon_text_init(void)
 {
        struct dentry *mondir;
 
-       mondir = debugfs_create_dir("usbmon", NULL);
+       mondir = debugfs_create_dir("usbmon", usb_debug_root);
        if (IS_ERR(mondir)) {
                printk(KERN_NOTICE TAG ": debugfs is not available\n");
                return -ENODEV;
index b66e8544d8b90761a80a11a5a2c524284dd0711b..70073b157f0ab7e875ab1fdad3bedaa4e97e5c8c 100644 (file)
@@ -10,6 +10,7 @@ comment "Enable Host or Gadget support to see Inventra options"
 config USB_MUSB_HDRC
        depends on (USB || USB_GADGET) && HAVE_CLK
        depends on !SUPERH
+       select NOP_USB_XCEIV if ARCH_DAVINCI
        select TWL4030_USB if MACH_OMAP_3430SDP
        select USB_OTG_UTILS
        tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
@@ -55,6 +56,7 @@ comment "Blackfin high speed USB Support"
 config USB_TUSB6010
        boolean "TUSB 6010 support"
        depends on USB_MUSB_HDRC && !USB_MUSB_SOC
+       select NOP_USB_XCEIV
        default y
        help
          The TUSB 6010 chip, from Texas Instruments, connects a discrete
index 786134852092cc0b324584577db51e5f8d054939..f2f66ebc73626a28265fe1f0dd0a6887fb10038b 100644 (file)
@@ -143,7 +143,7 @@ static void musb_conn_timer_handler(unsigned long _musb)
        u16 val;
 
        spin_lock_irqsave(&musb->lock, flags);
-       switch (musb->xceiv.state) {
+       switch (musb->xceiv->state) {
        case OTG_STATE_A_IDLE:
        case OTG_STATE_A_WAIT_BCON:
                /* Start a new session */
@@ -154,7 +154,7 @@ static void musb_conn_timer_handler(unsigned long _musb)
                val = musb_readw(musb->mregs, MUSB_DEVCTL);
                if (!(val & MUSB_DEVCTL_BDEVICE)) {
                        gpio_set_value(musb->config->gpio_vrsel, 1);
-                       musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
+                       musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
                } else {
                        gpio_set_value(musb->config->gpio_vrsel, 0);
 
@@ -247,6 +247,11 @@ int __init musb_platform_init(struct musb *musb)
        }
        gpio_direction_output(musb->config->gpio_vrsel, 0);
 
+       usb_nop_xceiv_register();
+       musb->xceiv = otg_get_transceiver();
+       if (!musb->xceiv)
+               return -ENODEV;
+
        if (ANOMALY_05000346) {
                bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value);
                SSYNC();
@@ -291,7 +296,7 @@ int __init musb_platform_init(struct musb *musb)
                        musb_conn_timer_handler, (unsigned long) musb);
        }
        if (is_peripheral_enabled(musb))
-               musb->xceiv.set_power = bfin_set_power;
+               musb->xceiv->set_power = bfin_set_power;
 
        musb->isr = blackfin_interrupt;
 
index 1976e9b41800b27f6b47925bed29a04872b62aa0..c3577bbbae6c76722b5d9e7699f6045c8baf6cbc 100644 (file)
@@ -6,6 +6,7 @@
  * The TUSB6020, using VLYNQ, has CPPI that looks much like DaVinci.
  */
 
+#include <linux/platform_device.h>
 #include <linux/usb.h>
 
 #include "musb_core.h"
@@ -1145,17 +1146,27 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch)
        return completed;
 }
 
-void cppi_completion(struct musb *musb, u32 rx, u32 tx)
+irqreturn_t cppi_interrupt(int irq, void *dev_id)
 {
-       void __iomem            *tibase;
-       int                     i, index;
+       struct musb             *musb = dev_id;
        struct cppi             *cppi;
+       void __iomem            *tibase;
        struct musb_hw_ep       *hw_ep = NULL;
+       u32                     rx, tx;
+       int                     i, index;
 
        cppi = container_of(musb->dma_controller, struct cppi, controller);
 
        tibase = musb->ctrl_base;
 
+       tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG);
+       rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG);
+
+       if (!tx && !rx)
+               return IRQ_NONE;
+
+       DBG(4, "CPPI IRQ Tx%x Rx%x\n", tx, rx);
+
        /* process TX channels */
        for (index = 0; tx; tx = tx >> 1, index++) {
                struct cppi_channel             *tx_ch;
@@ -1273,6 +1284,8 @@ void cppi_completion(struct musb *musb, u32 rx, u32 tx)
 
        /* write to CPPI EOI register to re-enable interrupts */
        musb_writel(tibase, DAVINCI_CPPI_EOI_REG, 0);
+
+       return IRQ_HANDLED;
 }
 
 /* Instantiate a software object representing a DMA controller. */
@@ -1280,6 +1293,9 @@ struct dma_controller *__init
 dma_controller_create(struct musb *musb, void __iomem *mregs)
 {
        struct cppi             *controller;
+       struct device           *dev = musb->controller;
+       struct platform_device  *pdev = to_platform_device(dev);
+       int                     irq = platform_get_irq(pdev, 1);
 
        controller = kzalloc(sizeof *controller, GFP_KERNEL);
        if (!controller)
@@ -1310,6 +1326,15 @@ dma_controller_create(struct musb *musb, void __iomem *mregs)
                return NULL;
        }
 
+       if (irq > 0) {
+               if (request_irq(irq, cppi_interrupt, 0, "cppi-dma", musb)) {
+                       dev_err(dev, "request_irq %d failed!\n", irq);
+                       dma_controller_destroy(&controller->controller);
+                       return NULL;
+               }
+               controller->irq = irq;
+       }
+
        return &controller->controller;
 }
 
@@ -1322,6 +1347,9 @@ void dma_controller_destroy(struct dma_controller *c)
 
        cppi = container_of(c, struct cppi, controller);
 
+       if (cppi->irq)
+               free_irq(cppi->irq, cppi->musb);
+
        /* assert:  caller stopped the controller first */
        dma_pool_destroy(cppi->pool);
 
index 729b4071787b3425a44e8f112c0704a4af9c5819..8a39de3e6e471c9c8f8c7b72f5b515218cb816c4 100644 (file)
@@ -119,6 +119,8 @@ struct cppi {
        void __iomem                    *mregs;         /* Mentor regs */
        void __iomem                    *tibase;        /* TI/CPPI regs */
 
+       int                             irq;
+
        struct cppi_channel             tx[4];
        struct cppi_channel             rx[4];
 
@@ -127,7 +129,7 @@ struct cppi {
        struct list_head                tx_complete;
 };
 
-/* irq handling hook */
-extern void cppi_completion(struct musb *, u32 rx, u32 tx);
+/* CPPI IRQ handler */
+extern irqreturn_t cppi_interrupt(int, void *);
 
 #endif                         /* end of ifndef _CPPI_DMA_H_ */
index 10d11ab113ab3c38b50b87172ed2a910c746e242..180d7daa4099d50231f81f92c8ce537ab72dcbcc 100644 (file)
@@ -215,7 +215,7 @@ static void otg_timer(unsigned long _musb)
        DBG(7, "poll devctl %02x (%s)\n", devctl, otg_state_string(musb));
 
        spin_lock_irqsave(&musb->lock, flags);
-       switch (musb->xceiv.state) {
+       switch (musb->xceiv->state) {
        case OTG_STATE_A_WAIT_VFALL:
                /* Wait till VBUS falls below SessionEnd (~0.2V); the 1.3 RTL
                 * seems to mis-handle session "start" otherwise (or in our
@@ -226,7 +226,7 @@ static void otg_timer(unsigned long _musb)
                        mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
                        break;
                }
-               musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
+               musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
                musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG,
                        MUSB_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT);
                break;
@@ -251,7 +251,7 @@ static void otg_timer(unsigned long _musb)
                if (devctl & MUSB_DEVCTL_BDEVICE)
                        mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
                else
-                       musb->xceiv.state = OTG_STATE_A_IDLE;
+                       musb->xceiv->state = OTG_STATE_A_IDLE;
                break;
        default:
                break;
@@ -265,6 +265,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
        irqreturn_t     retval = IRQ_NONE;
        struct musb     *musb = __hci;
        void __iomem    *tibase = musb->ctrl_base;
+       struct cppi     *cppi;
        u32             tmp;
 
        spin_lock_irqsave(&musb->lock, flags);
@@ -281,16 +282,9 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
        /* CPPI interrupts share the same IRQ line, but have their own
         * mask, state, "vector", and EOI registers.
         */
-       if (is_cppi_enabled()) {
-               u32 cppi_tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG);
-               u32 cppi_rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG);
-
-               if (cppi_tx || cppi_rx) {
-                       DBG(4, "CPPI IRQ t%x r%x\n", cppi_tx, cppi_rx);
-                       cppi_completion(musb, cppi_rx, cppi_tx);
-                       retval = IRQ_HANDLED;
-               }
-       }
+       cppi = container_of(musb->dma_controller, struct cppi, controller);
+       if (is_cppi_enabled() && musb->dma_controller && !cppi->irq)
+               retval = cppi_interrupt(irq, __hci);
 
        /* ack and handle non-CPPI interrupts */
        tmp = musb_readl(tibase, DAVINCI_USB_INT_SRC_MASKED_REG);
@@ -331,21 +325,21 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
                         * to stop registering in devctl.
                         */
                        musb->int_usb &= ~MUSB_INTR_VBUSERROR;
-                       musb->xceiv.state = OTG_STATE_A_WAIT_VFALL;
+                       musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
                        mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
                        WARNING("VBUS error workaround (delay coming)\n");
                } else if (is_host_enabled(musb) && drvvbus) {
                        musb->is_active = 1;
                        MUSB_HST_MODE(musb);
-                       musb->xceiv.default_a = 1;
-                       musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
+                       musb->xceiv->default_a = 1;
+                       musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
                        portstate(musb->port1_status |= USB_PORT_STAT_POWER);
                        del_timer(&otg_workaround);
                } else {
                        musb->is_active = 0;
                        MUSB_DEV_MODE(musb);
-                       musb->xceiv.default_a = 0;
-                       musb->xceiv.state = OTG_STATE_B_IDLE;
+                       musb->xceiv->default_a = 0;
+                       musb->xceiv->state = OTG_STATE_B_IDLE;
                        portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
                }
 
@@ -367,17 +361,12 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
 
        /* poll for ID change */
        if (is_otg_enabled(musb)
-                       && musb->xceiv.state == OTG_STATE_B_IDLE)
+                       && musb->xceiv->state == OTG_STATE_B_IDLE)
                mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
 
        spin_unlock_irqrestore(&musb->lock, flags);
 
-       /* REVISIT we sometimes get unhandled IRQs
-        * (e.g. ep0).  not clear why...
-        */
-       if (retval != IRQ_HANDLED)
-               DBG(5, "unhandled? %08x\n", tmp);
-       return IRQ_HANDLED;
+       return retval;
 }
 
 int musb_platform_set_mode(struct musb *musb, u8 mode)
@@ -391,6 +380,11 @@ int __init musb_platform_init(struct musb *musb)
        void __iomem    *tibase = musb->ctrl_base;
        u32             revision;
 
+       usb_nop_xceiv_register();
+       musb->xceiv = otg_get_transceiver();
+       if (!musb->xceiv)
+               return -ENODEV;
+
        musb->mregs += DAVINCI_BASE_OFFSET;
 
        clk_enable(musb->clock);
@@ -398,7 +392,7 @@ int __init musb_platform_init(struct musb *musb)
        /* returns zero if e.g. not clocked */
        revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG);
        if (revision == 0)
-               return -ENODEV;
+               goto fail;
 
        if (is_host_enabled(musb))
                setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
@@ -432,6 +426,10 @@ int __init musb_platform_init(struct musb *musb)
 
        musb->isr = davinci_interrupt;
        return 0;
+
+fail:
+       usb_nop_xceiv_unregister();
+       return -ENODEV;
 }
 
 int musb_platform_exit(struct musb *musb)
@@ -442,7 +440,7 @@ int musb_platform_exit(struct musb *musb)
        davinci_source_power(musb, 0 /*off*/, 1);
 
        /* delay, to avoid problems with module reload */
-       if (is_host_enabled(musb) && musb->xceiv.default_a) {
+       if (is_host_enabled(musb) && musb->xceiv->default_a) {
                int     maxdelay = 30;
                u8      devctl, warn = 0;
 
@@ -471,5 +469,7 @@ int musb_platform_exit(struct musb *musb)
 
        clk_disable(musb->clock);
 
+       usb_nop_xceiv_unregister();
+
        return 0;
 }
index 4000cf6d1e819a3cacd857b4316dd6efeeebe752..554a414f65d1104cbbbeeaed2885f2a209faf42d 100644 (file)
 #include "davinci.h"
 #endif
 
+#define TA_WAIT_BCON(m) max_t(int, (m)->a_wait_bcon, OTG_TIME_A_WAIT_BCON)
 
 
 unsigned musb_debug;
@@ -267,7 +268,7 @@ void musb_load_testpacket(struct musb *musb)
 
 const char *otg_state_string(struct musb *musb)
 {
-       switch (musb->xceiv.state) {
+       switch (musb->xceiv->state) {
        case OTG_STATE_A_IDLE:          return "a_idle";
        case OTG_STATE_A_WAIT_VRISE:    return "a_wait_vrise";
        case OTG_STATE_A_WAIT_BCON:     return "a_wait_bcon";
@@ -287,12 +288,6 @@ const char *otg_state_string(struct musb *musb)
 
 #ifdef CONFIG_USB_MUSB_OTG
 
-/*
- * See also USB_OTG_1-3.pdf 6.6.5 Timers
- * REVISIT: Are the other timers done in the hardware?
- */
-#define TB_ASE0_BRST           100     /* Min 3.125 ms */
-
 /*
  * Handles OTG hnp timeouts, such as b_ase0_brst
  */
@@ -302,16 +297,18 @@ void musb_otg_timer_func(unsigned long data)
        unsigned long   flags;
 
        spin_lock_irqsave(&musb->lock, flags);
-       switch (musb->xceiv.state) {
+       switch (musb->xceiv->state) {
        case OTG_STATE_B_WAIT_ACON:
                DBG(1, "HNP: b_wait_acon timeout; back to b_peripheral\n");
                musb_g_disconnect(musb);
-               musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+               musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
                musb->is_active = 0;
                break;
+       case OTG_STATE_A_SUSPEND:
        case OTG_STATE_A_WAIT_BCON:
-               DBG(1, "HNP: a_wait_bcon timeout; back to a_host\n");
-               musb_hnp_stop(musb);
+               DBG(1, "HNP: %s timeout\n", otg_state_string(musb));
+               musb_set_vbus(musb, 0);
+               musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
                break;
        default:
                DBG(1, "HNP: Unhandled mode %s\n", otg_state_string(musb));
@@ -320,10 +317,8 @@ void musb_otg_timer_func(unsigned long data)
        spin_unlock_irqrestore(&musb->lock, flags);
 }
 
-static DEFINE_TIMER(musb_otg_timer, musb_otg_timer_func, 0, 0);
-
 /*
- * Stops the B-device HNP state. Caller must take care of locking.
+ * Stops the HNP transition. Caller must take care of locking.
  */
 void musb_hnp_stop(struct musb *musb)
 {
@@ -331,20 +326,17 @@ void musb_hnp_stop(struct musb *musb)
        void __iomem    *mbase = musb->mregs;
        u8      reg;
 
-       switch (musb->xceiv.state) {
+       DBG(1, "HNP: stop from %s\n", otg_state_string(musb));
+
+       switch (musb->xceiv->state) {
        case OTG_STATE_A_PERIPHERAL:
-       case OTG_STATE_A_WAIT_VFALL:
-       case OTG_STATE_A_WAIT_BCON:
-               DBG(1, "HNP: Switching back to A-host\n");
                musb_g_disconnect(musb);
-               musb->xceiv.state = OTG_STATE_A_IDLE;
-               MUSB_HST_MODE(musb);
-               musb->is_active = 0;
+               DBG(1, "HNP: back to %s\n", otg_state_string(musb));
                break;
        case OTG_STATE_B_HOST:
                DBG(1, "HNP: Disabling HR\n");
                hcd->self.is_b_host = 0;
-               musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+               musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
                MUSB_DEV_MODE(musb);
                reg = musb_readb(mbase, MUSB_POWER);
                reg |= MUSB_POWER_SUSPENDM;
@@ -402,7 +394,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
 
                if (devctl & MUSB_DEVCTL_HM) {
 #ifdef CONFIG_USB_MUSB_HDRC_HCD
-                       switch (musb->xceiv.state) {
+                       switch (musb->xceiv->state) {
                        case OTG_STATE_A_SUSPEND:
                                /* remote wakeup?  later, GetPortStatus
                                 * will stop RESUME signaling
@@ -425,12 +417,12 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                                musb->rh_timer = jiffies
                                                + msecs_to_jiffies(20);
 
-                               musb->xceiv.state = OTG_STATE_A_HOST;
+                               musb->xceiv->state = OTG_STATE_A_HOST;
                                musb->is_active = 1;
                                usb_hcd_resume_root_hub(musb_to_hcd(musb));
                                break;
                        case OTG_STATE_B_WAIT_ACON:
-                               musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+                               musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
                                musb->is_active = 1;
                                MUSB_DEV_MODE(musb);
                                break;
@@ -441,11 +433,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                        }
 #endif
                } else {
-                       switch (musb->xceiv.state) {
+                       switch (musb->xceiv->state) {
 #ifdef CONFIG_USB_MUSB_HDRC_HCD
                        case OTG_STATE_A_SUSPEND:
                                /* possibly DISCONNECT is upcoming */
-                               musb->xceiv.state = OTG_STATE_A_HOST;
+                               musb->xceiv->state = OTG_STATE_A_HOST;
                                usb_hcd_resume_root_hub(musb_to_hcd(musb));
                                break;
 #endif
@@ -490,7 +482,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                 */
                musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION);
                musb->ep0_stage = MUSB_EP0_START;
-               musb->xceiv.state = OTG_STATE_A_IDLE;
+               musb->xceiv->state = OTG_STATE_A_IDLE;
                MUSB_HST_MODE(musb);
                musb_set_vbus(musb, 1);
 
@@ -516,7 +508,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                 * REVISIT:  do delays from lots of DEBUG_KERNEL checks
                 * make trouble here, keeping VBUS < 4.4V ?
                 */
-               switch (musb->xceiv.state) {
+               switch (musb->xceiv->state) {
                case OTG_STATE_A_HOST:
                        /* recovery is dicey once we've gotten past the
                         * initial stages of enumeration, but if VBUS
@@ -594,37 +586,40 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                if (devctl & MUSB_DEVCTL_LSDEV)
                        musb->port1_status |= USB_PORT_STAT_LOW_SPEED;
 
-               if (hcd->status_urb)
-                       usb_hcd_poll_rh_status(hcd);
-               else
-                       usb_hcd_resume_root_hub(hcd);
-
-               MUSB_HST_MODE(musb);
-
                /* indicate new connection to OTG machine */
-               switch (musb->xceiv.state) {
+               switch (musb->xceiv->state) {
                case OTG_STATE_B_PERIPHERAL:
                        if (int_usb & MUSB_INTR_SUSPEND) {
                                DBG(1, "HNP: SUSPEND+CONNECT, now b_host\n");
-                               musb->xceiv.state = OTG_STATE_B_HOST;
-                               hcd->self.is_b_host = 1;
                                int_usb &= ~MUSB_INTR_SUSPEND;
+                               goto b_host;
                        } else
                                DBG(1, "CONNECT as b_peripheral???\n");
                        break;
                case OTG_STATE_B_WAIT_ACON:
-                       DBG(1, "HNP: Waiting to switch to b_host state\n");
-                       musb->xceiv.state = OTG_STATE_B_HOST;
+                       DBG(1, "HNP: CONNECT, now b_host\n");
+b_host:
+                       musb->xceiv->state = OTG_STATE_B_HOST;
                        hcd->self.is_b_host = 1;
+                       musb->ignore_disconnect = 0;
+                       del_timer(&musb->otg_timer);
                        break;
                default:
                        if ((devctl & MUSB_DEVCTL_VBUS)
                                        == (3 << MUSB_DEVCTL_VBUS_SHIFT)) {
-                               musb->xceiv.state = OTG_STATE_A_HOST;
+                               musb->xceiv->state = OTG_STATE_A_HOST;
                                hcd->self.is_b_host = 0;
                        }
                        break;
                }
+
+               /* poke the root hub */
+               MUSB_HST_MODE(musb);
+               if (hcd->status_urb)
+                       usb_hcd_poll_rh_status(hcd);
+               else
+                       usb_hcd_resume_root_hub(hcd);
+
                DBG(1, "CONNECT (%s) devctl %02x\n",
                                otg_state_string(musb), devctl);
        }
@@ -650,7 +645,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                        }
                } else if (is_peripheral_capable()) {
                        DBG(1, "BUS RESET as %s\n", otg_state_string(musb));
-                       switch (musb->xceiv.state) {
+                       switch (musb->xceiv->state) {
 #ifdef CONFIG_USB_OTG
                        case OTG_STATE_A_SUSPEND:
                                /* We need to ignore disconnect on suspend
@@ -661,24 +656,27 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                                musb_g_reset(musb);
                                /* FALLTHROUGH */
                        case OTG_STATE_A_WAIT_BCON:     /* OPT TD.4.7-900ms */
-                               DBG(1, "HNP: Setting timer as %s\n",
-                                               otg_state_string(musb));
-                               musb_otg_timer.data = (unsigned long)musb;
-                               mod_timer(&musb_otg_timer, jiffies
-                                       + msecs_to_jiffies(100));
+                               /* never use invalid T(a_wait_bcon) */
+                               DBG(1, "HNP: in %s, %d msec timeout\n",
+                                               otg_state_string(musb),
+                                               TA_WAIT_BCON(musb));
+                               mod_timer(&musb->otg_timer, jiffies
+                                       + msecs_to_jiffies(TA_WAIT_BCON(musb)));
                                break;
                        case OTG_STATE_A_PERIPHERAL:
-                               musb_hnp_stop(musb);
+                               musb->ignore_disconnect = 0;
+                               del_timer(&musb->otg_timer);
+                               musb_g_reset(musb);
                                break;
                        case OTG_STATE_B_WAIT_ACON:
                                DBG(1, "HNP: RESET (%s), to b_peripheral\n",
                                        otg_state_string(musb));
-                               musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+                               musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
                                musb_g_reset(musb);
                                break;
 #endif
                        case OTG_STATE_B_IDLE:
-                               musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+                               musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
                                /* FALLTHROUGH */
                        case OTG_STATE_B_PERIPHERAL:
                                musb_g_reset(musb);
@@ -763,7 +761,7 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
                                MUSB_MODE(musb), devctl);
                handled = IRQ_HANDLED;
 
-               switch (musb->xceiv.state) {
+               switch (musb->xceiv->state) {
 #ifdef CONFIG_USB_MUSB_HDRC_HCD
                case OTG_STATE_A_HOST:
                case OTG_STATE_A_SUSPEND:
@@ -776,7 +774,16 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
 #endif /* HOST */
 #ifdef CONFIG_USB_MUSB_OTG
                case OTG_STATE_B_HOST:
-                       musb_hnp_stop(musb);
+                       /* REVISIT this behaves for "real disconnect"
+                        * cases; make sure the other transitions from
+                        * from B_HOST act right too.  The B_HOST code
+                        * in hnp_stop() is currently not used...
+                        */
+                       musb_root_disconnect(musb);
+                       musb_to_hcd(musb)->self.is_b_host = 0;
+                       musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+                       MUSB_DEV_MODE(musb);
+                       musb_g_disconnect(musb);
                        break;
                case OTG_STATE_A_PERIPHERAL:
                        musb_hnp_stop(musb);
@@ -805,26 +812,35 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
                                otg_state_string(musb), devctl, power);
                handled = IRQ_HANDLED;
 
-               switch (musb->xceiv.state) {
+               switch (musb->xceiv->state) {
 #ifdef CONFIG_USB_MUSB_OTG
                case OTG_STATE_A_PERIPHERAL:
-                       /*
-                        * We cannot stop HNP here, devctl BDEVICE might be
-                        * still set.
+                       /* We also come here if the cable is removed, since
+                        * this silicon doesn't report ID-no-longer-grounded.
+                        *
+                        * We depend on T(a_wait_bcon) to shut us down, and
+                        * hope users don't do anything dicey during this
+                        * undesired detour through A_WAIT_BCON.
                         */
+                       musb_hnp_stop(musb);
+                       usb_hcd_resume_root_hub(musb_to_hcd(musb));
+                       musb_root_disconnect(musb);
+                       musb_platform_try_idle(musb, jiffies
+                                       + msecs_to_jiffies(musb->a_wait_bcon
+                                               ? : OTG_TIME_A_WAIT_BCON));
                        break;
 #endif
                case OTG_STATE_B_PERIPHERAL:
                        musb_g_suspend(musb);
                        musb->is_active = is_otg_enabled(musb)
-                                       && musb->xceiv.gadget->b_hnp_enable;
+                                       && musb->xceiv->gadget->b_hnp_enable;
                        if (musb->is_active) {
 #ifdef CONFIG_USB_MUSB_OTG
-                               musb->xceiv.state = OTG_STATE_B_WAIT_ACON;
+                               musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
                                DBG(1, "HNP: Setting timer for b_ase0_brst\n");
-                               musb_otg_timer.data = (unsigned long)musb;
-                               mod_timer(&musb_otg_timer, jiffies
-                                       + msecs_to_jiffies(TB_ASE0_BRST));
+                               mod_timer(&musb->otg_timer, jiffies
+                                       + msecs_to_jiffies(
+                                                       OTG_TIME_B_ASE0_BRST));
 #endif
                        }
                        break;
@@ -834,9 +850,9 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
                                        + msecs_to_jiffies(musb->a_wait_bcon));
                        break;
                case OTG_STATE_A_HOST:
-                       musb->xceiv.state = OTG_STATE_A_SUSPEND;
+                       musb->xceiv->state = OTG_STATE_A_SUSPEND;
                        musb->is_active = is_otg_enabled(musb)
-                                       && musb->xceiv.host->b_hnp_enable;
+                                       && musb->xceiv->host->b_hnp_enable;
                        break;
                case OTG_STATE_B_HOST:
                        /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */
@@ -1068,14 +1084,13 @@ static struct fifo_cfg __initdata mode_4_cfg[] = {
 { .hw_ep_num =  8, .style = FIFO_RX,   .maxpacket = 512, },
 { .hw_ep_num =  9, .style = FIFO_TX,   .maxpacket = 512, },
 { .hw_ep_num =  9, .style = FIFO_RX,   .maxpacket = 512, },
-{ .hw_ep_num = 10, .style = FIFO_TX,   .maxpacket = 512, },
-{ .hw_ep_num = 10, .style = FIFO_RX,   .maxpacket = 512, },
-{ .hw_ep_num = 11, .style = FIFO_TX,   .maxpacket = 512, },
-{ .hw_ep_num = 11, .style = FIFO_RX,   .maxpacket = 512, },
-{ .hw_ep_num = 12, .style = FIFO_TX,   .maxpacket = 512, },
-{ .hw_ep_num = 12, .style = FIFO_RX,   .maxpacket = 512, },
-{ .hw_ep_num = 13, .style = FIFO_TX,   .maxpacket = 512, },
-{ .hw_ep_num = 13, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num = 10, .style = FIFO_TX,   .maxpacket = 256, },
+{ .hw_ep_num = 10, .style = FIFO_RX,   .maxpacket = 64, },
+{ .hw_ep_num = 11, .style = FIFO_TX,   .maxpacket = 256, },
+{ .hw_ep_num = 11, .style = FIFO_RX,   .maxpacket = 64, },
+{ .hw_ep_num = 12, .style = FIFO_TX,   .maxpacket = 256, },
+{ .hw_ep_num = 12, .style = FIFO_RX,   .maxpacket = 64, },
+{ .hw_ep_num = 13, .style = FIFO_RXTX, .maxpacket = 4096, },
 { .hw_ep_num = 14, .style = FIFO_RXTX, .maxpacket = 1024, },
 { .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, },
 };
@@ -1335,11 +1350,11 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
        }
        if (reg & MUSB_CONFIGDATA_HBRXE) {
                strcat(aInfo, ", HB-ISO Rx");
-               strcat(aInfo, " (X)");          /* no driver support */
+               musb->hb_iso_rx = true;
        }
        if (reg & MUSB_CONFIGDATA_HBTXE) {
                strcat(aInfo, ", HB-ISO Tx");
-               strcat(aInfo, " (X)");          /* no driver support */
+               musb->hb_iso_tx = true;
        }
        if (reg & MUSB_CONFIGDATA_SOFTCONE)
                strcat(aInfo, ", SoftConn");
@@ -1481,13 +1496,7 @@ static irqreturn_t generic_interrupt(int irq, void *__hci)
 
        spin_unlock_irqrestore(&musb->lock, flags);
 
-       /* REVISIT we sometimes get spurious IRQs on g_ep0
-        * not clear why...
-        */
-       if (retval != IRQ_HANDLED)
-               DBG(5, "spurious?\n");
-
-       return IRQ_HANDLED;
+       return retval;
 }
 
 #else
@@ -1687,8 +1696,9 @@ musb_vbus_store(struct device *dev, struct device_attribute *attr,
        }
 
        spin_lock_irqsave(&musb->lock, flags);
-       musb->a_wait_bcon = val;
-       if (musb->xceiv.state == OTG_STATE_A_WAIT_BCON)
+       /* force T(a_wait_bcon) to be zero/unlimited *OR* valid */
+       musb->a_wait_bcon = val ? max_t(int, val, OTG_TIME_A_WAIT_BCON) : 0 ;
+       if (musb->xceiv->state == OTG_STATE_A_WAIT_BCON)
                musb->is_active = 0;
        musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(val));
        spin_unlock_irqrestore(&musb->lock, flags);
@@ -1706,10 +1716,13 @@ musb_vbus_show(struct device *dev, struct device_attribute *attr, char *buf)
 
        spin_lock_irqsave(&musb->lock, flags);
        val = musb->a_wait_bcon;
+       /* FIXME get_vbus_status() is normally #defined as false...
+        * and is effectively TUSB-specific.
+        */
        vbus = musb_platform_get_vbus_status(musb);
        spin_unlock_irqrestore(&musb->lock, flags);
 
-       return sprintf(buf, "Vbus %s, timeout %lu\n",
+       return sprintf(buf, "Vbus %s, timeout %lu msec\n",
                        vbus ? "on" : "off", val);
 }
 static DEVICE_ATTR(vbus, 0644, musb_vbus_show, musb_vbus_store);
@@ -1749,8 +1762,8 @@ static void musb_irq_work(struct work_struct *data)
        struct musb *musb = container_of(data, struct musb, irq_work);
        static int old_state;
 
-       if (musb->xceiv.state != old_state) {
-               old_state = musb->xceiv.state;
+       if (musb->xceiv->state != old_state) {
+               old_state = musb->xceiv->state;
                sysfs_notify(&musb->controller->kobj, NULL, "mode");
        }
 }
@@ -1782,6 +1795,7 @@ allocate_instance(struct device *dev,
        hcd->uses_new_polling = 1;
 
        musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
+       musb->a_wait_bcon = OTG_TIME_A_WAIT_BCON;
 #else
        musb = kzalloc(sizeof *musb, GFP_KERNEL);
        if (!musb)
@@ -1847,7 +1861,7 @@ static void musb_free(struct musb *musb)
        }
 
 #ifdef CONFIG_USB_MUSB_OTG
-       put_device(musb->xceiv.dev);
+       put_device(musb->xceiv->dev);
 #endif
 
 #ifdef CONFIG_USB_MUSB_HDRC_HCD
@@ -1928,10 +1942,18 @@ bad_config:
                }
        }
 
-       /* assume vbus is off */
-
-       /* platform adjusts musb->mregs and musb->isr if needed,
-        * and activates clocks
+       /* The musb_platform_init() call:
+        *   - adjusts musb->mregs and musb->isr if needed,
+        *   - may initialize an integrated tranceiver
+        *   - initializes musb->xceiv, usually by otg_get_transceiver()
+        *   - activates clocks.
+        *   - stops powering VBUS
+        *   - assigns musb->board_set_vbus if host mode is enabled
+        *
+        * There are various transciever configurations.  Blackfin,
+        * DaVinci, TUSB60x0, and others integrate them.  OMAP3 uses
+        * external/discrete ones in various flavors (twl4030 family,
+        * isp1504, non-OTG, etc) mostly hooking up through ULPI.
         */
        musb->isr = generic_interrupt;
        status = musb_platform_init(musb);
@@ -1968,6 +1990,10 @@ bad_config:
        if (status < 0)
                goto fail2;
 
+#ifdef CONFIG_USB_OTG
+       setup_timer(&musb->otg_timer, musb_otg_timer_func, (unsigned long) musb);
+#endif
+
        /* Init IRQ workqueue before request_irq */
        INIT_WORK(&musb->irq_work, musb_irq_work);
 
@@ -1999,17 +2025,17 @@ bad_config:
                                ? "DMA" : "PIO",
                        musb->nIrq);
 
-#ifdef CONFIG_USB_MUSB_HDRC_HCD
-       /* host side needs more setup, except for no-host modes */
-       if (musb->board_mode != MUSB_PERIPHERAL) {
+       /* host side needs more setup */
+       if (is_host_enabled(musb)) {
                struct usb_hcd  *hcd = musb_to_hcd(musb);
 
-               if (musb->board_mode == MUSB_OTG)
+               otg_set_host(musb->xceiv, &hcd->self);
+
+               if (is_otg_enabled(musb))
                        hcd->self.otg_port = 1;
-               musb->xceiv.host = &hcd->self;
+               musb->xceiv->host = &hcd->self;
                hcd->power_budget = 2 * (plat->power ? : 250);
        }
-#endif                         /* CONFIG_USB_MUSB_HDRC_HCD */
 
        /* For the host-only role, we can activate right away.
         * (We expect the ID pin to be forcibly grounded!!)
@@ -2017,8 +2043,8 @@ bad_config:
         */
        if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
                MUSB_HST_MODE(musb);
-               musb->xceiv.default_a = 1;
-               musb->xceiv.state = OTG_STATE_A_IDLE;
+               musb->xceiv->default_a = 1;
+               musb->xceiv->state = OTG_STATE_A_IDLE;
 
                status = usb_add_hcd(musb_to_hcd(musb), -1, 0);
                if (status)
@@ -2033,8 +2059,8 @@ bad_config:
 
        } else /* peripheral is enabled */ {
                MUSB_DEV_MODE(musb);
-               musb->xceiv.default_a = 0;
-               musb->xceiv.state = OTG_STATE_B_IDLE;
+               musb->xceiv->default_a = 0;
+               musb->xceiv->state = OTG_STATE_B_IDLE;
 
                status = musb_gadget_setup(musb);
                if (status)
index efb39b5e55b5e62493dc64ea8d05ab15d10074b8..f3772ca3b2cf799569389870e60a159732f5ca70 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/interrupt.h>
 #include <linux/smp_lock.h>
 #include <linux/errno.h>
+#include <linux/timer.h>
 #include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/usb/ch9.h>
@@ -171,7 +172,8 @@ enum musb_h_ep0_state {
 
 /* peripheral side ep0 states */
 enum musb_g_ep0_state {
-       MUSB_EP0_STAGE_SETUP,           /* idle, waiting for setup */
+       MUSB_EP0_STAGE_IDLE,            /* idle, waiting for SETUP */
+       MUSB_EP0_STAGE_SETUP,           /* received SETUP */
        MUSB_EP0_STAGE_TX,              /* IN data */
        MUSB_EP0_STAGE_RX,              /* OUT data */
        MUSB_EP0_STAGE_STATUSIN,        /* (after OUT data) */
@@ -179,10 +181,15 @@ enum musb_g_ep0_state {
        MUSB_EP0_STAGE_ACKWAIT,         /* after zlp, before statusin */
 } __attribute__ ((packed));
 
-/* OTG protocol constants */
+/*
+ * OTG protocol constants.  See USB OTG 1.3 spec,
+ * sections 5.5 "Device Timings" and 6.6.5 "Timers".
+ */
 #define OTG_TIME_A_WAIT_VRISE  100             /* msec (max) */
-#define OTG_TIME_A_WAIT_BCON   0               /* 0=infinite; min 1000 msec */
-#define OTG_TIME_A_IDLE_BDIS   200             /* msec (min) */
+#define OTG_TIME_A_WAIT_BCON   1100            /* min 1 second */
+#define OTG_TIME_A_AIDL_BDIS   200             /* min 200 msec */
+#define OTG_TIME_B_ASE0_BRST   100             /* min 3.125 ms */
+
 
 /*************************** REGISTER ACCESS ********************************/
 
@@ -331,6 +338,8 @@ struct musb {
        struct list_head        control;        /* of musb_qh */
        struct list_head        in_bulk;        /* of musb_qh */
        struct list_head        out_bulk;       /* of musb_qh */
+
+       struct timer_list       otg_timer;
 #endif
 
        /* called with IRQs blocked; ON/nonzero implies starting a session,
@@ -355,7 +364,7 @@ struct musb {
        u16                     int_rx;
        u16                     int_tx;
 
-       struct otg_transceiver  xceiv;
+       struct otg_transceiver  *xceiv;
 
        int nIrq;
        unsigned                irq_wake:1;
@@ -386,6 +395,9 @@ struct musb {
        unsigned is_multipoint:1;
        unsigned ignore_disconnect:1;   /* during bus resets */
 
+       unsigned                hb_iso_rx:1;    /* high bandwidth iso rx? */
+       unsigned                hb_iso_tx:1;    /* high bandwidth iso tx? */
+
 #ifdef C_MP_TX
        unsigned bulk_split:1;
 #define        can_bulk_split(musb,type) \
index f79440cdfe7ee2e346ae59cd2e164618c7d2a3f7..8b3c4e2ed7b865aab0636bf18c6d5b7d0138da0f 100644 (file)
@@ -310,7 +310,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
                        /* setup DMA, then program endpoint CSR */
                        request_size = min(request->length,
                                                musb_ep->dma->max_len);
-                       if (request_size <= musb_ep->packet_sz)
+                       if (request_size < musb_ep->packet_sz)
                                musb_ep->dma->desired_mode = 0;
                        else
                                musb_ep->dma->desired_mode = 1;
@@ -349,7 +349,8 @@ static void txstate(struct musb *musb, struct musb_request *req)
 #elif defined(CONFIG_USB_TI_CPPI_DMA)
                /* program endpoint CSR first, then setup DMA */
                csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY);
-               csr |= MUSB_TXCSR_MODE | MUSB_TXCSR_DMAENAB;
+               csr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE |
+                      MUSB_TXCSR_MODE;
                musb_writew(epio, MUSB_TXCSR,
                        (MUSB_TXCSR_P_WZC_BITS & ~MUSB_TXCSR_P_UNDERRUN)
                                | csr);
@@ -1405,7 +1406,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)
 
        spin_lock_irqsave(&musb->lock, flags);
 
-       switch (musb->xceiv.state) {
+       switch (musb->xceiv->state) {
        case OTG_STATE_B_PERIPHERAL:
                /* NOTE:  OTG state machine doesn't include B_SUSPENDED;
                 * that's part of the standard usb 1.1 state machine, and
@@ -1507,9 +1508,9 @@ static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
 {
        struct musb     *musb = gadget_to_musb(gadget);
 
-       if (!musb->xceiv.set_power)
+       if (!musb->xceiv->set_power)
                return -EOPNOTSUPP;
-       return otg_set_power(&musb->xceiv, mA);
+       return otg_set_power(musb->xceiv, mA);
 }
 
 static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on)
@@ -1732,11 +1733,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
 
                spin_lock_irqsave(&musb->lock, flags);
 
-               /* REVISIT always use otg_set_peripheral(), handling
-                * issues including the root hub one below ...
-                */
-               musb->xceiv.gadget = &musb->g;
-               musb->xceiv.state = OTG_STATE_B_IDLE;
+               otg_set_peripheral(musb->xceiv, &musb->g);
                musb->is_active = 1;
 
                /* FIXME this ignores the softconnect flag.  Drivers are
@@ -1748,6 +1745,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
                if (!is_otg_enabled(musb))
                        musb_start(musb);
 
+               otg_set_peripheral(musb->xceiv, &musb->g);
+
                spin_unlock_irqrestore(&musb->lock, flags);
 
                if (is_otg_enabled(musb)) {
@@ -1761,8 +1760,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
                        if (retval < 0) {
                                DBG(1, "add_hcd failed, %d\n", retval);
                                spin_lock_irqsave(&musb->lock, flags);
-                               musb->xceiv.gadget = NULL;
-                               musb->xceiv.state = OTG_STATE_UNDEFINED;
+                               otg_set_peripheral(musb->xceiv, NULL);
                                musb->gadget_driver = NULL;
                                musb->g.dev.driver = NULL;
                                spin_unlock_irqrestore(&musb->lock, flags);
@@ -1845,8 +1843,9 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 
                (void) musb_gadget_vbus_draw(&musb->g, 0);
 
-               musb->xceiv.state = OTG_STATE_UNDEFINED;
+               musb->xceiv->state = OTG_STATE_UNDEFINED;
                stop_activity(musb, driver);
+               otg_set_peripheral(musb->xceiv, NULL);
 
                DBG(3, "unregistering driver %s\n", driver->function);
                spin_unlock_irqrestore(&musb->lock, flags);
@@ -1882,7 +1881,7 @@ EXPORT_SYMBOL(usb_gadget_unregister_driver);
 void musb_g_resume(struct musb *musb)
 {
        musb->is_suspended = 0;
-       switch (musb->xceiv.state) {
+       switch (musb->xceiv->state) {
        case OTG_STATE_B_IDLE:
                break;
        case OTG_STATE_B_WAIT_ACON:
@@ -1908,10 +1907,10 @@ void musb_g_suspend(struct musb *musb)
        devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
        DBG(3, "devctl %02x\n", devctl);
 
-       switch (musb->xceiv.state) {
+       switch (musb->xceiv->state) {
        case OTG_STATE_B_IDLE:
                if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
-                       musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+                       musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
                break;
        case OTG_STATE_B_PERIPHERAL:
                musb->is_suspended = 1;
@@ -1957,22 +1956,24 @@ void musb_g_disconnect(struct musb *musb)
                spin_lock(&musb->lock);
        }
 
-       switch (musb->xceiv.state) {
+       switch (musb->xceiv->state) {
        default:
 #ifdef CONFIG_USB_MUSB_OTG
                DBG(2, "Unhandled disconnect %s, setting a_idle\n",
                        otg_state_string(musb));
-               musb->xceiv.state = OTG_STATE_A_IDLE;
+               musb->xceiv->state = OTG_STATE_A_IDLE;
+               MUSB_HST_MODE(musb);
                break;
        case OTG_STATE_A_PERIPHERAL:
-               musb->xceiv.state = OTG_STATE_A_WAIT_VFALL;
+               musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
+               MUSB_HST_MODE(musb);
                break;
        case OTG_STATE_B_WAIT_ACON:
        case OTG_STATE_B_HOST:
 #endif
        case OTG_STATE_B_PERIPHERAL:
        case OTG_STATE_B_IDLE:
-               musb->xceiv.state = OTG_STATE_B_IDLE;
+               musb->xceiv->state = OTG_STATE_B_IDLE;
                break;
        case OTG_STATE_B_SRP_INIT:
                break;
@@ -2028,10 +2029,10 @@ __acquires(musb->lock)
         * or else after HNP, as A-Device
         */
        if (devctl & MUSB_DEVCTL_BDEVICE) {
-               musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
+               musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
                musb->g.is_a_peripheral = 0;
        } else if (is_otg_enabled(musb)) {
-               musb->xceiv.state = OTG_STATE_A_PERIPHERAL;
+               musb->xceiv->state = OTG_STATE_A_PERIPHERAL;
                musb->g.is_a_peripheral = 1;
        } else
                WARN_ON(1);
index 3f5e30ddfa275abc7a4523eeb45001164df9a0e0..40ed50ecedff6ed84a72d4342616a6f07e36f362 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright 2005 Mentor Graphics Corporation
  * Copyright (C) 2005-2006 by Texas Instruments
  * Copyright (C) 2006-2007 Nokia Corporation
+ * Copyright (C) 2008-2009 MontaVista Software, Inc. <source@mvista.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -58,7 +59,8 @@
 static char *decode_ep0stage(u8 stage)
 {
        switch (stage) {
-       case MUSB_EP0_STAGE_SETUP:      return "idle";
+       case MUSB_EP0_STAGE_IDLE:       return "idle";
+       case MUSB_EP0_STAGE_SETUP:      return "setup";
        case MUSB_EP0_STAGE_TX:         return "in";
        case MUSB_EP0_STAGE_RX:         return "out";
        case MUSB_EP0_STAGE_ACKWAIT:    return "wait";
@@ -628,7 +630,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
                musb_writew(regs, MUSB_CSR0,
                                csr & ~MUSB_CSR0_P_SENTSTALL);
                retval = IRQ_HANDLED;
-               musb->ep0_state = MUSB_EP0_STAGE_SETUP;
+               musb->ep0_state = MUSB_EP0_STAGE_IDLE;
                csr = musb_readw(regs, MUSB_CSR0);
        }
 
@@ -636,7 +638,18 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
        if (csr & MUSB_CSR0_P_SETUPEND) {
                musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SVDSETUPEND);
                retval = IRQ_HANDLED;
-               musb->ep0_state = MUSB_EP0_STAGE_SETUP;
+               /* Transition into the early status phase */
+               switch (musb->ep0_state) {
+               case MUSB_EP0_STAGE_TX:
+                       musb->ep0_state = MUSB_EP0_STAGE_STATUSOUT;
+                       break;
+               case MUSB_EP0_STAGE_RX:
+                       musb->ep0_state = MUSB_EP0_STAGE_STATUSIN;
+                       break;
+               default:
+                       ERR("SetupEnd came in a wrong ep0stage %s",
+                           decode_ep0stage(musb->ep0_state));
+               }
                csr = musb_readw(regs, MUSB_CSR0);
                /* NOTE:  request may need completion */
        }
@@ -697,11 +710,31 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
                        if (req)
                                musb_g_ep0_giveback(musb, req);
                }
+
+               /*
+                * In case when several interrupts can get coalesced,
+                * check to see if we've already received a SETUP packet...
+                */
+               if (csr & MUSB_CSR0_RXPKTRDY)
+                       goto setup;
+
+               retval = IRQ_HANDLED;
+               musb->ep0_state = MUSB_EP0_STAGE_IDLE;
+               break;
+
+       case MUSB_EP0_STAGE_IDLE:
+               /*
+                * This state is typically (but not always) indiscernible
+                * from the status states since the corresponding interrupts
+                * tend to happen within too little period of time (with only
+                * a zero-length packet in between) and so get coalesced...
+                */
                retval = IRQ_HANDLED;
                musb->ep0_state = MUSB_EP0_STAGE_SETUP;
                /* FALLTHROUGH */
 
        case MUSB_EP0_STAGE_SETUP:
+setup:
                if (csr & MUSB_CSR0_RXPKTRDY) {
                        struct usb_ctrlrequest  setup;
                        int                     handled = 0;
@@ -783,7 +816,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
 stall:
                                DBG(3, "stall (%d)\n", handled);
                                musb->ackpend |= MUSB_CSR0_P_SENDSTALL;
-                               musb->ep0_state = MUSB_EP0_STAGE_SETUP;
+                               musb->ep0_state = MUSB_EP0_STAGE_IDLE;
 finish:
                                musb_writew(regs, MUSB_CSR0,
                                                musb->ackpend);
@@ -803,7 +836,7 @@ finish:
                /* "can't happen" */
                WARN_ON(1);
                musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SENDSTALL);
-               musb->ep0_state = MUSB_EP0_STAGE_SETUP;
+               musb->ep0_state = MUSB_EP0_STAGE_IDLE;
                break;
        }
 
@@ -959,7 +992,7 @@ static int musb_g_ep0_halt(struct usb_ep *e, int value)
 
                csr |= MUSB_CSR0_P_SENDSTALL;
                musb_writew(regs, MUSB_CSR0, csr);
-               musb->ep0_state = MUSB_EP0_STAGE_SETUP;
+               musb->ep0_state = MUSB_EP0_STAGE_IDLE;
                musb->ackpend = 0;
                break;
        default:
index db1b57415ec7ad2a443d35cce7a8202de2f4bfef..94a2a350a4141521e9e4d93426700ed3a31aaf6b 100644 (file)
@@ -181,6 +181,19 @@ static inline void musb_h_tx_dma_start(struct musb_hw_ep *ep)
        musb_writew(ep->regs, MUSB_TXCSR, txcsr);
 }
 
+static void musb_ep_set_qh(struct musb_hw_ep *ep, int is_in, struct musb_qh *qh)
+{
+       if (is_in != 0 || ep->is_shared_fifo)
+               ep->in_qh  = qh;
+       if (is_in == 0 || ep->is_shared_fifo)
+               ep->out_qh = qh;
+}
+
+static struct musb_qh *musb_ep_get_qh(struct musb_hw_ep *ep, int is_in)
+{
+       return is_in ? ep->in_qh : ep->out_qh;
+}
+
 /*
  * Start the URB at the front of an endpoint's queue
  * end must be claimed from the caller.
@@ -210,7 +223,6 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
        case USB_ENDPOINT_XFER_CONTROL:
                /* control transfers always start with SETUP */
                is_in = 0;
-               hw_ep->out_qh = qh;
                musb->ep0_stage = MUSB_EP0_START;
                buf = urb->setup_packet;
                len = 8;
@@ -239,10 +251,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
                        epnum, buf + offset, len);
 
        /* Configure endpoint */
-       if (is_in || hw_ep->is_shared_fifo)
-               hw_ep->in_qh = qh;
-       else
-               hw_ep->out_qh = qh;
+       musb_ep_set_qh(hw_ep, is_in, qh);
        musb_ep_program(musb, epnum, urb, !is_in, buf, offset, len);
 
        /* transmit may have more work: start it when it is time */
@@ -286,9 +295,8 @@ start:
        }
 }
 
-/* caller owns controller lock, irqs are blocked */
-static void
-__musb_giveback(struct musb *musb, struct urb *urb, int status)
+/* Context: caller owns controller lock, IRQs are blocked */
+static void musb_giveback(struct musb *musb, struct urb *urb, int status)
 __releases(musb->lock)
 __acquires(musb->lock)
 {
@@ -321,60 +329,57 @@ __acquires(musb->lock)
        spin_lock(&musb->lock);
 }
 
-/* for bulk/interrupt endpoints only */
-static inline void
-musb_save_toggle(struct musb_hw_ep *ep, int is_in, struct urb *urb)
+/* For bulk/interrupt endpoints only */
+static inline void musb_save_toggle(struct musb_qh *qh, int is_in,
+                                   struct urb *urb)
 {
-       struct usb_device       *udev = urb->dev;
+       void __iomem            *epio = qh->hw_ep->regs;
        u16                     csr;
-       void __iomem            *epio = ep->regs;
-       struct musb_qh          *qh;
 
-       /* FIXME:  the current Mentor DMA code seems to have
+       /*
+        * FIXME: the current Mentor DMA code seems to have
         * problems getting toggle correct.
         */
 
-       if (is_in || ep->is_shared_fifo)
-               qh = ep->in_qh;
+       if (is_in)
+               csr = musb_readw(epio, MUSB_RXCSR) & MUSB_RXCSR_H_DATATOGGLE;
        else
-               qh = ep->out_qh;
+               csr = musb_readw(epio, MUSB_TXCSR) & MUSB_TXCSR_H_DATATOGGLE;
 
-       if (!is_in) {
-               csr = musb_readw(epio, MUSB_TXCSR);
-               usb_settoggle(udev, qh->epnum, 1,
-                       (csr & MUSB_TXCSR_H_DATATOGGLE)
-                               ? 1 : 0);
-       } else {
-               csr = musb_readw(epio, MUSB_RXCSR);
-               usb_settoggle(udev, qh->epnum, 0,
-                       (csr & MUSB_RXCSR_H_DATATOGGLE)
-                               ? 1 : 0);
-       }
+       usb_settoggle(urb->dev, qh->epnum, !is_in, csr ? 1 : 0);
 }
 
-/* caller owns controller lock, irqs are blocked */
-static struct musb_qh *
-musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
+/*
+ * Advance this hardware endpoint's queue, completing the specified URB and
+ * advancing to either the next URB queued to that qh, or else invalidating
+ * that qh and advancing to the next qh scheduled after the current one.
+ *
+ * Context: caller owns controller lock, IRQs are blocked
+ */
+static void musb_advance_schedule(struct musb *musb, struct urb *urb,
+                                 struct musb_hw_ep *hw_ep, int is_in)
 {
+       struct musb_qh          *qh = musb_ep_get_qh(hw_ep, is_in);
        struct musb_hw_ep       *ep = qh->hw_ep;
-       struct musb             *musb = ep->musb;
-       int                     is_in = usb_pipein(urb->pipe);
        int                     ready = qh->is_ready;
+       int                     status;
+
+       status = (urb->status == -EINPROGRESS) ? 0 : urb->status;
 
        /* save toggle eagerly, for paranoia */
        switch (qh->type) {
        case USB_ENDPOINT_XFER_BULK:
        case USB_ENDPOINT_XFER_INT:
-               musb_save_toggle(ep, is_in, urb);
+               musb_save_toggle(qh, is_in, urb);
                break;
        case USB_ENDPOINT_XFER_ISOC:
-               if (status == 0 && urb->error_count)
+               if (urb->error_count)
                        status = -EXDEV;
                break;
        }
 
        qh->is_ready = 0;
-       __musb_giveback(musb, urb, status);
+       musb_giveback(musb, urb, status);
        qh->is_ready = ready;
 
        /* reclaim resources (and bandwidth) ASAP; deschedule it, and
@@ -388,11 +393,8 @@ musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
                else
                        ep->tx_reinit = 1;
 
-               /* clobber old pointers to this qh */
-               if (is_in || ep->is_shared_fifo)
-                       ep->in_qh = NULL;
-               else
-                       ep->out_qh = NULL;
+               /* Clobber old pointers to this qh */
+               musb_ep_set_qh(ep, is_in, NULL);
                qh->hep->hcpriv = NULL;
 
                switch (qh->type) {
@@ -421,36 +423,10 @@ musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
                        break;
                }
        }
-       return qh;
-}
-
-/*
- * Advance this hardware endpoint's queue, completing the specified urb and
- * advancing to either the next urb queued to that qh, or else invalidating
- * that qh and advancing to the next qh scheduled after the current one.
- *
- * Context: caller owns controller lock, irqs are blocked
- */
-static void
-musb_advance_schedule(struct musb *musb, struct urb *urb,
-               struct musb_hw_ep *hw_ep, int is_in)
-{
-       struct musb_qh  *qh;
-
-       if (is_in || hw_ep->is_shared_fifo)
-               qh = hw_ep->in_qh;
-       else
-               qh = hw_ep->out_qh;
-
-       if (urb->status == -EINPROGRESS)
-               qh = musb_giveback(qh, urb, 0);
-       else
-               qh = musb_giveback(qh, urb, urb->status);
 
        if (qh != NULL && qh->is_ready) {
                DBG(4, "... next ep%d %cX urb %p\n",
-                               hw_ep->epnum, is_in ? 'R' : 'T',
-                               next_urb(qh));
+                   hw_ep->epnum, is_in ? 'R' : 'T', next_urb(qh));
                musb_start_urb(musb, is_in, qh);
        }
 }
@@ -629,7 +605,8 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep)
        musb_writeb(ep->regs, MUSB_RXTYPE, qh->type_reg);
        musb_writeb(ep->regs, MUSB_RXINTERVAL, qh->intv_reg);
        /* NOTE: bulk combining rewrites high bits of maxpacket */
-       musb_writew(ep->regs, MUSB_RXMAXP, qh->maxpacket);
+       musb_writew(ep->regs, MUSB_RXMAXP,
+                       qh->maxpacket | ((qh->hb_mult - 1) << 11));
 
        ep->rx_reinit = 0;
 }
@@ -651,9 +628,10 @@ static bool musb_tx_dma_program(struct dma_controller *dma,
        csr = musb_readw(epio, MUSB_TXCSR);
        if (length > pkt_size) {
                mode = 1;
-               csr |= MUSB_TXCSR_AUTOSET
-                       | MUSB_TXCSR_DMAMODE
-                       | MUSB_TXCSR_DMAENAB;
+               csr |= MUSB_TXCSR_DMAMODE | MUSB_TXCSR_DMAENAB;
+               /* autoset shouldn't be set in high bandwidth */
+               if (qh->hb_mult == 1)
+                       csr |= MUSB_TXCSR_AUTOSET;
        } else {
                mode = 0;
                csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAMODE);
@@ -703,15 +681,8 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
        void __iomem            *mbase = musb->mregs;
        struct musb_hw_ep       *hw_ep = musb->endpoints + epnum;
        void __iomem            *epio = hw_ep->regs;
-       struct musb_qh          *qh;
-       u16                     packet_sz;
-
-       if (!is_out || hw_ep->is_shared_fifo)
-               qh = hw_ep->in_qh;
-       else
-               qh = hw_ep->out_qh;
-
-       packet_sz = qh->maxpacket;
+       struct musb_qh          *qh = musb_ep_get_qh(hw_ep, !is_out);
+       u16                     packet_sz = qh->maxpacket;
 
        DBG(3, "%s hw%d urb %p spd%d dev%d ep%d%s "
                                "h_addr%02x h_port%02x bytes %d\n",
@@ -1129,17 +1100,14 @@ void musb_host_tx(struct musb *musb, u8 epnum)
        u16                     tx_csr;
        size_t                  length = 0;
        size_t                  offset = 0;
-       struct urb              *urb;
        struct musb_hw_ep       *hw_ep = musb->endpoints + epnum;
        void __iomem            *epio = hw_ep->regs;
-       struct musb_qh          *qh = hw_ep->is_shared_fifo ? hw_ep->in_qh
-                                                           : hw_ep->out_qh;
+       struct musb_qh          *qh = hw_ep->out_qh;
+       struct urb              *urb = next_urb(qh);
        u32                     status = 0;
        void __iomem            *mbase = musb->mregs;
        struct dma_channel      *dma;
 
-       urb = next_urb(qh);
-
        musb_ep_select(mbase, epnum);
        tx_csr = musb_readw(epio, MUSB_TXCSR);
 
@@ -1427,7 +1395,7 @@ static void musb_bulk_rx_nak_timeout(struct musb *musb, struct musb_hw_ep *ep)
                        urb->actual_length += dma->actual_len;
                        dma->actual_len = 0L;
                }
-               musb_save_toggle(ep, 1, urb);
+               musb_save_toggle(cur_qh, 1, urb);
 
                /* move cur_qh to end of queue */
                list_move_tail(&cur_qh->ring, &musb->in_bulk);
@@ -1531,6 +1499,10 @@ void musb_host_rx(struct musb *musb, u8 epnum)
                        /* packet error reported later */
                        iso_err = true;
                }
+       } else if (rx_csr & MUSB_RXCSR_INCOMPRX) {
+               DBG(3, "end %d high bandwidth incomplete ISO packet RX\n",
+                               epnum);
+               status = -EPROTO;
        }
 
        /* faults abort the transfer */
@@ -1738,7 +1710,11 @@ void musb_host_rx(struct musb *musb, u8 epnum)
                                val &= ~MUSB_RXCSR_H_AUTOREQ;
                        else
                                val |= MUSB_RXCSR_H_AUTOREQ;
-                       val |= MUSB_RXCSR_AUTOCLEAR | MUSB_RXCSR_DMAENAB;
+                       val |= MUSB_RXCSR_DMAENAB;
+
+                       /* autoclear shouldn't be set in high bandwidth */
+                       if (qh->hb_mult == 1)
+                               val |= MUSB_RXCSR_AUTOCLEAR;
 
                        musb_writew(epio, MUSB_RXCSR,
                                MUSB_RXCSR_H_WZC_BITS | val);
@@ -1817,19 +1793,17 @@ static int musb_schedule(
                        epnum++, hw_ep++) {
                int     diff;
 
-               if (is_in || hw_ep->is_shared_fifo) {
-                       if (hw_ep->in_qh  != NULL)
-                               continue;
-               } else  if (hw_ep->out_qh != NULL)
+               if (musb_ep_get_qh(hw_ep, is_in) != NULL)
                        continue;
 
                if (hw_ep == musb->bulk_ep)
                        continue;
 
                if (is_in)
-                       diff = hw_ep->max_packet_sz_rx - qh->maxpacket;
+                       diff = hw_ep->max_packet_sz_rx;
                else
-                       diff = hw_ep->max_packet_sz_tx - qh->maxpacket;
+                       diff = hw_ep->max_packet_sz_tx;
+               diff -= (qh->maxpacket * qh->hb_mult);
 
                if (diff >= 0 && best_diff > diff) {
                        best_diff = diff;
@@ -1932,15 +1906,27 @@ static int musb_urb_enqueue(
        qh->is_ready = 1;
 
        qh->maxpacket = le16_to_cpu(epd->wMaxPacketSize);
+       qh->type = usb_endpoint_type(epd);
 
-       /* no high bandwidth support yet */
-       if (qh->maxpacket & ~0x7ff) {
-               ret = -EMSGSIZE;
-               goto done;
+       /* Bits 11 & 12 of wMaxPacketSize encode high bandwidth multiplier.
+        * Some musb cores don't support high bandwidth ISO transfers; and
+        * we don't (yet!) support high bandwidth interrupt transfers.
+        */
+       qh->hb_mult = 1 + ((qh->maxpacket >> 11) & 0x03);
+       if (qh->hb_mult > 1) {
+               int ok = (qh->type == USB_ENDPOINT_XFER_ISOC);
+
+               if (ok)
+                       ok = (usb_pipein(urb->pipe) && musb->hb_iso_rx)
+                               || (usb_pipeout(urb->pipe) && musb->hb_iso_tx);
+               if (!ok) {
+                       ret = -EMSGSIZE;
+                       goto done;
+               }
+               qh->maxpacket &= 0x7ff;
        }
 
        qh->epnum = usb_endpoint_num(epd);
-       qh->type = usb_endpoint_type(epd);
 
        /* NOTE: urb->dev->devnum is wrong during SET_ADDRESS */
        qh->addr_reg = (u8) usb_pipedevice(urb->pipe);
@@ -2052,14 +2038,15 @@ done:
  * called with controller locked, irqs blocked
  * that hardware queue advances to the next transfer, unless prevented
  */
-static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh, int is_in)
+static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh)
 {
        struct musb_hw_ep       *ep = qh->hw_ep;
        void __iomem            *epio = ep->regs;
        unsigned                hw_end = ep->epnum;
        void __iomem            *regs = ep->musb->mregs;
-       u16                     csr;
+       int                     is_in = usb_pipein(urb->pipe);
        int                     status = 0;
+       u16                     csr;
 
        musb_ep_select(regs, hw_end);
 
@@ -2112,14 +2099,14 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
        struct musb             *musb = hcd_to_musb(hcd);
        struct musb_qh          *qh;
-       struct list_head        *sched;
        unsigned long           flags;
+       int                     is_in  = usb_pipein(urb->pipe);
        int                     ret;
 
        DBG(4, "urb=%p, dev%d ep%d%s\n", urb,
                        usb_pipedevice(urb->pipe),
                        usb_pipeendpoint(urb->pipe),
-                       usb_pipein(urb->pipe) ? "in" : "out");
+                       is_in ? "in" : "out");
 
        spin_lock_irqsave(&musb->lock, flags);
        ret = usb_hcd_check_unlink_urb(hcd, urb, status);
@@ -2130,47 +2117,25 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
        if (!qh)
                goto done;
 
-       /* Any URB not actively programmed into endpoint hardware can be
+       /*
+        * Any URB not actively programmed into endpoint hardware can be
         * immediately given back; that's any URB not at the head of an
         * endpoint queue, unless someday we get real DMA queues.  And even
         * if it's at the head, it might not be known to the hardware...
         *
-        * Otherwise abort current transfer, pending dma, etc.; urb->status
+        * Otherwise abort current transfer, pending DMA, etc.; urb->status
         * has already been updated.  This is a synchronous abort; it'd be
         * OK to hold off until after some IRQ, though.
+        *
+        * NOTE: qh is invalid unless !list_empty(&hep->urb_list)
         */
-       if (!qh->is_ready || urb->urb_list.prev != &qh->hep->urb_list)
-               ret = -EINPROGRESS;
-       else {
-               switch (qh->type) {
-               case USB_ENDPOINT_XFER_CONTROL:
-                       sched = &musb->control;
-                       break;
-               case USB_ENDPOINT_XFER_BULK:
-                       if (qh->mux == 1) {
-                               if (usb_pipein(urb->pipe))
-                                       sched = &musb->in_bulk;
-                               else
-                                       sched = &musb->out_bulk;
-                               break;
-                       }
-               default:
-                       /* REVISIT when we get a schedule tree, periodic
-                        * transfers won't always be at the head of a
-                        * singleton queue...
-                        */
-                       sched = NULL;
-                       break;
-               }
-       }
-
-       /* NOTE:  qh is invalid unless !list_empty(&hep->urb_list) */
-       if (ret < 0 || (sched && qh != first_qh(sched))) {
+       if (!qh->is_ready
+                       || urb->urb_list.prev != &qh->hep->urb_list
+                       || musb_ep_get_qh(qh->hw_ep, is_in) != qh) {
                int     ready = qh->is_ready;
 
-               ret = 0;
                qh->is_ready = 0;
-               __musb_giveback(musb, urb, 0);
+               musb_giveback(musb, urb, 0);
                qh->is_ready = ready;
 
                /* If nothing else (usually musb_giveback) is using it
@@ -2182,7 +2147,7 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                        kfree(qh);
                }
        } else
-               ret = musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
+               ret = musb_cleanup_urb(urb, qh);
 done:
        spin_unlock_irqrestore(&musb->lock, flags);
        return ret;
@@ -2192,13 +2157,11 @@ done:
 static void
 musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
 {
-       u8                      epnum = hep->desc.bEndpointAddress;
+       u8                      is_in = hep->desc.bEndpointAddress & USB_DIR_IN;
        unsigned long           flags;
        struct musb             *musb = hcd_to_musb(hcd);
-       u8                      is_in = epnum & USB_DIR_IN;
        struct musb_qh          *qh;
        struct urb              *urb;
-       struct list_head        *sched;
 
        spin_lock_irqsave(&musb->lock, flags);
 
@@ -2206,31 +2169,11 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
        if (qh == NULL)
                goto exit;
 
-       switch (qh->type) {
-       case USB_ENDPOINT_XFER_CONTROL:
-               sched = &musb->control;
-               break;
-       case USB_ENDPOINT_XFER_BULK:
-               if (qh->mux == 1) {
-                       if (is_in)
-                               sched = &musb->in_bulk;
-                       else
-                               sched = &musb->out_bulk;
-                       break;
-               }
-       default:
-               /* REVISIT when we get a schedule tree, periodic transfers
-                * won't always be at the head of a singleton queue...
-                */
-               sched = NULL;
-               break;
-       }
-
-       /* NOTE:  qh is invalid unless !list_empty(&hep->urb_list) */
+       /* NOTE: qh is invalid unless !list_empty(&hep->urb_list) */
 
-       /* kick first urb off the hardware, if needed */
+       /* Kick the first URB off the hardware, if needed */
        qh->is_ready = 0;
-       if (!sched || qh == first_qh(sched)) {
+       if (musb_ep_get_qh(qh->hw_ep, is_in) == qh) {
                urb = next_urb(qh);
 
                /* make software (then hardware) stop ASAP */
@@ -2238,7 +2181,7 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
                        urb->status = -ESHUTDOWN;
 
                /* cleanup */
-               musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
+               musb_cleanup_urb(urb, qh);
 
                /* Then nuke all the others ... and advance the
                 * queue on hw_ep (e.g. bulk ring) when we're done.
@@ -2254,7 +2197,7 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
                 * will activate any of these as it advances.
                 */
                while (!list_empty(&hep->urb_list))
-                       __musb_giveback(musb, next_urb(qh), -ESHUTDOWN);
+                       musb_giveback(musb, next_urb(qh), -ESHUTDOWN);
 
                hep->hcpriv = NULL;
                list_del(&qh->ring);
@@ -2293,7 +2236,7 @@ static int musb_bus_suspend(struct usb_hcd *hcd)
 {
        struct musb     *musb = hcd_to_musb(hcd);
 
-       if (musb->xceiv.state == OTG_STATE_A_SUSPEND)
+       if (musb->xceiv->state == OTG_STATE_A_SUSPEND)
                return 0;
 
        if (is_host_active(musb) && musb->is_active) {
index 0b7fbcd21963ebcc23435d168a061bed741ff612..14b00776638dab987c233d72b9b66da462214e90 100644 (file)
@@ -67,6 +67,7 @@ struct musb_qh {
        u8                      is_ready;       /* safe to modify hw_ep */
        u8                      type;           /* XFERTYPE_* */
        u8                      epnum;
+       u8                      hb_mult;        /* high bandwidth pkts per uf */
        u16                     maxpacket;
        u16                     frame;          /* for periodic schedule */
        unsigned                iso_idx;        /* in urb->iso_frame_desc[] */
index bf677acc83db03e781bb786642b1e5121ee1f627..bfe5fe4ebfeeb87b49e6f762aa670d0aed4da8aa 100644 (file)
@@ -78,18 +78,22 @@ static void musb_port_suspend(struct musb *musb, bool do_suspend)
                DBG(3, "Root port suspended, power %02x\n", power);
 
                musb->port1_status |= USB_PORT_STAT_SUSPEND;
-               switch (musb->xceiv.state) {
+               switch (musb->xceiv->state) {
                case OTG_STATE_A_HOST:
-                       musb->xceiv.state = OTG_STATE_A_SUSPEND;
+                       musb->xceiv->state = OTG_STATE_A_SUSPEND;
                        musb->is_active = is_otg_enabled(musb)
-                                       && musb->xceiv.host->b_hnp_enable;
+                                       && musb->xceiv->host->b_hnp_enable;
+                       if (musb->is_active)
+                               mod_timer(&musb->otg_timer, jiffies
+                                       + msecs_to_jiffies(
+                                               OTG_TIME_A_AIDL_BDIS));
                        musb_platform_try_idle(musb, 0);
                        break;
 #ifdef CONFIG_USB_MUSB_OTG
                case OTG_STATE_B_HOST:
-                       musb->xceiv.state = OTG_STATE_B_WAIT_ACON;
+                       musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
                        musb->is_active = is_otg_enabled(musb)
-                                       && musb->xceiv.host->b_hnp_enable;
+                                       && musb->xceiv->host->b_hnp_enable;
                        musb_platform_try_idle(musb, 0);
                        break;
 #endif
@@ -116,7 +120,7 @@ static void musb_port_reset(struct musb *musb, bool do_reset)
        void __iomem    *mbase = musb->mregs;
 
 #ifdef CONFIG_USB_MUSB_OTG
-       if (musb->xceiv.state == OTG_STATE_B_IDLE) {
+       if (musb->xceiv->state == OTG_STATE_B_IDLE) {
                DBG(2, "HNP: Returning from HNP; no hub reset from b_idle\n");
                musb->port1_status &= ~USB_PORT_STAT_RESET;
                return;
@@ -186,14 +190,23 @@ void musb_root_disconnect(struct musb *musb)
        usb_hcd_poll_rh_status(musb_to_hcd(musb));
        musb->is_active = 0;
 
-       switch (musb->xceiv.state) {
-       case OTG_STATE_A_HOST:
+       switch (musb->xceiv->state) {
        case OTG_STATE_A_SUSPEND:
-               musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
+#ifdef CONFIG_USB_MUSB_OTG
+               if (is_otg_enabled(musb)
+                               && musb->xceiv->host->b_hnp_enable) {
+                       musb->xceiv->state = OTG_STATE_A_PERIPHERAL;
+                       musb->g.is_a_peripheral = 1;
+                       break;
+               }
+#endif
+               /* FALLTHROUGH */
+       case OTG_STATE_A_HOST:
+               musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
                musb->is_active = 0;
                break;
        case OTG_STATE_A_WAIT_VFALL:
-               musb->xceiv.state = OTG_STATE_B_IDLE;
+               musb->xceiv->state = OTG_STATE_B_IDLE;
                break;
        default:
                DBG(1, "host disconnect (%s)\n", otg_state_string(musb));
@@ -332,7 +345,7 @@ int musb_hub_control(
                        musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
                        usb_hcd_poll_rh_status(musb_to_hcd(musb));
                        /* NOTE: it might really be A_WAIT_BCON ... */
-                       musb->xceiv.state = OTG_STATE_A_HOST;
+                       musb->xceiv->state = OTG_STATE_A_HOST;
                }
 
                put_unaligned(cpu_to_le32(musb->port1_status
index 60924ce084934f7f9a619a5ff12f6d1fd8afc3d9..34875201ee041220c715a9df268840b026009696 100644 (file)
@@ -44,7 +44,6 @@
 #define        get_cpu_rev()   2
 #endif
 
-#define MUSB_TIMEOUT_A_WAIT_BCON       1100
 
 static struct timer_list musb_idle_timer;
 
@@ -61,17 +60,17 @@ static void musb_do_idle(unsigned long _musb)
 
        devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
 
-       switch (musb->xceiv.state) {
+       switch (musb->xceiv->state) {
        case OTG_STATE_A_WAIT_BCON:
                devctl &= ~MUSB_DEVCTL_SESSION;
                musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
 
                devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
                if (devctl & MUSB_DEVCTL_BDEVICE) {
-                       musb->xceiv.state = OTG_STATE_B_IDLE;
+                       musb->xceiv->state = OTG_STATE_B_IDLE;
                        MUSB_DEV_MODE(musb);
                } else {
-                       musb->xceiv.state = OTG_STATE_A_IDLE;
+                       musb->xceiv->state = OTG_STATE_A_IDLE;
                        MUSB_HST_MODE(musb);
                }
                break;
@@ -89,7 +88,7 @@ static void musb_do_idle(unsigned long _musb)
                        musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
                        usb_hcd_poll_rh_status(musb_to_hcd(musb));
                        /* NOTE: it might really be A_WAIT_BCON ... */
-                       musb->xceiv.state = OTG_STATE_A_HOST;
+                       musb->xceiv->state = OTG_STATE_A_HOST;
                }
                break;
 #endif
@@ -97,9 +96,9 @@ static void musb_do_idle(unsigned long _musb)
        case OTG_STATE_A_HOST:
                devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
                if (devctl &  MUSB_DEVCTL_BDEVICE)
-                       musb->xceiv.state = OTG_STATE_B_IDLE;
+                       musb->xceiv->state = OTG_STATE_B_IDLE;
                else
-                       musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
+                       musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
 #endif
        default:
                break;
@@ -118,7 +117,7 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
 
        /* Never idle if active, or when VBUS timeout is not set as host */
        if (musb->is_active || ((musb->a_wait_bcon == 0)
-                       && (musb->xceiv.state == OTG_STATE_A_WAIT_BCON))) {
+                       && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) {
                DBG(4, "%s active, deleting timer\n", otg_state_string(musb));
                del_timer(&musb_idle_timer);
                last_timer = jiffies;
@@ -163,8 +162,8 @@ static void omap_set_vbus(struct musb *musb, int is_on)
 
        if (is_on) {
                musb->is_active = 1;
-               musb->xceiv.default_a = 1;
-               musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
+               musb->xceiv->default_a = 1;
+               musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
                devctl |= MUSB_DEVCTL_SESSION;
 
                MUSB_HST_MODE(musb);
@@ -175,8 +174,8 @@ static void omap_set_vbus(struct musb *musb, int is_on)
                 * jumping right to B_IDLE...
                 */
 
-               musb->xceiv.default_a = 0;
-               musb->xceiv.state = OTG_STATE_B_IDLE;
+               musb->xceiv->default_a = 0;
+               musb->xceiv->state = OTG_STATE_B_IDLE;
                devctl &= ~MUSB_DEVCTL_SESSION;
 
                MUSB_DEV_MODE(musb);
@@ -188,10 +187,6 @@ static void omap_set_vbus(struct musb *musb, int is_on)
                otg_state_string(musb),
                musb_readb(musb->mregs, MUSB_DEVCTL));
 }
-static int omap_set_power(struct otg_transceiver *x, unsigned mA)
-{
-       return 0;
-}
 
 static int musb_platform_resume(struct musb *musb);
 
@@ -202,24 +197,6 @@ int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
        devctl |= MUSB_DEVCTL_SESSION;
        musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
 
-       switch (musb_mode) {
-#ifdef CONFIG_USB_MUSB_HDRC_HCD
-       case MUSB_HOST:
-               otg_set_host(&musb->xceiv, musb->xceiv.host);
-               break;
-#endif
-#ifdef CONFIG_USB_GADGET_MUSB_HDRC
-       case MUSB_PERIPHERAL:
-               otg_set_peripheral(&musb->xceiv, musb->xceiv.gadget);
-               break;
-#endif
-#ifdef CONFIG_USB_MUSB_OTG
-       case MUSB_OTG:
-               break;
-#endif
-       default:
-               return -EINVAL;
-       }
        return 0;
 }
 
@@ -231,6 +208,16 @@ int __init musb_platform_init(struct musb *musb)
        omap_cfg_reg(AE5_2430_USB0HS_STP);
 #endif
 
+       /* We require some kind of external transceiver, hooked
+        * up through ULPI.  TWL4030-family PMICs include one,
+        * which needs a driver, drivers aren't always needed.
+        */
+       musb->xceiv = otg_get_transceiver();
+       if (!musb->xceiv) {
+               pr_err("HS USB OTG: no transceiver configured\n");
+               return -ENODEV;
+       }
+
        musb_platform_resume(musb);
 
        l = omap_readl(OTG_SYSCONFIG);
@@ -240,7 +227,12 @@ int __init musb_platform_init(struct musb *musb)
        l &= ~AUTOIDLE;         /* disable auto idle */
        l &= ~NOIDLE;           /* remove possible noidle */
        l |= SMARTIDLE;         /* enable smart idle */
-       l |= AUTOIDLE;          /* enable auto idle */
+       /*
+        * MUSB AUTOIDLE don't work in 3430.
+        * Workaround by Richard Woodruff/TI
+        */
+       if (!cpu_is_omap3430())
+               l |= AUTOIDLE;          /* enable auto idle */
        omap_writel(l, OTG_SYSCONFIG);
 
        l = omap_readl(OTG_INTERFSEL);
@@ -257,9 +249,6 @@ int __init musb_platform_init(struct musb *musb)
 
        if (is_host_enabled(musb))
                musb->board_set_vbus = omap_set_vbus;
-       if (is_peripheral_enabled(musb))
-               musb->xceiv.set_power = omap_set_power;
-       musb->a_wait_bcon = MUSB_TIMEOUT_A_WAIT_BCON;
 
        setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
 
@@ -282,8 +271,7 @@ int musb_platform_suspend(struct musb *musb)
        l |= ENABLEWAKEUP;      /* enable wakeup */
        omap_writel(l, OTG_SYSCONFIG);
 
-       if (musb->xceiv.set_suspend)
-               musb->xceiv.set_suspend(&musb->xceiv, 1);
+       otg_set_suspend(musb->xceiv, 1);
 
        if (musb->set_clock)
                musb->set_clock(musb->clock, 0);
@@ -300,8 +288,7 @@ static int musb_platform_resume(struct musb *musb)
        if (!musb->clock)
                return 0;
 
-       if (musb->xceiv.set_suspend)
-               musb->xceiv.set_suspend(&musb->xceiv, 0);
+       otg_set_suspend(musb->xceiv, 0);
 
        if (musb->set_clock)
                musb->set_clock(musb->clock, 1);
index 4ac1477d356901b62b10758b9d5e073ff940d30e..88b587c703e96cfea7ce2149190cdecb1003ba42 100644 (file)
@@ -259,6 +259,8 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf)
                tusb_fifo_read_unaligned(fifo, buf, len);
 }
 
+static struct musb *the_musb;
+
 #ifdef CONFIG_USB_GADGET_MUSB_HDRC
 
 /* This is used by gadget drivers, and OTG transceiver logic, allowing
@@ -269,7 +271,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf)
  */
 static int tusb_draw_power(struct otg_transceiver *x, unsigned mA)
 {
-       struct musb     *musb = container_of(x, struct musb, xceiv);
+       struct musb     *musb = the_musb;
        void __iomem    *tbase = musb->ctrl_base;
        u32             reg;
 
@@ -419,7 +421,7 @@ static void musb_do_idle(unsigned long _musb)
 
        spin_lock_irqsave(&musb->lock, flags);
 
-       switch (musb->xceiv.state) {
+       switch (musb->xceiv->state) {
        case OTG_STATE_A_WAIT_BCON:
                if ((musb->a_wait_bcon != 0)
                        && (musb->idle_timeout == 0
@@ -483,7 +485,7 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
 
        /* Never idle if active, or when VBUS timeout is not set as host */
        if (musb->is_active || ((musb->a_wait_bcon == 0)
-                       && (musb->xceiv.state == OTG_STATE_A_WAIT_BCON))) {
+                       && (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) {
                DBG(4, "%s active, deleting timer\n", otg_state_string(musb));
                del_timer(&musb_idle_timer);
                last_timer = jiffies;
@@ -532,8 +534,8 @@ static void tusb_source_power(struct musb *musb, int is_on)
                if (musb->set_clock)
                        musb->set_clock(musb->clock, 1);
                timer = OTG_TIMER_MS(OTG_TIME_A_WAIT_VRISE);
-               musb->xceiv.default_a = 1;
-               musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
+               musb->xceiv->default_a = 1;
+               musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
                devctl |= MUSB_DEVCTL_SESSION;
 
                conf |= TUSB_DEV_CONF_USB_HOST_MODE;
@@ -546,24 +548,24 @@ static void tusb_source_power(struct musb *musb, int is_on)
                /* If ID pin is grounded, we want to be a_idle */
                otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT);
                if (!(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS)) {
-                       switch (musb->xceiv.state) {
+                       switch (musb->xceiv->state) {
                        case OTG_STATE_A_WAIT_VRISE:
                        case OTG_STATE_A_WAIT_BCON:
-                               musb->xceiv.state = OTG_STATE_A_WAIT_VFALL;
+                               musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
                                break;
                        case OTG_STATE_A_WAIT_VFALL:
-                               musb->xceiv.state = OTG_STATE_A_IDLE;
+                               musb->xceiv->state = OTG_STATE_A_IDLE;
                                break;
                        default:
-                               musb->xceiv.state = OTG_STATE_A_IDLE;
+                               musb->xceiv->state = OTG_STATE_A_IDLE;
                        }
                        musb->is_active = 0;
-                       musb->xceiv.default_a = 1;
+                       musb->xceiv->default_a = 1;
                        MUSB_HST_MODE(musb);
                } else {
                        musb->is_active = 0;
-                       musb->xceiv.default_a = 0;
-                       musb->xceiv.state = OTG_STATE_B_IDLE;
+                       musb->xceiv->default_a = 0;
+                       musb->xceiv->state = OTG_STATE_B_IDLE;
                        MUSB_DEV_MODE(musb);
                }
 
@@ -674,7 +676,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
                else
                        default_a = is_host_enabled(musb);
                DBG(2, "Default-%c\n", default_a ? 'A' : 'B');
-               musb->xceiv.default_a = default_a;
+               musb->xceiv->default_a = default_a;
                tusb_source_power(musb, default_a);
 
                /* Don't allow idling immediately */
@@ -686,7 +688,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
        if (int_src & TUSB_INT_SRC_VBUS_SENSE_CHNG) {
 
                /* B-dev state machine:  no vbus ~= disconnect */
-               if ((is_otg_enabled(musb) && !musb->xceiv.default_a)
+               if ((is_otg_enabled(musb) && !musb->xceiv->default_a)
                                || !is_host_enabled(musb)) {
 #ifdef CONFIG_USB_MUSB_HDRC_HCD
                        /* ? musb_root_disconnect(musb); */
@@ -701,9 +703,9 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
 
                        if (otg_stat & TUSB_DEV_OTG_STAT_SESS_END) {
                                DBG(1, "Forcing disconnect (no interrupt)\n");
-                               if (musb->xceiv.state != OTG_STATE_B_IDLE) {
+                               if (musb->xceiv->state != OTG_STATE_B_IDLE) {
                                        /* INTR_DISCONNECT can hide... */
-                                       musb->xceiv.state = OTG_STATE_B_IDLE;
+                                       musb->xceiv->state = OTG_STATE_B_IDLE;
                                        musb->int_usb |= MUSB_INTR_DISCONNECT;
                                }
                                musb->is_active = 0;
@@ -717,7 +719,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
                        DBG(2, "vbus change, %s, otg %03x\n",
                                otg_state_string(musb), otg_stat);
 
-                       switch (musb->xceiv.state) {
+                       switch (musb->xceiv->state) {
                        case OTG_STATE_A_IDLE:
                                DBG(2, "Got SRP, turning on VBUS\n");
                                musb_set_vbus(musb, 1);
@@ -765,7 +767,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
 
                DBG(4, "%s timer, %03x\n", otg_state_string(musb), otg_stat);
 
-               switch (musb->xceiv.state) {
+               switch (musb->xceiv->state) {
                case OTG_STATE_A_WAIT_VRISE:
                        /* VBUS has probably been valid for a while now,
                         * but may well have bounced out of range a bit
@@ -777,7 +779,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
                                        DBG(2, "devctl %02x\n", devctl);
                                        break;
                                }
-                               musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
+                               musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
                                musb->is_active = 0;
                                idle_timeout = jiffies
                                        + msecs_to_jiffies(musb->a_wait_bcon);
@@ -1093,9 +1095,14 @@ int __init musb_platform_init(struct musb *musb)
 {
        struct platform_device  *pdev;
        struct resource         *mem;
-       void __iomem            *sync;
+       void __iomem            *sync = NULL;
        int                     ret;
 
+       usb_nop_xceiv_register();
+       musb->xceiv = otg_get_transceiver();
+       if (!musb->xceiv)
+               return -ENODEV;
+
        pdev = to_platform_device(musb->controller);
 
        /* dma address for async dma */
@@ -1106,14 +1113,16 @@ int __init musb_platform_init(struct musb *musb)
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        if (!mem) {
                pr_debug("no sync dma resource?\n");
-               return -ENODEV;
+               ret = -ENODEV;
+               goto done;
        }
        musb->sync = mem->start;
 
        sync = ioremap(mem->start, mem->end - mem->start + 1);
        if (!sync) {
                pr_debug("ioremap for sync failed\n");
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto done;
        }
        musb->sync_va = sync;
 
@@ -1126,28 +1135,37 @@ int __init musb_platform_init(struct musb *musb)
        if (ret) {
                printk(KERN_ERR "Could not start tusb6010 (%d)\n",
                                ret);
-               return -ENODEV;
+               goto done;
        }
        musb->isr = tusb_interrupt;
 
        if (is_host_enabled(musb))
                musb->board_set_vbus = tusb_source_power;
-       if (is_peripheral_enabled(musb))
-               musb->xceiv.set_power = tusb_draw_power;
+       if (is_peripheral_enabled(musb)) {
+               musb->xceiv->set_power = tusb_draw_power;
+               the_musb = musb;
+       }
 
        setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
 
+done:
+       if (ret < 0) {
+               if (sync)
+                       iounmap(sync);
+               usb_nop_xceiv_unregister();
+       }
        return ret;
 }
 
 int musb_platform_exit(struct musb *musb)
 {
        del_timer_sync(&musb_idle_timer);
+       the_musb = NULL;
 
        if (musb->board_set_power)
                musb->board_set_power(0);
 
        iounmap(musb->sync_va);
-
+       usb_nop_xceiv_unregister();
        return 0;
 }
index aa884d072f0b4c7202e5b421e52b0ca37a5163de..69feeec1628ce28bd8744ef5c6048d0b7a12746c 100644 (file)
@@ -59,4 +59,18 @@ config NOP_USB_XCEIV
         built-in with usb ip or which are autonomous and doesn't require any
         phy programming such as ISP1x04 etc.
 
+config USB_LANGWELL_OTG
+       tristate "Intel Langwell USB OTG dual-role support"
+       depends on USB && MRST
+       select USB_OTG
+       select USB_OTG_UTILS
+       help
+         Say Y here if you want to build Intel Langwell USB OTG
+         transciever driver in kernel. This driver implements role
+         switch between EHCI host driver and Langwell USB OTG
+         client driver.
+
+         To compile this driver as a module, choose M here: the
+         module will be called langwell_otg.
+
 endif # USB || OTG
index 208167856529f26225807cd7edea4fb29a3640e9..6d1abdd3c0ac9cc1a2cd688dd9fda768ee2562a1 100644 (file)
@@ -9,6 +9,7 @@ obj-$(CONFIG_USB_OTG_UTILS)     += otg.o
 obj-$(CONFIG_USB_GPIO_VBUS)    += gpio_vbus.o
 obj-$(CONFIG_ISP1301_OMAP)     += isp1301_omap.o
 obj-$(CONFIG_TWL4030_USB)      += twl4030-usb.o
+obj-$(CONFIG_USB_LANGWELL_OTG) += langwell_otg.o
 obj-$(CONFIG_NOP_USB_XCEIV)    += nop-usb-xceiv.o
 
 ccflags-$(CONFIG_USB_DEBUG)    += -DDEBUG
diff --git a/drivers/usb/otg/langwell_otg.c b/drivers/usb/otg/langwell_otg.c
new file mode 100644 (file)
index 0000000..6f628d0
--- /dev/null
@@ -0,0 +1,1915 @@
+/*
+ * Intel Langwell USB OTG transceiver driver
+ * Copyright (C) 2008 - 2009, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+/* This driver helps to switch Langwell OTG controller function between host
+ * and peripheral. It works with EHCI driver and Langwell client controller
+ * driver together.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/moduleparam.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb.h>
+#include <linux/usb/otg.h>
+#include <linux/notifier.h>
+#include <asm/ipc_defs.h>
+#include <linux/delay.h>
+#include "../core/hcd.h"
+
+#include <linux/usb/langwell_otg.h>
+
+#define        DRIVER_DESC             "Intel Langwell USB OTG transceiver driver"
+#define        DRIVER_VERSION          "3.0.0.32L.0002"
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Henry Yuan <hang.yuan@intel.com>, Hao Wu <hao.wu@intel.com>");
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
+static const char driver_name[] = "langwell_otg";
+
+static int langwell_otg_probe(struct pci_dev *pdev,
+                       const struct pci_device_id *id);
+static void langwell_otg_remove(struct pci_dev *pdev);
+static int langwell_otg_suspend(struct pci_dev *pdev, pm_message_t message);
+static int langwell_otg_resume(struct pci_dev *pdev);
+
+static int langwell_otg_set_host(struct otg_transceiver *otg,
+                               struct usb_bus *host);
+static int langwell_otg_set_peripheral(struct otg_transceiver *otg,
+                               struct usb_gadget *gadget);
+static int langwell_otg_start_srp(struct otg_transceiver *otg);
+
+static const struct pci_device_id pci_ids[] = {{
+       .class =        ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+       .class_mask =   ~0,
+       .vendor =       0x8086,
+       .device =       0x0811,
+       .subvendor =    PCI_ANY_ID,
+       .subdevice =    PCI_ANY_ID,
+}, { /* end: all zeroes */ }
+};
+
+static struct pci_driver otg_pci_driver = {
+       .name =         (char *) driver_name,
+       .id_table =     pci_ids,
+
+       .probe =        langwell_otg_probe,
+       .remove =       langwell_otg_remove,
+
+       .suspend =      langwell_otg_suspend,
+       .resume =       langwell_otg_resume,
+};
+
+static const char *state_string(enum usb_otg_state state)
+{
+       switch (state) {
+       case OTG_STATE_A_IDLE:
+               return "a_idle";
+       case OTG_STATE_A_WAIT_VRISE:
+               return "a_wait_vrise";
+       case OTG_STATE_A_WAIT_BCON:
+               return "a_wait_bcon";
+       case OTG_STATE_A_HOST:
+               return "a_host";
+       case OTG_STATE_A_SUSPEND:
+               return "a_suspend";
+       case OTG_STATE_A_PERIPHERAL:
+               return "a_peripheral";
+       case OTG_STATE_A_WAIT_VFALL:
+               return "a_wait_vfall";
+       case OTG_STATE_A_VBUS_ERR:
+               return "a_vbus_err";
+       case OTG_STATE_B_IDLE:
+               return "b_idle";
+       case OTG_STATE_B_SRP_INIT:
+               return "b_srp_init";
+       case OTG_STATE_B_PERIPHERAL:
+               return "b_peripheral";
+       case OTG_STATE_B_WAIT_ACON:
+               return "b_wait_acon";
+       case OTG_STATE_B_HOST:
+               return "b_host";
+       default:
+               return "UNDEFINED";
+       }
+}
+
+/* HSM timers */
+static inline struct langwell_otg_timer *otg_timer_initializer
+(void (*function)(unsigned long), unsigned long expires, unsigned long data)
+{
+       struct langwell_otg_timer *timer;
+       timer = kmalloc(sizeof(struct langwell_otg_timer), GFP_KERNEL);
+       timer->function = function;
+       timer->expires = expires;
+       timer->data = data;
+       return timer;
+}
+
+static struct langwell_otg_timer *a_wait_vrise_tmr, *a_wait_bcon_tmr,
+       *a_aidl_bdis_tmr, *b_ase0_brst_tmr, *b_se0_srp_tmr, *b_srp_res_tmr,
+       *b_bus_suspend_tmr;
+
+static struct list_head active_timers;
+
+static struct langwell_otg *the_transceiver;
+
+/* host/client notify transceiver when event affects HNP state */
+void langwell_update_transceiver()
+{
+       otg_dbg("transceiver driver is notified\n");
+       queue_work(the_transceiver->qwork, &the_transceiver->work);
+}
+EXPORT_SYMBOL(langwell_update_transceiver);
+
+static int langwell_otg_set_host(struct otg_transceiver *otg,
+                                       struct usb_bus *host)
+{
+       otg->host = host;
+
+       return 0;
+}
+
+static int langwell_otg_set_peripheral(struct otg_transceiver *otg,
+                                       struct usb_gadget *gadget)
+{
+       otg->gadget = gadget;
+
+       return 0;
+}
+
+static int langwell_otg_set_power(struct otg_transceiver *otg,
+                               unsigned mA)
+{
+       return 0;
+}
+
+/* A-device drives vbus, controlled through PMIC CHRGCNTL register*/
+static void langwell_otg_drv_vbus(int on)
+{
+       struct ipc_pmic_reg_data        pmic_data = {0};
+       struct ipc_pmic_reg_data        battery_data;
+
+       /* Check if battery is attached or not */
+       battery_data.pmic_reg_data[0].register_address = 0xd2;
+       battery_data.ioc = 0;
+       battery_data.num_entries = 1;
+       if (ipc_pmic_register_read(&battery_data)) {
+               otg_dbg("Failed to read PMIC register 0xd2.\n");
+               return;
+       }
+
+       if ((battery_data.pmic_reg_data[0].value & 0x20) == 0) {
+               otg_dbg("no battery attached\n");
+               return;
+       }
+
+       /* Workaround for battery attachment issue */
+       if (battery_data.pmic_reg_data[0].value == 0x34) {
+               otg_dbg("battery \n");
+               return;
+       }
+
+       otg_dbg("battery attached\n");
+
+       pmic_data.ioc = 0;
+       pmic_data.pmic_reg_data[0].register_address = 0xD4;
+       pmic_data.num_entries = 1;
+       if (on)
+               pmic_data.pmic_reg_data[0].value = 0x20;
+       else
+               pmic_data.pmic_reg_data[0].value = 0xc0;
+
+       if (ipc_pmic_register_write(&pmic_data, TRUE))
+               otg_dbg("Failed to write PMIC.\n");
+
+}
+
+/* charge vbus or discharge vbus through a resistor to ground */
+static void langwell_otg_chrg_vbus(int on)
+{
+
+       u32     val;
+
+       val = readl(the_transceiver->regs + CI_OTGSC);
+
+       if (on)
+               writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_VC,
+                               the_transceiver->regs + CI_OTGSC);
+       else
+               writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_VD,
+                               the_transceiver->regs + CI_OTGSC);
+
+}
+
+/* Start SRP */
+static int langwell_otg_start_srp(struct otg_transceiver *otg)
+{
+       u32     val;
+
+       otg_dbg("Start SRP ->\n");
+
+       val = readl(the_transceiver->regs + CI_OTGSC);
+
+       writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HADP,
+               the_transceiver->regs + CI_OTGSC);
+
+       /* Check if the data plus is finished or not */
+       msleep(8);
+       val = readl(the_transceiver->regs + CI_OTGSC);
+       if (val & (OTGSC_HADP | OTGSC_DP))
+               otg_dbg("DataLine SRP Error\n");
+
+       /* FIXME: VBus SRP */
+
+       return 0;
+}
+
+
+/* stop SOF via bus_suspend */
+static void langwell_otg_loc_sof(int on)
+{
+       struct usb_hcd  *hcd;
+       int             err;
+
+       otg_dbg("loc_sof -> %d\n", on);
+
+       hcd = bus_to_hcd(the_transceiver->otg.host);
+       if (on)
+               err = hcd->driver->bus_resume(hcd);
+       else
+               err = hcd->driver->bus_suspend(hcd);
+
+       if (err)
+               otg_dbg("Failed to resume/suspend bus - %d\n", err);
+}
+
+static void langwell_otg_phy_low_power(int on)
+{
+       u32     val;
+
+       otg_dbg("phy low power mode-> %d\n", on);
+
+       val = readl(the_transceiver->regs + CI_HOSTPC1);
+       if (on)
+               writel(val | HOSTPC1_PHCD, the_transceiver->regs + CI_HOSTPC1);
+       else
+               writel(val & ~HOSTPC1_PHCD, the_transceiver->regs + CI_HOSTPC1);
+}
+
+/* Enable/Disable OTG interrupt */
+static void langwell_otg_intr(int on)
+{
+       u32 val;
+
+       otg_dbg("interrupt -> %d\n", on);
+
+       val = readl(the_transceiver->regs + CI_OTGSC);
+       if (on) {
+               val = val | (OTGSC_INTEN_MASK | OTGSC_IDPU);
+               writel(val, the_transceiver->regs + CI_OTGSC);
+       } else {
+               val = val & ~(OTGSC_INTEN_MASK | OTGSC_IDPU);
+               writel(val, the_transceiver->regs + CI_OTGSC);
+       }
+}
+
+/* set HAAR: Hardware Assist Auto-Reset */
+static void langwell_otg_HAAR(int on)
+{
+       u32     val;
+
+       otg_dbg("HAAR -> %d\n", on);
+
+       val = readl(the_transceiver->regs + CI_OTGSC);
+       if (on)
+               writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HAAR,
+                               the_transceiver->regs + CI_OTGSC);
+       else
+               writel((val & ~OTGSC_INTSTS_MASK) & ~OTGSC_HAAR,
+                               the_transceiver->regs + CI_OTGSC);
+}
+
+/* set HABA: Hardware Assist B-Disconnect to A-Connect */
+static void langwell_otg_HABA(int on)
+{
+       u32     val;
+
+       otg_dbg("HABA -> %d\n", on);
+
+       val = readl(the_transceiver->regs + CI_OTGSC);
+       if (on)
+               writel((val & ~OTGSC_INTSTS_MASK) | OTGSC_HABA,
+                               the_transceiver->regs + CI_OTGSC);
+       else
+               writel((val & ~OTGSC_INTSTS_MASK) & ~OTGSC_HABA,
+                               the_transceiver->regs + CI_OTGSC);
+}
+
+static int langwell_otg_check_se0_srp(int on)
+{
+       u32 val;
+
+       int delay_time = TB_SE0_SRP * 10; /* step is 100us */
+
+       otg_dbg("check_se0_srp -> \n");
+
+       do {
+               udelay(100);
+               if (!delay_time--)
+                       break;
+               val = readl(the_transceiver->regs + CI_PORTSC1);
+               val &= PORTSC_LS;
+       } while (!val);
+
+       otg_dbg("check_se0_srp <- \n");
+       return val;
+}
+
+/* The timeout callback function to set time out bit */
+static void set_tmout(unsigned long indicator)
+{
+       *(int *)indicator = 1;
+}
+
+void langwell_otg_nsf_msg(unsigned long indicator)
+{
+       switch (indicator) {
+       case 2:
+       case 4:
+       case 6:
+       case 7:
+               printk(KERN_ERR "OTG:NSF-%lu - deivce not responding\n",
+                               indicator);
+               break;
+       case 3:
+               printk(KERN_ERR "OTG:NSF-%lu - deivce not supported\n",
+                               indicator);
+               break;
+       default:
+               printk(KERN_ERR "Do not have this kind of NSF\n");
+               break;
+       }
+}
+
+/* Initialize timers */
+static void langwell_otg_init_timers(struct otg_hsm *hsm)
+{
+       /* HSM used timers */
+       a_wait_vrise_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_VRISE,
+                               (unsigned long)&hsm->a_wait_vrise_tmout);
+       a_wait_bcon_tmr = otg_timer_initializer(&set_tmout, TA_WAIT_BCON,
+                               (unsigned long)&hsm->a_wait_bcon_tmout);
+       a_aidl_bdis_tmr = otg_timer_initializer(&set_tmout, TA_AIDL_BDIS,
+                               (unsigned long)&hsm->a_aidl_bdis_tmout);
+       b_ase0_brst_tmr = otg_timer_initializer(&set_tmout, TB_ASE0_BRST,
+                               (unsigned long)&hsm->b_ase0_brst_tmout);
+       b_se0_srp_tmr = otg_timer_initializer(&set_tmout, TB_SE0_SRP,
+                               (unsigned long)&hsm->b_se0_srp);
+       b_srp_res_tmr = otg_timer_initializer(&set_tmout, TB_SRP_RES,
+                               (unsigned long)&hsm->b_srp_res_tmout);
+       b_bus_suspend_tmr = otg_timer_initializer(&set_tmout, TB_BUS_SUSPEND,
+                               (unsigned long)&hsm->b_bus_suspend_tmout);
+}
+
+/* Free timers */
+static void langwell_otg_free_timers(void)
+{
+       kfree(a_wait_vrise_tmr);
+       kfree(a_wait_bcon_tmr);
+       kfree(a_aidl_bdis_tmr);
+       kfree(b_ase0_brst_tmr);
+       kfree(b_se0_srp_tmr);
+       kfree(b_srp_res_tmr);
+       kfree(b_bus_suspend_tmr);
+}
+
+/* Add timer to timer list */
+static void langwell_otg_add_timer(void *gtimer)
+{
+       struct langwell_otg_timer *timer = (struct langwell_otg_timer *)gtimer;
+       struct langwell_otg_timer *tmp_timer;
+       u32     val32;
+
+       /* Check if the timer is already in the active list,
+        * if so update timer count
+        */
+       list_for_each_entry(tmp_timer, &active_timers, list)
+               if (tmp_timer == timer) {
+                       timer->count = timer->expires;
+                       return;
+               }
+       timer->count = timer->expires;
+
+       if (list_empty(&active_timers)) {
+               val32 = readl(the_transceiver->regs + CI_OTGSC);
+               writel(val32 | OTGSC_1MSE, the_transceiver->regs + CI_OTGSC);
+       }
+
+       list_add_tail(&timer->list, &active_timers);
+}
+
+/* Remove timer from the timer list; clear timeout status */
+static void langwell_otg_del_timer(void *gtimer)
+{
+       struct langwell_otg_timer *timer = (struct langwell_otg_timer *)gtimer;
+       struct langwell_otg_timer *tmp_timer, *del_tmp;
+       u32 val32;
+
+       list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list)
+               if (tmp_timer == timer)
+                       list_del(&timer->list);
+
+       if (list_empty(&active_timers)) {
+               val32 = readl(the_transceiver->regs + CI_OTGSC);
+               writel(val32 & ~OTGSC_1MSE, the_transceiver->regs + CI_OTGSC);
+       }
+}
+
+/* Reduce timer count by 1, and find timeout conditions.*/
+static int langwell_otg_tick_timer(u32 *int_sts)
+{
+       struct langwell_otg_timer *tmp_timer, *del_tmp;
+       int expired = 0;
+
+       list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) {
+               tmp_timer->count--;
+               /* check if timer expires */
+               if (!tmp_timer->count) {
+                       list_del(&tmp_timer->list);
+                       tmp_timer->function(tmp_timer->data);
+                       expired = 1;
+               }
+       }
+
+       if (list_empty(&active_timers)) {
+               otg_dbg("tick timer: disable 1ms int\n");
+               *int_sts = *int_sts & ~OTGSC_1MSE;
+       }
+       return expired;
+}
+
+static void reset_otg(void)
+{
+       u32     val;
+       int     delay_time = 1000;
+
+       otg_dbg("reseting OTG controller ...\n");
+       val = readl(the_transceiver->regs + CI_USBCMD);
+       writel(val | USBCMD_RST, the_transceiver->regs + CI_USBCMD);
+       do {
+               udelay(100);
+               if (!delay_time--)
+                       otg_dbg("reset timeout\n");
+               val = readl(the_transceiver->regs + CI_USBCMD);
+               val &= USBCMD_RST;
+       } while (val != 0);
+       otg_dbg("reset done.\n");
+}
+
+static void set_host_mode(void)
+{
+       u32     val;
+
+       reset_otg();
+       val = readl(the_transceiver->regs + CI_USBMODE);
+       val = (val & (~USBMODE_CM)) | USBMODE_HOST;
+       writel(val, the_transceiver->regs + CI_USBMODE);
+}
+
+static void set_client_mode(void)
+{
+       u32     val;
+
+       reset_otg();
+       val = readl(the_transceiver->regs + CI_USBMODE);
+       val = (val & (~USBMODE_CM)) | USBMODE_DEVICE;
+       writel(val, the_transceiver->regs + CI_USBMODE);
+}
+
+static void init_hsm(void)
+{
+       struct langwell_otg     *langwell = the_transceiver;
+       u32                     val32;
+
+       /* read OTGSC after reset */
+       val32 = readl(langwell->regs + CI_OTGSC);
+       otg_dbg("%s: OTGSC init value = 0x%x\n", __func__, val32);
+
+       /* set init state */
+       if (val32 & OTGSC_ID) {
+               langwell->hsm.id = 1;
+               langwell->otg.default_a = 0;
+               set_client_mode();
+               langwell->otg.state = OTG_STATE_B_IDLE;
+               langwell_otg_drv_vbus(0);
+       } else {
+               langwell->hsm.id = 0;
+               langwell->otg.default_a = 1;
+               set_host_mode();
+               langwell->otg.state = OTG_STATE_A_IDLE;
+       }
+
+       /* set session indicator */
+       if (val32 & OTGSC_BSE)
+               langwell->hsm.b_sess_end = 1;
+       if (val32 & OTGSC_BSV)
+               langwell->hsm.b_sess_vld = 1;
+       if (val32 & OTGSC_ASV)
+               langwell->hsm.a_sess_vld = 1;
+       if (val32 & OTGSC_AVV)
+               langwell->hsm.a_vbus_vld = 1;
+
+       /* defautly power the bus */
+       langwell->hsm.a_bus_req = 1;
+       langwell->hsm.a_bus_drop = 0;
+       /* defautly don't request bus as B device */
+       langwell->hsm.b_bus_req = 0;
+       /* no system error */
+       langwell->hsm.a_clr_err = 0;
+}
+
+static irqreturn_t otg_dummy_irq(int irq, void *_dev)
+{
+       void __iomem    *reg_base = _dev;
+       u32     val;
+       u32     int_mask = 0;
+
+       val = readl(reg_base + CI_USBMODE);
+       if ((val & USBMODE_CM) != USBMODE_DEVICE)
+               return IRQ_NONE;
+
+       val = readl(reg_base + CI_USBSTS);
+       int_mask = val & INTR_DUMMY_MASK;
+
+       if (int_mask == 0)
+               return IRQ_NONE;
+
+       /* clear hsm.b_conn here since host driver can't detect it
+       *  otg_dummy_irq called means B-disconnect happened.
+       */
+       if (the_transceiver->hsm.b_conn) {
+               the_transceiver->hsm.b_conn = 0;
+               if (spin_trylock(&the_transceiver->wq_lock)) {
+                       queue_work(the_transceiver->qwork,
+                               &the_transceiver->work);
+                       spin_unlock(&the_transceiver->wq_lock);
+               }
+       }
+       /* Clear interrupts */
+       writel(int_mask, reg_base + CI_USBSTS);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t otg_irq(int irq, void *_dev)
+{
+       struct  langwell_otg *langwell = _dev;
+       u32     int_sts, int_en;
+       u32     int_mask = 0;
+       int     flag = 0;
+
+       int_sts = readl(langwell->regs + CI_OTGSC);
+       int_en = (int_sts & OTGSC_INTEN_MASK) >> 8;
+       int_mask = int_sts & int_en;
+       if (int_mask == 0)
+               return IRQ_NONE;
+
+       if (int_mask & OTGSC_IDIS) {
+               otg_dbg("%s: id change int\n", __func__);
+               langwell->hsm.id = (int_sts & OTGSC_ID) ? 1 : 0;
+               flag = 1;
+       }
+       if (int_mask & OTGSC_DPIS) {
+               otg_dbg("%s: data pulse int\n", __func__);
+               langwell->hsm.a_srp_det = (int_sts & OTGSC_DPS) ? 1 : 0;
+               flag = 1;
+       }
+       if (int_mask & OTGSC_BSEIS) {
+               otg_dbg("%s: b session end int\n", __func__);
+               langwell->hsm.b_sess_end = (int_sts & OTGSC_BSE) ? 1 : 0;
+               flag = 1;
+       }
+       if (int_mask & OTGSC_BSVIS) {
+               otg_dbg("%s: b session valid int\n", __func__);
+               langwell->hsm.b_sess_vld = (int_sts & OTGSC_BSV) ? 1 : 0;
+               flag = 1;
+       }
+       if (int_mask & OTGSC_ASVIS) {
+               otg_dbg("%s: a session valid int\n", __func__);
+               langwell->hsm.a_sess_vld = (int_sts & OTGSC_ASV) ? 1 : 0;
+               flag = 1;
+       }
+       if (int_mask & OTGSC_AVVIS) {
+               otg_dbg("%s: a vbus valid int\n", __func__);
+               langwell->hsm.a_vbus_vld = (int_sts & OTGSC_AVV) ? 1 : 0;
+               flag = 1;
+       }
+
+       if (int_mask & OTGSC_1MSS) {
+               /* need to schedule otg_work if any timer is expired */
+               if (langwell_otg_tick_timer(&int_sts))
+                       flag = 1;
+       }
+
+       writel((int_sts & ~OTGSC_INTSTS_MASK) | int_mask,
+                       langwell->regs + CI_OTGSC);
+       if (flag)
+               queue_work(langwell->qwork, &langwell->work);
+
+       return IRQ_HANDLED;
+}
+
+static void langwell_otg_work(struct work_struct *work)
+{
+       struct langwell_otg *langwell = container_of(work,
+                                       struct langwell_otg, work);
+       int     retval;
+
+       otg_dbg("%s: old state = %s\n", __func__,
+                       state_string(langwell->otg.state));
+
+       switch (langwell->otg.state) {
+       case OTG_STATE_UNDEFINED:
+       case OTG_STATE_B_IDLE:
+               if (!langwell->hsm.id) {
+                       langwell_otg_del_timer(b_srp_res_tmr);
+                       langwell->otg.default_a = 1;
+                       langwell->hsm.a_srp_det = 0;
+
+                       langwell_otg_chrg_vbus(0);
+                       langwell_otg_drv_vbus(0);
+
+                       set_host_mode();
+                       langwell->otg.state = OTG_STATE_A_IDLE;
+                       queue_work(langwell->qwork, &langwell->work);
+               } else if (langwell->hsm.b_srp_res_tmout) {
+                       langwell->hsm.b_srp_res_tmout = 0;
+                       langwell->hsm.b_bus_req = 0;
+                       langwell_otg_nsf_msg(6);
+               } else if (langwell->hsm.b_sess_vld) {
+                       langwell_otg_del_timer(b_srp_res_tmr);
+                       langwell->hsm.b_sess_end = 0;
+                       langwell->hsm.a_bus_suspend = 0;
+
+                       langwell_otg_chrg_vbus(0);
+                       if (langwell->client_ops) {
+                               langwell->client_ops->resume(langwell->pdev);
+                               langwell->otg.state = OTG_STATE_B_PERIPHERAL;
+                       } else
+                               otg_dbg("client driver not loaded.\n");
+
+               } else if (langwell->hsm.b_bus_req &&
+                               (langwell->hsm.b_sess_end)) {
+                       /* workaround for b_se0_srp detection */
+                       retval = langwell_otg_check_se0_srp(0);
+                       if (retval) {
+                               langwell->hsm.b_bus_req = 0;
+                               otg_dbg("LS is not SE0, try again later\n");
+                       } else {
+                               /* Start SRP */
+                               langwell_otg_start_srp(&langwell->otg);
+                               langwell_otg_add_timer(b_srp_res_tmr);
+                       }
+               }
+               break;
+       case OTG_STATE_B_SRP_INIT:
+               if (!langwell->hsm.id) {
+                       langwell->otg.default_a = 1;
+                       langwell->hsm.a_srp_det = 0;
+
+                       langwell_otg_drv_vbus(0);
+                       langwell_otg_chrg_vbus(0);
+
+                       langwell->otg.state = OTG_STATE_A_IDLE;
+                       queue_work(langwell->qwork, &langwell->work);
+               } else if (langwell->hsm.b_sess_vld) {
+                       langwell_otg_chrg_vbus(0);
+                       if (langwell->client_ops) {
+                               langwell->client_ops->resume(langwell->pdev);
+                               langwell->otg.state = OTG_STATE_B_PERIPHERAL;
+                       } else
+                               otg_dbg("client driver not loaded.\n");
+               }
+               break;
+       case OTG_STATE_B_PERIPHERAL:
+               if (!langwell->hsm.id) {
+                       langwell->otg.default_a = 1;
+                       langwell->hsm.a_srp_det = 0;
+
+                       langwell_otg_drv_vbus(0);
+                       langwell_otg_chrg_vbus(0);
+                       set_host_mode();
+
+                       if (langwell->client_ops) {
+                               langwell->client_ops->suspend(langwell->pdev,
+                                       PMSG_FREEZE);
+                       } else
+                               otg_dbg("client driver has been removed.\n");
+
+                       langwell->otg.state = OTG_STATE_A_IDLE;
+                       queue_work(langwell->qwork, &langwell->work);
+               } else if (!langwell->hsm.b_sess_vld) {
+                       langwell->hsm.b_hnp_enable = 0;
+
+                       if (langwell->client_ops) {
+                               langwell->client_ops->suspend(langwell->pdev,
+                                       PMSG_FREEZE);
+                       } else
+                               otg_dbg("client driver has been removed.\n");
+
+                       langwell->otg.state = OTG_STATE_B_IDLE;
+               } else if (langwell->hsm.b_bus_req && langwell->hsm.b_hnp_enable
+                       && langwell->hsm.a_bus_suspend) {
+
+                       if (langwell->client_ops) {
+                               langwell->client_ops->suspend(langwell->pdev,
+                                       PMSG_FREEZE);
+                       } else
+                               otg_dbg("client driver has been removed.\n");
+
+                       langwell_otg_HAAR(1);
+                       langwell->hsm.a_conn = 0;
+
+                       if (langwell->host_ops) {
+                               langwell->host_ops->probe(langwell->pdev,
+                                       langwell->host_ops->id_table);
+                               langwell->otg.state = OTG_STATE_B_WAIT_ACON;
+                       } else
+                               otg_dbg("host driver not loaded.\n");
+
+                       langwell->hsm.a_bus_resume = 0;
+                       langwell->hsm.b_ase0_brst_tmout = 0;
+                       langwell_otg_add_timer(b_ase0_brst_tmr);
+               }
+               break;
+
+       case OTG_STATE_B_WAIT_ACON:
+               if (!langwell->hsm.id) {
+                       langwell_otg_del_timer(b_ase0_brst_tmr);
+                       langwell->otg.default_a = 1;
+                       langwell->hsm.a_srp_det = 0;
+
+                       langwell_otg_drv_vbus(0);
+                       langwell_otg_chrg_vbus(0);
+                       set_host_mode();
+
+                       langwell_otg_HAAR(0);
+                       if (langwell->host_ops)
+                               langwell->host_ops->remove(langwell->pdev);
+                       else
+                               otg_dbg("host driver has been removed.\n");
+                       langwell->otg.state = OTG_STATE_A_IDLE;
+                       queue_work(langwell->qwork, &langwell->work);
+               } else if (!langwell->hsm.b_sess_vld) {
+                       langwell_otg_del_timer(b_ase0_brst_tmr);
+                       langwell->hsm.b_hnp_enable = 0;
+                       langwell->hsm.b_bus_req = 0;
+                       langwell_otg_chrg_vbus(0);
+                       langwell_otg_HAAR(0);
+
+                       if (langwell->host_ops)
+                               langwell->host_ops->remove(langwell->pdev);
+                       else
+                               otg_dbg("host driver has been removed.\n");
+                       langwell->otg.state = OTG_STATE_B_IDLE;
+               } else if (langwell->hsm.a_conn) {
+                       langwell_otg_del_timer(b_ase0_brst_tmr);
+                       langwell_otg_HAAR(0);
+                       langwell->otg.state = OTG_STATE_B_HOST;
+                       queue_work(langwell->qwork, &langwell->work);
+               } else if (langwell->hsm.a_bus_resume ||
+                               langwell->hsm.b_ase0_brst_tmout) {
+                       langwell_otg_del_timer(b_ase0_brst_tmr);
+                       langwell_otg_HAAR(0);
+                       langwell_otg_nsf_msg(7);
+
+                       if (langwell->host_ops)
+                               langwell->host_ops->remove(langwell->pdev);
+                       else
+                               otg_dbg("host driver has been removed.\n");
+
+                       langwell->hsm.a_bus_suspend = 0;
+                       langwell->hsm.b_bus_req = 0;
+
+                       if (langwell->client_ops)
+                               langwell->client_ops->resume(langwell->pdev);
+                       else
+                               otg_dbg("client driver not loaded.\n");
+
+                       langwell->otg.state = OTG_STATE_B_PERIPHERAL;
+               }
+               break;
+
+       case OTG_STATE_B_HOST:
+               if (!langwell->hsm.id) {
+                       langwell->otg.default_a = 1;
+                       langwell->hsm.a_srp_det = 0;
+
+                       langwell_otg_drv_vbus(0);
+                       langwell_otg_chrg_vbus(0);
+                       set_host_mode();
+                       if (langwell->host_ops)
+                               langwell->host_ops->remove(langwell->pdev);
+                       else
+                               otg_dbg("host driver has been removed.\n");
+                       langwell->otg.state = OTG_STATE_A_IDLE;
+                       queue_work(langwell->qwork, &langwell->work);
+               } else if (!langwell->hsm.b_sess_vld) {
+                       langwell->hsm.b_hnp_enable = 0;
+                       langwell->hsm.b_bus_req = 0;
+                       langwell_otg_chrg_vbus(0);
+                       if (langwell->host_ops)
+                               langwell->host_ops->remove(langwell->pdev);
+                       else
+                               otg_dbg("host driver has been removed.\n");
+                       langwell->otg.state = OTG_STATE_B_IDLE;
+               } else if ((!langwell->hsm.b_bus_req) ||
+                               (!langwell->hsm.a_conn)) {
+                       langwell->hsm.b_bus_req = 0;
+                       langwell_otg_loc_sof(0);
+                       if (langwell->host_ops)
+                               langwell->host_ops->remove(langwell->pdev);
+                       else
+                               otg_dbg("host driver has been removed.\n");
+
+                       langwell->hsm.a_bus_suspend = 0;
+
+                       if (langwell->client_ops)
+                               langwell->client_ops->resume(langwell->pdev);
+                       else
+                               otg_dbg("client driver not loaded.\n");
+
+                       langwell->otg.state = OTG_STATE_B_PERIPHERAL;
+               }
+               break;
+
+       case OTG_STATE_A_IDLE:
+               langwell->otg.default_a = 1;
+               if (langwell->hsm.id) {
+                       langwell->otg.default_a = 0;
+                       langwell->hsm.b_bus_req = 0;
+                       langwell_otg_drv_vbus(0);
+                       langwell_otg_chrg_vbus(0);
+
+                       langwell->otg.state = OTG_STATE_B_IDLE;
+                       queue_work(langwell->qwork, &langwell->work);
+               } else if (langwell->hsm.a_sess_vld) {
+                       langwell_otg_drv_vbus(1);
+                       langwell->hsm.a_srp_det = 1;
+                       langwell->hsm.a_wait_vrise_tmout = 0;
+                       langwell_otg_add_timer(a_wait_vrise_tmr);
+                       langwell->otg.state = OTG_STATE_A_WAIT_VRISE;
+                       queue_work(langwell->qwork, &langwell->work);
+               } else if (!langwell->hsm.a_bus_drop &&
+                       (langwell->hsm.a_srp_det || langwell->hsm.a_bus_req)) {
+                       langwell_otg_drv_vbus(1);
+                       langwell->hsm.a_wait_vrise_tmout = 0;
+                       langwell_otg_add_timer(a_wait_vrise_tmr);
+                       langwell->otg.state = OTG_STATE_A_WAIT_VRISE;
+                       queue_work(langwell->qwork, &langwell->work);
+               }
+               break;
+       case OTG_STATE_A_WAIT_VRISE:
+               if (langwell->hsm.id) {
+                       langwell_otg_del_timer(a_wait_vrise_tmr);
+                       langwell->hsm.b_bus_req = 0;
+                       langwell->otg.default_a = 0;
+                       langwell_otg_drv_vbus(0);
+                       langwell->otg.state = OTG_STATE_B_IDLE;
+               } else if (langwell->hsm.a_vbus_vld) {
+                       langwell_otg_del_timer(a_wait_vrise_tmr);
+                       if (langwell->host_ops)
+                               langwell->host_ops->probe(langwell->pdev,
+                                               langwell->host_ops->id_table);
+                       else
+                               otg_dbg("host driver not loaded.\n");
+                       langwell->hsm.b_conn = 0;
+                       langwell->hsm.a_set_b_hnp_en = 0;
+                       langwell->hsm.a_wait_bcon_tmout = 0;
+                       langwell_otg_add_timer(a_wait_bcon_tmr);
+                       langwell->otg.state = OTG_STATE_A_WAIT_BCON;
+               } else if (langwell->hsm.a_wait_vrise_tmout) {
+                       if (langwell->hsm.a_vbus_vld) {
+                               if (langwell->host_ops)
+                                       langwell->host_ops->probe(
+                                               langwell->pdev,
+                                               langwell->host_ops->id_table);
+                               else
+                                       otg_dbg("host driver not loaded.\n");
+                               langwell->hsm.b_conn = 0;
+                               langwell->hsm.a_set_b_hnp_en = 0;
+                               langwell->hsm.a_wait_bcon_tmout = 0;
+                               langwell_otg_add_timer(a_wait_bcon_tmr);
+                               langwell->otg.state = OTG_STATE_A_WAIT_BCON;
+                       } else {
+                               langwell_otg_drv_vbus(0);
+                               langwell->otg.state = OTG_STATE_A_VBUS_ERR;
+                       }
+               }
+               break;
+       case OTG_STATE_A_WAIT_BCON:
+               if (langwell->hsm.id) {
+                       langwell_otg_del_timer(a_wait_bcon_tmr);
+
+                       langwell->otg.default_a = 0;
+                       langwell->hsm.b_bus_req = 0;
+                       if (langwell->host_ops)
+                               langwell->host_ops->remove(langwell->pdev);
+                       else
+                               otg_dbg("host driver has been removed.\n");
+                       langwell_otg_drv_vbus(0);
+                       langwell->otg.state = OTG_STATE_B_IDLE;
+                       queue_work(langwell->qwork, &langwell->work);
+               } else if (!langwell->hsm.a_vbus_vld) {
+                       langwell_otg_del_timer(a_wait_bcon_tmr);
+
+                       if (langwell->host_ops)
+                               langwell->host_ops->remove(langwell->pdev);
+                       else
+                               otg_dbg("host driver has been removed.\n");
+                       langwell_otg_drv_vbus(0);
+                       langwell->otg.state = OTG_STATE_A_VBUS_ERR;
+               } else if (langwell->hsm.a_bus_drop ||
+                               (langwell->hsm.a_wait_bcon_tmout &&
+                               !langwell->hsm.a_bus_req)) {
+                       langwell_otg_del_timer(a_wait_bcon_tmr);
+
+                       if (langwell->host_ops)
+                               langwell->host_ops->remove(langwell->pdev);
+                       else
+                               otg_dbg("host driver has been removed.\n");
+                       langwell_otg_drv_vbus(0);
+                       langwell->otg.state = OTG_STATE_A_WAIT_VFALL;
+               } else if (langwell->hsm.b_conn) {
+                       langwell_otg_del_timer(a_wait_bcon_tmr);
+
+                       langwell->hsm.a_suspend_req = 0;
+                       langwell->otg.state = OTG_STATE_A_HOST;
+                       if (!langwell->hsm.a_bus_req &&
+                               langwell->hsm.a_set_b_hnp_en) {
+                               /* It is not safe enough to do a fast
+                                * transistion from A_WAIT_BCON to
+                                * A_SUSPEND */
+                               msleep(10000);
+                               if (langwell->hsm.a_bus_req)
+                                       break;
+
+                               if (request_irq(langwell->pdev->irq,
+                                       otg_dummy_irq, IRQF_SHARED,
+                                       driver_name, langwell->regs) != 0) {
+                                       otg_dbg("request interrupt %d fail\n",
+                                       langwell->pdev->irq);
+                               }
+
+                               langwell_otg_HABA(1);
+                               langwell->hsm.b_bus_resume = 0;
+                               langwell->hsm.a_aidl_bdis_tmout = 0;
+                               langwell_otg_add_timer(a_aidl_bdis_tmr);
+
+                               langwell_otg_loc_sof(0);
+                               langwell->otg.state = OTG_STATE_A_SUSPEND;
+                       } else if (!langwell->hsm.a_bus_req &&
+                               !langwell->hsm.a_set_b_hnp_en) {
+                               struct pci_dev *pdev = langwell->pdev;
+                               if (langwell->host_ops)
+                                       langwell->host_ops->remove(pdev);
+                               else
+                                       otg_dbg("host driver removed.\n");
+                               langwell_otg_drv_vbus(0);
+                               langwell->otg.state = OTG_STATE_A_WAIT_VFALL;
+                       }
+               }
+               break;
+       case OTG_STATE_A_HOST:
+               if (langwell->hsm.id) {
+                       langwell->otg.default_a = 0;
+                       langwell->hsm.b_bus_req = 0;
+                       if (langwell->host_ops)
+                               langwell->host_ops->remove(langwell->pdev);
+                       else
+                               otg_dbg("host driver has been removed.\n");
+                       langwell_otg_drv_vbus(0);
+                       langwell->otg.state = OTG_STATE_B_IDLE;
+                       queue_work(langwell->qwork, &langwell->work);
+               } else if (langwell->hsm.a_bus_drop ||
+               (!langwell->hsm.a_set_b_hnp_en && !langwell->hsm.a_bus_req)) {
+                       if (langwell->host_ops)
+                               langwell->host_ops->remove(langwell->pdev);
+                       else
+                               otg_dbg("host driver has been removed.\n");
+                       langwell_otg_drv_vbus(0);
+                       langwell->otg.state = OTG_STATE_A_WAIT_VFALL;
+               } else if (!langwell->hsm.a_vbus_vld) {
+                       if (langwell->host_ops)
+                               langwell->host_ops->remove(langwell->pdev);
+                       else
+                               otg_dbg("host driver has been removed.\n");
+                       langwell_otg_drv_vbus(0);
+                       langwell->otg.state = OTG_STATE_A_VBUS_ERR;
+               } else if (langwell->hsm.a_set_b_hnp_en
+                               && !langwell->hsm.a_bus_req) {
+                       /* Set HABA to enable hardware assistance to signal
+                        *  A-connect after receiver B-disconnect. Hardware
+                        *  will then set client mode and enable URE, SLE and
+                        *  PCE after the assistance. otg_dummy_irq is used to
+                        *  clean these ints when client driver is not resumed.
+                        */
+                       if (request_irq(langwell->pdev->irq,
+                               otg_dummy_irq, IRQF_SHARED, driver_name,
+                               langwell->regs) != 0) {
+                               otg_dbg("request interrupt %d failed\n",
+                                               langwell->pdev->irq);
+                       }
+
+                       /* set HABA */
+                       langwell_otg_HABA(1);
+                       langwell->hsm.b_bus_resume = 0;
+                       langwell->hsm.a_aidl_bdis_tmout = 0;
+                       langwell_otg_add_timer(a_aidl_bdis_tmr);
+                       langwell_otg_loc_sof(0);
+                       langwell->otg.state = OTG_STATE_A_SUSPEND;
+               } else if (!langwell->hsm.b_conn || !langwell->hsm.a_bus_req) {
+                       langwell->hsm.a_wait_bcon_tmout = 0;
+                       langwell->hsm.a_set_b_hnp_en = 0;
+                       langwell_otg_add_timer(a_wait_bcon_tmr);
+                       langwell->otg.state = OTG_STATE_A_WAIT_BCON;
+               }
+               break;
+       case OTG_STATE_A_SUSPEND:
+               if (langwell->hsm.id) {
+                       langwell_otg_del_timer(a_aidl_bdis_tmr);
+                       langwell_otg_HABA(0);
+                       free_irq(langwell->pdev->irq, langwell->regs);
+                       langwell->otg.default_a = 0;
+                       langwell->hsm.b_bus_req = 0;
+                       if (langwell->host_ops)
+                               langwell->host_ops->remove(langwell->pdev);
+                       else
+                               otg_dbg("host driver has been removed.\n");
+                       langwell_otg_drv_vbus(0);
+                       langwell->otg.state = OTG_STATE_B_IDLE;
+                       queue_work(langwell->qwork, &langwell->work);
+               } else if (langwell->hsm.a_bus_req ||
+                               langwell->hsm.b_bus_resume) {
+                       langwell_otg_del_timer(a_aidl_bdis_tmr);
+                       langwell_otg_HABA(0);
+                       free_irq(langwell->pdev->irq, langwell->regs);
+                       langwell->hsm.a_suspend_req = 0;
+                       langwell_otg_loc_sof(1);
+                       langwell->otg.state = OTG_STATE_A_HOST;
+               } else if (langwell->hsm.a_aidl_bdis_tmout ||
+                               langwell->hsm.a_bus_drop) {
+                       langwell_otg_del_timer(a_aidl_bdis_tmr);
+                       langwell_otg_HABA(0);
+                       free_irq(langwell->pdev->irq, langwell->regs);
+                       if (langwell->host_ops)
+                               langwell->host_ops->remove(langwell->pdev);
+                       else
+                               otg_dbg("host driver has been removed.\n");
+                       langwell_otg_drv_vbus(0);
+                       langwell->otg.state = OTG_STATE_A_WAIT_VFALL;
+               } else if (!langwell->hsm.b_conn &&
+                               langwell->hsm.a_set_b_hnp_en) {
+                       langwell_otg_del_timer(a_aidl_bdis_tmr);
+                       langwell_otg_HABA(0);
+                       free_irq(langwell->pdev->irq, langwell->regs);
+
+                       if (langwell->host_ops)
+                               langwell->host_ops->remove(langwell->pdev);
+                       else
+                               otg_dbg("host driver has been removed.\n");
+
+                       langwell->hsm.b_bus_suspend = 0;
+                       langwell->hsm.b_bus_suspend_vld = 0;
+                       langwell->hsm.b_bus_suspend_tmout = 0;
+
+                       /* msleep(200); */
+                       if (langwell->client_ops)
+                               langwell->client_ops->resume(langwell->pdev);
+                       else
+                               otg_dbg("client driver not loaded.\n");
+
+                       langwell_otg_add_timer(b_bus_suspend_tmr);
+                       langwell->otg.state = OTG_STATE_A_PERIPHERAL;
+                       break;
+               } else if (!langwell->hsm.a_vbus_vld) {
+                       langwell_otg_del_timer(a_aidl_bdis_tmr);
+                       langwell_otg_HABA(0);
+                       free_irq(langwell->pdev->irq, langwell->regs);
+                       if (langwell->host_ops)
+                               langwell->host_ops->remove(langwell->pdev);
+                       else
+                               otg_dbg("host driver has been removed.\n");
+                       langwell_otg_drv_vbus(0);
+                       langwell->otg.state = OTG_STATE_A_VBUS_ERR;
+               }
+               break;
+       case OTG_STATE_A_PERIPHERAL:
+               if (langwell->hsm.id) {
+                       langwell_otg_del_timer(b_bus_suspend_tmr);
+                       langwell->otg.default_a = 0;
+                       langwell->hsm.b_bus_req = 0;
+                       if (langwell->client_ops)
+                               langwell->client_ops->suspend(langwell->pdev,
+                                       PMSG_FREEZE);
+                       else
+                               otg_dbg("client driver has been removed.\n");
+                       langwell_otg_drv_vbus(0);
+                       langwell->otg.state = OTG_STATE_B_IDLE;
+                       queue_work(langwell->qwork, &langwell->work);
+               } else if (!langwell->hsm.a_vbus_vld) {
+                       langwell_otg_del_timer(b_bus_suspend_tmr);
+                       if (langwell->client_ops)
+                               langwell->client_ops->suspend(langwell->pdev,
+                                       PMSG_FREEZE);
+                       else
+                               otg_dbg("client driver has been removed.\n");
+                       langwell_otg_drv_vbus(0);
+                       langwell->otg.state = OTG_STATE_A_VBUS_ERR;
+               } else if (langwell->hsm.a_bus_drop) {
+                       langwell_otg_del_timer(b_bus_suspend_tmr);
+                       if (langwell->client_ops)
+                               langwell->client_ops->suspend(langwell->pdev,
+                                       PMSG_FREEZE);
+                       else
+                               otg_dbg("client driver has been removed.\n");
+                       langwell_otg_drv_vbus(0);
+                       langwell->otg.state = OTG_STATE_A_WAIT_VFALL;
+               } else if (langwell->hsm.b_bus_suspend) {
+                       langwell_otg_del_timer(b_bus_suspend_tmr);
+                       if (langwell->client_ops)
+                               langwell->client_ops->suspend(langwell->pdev,
+                                       PMSG_FREEZE);
+                       else
+                               otg_dbg("client driver has been removed.\n");
+
+                       if (langwell->host_ops)
+                               langwell->host_ops->probe(langwell->pdev,
+                                               langwell->host_ops->id_table);
+                       else
+                               otg_dbg("host driver not loaded.\n");
+                       langwell->hsm.a_set_b_hnp_en = 0;
+                       langwell->hsm.a_wait_bcon_tmout = 0;
+                       langwell_otg_add_timer(a_wait_bcon_tmr);
+                       langwell->otg.state = OTG_STATE_A_WAIT_BCON;
+               } else if (langwell->hsm.b_bus_suspend_tmout) {
+                       u32     val;
+                       val = readl(langwell->regs + CI_PORTSC1);
+                       if (!(val & PORTSC_SUSP))
+                               break;
+                       if (langwell->client_ops)
+                               langwell->client_ops->suspend(langwell->pdev,
+                                               PMSG_FREEZE);
+                       else
+                               otg_dbg("client driver has been removed.\n");
+                       if (langwell->host_ops)
+                               langwell->host_ops->probe(langwell->pdev,
+                                               langwell->host_ops->id_table);
+                       else
+                               otg_dbg("host driver not loaded.\n");
+                       langwell->hsm.a_set_b_hnp_en = 0;
+                       langwell->hsm.a_wait_bcon_tmout = 0;
+                       langwell_otg_add_timer(a_wait_bcon_tmr);
+                       langwell->otg.state = OTG_STATE_A_WAIT_BCON;
+               }
+               break;
+       case OTG_STATE_A_VBUS_ERR:
+               if (langwell->hsm.id) {
+                       langwell->otg.default_a = 0;
+                       langwell->hsm.a_clr_err = 0;
+                       langwell->hsm.a_srp_det = 0;
+                       langwell->otg.state = OTG_STATE_B_IDLE;
+                       queue_work(langwell->qwork, &langwell->work);
+               } else if (langwell->hsm.a_clr_err) {
+                       langwell->hsm.a_clr_err = 0;
+                       langwell->hsm.a_srp_det = 0;
+                       reset_otg();
+                       init_hsm();
+                       if (langwell->otg.state == OTG_STATE_A_IDLE)
+                               queue_work(langwell->qwork, &langwell->work);
+               }
+               break;
+       case OTG_STATE_A_WAIT_VFALL:
+               if (langwell->hsm.id) {
+                       langwell->otg.default_a = 0;
+                       langwell->otg.state = OTG_STATE_B_IDLE;
+                       queue_work(langwell->qwork, &langwell->work);
+               } else if (langwell->hsm.a_bus_req) {
+                       langwell_otg_drv_vbus(1);
+                       langwell->hsm.a_wait_vrise_tmout = 0;
+                       langwell_otg_add_timer(a_wait_vrise_tmr);
+                       langwell->otg.state = OTG_STATE_A_WAIT_VRISE;
+               } else if (!langwell->hsm.a_sess_vld) {
+                       langwell->hsm.a_srp_det = 0;
+                       langwell_otg_drv_vbus(0);
+                       set_host_mode();
+                       langwell->otg.state = OTG_STATE_A_IDLE;
+               }
+               break;
+       default:
+               ;
+       }
+
+       otg_dbg("%s: new state = %s\n", __func__,
+                       state_string(langwell->otg.state));
+}
+
+       static ssize_t
+show_registers(struct device *_dev, struct device_attribute *attr, char *buf)
+{
+       struct langwell_otg *langwell;
+       char *next;
+       unsigned size;
+       unsigned t;
+
+       langwell = the_transceiver;
+       next = buf;
+       size = PAGE_SIZE;
+
+       t = scnprintf(next, size,
+               "\n"
+               "USBCMD = 0x%08x \n"
+               "USBSTS = 0x%08x \n"
+               "USBINTR = 0x%08x \n"
+               "ASYNCLISTADDR = 0x%08x \n"
+               "PORTSC1 = 0x%08x \n"
+               "HOSTPC1 = 0x%08x \n"
+               "OTGSC = 0x%08x \n"
+               "USBMODE = 0x%08x \n",
+               readl(langwell->regs + 0x30),
+               readl(langwell->regs + 0x34),
+               readl(langwell->regs + 0x38),
+               readl(langwell->regs + 0x48),
+               readl(langwell->regs + 0x74),
+               readl(langwell->regs + 0xb4),
+               readl(langwell->regs + 0xf4),
+               readl(langwell->regs + 0xf8)
+               );
+       size -= t;
+       next += t;
+
+       return PAGE_SIZE - size;
+}
+static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL);
+
+static ssize_t
+show_hsm(struct device *_dev, struct device_attribute *attr, char *buf)
+{
+       struct langwell_otg *langwell;
+       char *next;
+       unsigned size;
+       unsigned t;
+
+       langwell = the_transceiver;
+       next = buf;
+       size = PAGE_SIZE;
+
+       t = scnprintf(next, size,
+               "\n"
+               "current state = %s\n"
+               "a_bus_resume = \t%d\n"
+               "a_bus_suspend = \t%d\n"
+               "a_conn = \t%d\n"
+               "a_sess_vld = \t%d\n"
+               "a_srp_det = \t%d\n"
+               "a_vbus_vld = \t%d\n"
+               "b_bus_resume = \t%d\n"
+               "b_bus_suspend = \t%d\n"
+               "b_conn = \t%d\n"
+               "b_se0_srp = \t%d\n"
+               "b_sess_end = \t%d\n"
+               "b_sess_vld = \t%d\n"
+               "id = \t%d\n"
+               "a_set_b_hnp_en = \t%d\n"
+               "b_srp_done = \t%d\n"
+               "b_hnp_enable = \t%d\n"
+               "a_wait_vrise_tmout = \t%d\n"
+               "a_wait_bcon_tmout = \t%d\n"
+               "a_aidl_bdis_tmout = \t%d\n"
+               "b_ase0_brst_tmout = \t%d\n"
+               "a_bus_drop = \t%d\n"
+               "a_bus_req = \t%d\n"
+               "a_clr_err = \t%d\n"
+               "a_suspend_req = \t%d\n"
+               "b_bus_req = \t%d\n"
+               "b_bus_suspend_tmout = \t%d\n"
+               "b_bus_suspend_vld = \t%d\n",
+               state_string(langwell->otg.state),
+               langwell->hsm.a_bus_resume,
+               langwell->hsm.a_bus_suspend,
+               langwell->hsm.a_conn,
+               langwell->hsm.a_sess_vld,
+               langwell->hsm.a_srp_det,
+               langwell->hsm.a_vbus_vld,
+               langwell->hsm.b_bus_resume,
+               langwell->hsm.b_bus_suspend,
+               langwell->hsm.b_conn,
+               langwell->hsm.b_se0_srp,
+               langwell->hsm.b_sess_end,
+               langwell->hsm.b_sess_vld,
+               langwell->hsm.id,
+               langwell->hsm.a_set_b_hnp_en,
+               langwell->hsm.b_srp_done,
+               langwell->hsm.b_hnp_enable,
+               langwell->hsm.a_wait_vrise_tmout,
+               langwell->hsm.a_wait_bcon_tmout,
+               langwell->hsm.a_aidl_bdis_tmout,
+               langwell->hsm.b_ase0_brst_tmout,
+               langwell->hsm.a_bus_drop,
+               langwell->hsm.a_bus_req,
+               langwell->hsm.a_clr_err,
+               langwell->hsm.a_suspend_req,
+               langwell->hsm.b_bus_req,
+               langwell->hsm.b_bus_suspend_tmout,
+               langwell->hsm.b_bus_suspend_vld
+               );
+       size -= t;
+       next += t;
+
+       return PAGE_SIZE - size;
+}
+static DEVICE_ATTR(hsm, S_IRUGO, show_hsm, NULL);
+
+static ssize_t
+get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct langwell_otg *langwell;
+       char *next;
+       unsigned size;
+       unsigned t;
+
+       langwell =  the_transceiver;
+       next = buf;
+       size = PAGE_SIZE;
+
+       t = scnprintf(next, size, "%d", langwell->hsm.a_bus_req);
+       size -= t;
+       next += t;
+
+       return PAGE_SIZE - size;
+}
+
+static ssize_t
+set_a_bus_req(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct langwell_otg *langwell;
+       langwell = the_transceiver;
+       if (!langwell->otg.default_a)
+               return -1;
+       if (count > 2)
+               return -1;
+
+       if (buf[0] == '0') {
+               langwell->hsm.a_bus_req = 0;
+               otg_dbg("a_bus_req = 0\n");
+       } else if (buf[0] == '1') {
+               /* If a_bus_drop is TRUE, a_bus_req can't be set */
+               if (langwell->hsm.a_bus_drop)
+                       return -1;
+               langwell->hsm.a_bus_req = 1;
+               otg_dbg("a_bus_req = 1\n");
+       }
+       if (spin_trylock(&langwell->wq_lock)) {
+               queue_work(langwell->qwork, &langwell->work);
+               spin_unlock(&langwell->wq_lock);
+       }
+       return count;
+}
+static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUGO, get_a_bus_req, set_a_bus_req);
+
+static ssize_t
+get_a_bus_drop(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct langwell_otg *langwell;
+       char *next;
+       unsigned size;
+       unsigned t;
+
+       langwell =  the_transceiver;
+       next = buf;
+       size = PAGE_SIZE;
+
+       t = scnprintf(next, size, "%d", langwell->hsm.a_bus_drop);
+       size -= t;
+       next += t;
+
+       return PAGE_SIZE - size;
+}
+
+static ssize_t
+set_a_bus_drop(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct langwell_otg *langwell;
+       langwell = the_transceiver;
+       if (!langwell->otg.default_a)
+               return -1;
+       if (count > 2)
+               return -1;
+
+       if (buf[0] == '0') {
+               langwell->hsm.a_bus_drop = 0;
+               otg_dbg("a_bus_drop = 0\n");
+       } else if (buf[0] == '1') {
+               langwell->hsm.a_bus_drop = 1;
+               langwell->hsm.a_bus_req = 0;
+               otg_dbg("a_bus_drop = 1, then a_bus_req = 0\n");
+       }
+       if (spin_trylock(&langwell->wq_lock)) {
+               queue_work(langwell->qwork, &langwell->work);
+               spin_unlock(&langwell->wq_lock);
+       }
+       return count;
+}
+static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUGO,
+       get_a_bus_drop, set_a_bus_drop);
+
+static ssize_t
+get_b_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct langwell_otg *langwell;
+       char *next;
+       unsigned size;
+       unsigned t;
+
+       langwell =  the_transceiver;
+       next = buf;
+       size = PAGE_SIZE;
+
+       t = scnprintf(next, size, "%d", langwell->hsm.b_bus_req);
+       size -= t;
+       next += t;
+
+       return PAGE_SIZE - size;
+}
+
+static ssize_t
+set_b_bus_req(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct langwell_otg *langwell;
+       langwell = the_transceiver;
+
+       if (langwell->otg.default_a)
+               return -1;
+
+       if (count > 2)
+               return -1;
+
+       if (buf[0] == '0') {
+               langwell->hsm.b_bus_req = 0;
+               otg_dbg("b_bus_req = 0\n");
+       } else if (buf[0] == '1') {
+               langwell->hsm.b_bus_req = 1;
+               otg_dbg("b_bus_req = 1\n");
+       }
+       if (spin_trylock(&langwell->wq_lock)) {
+               queue_work(langwell->qwork, &langwell->work);
+               spin_unlock(&langwell->wq_lock);
+       }
+       return count;
+}
+static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUGO, get_b_bus_req, set_b_bus_req);
+
+static ssize_t
+set_a_clr_err(struct device *dev, struct device_attribute *attr,
+               const char *buf, size_t count)
+{
+       struct langwell_otg *langwell;
+       langwell = the_transceiver;
+
+       if (!langwell->otg.default_a)
+               return -1;
+       if (count > 2)
+               return -1;
+
+       if (buf[0] == '1') {
+               langwell->hsm.a_clr_err = 1;
+               otg_dbg("a_clr_err = 1\n");
+       }
+       if (spin_trylock(&langwell->wq_lock)) {
+               queue_work(langwell->qwork, &langwell->work);
+               spin_unlock(&langwell->wq_lock);
+       }
+       return count;
+}
+static DEVICE_ATTR(a_clr_err, S_IWUGO, NULL, set_a_clr_err);
+
+static struct attribute *inputs_attrs[] = {
+       &dev_attr_a_bus_req.attr,
+       &dev_attr_a_bus_drop.attr,
+       &dev_attr_b_bus_req.attr,
+       &dev_attr_a_clr_err.attr,
+       NULL,
+};
+
+static struct attribute_group debug_dev_attr_group = {
+       .name = "inputs",
+       .attrs = inputs_attrs,
+};
+
+int langwell_register_host(struct pci_driver *host_driver)
+{
+       int     ret = 0;
+
+       the_transceiver->host_ops = host_driver;
+       queue_work(the_transceiver->qwork, &the_transceiver->work);
+       otg_dbg("host controller driver is registered\n");
+
+       return ret;
+}
+EXPORT_SYMBOL(langwell_register_host);
+
+void langwell_unregister_host(struct pci_driver *host_driver)
+{
+       if (the_transceiver->host_ops)
+               the_transceiver->host_ops->remove(the_transceiver->pdev);
+       the_transceiver->host_ops = NULL;
+       the_transceiver->hsm.a_bus_drop = 1;
+       queue_work(the_transceiver->qwork, &the_transceiver->work);
+       otg_dbg("host controller driver is unregistered\n");
+}
+EXPORT_SYMBOL(langwell_unregister_host);
+
+int langwell_register_peripheral(struct pci_driver *client_driver)
+{
+       int     ret = 0;
+
+       if (client_driver)
+               ret = client_driver->probe(the_transceiver->pdev,
+                               client_driver->id_table);
+       if (!ret) {
+               the_transceiver->client_ops = client_driver;
+               queue_work(the_transceiver->qwork, &the_transceiver->work);
+               otg_dbg("client controller driver is registered\n");
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL(langwell_register_peripheral);
+
+void langwell_unregister_peripheral(struct pci_driver *client_driver)
+{
+       if (the_transceiver->client_ops)
+               the_transceiver->client_ops->remove(the_transceiver->pdev);
+       the_transceiver->client_ops = NULL;
+       the_transceiver->hsm.b_bus_req = 0;
+       queue_work(the_transceiver->qwork, &the_transceiver->work);
+       otg_dbg("client controller driver is unregistered\n");
+}
+EXPORT_SYMBOL(langwell_unregister_peripheral);
+
+static int langwell_otg_probe(struct pci_dev *pdev,
+               const struct pci_device_id *id)
+{
+       unsigned long           resource, len;
+       void __iomem            *base = NULL;
+       int                     retval;
+       u32                     val32;
+       struct langwell_otg     *langwell;
+       char                    qname[] = "langwell_otg_queue";
+
+       retval = 0;
+       otg_dbg("\notg controller is detected.\n");
+       if (pci_enable_device(pdev) < 0) {
+               retval = -ENODEV;
+               goto done;
+       }
+
+       langwell = kzalloc(sizeof *langwell, GFP_KERNEL);
+       if (langwell == NULL) {
+               retval = -ENOMEM;
+               goto done;
+       }
+       the_transceiver = langwell;
+
+       /* control register: BAR 0 */
+       resource = pci_resource_start(pdev, 0);
+       len = pci_resource_len(pdev, 0);
+       if (!request_mem_region(resource, len, driver_name)) {
+               retval = -EBUSY;
+               goto err;
+       }
+       langwell->region = 1;
+
+       base = ioremap_nocache(resource, len);
+       if (base == NULL) {
+               retval = -EFAULT;
+               goto err;
+       }
+       langwell->regs = base;
+
+       if (!pdev->irq) {
+               otg_dbg("No IRQ.\n");
+               retval = -ENODEV;
+               goto err;
+       }
+
+       langwell->qwork = create_workqueue(qname);
+       if (!langwell->qwork) {
+               otg_dbg("cannot create workqueue %s\n", qname);
+               retval = -ENOMEM;
+               goto err;
+       }
+       INIT_WORK(&langwell->work, langwell_otg_work);
+
+       /* OTG common part */
+       langwell->pdev = pdev;
+       langwell->otg.dev = &pdev->dev;
+       langwell->otg.label = driver_name;
+       langwell->otg.set_host = langwell_otg_set_host;
+       langwell->otg.set_peripheral = langwell_otg_set_peripheral;
+       langwell->otg.set_power = langwell_otg_set_power;
+       langwell->otg.start_srp = langwell_otg_start_srp;
+       langwell->otg.state = OTG_STATE_UNDEFINED;
+       if (otg_set_transceiver(&langwell->otg)) {
+               otg_dbg("can't set transceiver\n");
+               retval = -EBUSY;
+               goto err;
+       }
+
+       reset_otg();
+       init_hsm();
+
+       spin_lock_init(&langwell->lock);
+       spin_lock_init(&langwell->wq_lock);
+       INIT_LIST_HEAD(&active_timers);
+       langwell_otg_init_timers(&langwell->hsm);
+
+       if (request_irq(pdev->irq, otg_irq, IRQF_SHARED,
+                               driver_name, langwell) != 0) {
+               otg_dbg("request interrupt %d failed\n", pdev->irq);
+               retval = -EBUSY;
+               goto err;
+       }
+
+       /* enable OTGSC int */
+       val32 = OTGSC_DPIE | OTGSC_BSEIE | OTGSC_BSVIE |
+               OTGSC_ASVIE | OTGSC_AVVIE | OTGSC_IDIE | OTGSC_IDPU;
+       writel(val32, langwell->regs + CI_OTGSC);
+
+       retval = device_create_file(&pdev->dev, &dev_attr_registers);
+       if (retval < 0) {
+               otg_dbg("Can't register sysfs attribute: %d\n", retval);
+               goto err;
+       }
+
+       retval = device_create_file(&pdev->dev, &dev_attr_hsm);
+       if (retval < 0) {
+               otg_dbg("Can't hsm sysfs attribute: %d\n", retval);
+               goto err;
+       }
+
+       retval = sysfs_create_group(&pdev->dev.kobj, &debug_dev_attr_group);
+       if (retval < 0) {
+               otg_dbg("Can't register sysfs attr group: %d\n", retval);
+               goto err;
+       }
+
+       if (langwell->otg.state == OTG_STATE_A_IDLE)
+               queue_work(langwell->qwork, &langwell->work);
+
+       return 0;
+
+err:
+       if (the_transceiver)
+               langwell_otg_remove(pdev);
+done:
+       return retval;
+}
+
+static void langwell_otg_remove(struct pci_dev *pdev)
+{
+       struct langwell_otg *langwell;
+
+       langwell = the_transceiver;
+
+       if (langwell->qwork) {
+               flush_workqueue(langwell->qwork);
+               destroy_workqueue(langwell->qwork);
+       }
+       langwell_otg_free_timers();
+
+       /* disable OTGSC interrupt as OTGSC doesn't change in reset */
+       writel(0, langwell->regs + CI_OTGSC);
+
+       if (pdev->irq)
+               free_irq(pdev->irq, langwell);
+       if (langwell->regs)
+               iounmap(langwell->regs);
+       if (langwell->region)
+               release_mem_region(pci_resource_start(pdev, 0),
+                               pci_resource_len(pdev, 0));
+
+       otg_set_transceiver(NULL);
+       pci_disable_device(pdev);
+       sysfs_remove_group(&pdev->dev.kobj, &debug_dev_attr_group);
+       device_remove_file(&pdev->dev, &dev_attr_hsm);
+       device_remove_file(&pdev->dev, &dev_attr_registers);
+       kfree(langwell);
+       langwell = NULL;
+}
+
+static void transceiver_suspend(struct pci_dev *pdev)
+{
+       pci_save_state(pdev);
+       pci_set_power_state(pdev, PCI_D3hot);
+       langwell_otg_phy_low_power(1);
+}
+
+static int langwell_otg_suspend(struct pci_dev *pdev, pm_message_t message)
+{
+       int     ret = 0;
+       struct langwell_otg *langwell;
+
+       langwell = the_transceiver;
+
+       /* Disbale OTG interrupts */
+       langwell_otg_intr(0);
+
+       if (pdev->irq)
+               free_irq(pdev->irq, langwell);
+
+       /* Prevent more otg_work */
+       flush_workqueue(langwell->qwork);
+       spin_lock(&langwell->wq_lock);
+
+       /* start actions */
+       switch (langwell->otg.state) {
+       case OTG_STATE_A_IDLE:
+       case OTG_STATE_B_IDLE:
+       case OTG_STATE_A_WAIT_VFALL:
+       case OTG_STATE_A_VBUS_ERR:
+               transceiver_suspend(pdev);
+               break;
+       case OTG_STATE_A_WAIT_VRISE:
+               langwell_otg_del_timer(a_wait_vrise_tmr);
+               langwell->hsm.a_srp_det = 0;
+               langwell_otg_drv_vbus(0);
+               langwell->otg.state = OTG_STATE_A_IDLE;
+               transceiver_suspend(pdev);
+               break;
+       case OTG_STATE_A_WAIT_BCON:
+               langwell_otg_del_timer(a_wait_bcon_tmr);
+               if (langwell->host_ops)
+                       ret = langwell->host_ops->suspend(pdev, message);
+               langwell_otg_drv_vbus(0);
+               break;
+       case OTG_STATE_A_HOST:
+               if (langwell->host_ops)
+                       ret = langwell->host_ops->suspend(pdev, message);
+               langwell_otg_drv_vbus(0);
+               langwell_otg_phy_low_power(1);
+               break;
+       case OTG_STATE_A_SUSPEND:
+               langwell_otg_del_timer(a_aidl_bdis_tmr);
+               langwell_otg_HABA(0);
+               if (langwell->host_ops)
+                       langwell->host_ops->remove(pdev);
+               else
+                       otg_dbg("host driver has been removed.\n");
+               langwell_otg_drv_vbus(0);
+               transceiver_suspend(pdev);
+               langwell->otg.state = OTG_STATE_A_WAIT_VFALL;
+               break;
+       case OTG_STATE_A_PERIPHERAL:
+               if (langwell->client_ops)
+                       ret = langwell->client_ops->suspend(pdev, message);
+               else
+                       otg_dbg("client driver has been removed.\n");
+               langwell_otg_drv_vbus(0);
+               transceiver_suspend(pdev);
+               langwell->otg.state = OTG_STATE_A_WAIT_VFALL;
+               break;
+       case OTG_STATE_B_HOST:
+               if (langwell->host_ops)
+                       langwell->host_ops->remove(pdev);
+               else
+                       otg_dbg("host driver has been removed.\n");
+               langwell->hsm.b_bus_req = 0;
+               transceiver_suspend(pdev);
+               langwell->otg.state = OTG_STATE_B_IDLE;
+               break;
+       case OTG_STATE_B_PERIPHERAL:
+               if (langwell->client_ops)
+                       ret = langwell->client_ops->suspend(pdev, message);
+               else
+                       otg_dbg("client driver has been removed.\n");
+               break;
+       case OTG_STATE_B_WAIT_ACON:
+               langwell_otg_del_timer(b_ase0_brst_tmr);
+               langwell_otg_HAAR(0);
+               if (langwell->host_ops)
+                       langwell->host_ops->remove(pdev);
+               else
+                       otg_dbg("host driver has been removed.\n");
+               langwell->hsm.b_bus_req = 0;
+               langwell->otg.state = OTG_STATE_B_IDLE;
+               transceiver_suspend(pdev);
+               break;
+       default:
+               otg_dbg("error state before suspend\n ");
+               break;
+       }
+       spin_unlock(&langwell->wq_lock);
+
+       return ret;
+}
+
+static void transceiver_resume(struct pci_dev *pdev)
+{
+       pci_restore_state(pdev);
+       pci_set_power_state(pdev, PCI_D0);
+       langwell_otg_phy_low_power(0);
+}
+
+static int langwell_otg_resume(struct pci_dev *pdev)
+{
+       int     ret = 0;
+       struct langwell_otg *langwell;
+
+       langwell = the_transceiver;
+
+       spin_lock(&langwell->wq_lock);
+
+       switch (langwell->otg.state) {
+       case OTG_STATE_A_IDLE:
+       case OTG_STATE_B_IDLE:
+       case OTG_STATE_A_WAIT_VFALL:
+       case OTG_STATE_A_VBUS_ERR:
+               transceiver_resume(pdev);
+               break;
+       case OTG_STATE_A_WAIT_BCON:
+               langwell_otg_add_timer(a_wait_bcon_tmr);
+               langwell_otg_drv_vbus(1);
+               if (langwell->host_ops)
+                       ret = langwell->host_ops->resume(pdev);
+               break;
+       case OTG_STATE_A_HOST:
+               langwell_otg_drv_vbus(1);
+               langwell_otg_phy_low_power(0);
+               if (langwell->host_ops)
+                       ret = langwell->host_ops->resume(pdev);
+               break;
+       case OTG_STATE_B_PERIPHERAL:
+               if (langwell->client_ops)
+                       ret = langwell->client_ops->resume(pdev);
+               else
+                       otg_dbg("client driver not loaded.\n");
+               break;
+       default:
+               otg_dbg("error state before suspend\n ");
+               break;
+       }
+
+       if (request_irq(pdev->irq, otg_irq, IRQF_SHARED,
+                               driver_name, the_transceiver) != 0) {
+               otg_dbg("request interrupt %d failed\n", pdev->irq);
+               ret = -EBUSY;
+       }
+
+       /* enable OTG interrupts */
+       langwell_otg_intr(1);
+
+       spin_unlock(&langwell->wq_lock);
+
+       queue_work(langwell->qwork, &langwell->work);
+
+
+       return ret;
+}
+
+static int __init langwell_otg_init(void)
+{
+       return pci_register_driver(&otg_pci_driver);
+}
+module_init(langwell_otg_init);
+
+static void __exit langwell_otg_cleanup(void)
+{
+       pci_unregister_driver(&otg_pci_driver);
+}
+module_exit(langwell_otg_cleanup);
index c567168f89af54c63a1b1f386758088c99ec3de6..9ed5ea568679c3715eae4a03700d1ff8bd05e409 100644 (file)
@@ -22,8 +22,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  * Current status:
- *     this is to add "nop" transceiver for all those phy which is
- *     autonomous such as isp1504 etc.
+ *     This provides a "nop" transceiver for PHYs which are
+ *     autonomous such as isp1504, isp1707, etc.
  */
 
 #include <linux/module.h>
@@ -36,30 +36,25 @@ struct nop_usb_xceiv {
        struct device           *dev;
 };
 
-static u64 nop_xceiv_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device nop_xceiv_device = {
-       .name           = "nop_usb_xceiv",
-       .id             = -1,
-       .dev = {
-               .dma_mask               = &nop_xceiv_dmamask,
-               .coherent_dma_mask      = DMA_BIT_MASK(32),
-               .platform_data          = NULL,
-       },
-};
+static struct platform_device *pd;
 
 void usb_nop_xceiv_register(void)
 {
-       if (platform_device_register(&nop_xceiv_device) < 0) {
+       if (pd)
+               return;
+       pd = platform_device_register_simple("nop_usb_xceiv", -1, NULL, 0);
+       if (!pd) {
                printk(KERN_ERR "Unable to register usb nop transceiver\n");
                return;
        }
 }
+EXPORT_SYMBOL(usb_nop_xceiv_register);
 
 void usb_nop_xceiv_unregister(void)
 {
-       platform_device_unregister(&nop_xceiv_device);
+       platform_device_unregister(pd);
 }
+EXPORT_SYMBOL(usb_nop_xceiv_unregister);
 
 static inline struct nop_usb_xceiv *xceiv_to_nop(struct otg_transceiver *x)
 {
index d9478d0e1c8bd6bb6d45c778d220a6ee96c8139a..9e3e7a5c258bc32d78678e5b05bb877dcac46be6 100644 (file)
 
 /* In module TWL4030_MODULE_PM_MASTER */
 #define PROTECT_KEY                    0x0E
+#define STS_HW_CONDITIONS              0x0F
 
 /* In module TWL4030_MODULE_PM_RECEIVER */
 #define VUSB_DEDICATED1                        0x7D
@@ -351,15 +352,26 @@ static enum linkstat twl4030_usb_linkstat(struct twl4030_usb *twl)
        int     status;
        int     linkstat = USB_LINK_UNKNOWN;
 
-       /* STS_HW_CONDITIONS */
-       status = twl4030_readb(twl, TWL4030_MODULE_PM_MASTER, 0x0f);
+       /*
+        * For ID/VBUS sensing, see manual section 15.4.8 ...
+        * except when using only battery backup power, two
+        * comparators produce VBUS_PRES and ID_PRES signals,
+        * which don't match docs elsewhere.  But ... BIT(7)
+        * and BIT(2) of STS_HW_CONDITIONS, respectively, do
+        * seem to match up.  If either is true the USB_PRES
+        * signal is active, the OTG module is activated, and
+        * its interrupt may be raised (may wake the system).
+        */
+       status = twl4030_readb(twl, TWL4030_MODULE_PM_MASTER,
+                       STS_HW_CONDITIONS);
        if (status < 0)
                dev_err(twl->dev, "USB link status err %d\n", status);
-       else if (status & BIT(7))
-               linkstat = USB_LINK_VBUS;
-       else if (status & BIT(2))
-               linkstat = USB_LINK_ID;
-       else
+       else if (status & (BIT(7) | BIT(2))) {
+               if (status & BIT(2))
+                       linkstat = USB_LINK_ID;
+               else
+                       linkstat = USB_LINK_VBUS;
+       } else
                linkstat = USB_LINK_NONE;
 
        dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n",
@@ -641,7 +653,7 @@ static int twl4030_set_host(struct otg_transceiver *x, struct usb_bus *host)
        return 0;
 }
 
-static int __init twl4030_usb_probe(struct platform_device *pdev)
+static int __devinit twl4030_usb_probe(struct platform_device *pdev)
 {
        struct twl4030_usb_data *pdata = pdev->dev.platform_data;
        struct twl4030_usb      *twl;
index 6d106e74265e9d839e7a4e5123bb4ce11c97a538..2cbfab3716e59c3764cf333d5bdb933add1e69a9 100644 (file)
@@ -364,7 +364,7 @@ static int aircable_attach(struct usb_serial *serial)
        return 0;
 }
 
-static void aircable_shutdown(struct usb_serial *serial)
+static void aircable_release(struct usb_serial *serial)
 {
 
        struct usb_serial_port *port = serial->port[0];
@@ -375,7 +375,6 @@ static void aircable_shutdown(struct usb_serial *serial)
        if (priv) {
                serial_buf_free(priv->tx_buf);
                serial_buf_free(priv->rx_buf);
-               usb_set_serial_port_data(port, NULL);
                kfree(priv);
        }
 }
@@ -601,7 +600,7 @@ static struct usb_serial_driver aircable_device = {
        .num_ports =            1,
        .attach =               aircable_attach,
        .probe =                aircable_probe,
-       .shutdown =             aircable_shutdown,
+       .release =              aircable_release,
        .write =                aircable_write,
        .write_room =           aircable_write_room,
        .write_bulk_callback =  aircable_write_bulk_callback,
index 2bfd6dd85b5ad23624cef600a2e8e5f76de5fa18..7033b031b4439da94bb5a9c1015e7070a6721a45 100644 (file)
@@ -90,7 +90,7 @@ static int debug;
 
 /* function prototypes for a Belkin USB Serial Adapter F5U103 */
 static int  belkin_sa_startup(struct usb_serial *serial);
-static void belkin_sa_shutdown(struct usb_serial *serial);
+static void belkin_sa_release(struct usb_serial *serial);
 static int  belkin_sa_open(struct tty_struct *tty,
                        struct usb_serial_port *port, struct file *filp);
 static void belkin_sa_close(struct usb_serial_port *port);
@@ -142,7 +142,7 @@ static struct usb_serial_driver belkin_device = {
        .tiocmget =             belkin_sa_tiocmget,
        .tiocmset =             belkin_sa_tiocmset,
        .attach =               belkin_sa_startup,
-       .shutdown =             belkin_sa_shutdown,
+       .release =              belkin_sa_release,
 };
 
 
@@ -197,14 +197,13 @@ static int belkin_sa_startup(struct usb_serial *serial)
 }
 
 
-static void belkin_sa_shutdown(struct usb_serial *serial)
+static void belkin_sa_release(struct usb_serial *serial)
 {
        struct belkin_sa_private *priv;
        int i;
 
        dbg("%s", __func__);
 
-       /* stop reads and writes on all ports */
        for (i = 0; i < serial->num_ports; ++i) {
                /* My special items, the standard routines free my urbs */
                priv = usb_get_serial_port_data(serial->port[i]);
index 83bbb5bca2efcc05af2aba7023f7a846f8fafa0a..ba555c528cc6cc8c5b88356140cd0a4e288d1ed1 100644 (file)
@@ -59,23 +59,22 @@ static int usb_serial_device_probe(struct device *dev)
                retval = -ENODEV;
                goto exit;
        }
+       if (port->dev_state != PORT_REGISTERING)
+               goto exit;
 
        driver = port->serial->type;
        if (driver->port_probe) {
-               if (!try_module_get(driver->driver.owner)) {
-                       dev_err(dev, "module get failed, exiting\n");
-                       retval = -EIO;
-                       goto exit;
-               }
                retval = driver->port_probe(port);
-               module_put(driver->driver.owner);
                if (retval)
                        goto exit;
        }
 
        retval = device_create_file(dev, &dev_attr_port_number);
-       if (retval)
+       if (retval) {
+               if (driver->port_remove)
+                       retval = driver->port_remove(port);
                goto exit;
+       }
 
        minor = port->number;
        tty_register_device(usb_serial_tty_driver, minor, dev);
@@ -98,19 +97,15 @@ static int usb_serial_device_remove(struct device *dev)
        if (!port)
                return -ENODEV;
 
+       if (port->dev_state != PORT_UNREGISTERING)
+               return retval;
+
        device_remove_file(&port->dev, &dev_attr_port_number);
 
        driver = port->serial->type;
-       if (driver->port_remove) {
-               if (!try_module_get(driver->driver.owner)) {
-                       dev_err(dev, "module get failed, exiting\n");
-                       retval = -EIO;
-                       goto exit;
-               }
+       if (driver->port_remove)
                retval = driver->port_remove(port);
-               module_put(driver->driver.owner);
-       }
-exit:
+
        minor = port->number;
        tty_unregister_device(usb_serial_tty_driver, minor);
        dev_info(dev, "%s converter now disconnected from ttyUSB%d\n",
index 16a154d3b2feeaaacf0e0c949405d992a66165be..2b9eeda62bfe7beb12a4b3abb8aec6b3954e9f9c 100644 (file)
@@ -50,7 +50,7 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port, struct file *,
                unsigned int, unsigned int);
 static void cp210x_break_ctl(struct tty_struct *, int);
 static int cp210x_startup(struct usb_serial *);
-static void cp210x_shutdown(struct usb_serial *);
+static void cp210x_disconnect(struct usb_serial *);
 
 static int debug;
 
@@ -137,7 +137,7 @@ static struct usb_serial_driver cp210x_device = {
        .tiocmget               = cp210x_tiocmget,
        .tiocmset               = cp210x_tiocmset,
        .attach                 = cp210x_startup,
-       .shutdown               = cp210x_shutdown,
+       .disconnect             = cp210x_disconnect,
 };
 
 /* Config request types */
@@ -792,7 +792,7 @@ static int cp210x_startup(struct usb_serial *serial)
        return 0;
 }
 
-static void cp210x_shutdown(struct usb_serial *serial)
+static void cp210x_disconnect(struct usb_serial *serial)
 {
        int i;
 
index 933ba913e66c5fc21950a3ccc2e5b8229f8c9d63..336523fd736671a4e8e98b1217070fc81360b7b5 100644 (file)
@@ -58,7 +58,8 @@ static int debug;
 
 /* Function prototypes */
 static int cyberjack_startup(struct usb_serial *serial);
-static void cyberjack_shutdown(struct usb_serial *serial);
+static void cyberjack_disconnect(struct usb_serial *serial);
+static void cyberjack_release(struct usb_serial *serial);
 static int  cyberjack_open(struct tty_struct *tty,
                        struct usb_serial_port *port, struct file *filp);
 static void cyberjack_close(struct usb_serial_port *port);
@@ -94,7 +95,8 @@ static struct usb_serial_driver cyberjack_device = {
        .id_table =             id_table,
        .num_ports =            1,
        .attach =               cyberjack_startup,
-       .shutdown =             cyberjack_shutdown,
+       .disconnect =           cyberjack_disconnect,
+       .release =              cyberjack_release,
        .open =                 cyberjack_open,
        .close =                cyberjack_close,
        .write =                cyberjack_write,
@@ -148,17 +150,25 @@ static int cyberjack_startup(struct usb_serial *serial)
        return 0;
 }
 
-static void cyberjack_shutdown(struct usb_serial *serial)
+static void cyberjack_disconnect(struct usb_serial *serial)
 {
        int i;
 
        dbg("%s", __func__);
 
-       for (i = 0; i < serial->num_ports; ++i) {
+       for (i = 0; i < serial->num_ports; ++i)
                usb_kill_urb(serial->port[i]->interrupt_in_urb);
+}
+
+static void cyberjack_release(struct usb_serial *serial)
+{
+       int i;
+
+       dbg("%s", __func__);
+
+       for (i = 0; i < serial->num_ports; ++i) {
                /* My special items, the standard routines free my urbs */
                kfree(usb_get_serial_port_data(serial->port[i]));
-               usb_set_serial_port_data(serial->port[i], NULL);
        }
 }
 
index 669f93848539560182b589131cc18788487477dc..9734085fd2fee19f99051320db97ae22d867dc1e 100644 (file)
@@ -171,7 +171,7 @@ struct cypress_buf {
 static int  cypress_earthmate_startup(struct usb_serial *serial);
 static int  cypress_hidcom_startup(struct usb_serial *serial);
 static int  cypress_ca42v2_startup(struct usb_serial *serial);
-static void cypress_shutdown(struct usb_serial *serial);
+static void cypress_release(struct usb_serial *serial);
 static int  cypress_open(struct tty_struct *tty,
                        struct usb_serial_port *port, struct file *filp);
 static void cypress_close(struct usb_serial_port *port);
@@ -215,7 +215,7 @@ static struct usb_serial_driver cypress_earthmate_device = {
        .id_table =                     id_table_earthmate,
        .num_ports =                    1,
        .attach =                       cypress_earthmate_startup,
-       .shutdown =                     cypress_shutdown,
+       .release =                      cypress_release,
        .open =                         cypress_open,
        .close =                        cypress_close,
        .dtr_rts =                      cypress_dtr_rts,
@@ -242,7 +242,7 @@ static struct usb_serial_driver cypress_hidcom_device = {
        .id_table =                     id_table_cyphidcomrs232,
        .num_ports =                    1,
        .attach =                       cypress_hidcom_startup,
-       .shutdown =                     cypress_shutdown,
+       .release =                      cypress_release,
        .open =                         cypress_open,
        .close =                        cypress_close,
        .dtr_rts =                      cypress_dtr_rts,
@@ -269,7 +269,7 @@ static struct usb_serial_driver cypress_ca42v2_device = {
        .id_table =                     id_table_nokiaca42v2,
        .num_ports =                    1,
        .attach =                       cypress_ca42v2_startup,
-       .shutdown =                     cypress_shutdown,
+       .release =                      cypress_release,
        .open =                         cypress_open,
        .close =                        cypress_close,
        .dtr_rts =                      cypress_dtr_rts,
@@ -616,7 +616,7 @@ static int cypress_ca42v2_startup(struct usb_serial *serial)
 } /* cypress_ca42v2_startup */
 
 
-static void cypress_shutdown(struct usb_serial *serial)
+static void cypress_release(struct usb_serial *serial)
 {
        struct cypress_private *priv;
 
@@ -629,7 +629,6 @@ static void cypress_shutdown(struct usb_serial *serial)
        if (priv) {
                cypress_buf_free(priv->buf);
                kfree(priv);
-               usb_set_serial_port_data(serial->port[0], NULL);
        }
 }
 
index 30f5140eff03a3bbeef50e90f28c942223c99e0e..f4808091c47ca873e3e39f353ea415837d232203 100644 (file)
@@ -460,7 +460,8 @@ static int digi_carrier_raised(struct usb_serial_port *port);
 static void digi_dtr_rts(struct usb_serial_port *port, int on);
 static int digi_startup_device(struct usb_serial *serial);
 static int digi_startup(struct usb_serial *serial);
-static void digi_shutdown(struct usb_serial *serial);
+static void digi_disconnect(struct usb_serial *serial);
+static void digi_release(struct usb_serial *serial);
 static void digi_read_bulk_callback(struct urb *urb);
 static int digi_read_inb_callback(struct urb *urb);
 static int digi_read_oob_callback(struct urb *urb);
@@ -524,7 +525,8 @@ static struct usb_serial_driver digi_acceleport_2_device = {
        .tiocmget =                     digi_tiocmget,
        .tiocmset =                     digi_tiocmset,
        .attach =                       digi_startup,
-       .shutdown =                     digi_shutdown,
+       .disconnect =                   digi_disconnect,
+       .release =                      digi_release,
 };
 
 static struct usb_serial_driver digi_acceleport_4_device = {
@@ -550,7 +552,8 @@ static struct usb_serial_driver digi_acceleport_4_device = {
        .tiocmget =                     digi_tiocmget,
        .tiocmset =                     digi_tiocmset,
        .attach =                       digi_startup,
-       .shutdown =                     digi_shutdown,
+       .disconnect =                   digi_disconnect,
+       .release =                      digi_release,
 };
 
 
@@ -1556,16 +1559,23 @@ static int digi_startup(struct usb_serial *serial)
 }
 
 
-static void digi_shutdown(struct usb_serial *serial)
+static void digi_disconnect(struct usb_serial *serial)
 {
        int i;
-       dbg("digi_shutdown: TOP, in_interrupt()=%ld", in_interrupt());
+       dbg("digi_disconnect: TOP, in_interrupt()=%ld", in_interrupt());
 
        /* stop reads and writes on all ports */
        for (i = 0; i < serial->type->num_ports + 1; i++) {
                usb_kill_urb(serial->port[i]->read_urb);
                usb_kill_urb(serial->port[i]->write_urb);
        }
+}
+
+
+static void digi_release(struct usb_serial *serial)
+{
+       int i;
+       dbg("digi_release: TOP, in_interrupt()=%ld", in_interrupt());
 
        /* free the private data structures for all ports */
        /* number of regular ports + 1 for the out-of-band port */
index 2b141ccb0cd958ca56d51c476075dc621e0a5a4a..80cb3471adbe0fe64cae662184aef149180a942b 100644 (file)
@@ -90,7 +90,6 @@ static int  empeg_chars_in_buffer(struct tty_struct *tty);
 static void empeg_throttle(struct tty_struct *tty);
 static void empeg_unthrottle(struct tty_struct *tty);
 static int  empeg_startup(struct usb_serial *serial);
-static void empeg_shutdown(struct usb_serial *serial);
 static void empeg_set_termios(struct tty_struct *tty,
                struct usb_serial_port *port, struct ktermios *old_termios);
 static void empeg_write_bulk_callback(struct urb *urb);
@@ -124,7 +123,6 @@ static struct usb_serial_driver empeg_device = {
        .throttle =             empeg_throttle,
        .unthrottle =           empeg_unthrottle,
        .attach =               empeg_startup,
-       .shutdown =             empeg_shutdown,
        .set_termios =          empeg_set_termios,
        .write =                empeg_write,
        .write_room =           empeg_write_room,
@@ -427,12 +425,6 @@ static int  empeg_startup(struct usb_serial *serial)
 }
 
 
-static void empeg_shutdown(struct usb_serial *serial)
-{
-       dbg("%s", __func__);
-}
-
-
 static void empeg_set_termios(struct tty_struct *tty,
                struct usb_serial_port *port, struct ktermios *old_termios)
 {
index 683304d60615a334554c3b6a0328de5d96879df5..3dc3768ca71ca0afb4a2a8f19541b3b345787b72 100644 (file)
@@ -47,7 +47,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.4.3"
+#define DRIVER_VERSION "v1.5.0"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>"
 #define DRIVER_DESC "USB FTDI Serial Converters Driver"
 
@@ -82,7 +82,8 @@ struct ftdi_private {
        int rx_processed;
        unsigned long rx_bytes;
 
-       __u16 interface;        /* FT2232C port interface (0 for FT232/245) */
+       __u16 interface;        /* FT2232C, FT2232H or FT4232H port interface
+                                  (0 for FT232/245) */
 
        speed_t force_baud;     /* if non-zero, force the baud rate to
                                   this value */
@@ -94,6 +95,7 @@ struct ftdi_private {
        unsigned long tx_bytes;
        unsigned long tx_outstanding_bytes;
        unsigned long tx_outstanding_urbs;
+       unsigned short max_packet_size;
 };
 
 /* struct ftdi_sio_quirk is used by devices requiring special attention. */
@@ -164,6 +166,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_232RL_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) },
+       { USB_DEVICE(FTDI_VID, FTDI_4232H_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) },
@@ -673,6 +676,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(JETI_VID, JETI_SPC1201_PID) },
        { USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID),
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+       { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) },
        { },                                    /* Optional parameter entry */
        { }                                     /* Terminating entry */
 };
@@ -693,12 +697,13 @@ static const char *ftdi_chip_name[] = {
        [FT232BM] = "FT232BM",
        [FT2232C] = "FT2232C",
        [FT232RL] = "FT232RL",
+       [FT2232H] = "FT2232H",
+       [FT4232H] = "FT4232H"
 };
 
 
 /* Constants for read urb and write urb */
 #define BUFSZ 512
-#define PKTSZ 64
 
 /* rx_flags */
 #define THROTTLED              0x01
@@ -715,7 +720,6 @@ static const char *ftdi_chip_name[] = {
 /* function prototypes for a FTDI serial converter */
 static int  ftdi_sio_probe(struct usb_serial *serial,
                                        const struct usb_device_id *id);
-static void ftdi_shutdown(struct usb_serial *serial);
 static int  ftdi_sio_port_probe(struct usb_serial_port *port);
 static int  ftdi_sio_port_remove(struct usb_serial_port *port);
 static int  ftdi_open(struct tty_struct *tty,
@@ -744,6 +748,8 @@ static unsigned short int ftdi_232am_baud_base_to_divisor(int baud, int base);
 static unsigned short int ftdi_232am_baud_to_divisor(int baud);
 static __u32 ftdi_232bm_baud_base_to_divisor(int baud, int base);
 static __u32 ftdi_232bm_baud_to_divisor(int baud);
+static __u32 ftdi_2232h_baud_base_to_divisor(int baud, int base);
+static __u32 ftdi_2232h_baud_to_divisor(int baud);
 
 static struct usb_serial_driver ftdi_sio_device = {
        .driver = {
@@ -772,7 +778,6 @@ static struct usb_serial_driver ftdi_sio_device = {
        .ioctl =                ftdi_ioctl,
        .set_termios =          ftdi_set_termios,
        .break_ctl =            ftdi_break_ctl,
-       .shutdown =             ftdi_shutdown,
 };
 
 
@@ -838,6 +843,36 @@ static __u32 ftdi_232bm_baud_to_divisor(int baud)
         return ftdi_232bm_baud_base_to_divisor(baud, 48000000);
 }
 
+static __u32 ftdi_2232h_baud_base_to_divisor(int baud, int base)
+{
+       static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 };
+       __u32 divisor;
+       int divisor3;
+
+       /* hi-speed baud rate is 10-bit sampling instead of 16-bit */
+       divisor3 = (base / 10 / baud) * 8;
+
+       divisor = divisor3 >> 3;
+       divisor |= (__u32)divfrac[divisor3 & 0x7] << 14;
+       /* Deal with special cases for highest baud rates. */
+       if (divisor == 1)
+               divisor = 0;
+       else if (divisor == 0x4001)
+               divisor = 1;
+       /*
+        * Set this bit to turn off a divide by 2.5 on baud rate generator
+        * This enables baud rates up to 12Mbaud but cannot reach below 1200
+        * baud with this bit set
+        */
+       divisor |= 0x00020000;
+       return divisor;
+}
+
+static __u32 ftdi_2232h_baud_to_divisor(int baud)
+{
+        return ftdi_2232h_baud_base_to_divisor(baud, 120000000);
+}
+
 #define set_mctrl(port, set)           update_mctrl((port), (set), 0)
 #define clear_mctrl(port, clear)       update_mctrl((port), 0, (clear))
 
@@ -996,6 +1031,19 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty,
                        baud = 9600;
                }
                break;
+       case FT2232H: /* FT2232H chip */
+       case FT4232H: /* FT4232H chip */
+               if ((baud <= 12000000) & (baud >= 1200)) {
+                       div_value = ftdi_2232h_baud_to_divisor(baud);
+               } else if (baud < 1200) {
+                       div_value = ftdi_232bm_baud_to_divisor(baud);
+               } else {
+                       dbg("%s - Baud rate too high!", __func__);
+                       div_value = ftdi_232bm_baud_to_divisor(9600);
+                       div_okay = 0;
+                       baud = 9600;
+               }
+               break;
        } /* priv->chip_type */
 
        if (div_okay) {
@@ -1196,14 +1244,29 @@ static void ftdi_determine_type(struct usb_serial_port *port)
        if (interfaces > 1) {
                int inter;
 
-               /* Multiple interfaces.  Assume FT2232C. */
-               priv->chip_type = FT2232C;
+               /* Multiple interfaces.*/
+               if (version == 0x0800) {
+                       priv->chip_type = FT4232H;
+                       /* Hi-speed - baud clock runs at 120MHz */
+                       priv->baud_base = 120000000 / 2;
+               } else if (version == 0x0700) {
+                       priv->chip_type = FT2232H;
+                       /* Hi-speed - baud clock runs at 120MHz */
+                       priv->baud_base = 120000000 / 2;
+               } else
+                       priv->chip_type = FT2232C;
+
                /* Determine interface code. */
                inter = serial->interface->altsetting->desc.bInterfaceNumber;
-               if (inter == 0)
-                       priv->interface = PIT_SIOA;
-               else
-                       priv->interface = PIT_SIOB;
+               if (inter == 0) {
+                       priv->interface = INTERFACE_A;
+               } else  if (inter == 1) {
+                       priv->interface = INTERFACE_B;
+               } else  if (inter == 2) {
+                       priv->interface = INTERFACE_C;
+               } else  if (inter == 3) {
+                       priv->interface = INTERFACE_D;
+               }
                /* BM-type devices have a bug where bcdDevice gets set
                 * to 0x200 when iSerialNumber is 0.  */
                if (version < 0x500) {
@@ -1231,6 +1294,45 @@ static void ftdi_determine_type(struct usb_serial_port *port)
 }
 
 
+/* Determine the maximum packet size for the device.  This depends on the chip
+ * type and the USB host capabilities.  The value should be obtained from the
+ * device descriptor as the chip will use the appropriate values for the host.*/
+static void ftdi_set_max_packet_size(struct usb_serial_port *port)
+{
+       struct ftdi_private *priv = usb_get_serial_port_data(port);
+       struct usb_serial *serial = port->serial;
+       struct usb_device *udev = serial->dev;
+
+       struct usb_interface *interface = serial->interface;
+       struct usb_endpoint_descriptor *ep_desc = &interface->cur_altsetting->endpoint[1].desc;
+
+       unsigned num_endpoints;
+       int i = 0;
+
+       num_endpoints = interface->cur_altsetting->desc.bNumEndpoints;
+       dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints);
+
+       /* NOTE: some customers have programmed FT232R/FT245R devices
+        * with an endpoint size of 0 - not good.  In this case, we
+        * want to override the endpoint descriptor setting and use a
+        * value of 64 for wMaxPacketSize */
+       for (i = 0; i < num_endpoints; i++) {
+               dev_info(&udev->dev, "Endpoint %d MaxPacketSize %d\n", i+1,
+                       interface->cur_altsetting->endpoint[i].desc.wMaxPacketSize);
+               ep_desc = &interface->cur_altsetting->endpoint[i].desc;
+               if (ep_desc->wMaxPacketSize == 0) {
+                       ep_desc->wMaxPacketSize = cpu_to_le16(0x40);
+                       dev_info(&udev->dev, "Overriding wMaxPacketSize on endpoint %d\n", i);
+               }
+       }
+
+       /* set max packet size based on descriptor */
+       priv->max_packet_size = ep_desc->wMaxPacketSize;
+
+       dev_info(&udev->dev, "Setting MaxPacketSize %d\n", priv->max_packet_size);
+}
+
+
 /*
  * ***************************************************************************
  * Sysfs Attribute
@@ -1314,7 +1416,9 @@ static int create_sysfs_attrs(struct usb_serial_port *port)
                if ((!retval) &&
                    (priv->chip_type == FT232BM ||
                     priv->chip_type == FT2232C ||
-                    priv->chip_type == FT232RL)) {
+                    priv->chip_type == FT232RL ||
+                    priv->chip_type == FT2232H ||
+                    priv->chip_type == FT4232H)) {
                        retval = device_create_file(&port->dev,
                                                    &dev_attr_latency_timer);
                }
@@ -1333,7 +1437,9 @@ static void remove_sysfs_attrs(struct usb_serial_port *port)
                device_remove_file(&port->dev, &dev_attr_event_char);
                if (priv->chip_type == FT232BM ||
                    priv->chip_type == FT2232C ||
-                   priv->chip_type == FT232RL) {
+                   priv->chip_type == FT232RL ||
+                   priv->chip_type == FT2232H ||
+                   priv->chip_type == FT4232H) {
                        device_remove_file(&port->dev, &dev_attr_latency_timer);
                }
        }
@@ -1416,6 +1522,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
        usb_set_serial_port_data(port, priv);
 
        ftdi_determine_type(port);
+       ftdi_set_max_packet_size(port);
        read_latency_timer(port);
        create_sysfs_attrs(port);
        return 0;
@@ -1485,18 +1592,6 @@ static int ftdi_mtxorb_hack_setup(struct usb_serial *serial)
        return 0;
 }
 
-/* ftdi_shutdown is called from usbserial:usb_serial_disconnect
- *   it is called when the usb device is disconnected
- *
- *   usbserial:usb_serial_disconnect
- *      calls __serial_close for each open of the port
- *      shutdown is called then (ie ftdi_shutdown)
- */
-static void ftdi_shutdown(struct usb_serial *serial)
-{
-       dbg("%s", __func__);
-}
-
 static void ftdi_sio_priv_release(struct kref *k)
 {
        struct ftdi_private *priv = container_of(k, struct ftdi_private, kref);
@@ -1671,8 +1766,8 @@ static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port,
        if (data_offset > 0) {
                /* Original sio needs control bytes too... */
                transfer_size += (data_offset *
-                               ((count + (PKTSZ - 1 - data_offset)) /
-                                (PKTSZ - data_offset)));
+                               ((count + (priv->max_packet_size - 1 - data_offset)) /
+                                (priv->max_packet_size - data_offset)));
        }
 
        buffer = kmalloc(transfer_size, GFP_ATOMIC);
@@ -1694,7 +1789,7 @@ static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port,
        if (data_offset > 0) {
                /* Original sio requires control byte at start of
                   each packet. */
-               int user_pktsz = PKTSZ - data_offset;
+               int user_pktsz = priv->max_packet_size - data_offset;
                int todo = count;
                unsigned char *first_byte = buffer;
                const unsigned char *current_position = buf;
@@ -1775,11 +1870,6 @@ static void ftdi_write_bulk_callback(struct urb *urb)
 
        dbg("%s - port %d", __func__, port->number);
 
-       if (status) {
-               dbg("nonzero write bulk status received: %d", status);
-               return;
-       }
-
        priv = usb_get_serial_port_data(port);
        if (!priv) {
                dbg("%s - bad port private data pointer - exiting", __func__);
@@ -1790,13 +1880,18 @@ static void ftdi_write_bulk_callback(struct urb *urb)
        data_offset = priv->write_offset;
        if (data_offset > 0) {
                /* Subtract the control bytes */
-               countback -= (data_offset * DIV_ROUND_UP(countback, PKTSZ));
+               countback -= (data_offset * DIV_ROUND_UP(countback, priv->max_packet_size));
        }
        spin_lock_irqsave(&priv->tx_lock, flags);
        --priv->tx_outstanding_urbs;
        priv->tx_outstanding_bytes -= countback;
        spin_unlock_irqrestore(&priv->tx_lock, flags);
 
+       if (status) {
+               dbg("nonzero write bulk status received: %d", status);
+               return;
+       }
+
        usb_serial_port_softint(port);
 } /* ftdi_write_bulk_callback */
 
@@ -1892,7 +1987,7 @@ static void ftdi_read_bulk_callback(struct urb *urb)
 
        /* count data bytes, but not status bytes */
        countread = urb->actual_length;
-       countread -= 2 * DIV_ROUND_UP(countread, PKTSZ);
+       countread -= 2 * DIV_ROUND_UP(countread, priv->max_packet_size);
        spin_lock_irqsave(&priv->rx_lock, flags);
        priv->rx_bytes += countread;
        spin_unlock_irqrestore(&priv->rx_lock, flags);
@@ -1965,7 +2060,7 @@ static void ftdi_process_read(struct work_struct *work)
 
        need_flip = 0;
        for (packet_offset = priv->rx_processed;
-               packet_offset < urb->actual_length; packet_offset += PKTSZ) {
+               packet_offset < urb->actual_length; packet_offset += priv->max_packet_size) {
                int length;
 
                /* Compare new line status to the old one, signal if different/
@@ -1980,7 +2075,7 @@ static void ftdi_process_read(struct work_struct *work)
                        priv->prev_status = new_status;
                }
 
-               length = min_t(u32, PKTSZ, urb->actual_length-packet_offset)-2;
+               length = min_t(u32, priv->max_packet_size, urb->actual_length-packet_offset)-2;
                if (length < 0) {
                        dev_err(&port->dev, "%s - bad packet length: %d\n",
                                __func__, length+2);
@@ -2011,6 +2106,7 @@ static void ftdi_process_read(struct work_struct *work)
                if (data[packet_offset+1] & FTDI_RS_BI) {
                        error_flag = TTY_BREAK;
                        dbg("BREAK received");
+                       usb_serial_handle_break(port);
                }
                if (data[packet_offset+1] & FTDI_RS_PE) {
                        error_flag = TTY_PARITY;
@@ -2025,8 +2121,11 @@ static void ftdi_process_read(struct work_struct *work)
                                /* Note that the error flag is duplicated for
                                   every character received since we don't know
                                   which character it applied to */
-                               tty_insert_flip_char(tty,
-                                       data[packet_offset + i], error_flag);
+                               if (!usb_serial_handle_sysrq_char(port,
+                                               data[packet_offset + i]))
+                                       tty_insert_flip_char(tty,
+                                               data[packet_offset + i],
+                                               error_flag);
                        }
                        need_flip = 1;
                }
@@ -2332,6 +2431,8 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
        case FT232BM:
        case FT2232C:
        case FT232RL:
+       case FT2232H:
+       case FT4232H:
                /* the 8U232AM returns a two byte value (the sio is a 1 byte
                   value) - in the same format as the data returned from the in
                   point */
index 12330fa1c095b47fd875a758a3ae9eea56d7d914..f1d440a728a376770617ad7776a52eba590cc282 100644 (file)
@@ -10,7 +10,7 @@
  * The device is based on the FTDI FT8U100AX chip. It has a DB25 on one side,
  * USB on the other.
  *
- * Thanx to FTDI (http://www.ftdi.co.uk) for so kindly providing details
+ * Thanx to FTDI (http://www.ftdichip.com) for so kindly providing details
  * of the protocol required to talk to the device and ongoing assistence
  * during development.
  *
 #define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */
 #define FTDI_8U2232C_PID 0x6010 /* Dual channel device */
 #define FTDI_232RL_PID  0xFBFA  /* Product ID for FT232RL */
+#define FTDI_4232H_PID 0x6011 /* Quad channel hi-speed device */
 #define FTDI_RELAIS_PID        0xFA10  /* Relais device from Rudolf Gugler */
 #define FTDI_NF_RIC_VID        0x0DCD  /* Vendor Id */
 #define FTDI_NF_RIC_PID        0x0001  /* Product Id */
 #define FTDI_USBX_707_PID 0xF857       /* ADSTech IR Blaster USBX-707 */
 
+/* Larsen and Brusgaard AltiTrack/USBtrack  */
+#define LARSENBRUSGAARD_VID            0x0FD8
+#define LB_ALTITRACK_PID               0x0001
 
 /* www.canusb.com Lawicel CANUSB device */
 #define FTDI_CANUSB_PID 0xFFA8 /* Product Id */
 #define FTDI_SIO_SET_LATENCY_TIMER     9 /* Set the latency timer */
 #define FTDI_SIO_GET_LATENCY_TIMER     10 /* Get the latency timer */
 
+/* Interface indicies for FT2232, FT2232H and FT4232H devices*/
+#define INTERFACE_A            1
+#define INTERFACE_B            2
+#define INTERFACE_C            3
+#define INTERFACE_D            4
 
 /*
  * FIC / OpenMoko, Inc. http://wiki.openmoko.org/wiki/Neo1973_Debug_Board_v3
@@ -1036,6 +1045,8 @@ typedef enum {
        FT232BM = 3,
        FT2232C = 4,
        FT232RL = 5,
+       FT2232H = 6,
+       FT4232H = 7
 } ftdi_chip_type_t;
 
 typedef enum {
index ee25a3fe3b09c317b0ecbb86f8dde60301bbc9b9..8839f1c70b7fc186ebe5c2b4f169467765086428 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Garmin GPS driver
  *
- * Copyright (C) 2006,2007 Hermann Kneissel herkne@users.sourceforge.net
+ * Copyright (C) 2006-2009 Hermann Kneissel herkne@users.sourceforge.net
  *
  * The latest version of the driver can be found at
  * http://sourceforge.net/projects/garmin-gps/
@@ -51,7 +51,7 @@ static int debug;
  */
 
 #define VERSION_MAJOR  0
-#define VERSION_MINOR  31
+#define VERSION_MINOR  33
 
 #define _STR(s) #s
 #define _DRIVER_VERSION(a, b) "v" _STR(a) "." _STR(b)
@@ -129,7 +129,6 @@ struct garmin_data {
        __u8   state;
        __u16  flags;
        __u8   mode;
-       __u8   ignorePkts;
        __u8   count;
        __u8   pkt_id;
        __u32  serial_num;
@@ -141,8 +140,6 @@ struct garmin_data {
        __u8   inbuffer [GPS_IN_BUFSIZ];  /* tty -> usb */
        __u8   outbuffer[GPS_OUT_BUFSIZ]; /* usb -> tty */
        __u8   privpkt[4*6];
-       atomic_t req_count;
-       atomic_t resp_count;
        spinlock_t lock;
        struct list_head pktlist;
 };
@@ -170,6 +167,8 @@ struct garmin_data {
 #define FLAGS_BULK_IN_ACTIVE      0x0020
 #define FLAGS_BULK_IN_RESTART     0x0010
 #define FLAGS_THROTTLED           0x0008
+#define APP_REQ_SEEN              0x0004
+#define APP_RESP_SEEN             0x0002
 #define CLEAR_HALT_REQUIRED       0x0001
 
 #define FLAGS_QUEUING             0x0100
@@ -184,20 +183,16 @@ struct garmin_data {
 
 
 /* function prototypes */
-static void gsp_next_packet(struct garmin_data *garmin_data_p);
-static int  garmin_write_bulk(struct usb_serial_port *port,
+static int gsp_next_packet(struct garmin_data *garmin_data_p);
+static int garmin_write_bulk(struct usb_serial_port *port,
                             const unsigned char *buf, int count,
                             int dismiss_ack);
 
 /* some special packets to be send or received */
 static unsigned char const GARMIN_START_SESSION_REQ[]
        = { 0, 0, 0, 0,  5, 0, 0, 0, 0, 0, 0, 0 };
-static unsigned char const GARMIN_START_SESSION_REQ2[]
-       = { 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0 };
 static unsigned char const GARMIN_START_SESSION_REPLY[]
        = { 0, 0, 0, 0,  6, 0, 0, 0, 4, 0, 0, 0 };
-static unsigned char const GARMIN_SESSION_ACTIVE_REPLY[]
-       = { 0, 0, 0, 0, 17, 0, 0, 0, 4, 0, 0, 0, 0, 16, 0, 0 };
 static unsigned char const GARMIN_BULK_IN_AVAIL_REPLY[]
        = { 0, 0, 0, 0,  2, 0, 0, 0, 0, 0, 0, 0 };
 static unsigned char const GARMIN_APP_LAYER_REPLY[]
@@ -233,13 +228,6 @@ static struct usb_driver garmin_driver = {
 };
 
 
-static inline int noResponseFromAppLayer(struct garmin_data *garmin_data_p)
-{
-       return atomic_read(&garmin_data_p->req_count) ==
-                               atomic_read(&garmin_data_p->resp_count);
-}
-
-
 static inline int getLayerId(const __u8 *usbPacket)
 {
        return __le32_to_cpup((__le32 *)(usbPacket));
@@ -325,8 +313,11 @@ static int pkt_add(struct garmin_data *garmin_data_p,
                state = garmin_data_p->state;
                spin_unlock_irqrestore(&garmin_data_p->lock, flags);
 
+               dbg("%s - added: pkt: %d - %d bytes",
+                       __func__, pkt->seq, data_length);
+
                /* in serial mode, if someone is waiting for data from
-                  the device, iconvert and send the next packet to tty. */
+                  the device, convert and send the next packet to tty. */
                if (result && (state == STATE_GSP_WAIT_DATA))
                        gsp_next_packet(garmin_data_p);
        }
@@ -411,7 +402,7 @@ static int gsp_send_ack(struct garmin_data *garmin_data_p, __u8 pkt_id)
 /*
  * called for a complete packet received from tty layer
  *
- * the complete packet (pkzid ... cksum) is in garmin_data_p->inbuf starting
+ * the complete packet (pktid ... cksum) is in garmin_data_p->inbuf starting
  * at GSP_INITIAL_OFFSET.
  *
  * count - number of bytes in the input buffer including space reserved for
@@ -501,7 +492,6 @@ static int gsp_receive(struct garmin_data *garmin_data_p,
        unsigned long flags;
        int offs = 0;
        int ack_or_nak_seen = 0;
-       int i = 0;
        __u8 *dest;
        int size;
        /* dleSeen: set if last byte read was a DLE */
@@ -519,8 +509,8 @@ static int gsp_receive(struct garmin_data *garmin_data_p,
        skip = garmin_data_p->flags & FLAGS_GSP_SKIP;
        spin_unlock_irqrestore(&garmin_data_p->lock, flags);
 
-       dbg("%s - dle=%d skip=%d size=%d count=%d",
-               __func__, dleSeen, skip, size, count);
+       /* dbg("%s - dle=%d skip=%d size=%d count=%d",
+               __func__, dleSeen, skip, size, count); */
 
        if (size == 0)
                size = GSP_INITIAL_OFFSET;
@@ -568,7 +558,6 @@ static int gsp_receive(struct garmin_data *garmin_data_p,
                } else if (!skip) {
 
                        if (dleSeen) {
-                               dbg("non-masked DLE at %d - restarting", i);
                                size = GSP_INITIAL_OFFSET;
                                dleSeen = 0;
                        }
@@ -599,19 +588,19 @@ static int gsp_receive(struct garmin_data *garmin_data_p,
        else
                garmin_data_p->flags &= ~FLAGS_GSP_DLESEEN;
 
-       if (ack_or_nak_seen)
-               garmin_data_p->state = STATE_GSP_WAIT_DATA;
-
        spin_unlock_irqrestore(&garmin_data_p->lock, flags);
 
-       if (ack_or_nak_seen)
-               gsp_next_packet(garmin_data_p);
+       if (ack_or_nak_seen) {
+               if (gsp_next_packet(garmin_data_p) > 0)
+                       garmin_data_p->state = STATE_ACTIVE;
+               else
+                       garmin_data_p->state = STATE_GSP_WAIT_DATA;
+       }
        return count;
 }
 
 
 
-
 /*
  * Sends a usb packet to the tty
  *
@@ -733,29 +722,28 @@ static int gsp_send(struct garmin_data *garmin_data_p,
 }
 
 
-
-
-
 /*
  * Process the next pending data packet - if there is one
  */
-static void gsp_next_packet(struct garmin_data *garmin_data_p)
+static int gsp_next_packet(struct garmin_data *garmin_data_p)
 {
+       int result = 0;
        struct garmin_packet *pkt = NULL;
 
        while ((pkt = pkt_pop(garmin_data_p)) != NULL) {
                dbg("%s - next pkt: %d", __func__, pkt->seq);
-               if (gsp_send(garmin_data_p, pkt->data, pkt->size) > 0) {
+               result = gsp_send(garmin_data_p, pkt->data, pkt->size);
+               if (result > 0) {
                        kfree(pkt);
-                       return;
+                       return result;
                }
                kfree(pkt);
        }
+       return result;
 }
 
 
 
-
 /******************************************************************************
  * garmin native mode
  ******************************************************************************/
@@ -888,14 +876,6 @@ static int garmin_clear(struct garmin_data *garmin_data_p)
        unsigned long flags;
        int status = 0;
 
-       struct usb_serial_port *port = garmin_data_p->port;
-
-       if (port != NULL && atomic_read(&garmin_data_p->resp_count)) {
-               /* send a terminate command */
-               status = garmin_write_bulk(port, GARMIN_STOP_TRANSFER_REQ,
-                                       sizeof(GARMIN_STOP_TRANSFER_REQ), 1);
-       }
-
        /* flush all queued data */
        pkt_clear(garmin_data_p);
 
@@ -908,16 +888,12 @@ static int garmin_clear(struct garmin_data *garmin_data_p)
 }
 
 
-
-
-
-
 static int garmin_init_session(struct usb_serial_port *port)
 {
-       unsigned long flags;
        struct usb_serial *serial = port->serial;
        struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
        int status = 0;
+       int i = 0;
 
        if (status == 0) {
                usb_kill_urb(port->interrupt_in_urb);
@@ -931,30 +907,25 @@ static int garmin_init_session(struct usb_serial_port *port)
                                                        __func__, status);
        }
 
+       /*
+        * using the initialization method from gpsbabel. See comments in
+        * gpsbabel/jeeps/gpslibusb.c gusb_reset_toggles()
+        */
        if (status == 0) {
                dbg("%s - starting session ...", __func__);
                garmin_data_p->state = STATE_ACTIVE;
-               status = garmin_write_bulk(port, GARMIN_START_SESSION_REQ,
-                                       sizeof(GARMIN_START_SESSION_REQ), 0);
-
-               if (status >= 0) {
-
-                       spin_lock_irqsave(&garmin_data_p->lock, flags);
-                       garmin_data_p->ignorePkts++;
-                       spin_unlock_irqrestore(&garmin_data_p->lock, flags);
 
-                       /* not needed, but the win32 driver does it too ... */
+               for (i = 0; i < 3; i++) {
                        status = garmin_write_bulk(port,
-                                       GARMIN_START_SESSION_REQ2,
-                                       sizeof(GARMIN_START_SESSION_REQ2), 0);
-                       if (status >= 0) {
-                               status = 0;
-                               spin_lock_irqsave(&garmin_data_p->lock, flags);
-                               garmin_data_p->ignorePkts++;
-                               spin_unlock_irqrestore(&garmin_data_p->lock,
-                                                                       flags);
-                       }
+                                       GARMIN_START_SESSION_REQ,
+                                       sizeof(GARMIN_START_SESSION_REQ), 0);
+
+                       if (status < 0)
+                               break;
                }
+
+               if (status > 0)
+                       status = 0;
        }
 
        return status;
@@ -962,8 +933,6 @@ static int garmin_init_session(struct usb_serial_port *port)
 
 
 
-
-
 static int garmin_open(struct tty_struct *tty,
                        struct usb_serial_port *port, struct file *filp)
 {
@@ -977,8 +946,6 @@ static int garmin_open(struct tty_struct *tty,
        garmin_data_p->mode  = initial_mode;
        garmin_data_p->count = 0;
        garmin_data_p->flags = 0;
-       atomic_set(&garmin_data_p->req_count, 0);
-       atomic_set(&garmin_data_p->resp_count, 0);
        spin_unlock_irqrestore(&garmin_data_p->lock, flags);
 
        /* shutdown any bulk reads that might be going on */
@@ -1006,6 +973,7 @@ static void garmin_close(struct usb_serial_port *port)
                return;
 
        mutex_lock(&port->serial->disc_mutex);
+
        if (!port->serial->disconnected)
                garmin_clear(garmin_data_p);
 
@@ -1013,25 +981,17 @@ static void garmin_close(struct usb_serial_port *port)
        usb_kill_urb(port->read_urb);
        usb_kill_urb(port->write_urb);
 
-       if (!port->serial->disconnected) {
-               if (noResponseFromAppLayer(garmin_data_p) ||
-                   ((garmin_data_p->flags & CLEAR_HALT_REQUIRED) != 0)) {
-                       process_resetdev_request(port);
-                       garmin_data_p->state = STATE_RESET;
-               } else {
-                       garmin_data_p->state = STATE_DISCONNECTED;
-               }
-       } else {
+       /* keep reset state so we know that we must start a new session */
+       if (garmin_data_p->state != STATE_RESET)
                garmin_data_p->state = STATE_DISCONNECTED;
-       }
+
        mutex_unlock(&port->serial->disc_mutex);
 }
 
+
 static void garmin_write_bulk_callback(struct urb *urb)
 {
-       unsigned long flags;
        struct usb_serial_port *port = urb->context;
-       int status = urb->status;
 
        if (port) {
                struct garmin_data *garmin_data_p =
@@ -1039,20 +999,13 @@ static void garmin_write_bulk_callback(struct urb *urb)
 
                dbg("%s - port %d", __func__, port->number);
 
-               if (GARMIN_LAYERID_APPL == getLayerId(urb->transfer_buffer)
-                   && (garmin_data_p->mode == MODE_GARMIN_SERIAL))  {
-                       gsp_send_ack(garmin_data_p,
-                                       ((__u8 *)urb->transfer_buffer)[4]);
-               }
+               if (GARMIN_LAYERID_APPL == getLayerId(urb->transfer_buffer)) {
 
-               if (status) {
-                       dbg("%s - nonzero write bulk status received: %d",
-                           __func__, status);
-                       spin_lock_irqsave(&garmin_data_p->lock, flags);
-                       garmin_data_p->flags |= CLEAR_HALT_REQUIRED;
-                       spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+                       if (garmin_data_p->mode == MODE_GARMIN_SERIAL) {
+                               gsp_send_ack(garmin_data_p,
+                                       ((__u8 *)urb->transfer_buffer)[4]);
+                       }
                }
-
                usb_serial_port_softint(port);
        }
 
@@ -1108,7 +1061,11 @@ static int garmin_write_bulk(struct usb_serial_port *port,
        urb->transfer_flags |= URB_ZERO_PACKET;
 
        if (GARMIN_LAYERID_APPL == getLayerId(buffer)) {
-               atomic_inc(&garmin_data_p->req_count);
+
+               spin_lock_irqsave(&garmin_data_p->lock, flags);
+               garmin_data_p->flags |= APP_REQ_SEEN;
+               spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+
                if (garmin_data_p->mode == MODE_GARMIN_SERIAL)  {
                        pkt_clear(garmin_data_p);
                        garmin_data_p->state = STATE_GSP_WAIT_DATA;
@@ -1140,6 +1097,9 @@ static int garmin_write(struct tty_struct *tty, struct usb_serial_port *port,
 
        usb_serial_debug_data(debug, &port->dev, __func__, count, buf);
 
+       if (garmin_data_p->state == STATE_RESET)
+               return -EIO;
+
        /* check for our private packets */
        if (count >= GARMIN_PKTHDR_LENGTH) {
                len = PRIVPKTSIZ;
@@ -1184,7 +1144,7 @@ static int garmin_write(struct tty_struct *tty, struct usb_serial_port *port,
                                break;
 
                        case PRIV_PKTID_RESET_REQ:
-                               atomic_inc(&garmin_data_p->req_count);
+                               process_resetdev_request(port);
                                break;
 
                        case PRIV_PKTID_SET_DEF_MODE:
@@ -1200,8 +1160,6 @@ static int garmin_write(struct tty_struct *tty, struct usb_serial_port *port,
                }
        }
 
-       garmin_data_p->ignorePkts = 0;
-
        if (garmin_data_p->mode == MODE_GARMIN_SERIAL) {
                return gsp_receive(garmin_data_p, buf, count);
        } else {        /* MODE_NATIVE */
@@ -1224,31 +1182,33 @@ static int garmin_write_room(struct tty_struct *tty)
 static void garmin_read_process(struct garmin_data *garmin_data_p,
                                 unsigned char *data, unsigned data_length)
 {
+       unsigned long flags;
+
        if (garmin_data_p->flags & FLAGS_DROP_DATA) {
                /* abort-transfer cmd is actice */
                dbg("%s - pkt dropped", __func__);
        } else if (garmin_data_p->state != STATE_DISCONNECTED &&
                garmin_data_p->state != STATE_RESET) {
 
-               /* remember any appl.layer packets, so we know
-                  if a reset is required or not when closing
-                  the device */
-               if (0 == memcmp(data, GARMIN_APP_LAYER_REPLY,
-                               sizeof(GARMIN_APP_LAYER_REPLY))) {
-                       atomic_inc(&garmin_data_p->resp_count);
-               }
-
                /* if throttling is active or postprecessing is required
                   put the received data in the input queue, otherwise
                   send it directly to the tty port */
                if (garmin_data_p->flags & FLAGS_QUEUING) {
                        pkt_add(garmin_data_p, data, data_length);
-               } else if (garmin_data_p->mode == MODE_GARMIN_SERIAL) {
-                       if (getLayerId(data) == GARMIN_LAYERID_APPL)
+               } else if (getLayerId(data) == GARMIN_LAYERID_APPL) {
+
+                       spin_lock_irqsave(&garmin_data_p->lock, flags);
+                       garmin_data_p->flags |= APP_RESP_SEEN;
+                       spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+
+                       if (garmin_data_p->mode == MODE_GARMIN_SERIAL) {
                                pkt_add(garmin_data_p, data, data_length);
-               } else {
-                       send_to_tty(garmin_data_p->port, data, data_length);
+                       } else {
+                               send_to_tty(garmin_data_p->port, data,
+                                               data_length);
+                       }
                }
+               /* ignore system layer packets ... */
        }
 }
 
@@ -1363,8 +1323,6 @@ static void garmin_read_int_callback(struct urb *urb)
                        } else {
                                spin_lock_irqsave(&garmin_data_p->lock, flags);
                                garmin_data_p->flags |= FLAGS_BULK_IN_ACTIVE;
-                               /* do not send this packet to the user */
-                               garmin_data_p->ignorePkts = 1;
                                spin_unlock_irqrestore(&garmin_data_p->lock,
                                                                        flags);
                        }
@@ -1391,17 +1349,7 @@ static void garmin_read_int_callback(struct urb *urb)
                        __func__, garmin_data_p->serial_num);
        }
 
-       if (garmin_data_p->ignorePkts) {
-               /* this reply belongs to a request generated by the driver,
-                  ignore it. */
-               dbg("%s - pkt ignored (%d)",
-                       __func__, garmin_data_p->ignorePkts);
-               spin_lock_irqsave(&garmin_data_p->lock, flags);
-               garmin_data_p->ignorePkts--;
-               spin_unlock_irqrestore(&garmin_data_p->lock, flags);
-       } else {
-               garmin_read_process(garmin_data_p, data, urb->actual_length);
-       }
+       garmin_read_process(garmin_data_p, data, urb->actual_length);
 
        port->interrupt_in_urb->dev = port->serial->dev;
        retval = usb_submit_urb(urb, GFP_ATOMIC);
@@ -1527,7 +1475,7 @@ static int garmin_attach(struct usb_serial *serial)
 }
 
 
-static void garmin_shutdown(struct usb_serial *serial)
+static void garmin_disconnect(struct usb_serial *serial)
 {
        struct usb_serial_port *port = serial->port[0];
        struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
@@ -1536,8 +1484,17 @@ static void garmin_shutdown(struct usb_serial *serial)
 
        usb_kill_urb(port->interrupt_in_urb);
        del_timer_sync(&garmin_data_p->timer);
+}
+
+
+static void garmin_release(struct usb_serial *serial)
+{
+       struct usb_serial_port *port = serial->port[0];
+       struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
+
+       dbg("%s", __func__);
+
        kfree(garmin_data_p);
-       usb_set_serial_port_data(port, NULL);
 }
 
 
@@ -1556,7 +1513,8 @@ static struct usb_serial_driver garmin_device = {
        .throttle            = garmin_throttle,
        .unthrottle          = garmin_unthrottle,
        .attach              = garmin_attach,
-       .shutdown            = garmin_shutdown,
+       .disconnect          = garmin_disconnect,
+       .release             = garmin_release,
        .write               = garmin_write,
        .write_room          = garmin_write_room,
        .write_bulk_callback = garmin_write_bulk_callback,
index be82ea956720184d545a0c43bce6f684c032fb7e..932d6241b787d2c399bae70f70bec85e4c979d71 100644 (file)
@@ -63,7 +63,8 @@ struct usb_serial_driver usb_serial_generic_device = {
        .id_table =             generic_device_ids,
        .usb_driver =           &generic_driver,
        .num_ports =            1,
-       .shutdown =             usb_serial_generic_shutdown,
+       .disconnect =           usb_serial_generic_disconnect,
+       .release =              usb_serial_generic_release,
        .throttle =             usb_serial_generic_throttle,
        .unthrottle =           usb_serial_generic_unthrottle,
        .resume =               usb_serial_generic_resume,
@@ -190,6 +191,88 @@ void usb_serial_generic_close(struct usb_serial_port *port)
        generic_cleanup(port);
 }
 
+static int usb_serial_multi_urb_write(struct tty_struct *tty,
+       struct usb_serial_port *port, const unsigned char *buf, int count)
+{
+       unsigned long flags;
+       struct urb *urb;
+       unsigned char *buffer;
+       int status;
+       int towrite;
+       int bwrite = 0;
+
+       dbg("%s - port %d", __func__, port->number);
+
+       if (count == 0)
+               dbg("%s - write request of 0 bytes", __func__);
+
+       while (count > 0) {
+               towrite = (count > port->bulk_out_size) ?
+                       port->bulk_out_size : count;
+               spin_lock_irqsave(&port->lock, flags);
+               if (port->urbs_in_flight >
+                   port->serial->type->max_in_flight_urbs) {
+                       spin_unlock_irqrestore(&port->lock, flags);
+                       dbg("%s - write limit hit\n", __func__);
+                       return bwrite;
+               }
+               port->tx_bytes_flight += towrite;
+               port->urbs_in_flight++;
+               spin_unlock_irqrestore(&port->lock, flags);
+
+               buffer = kmalloc(towrite, GFP_ATOMIC);
+               if (!buffer) {
+                       dev_err(&port->dev,
+                       "%s ran out of kernel memory for urb ...\n", __func__);
+                       goto error_no_buffer;
+               }
+
+               urb = usb_alloc_urb(0, GFP_ATOMIC);
+               if (!urb) {
+                       dev_err(&port->dev, "%s - no more free urbs\n",
+                               __func__);
+                       goto error_no_urb;
+               }
+
+               /* Copy data */
+               memcpy(buffer, buf + bwrite, towrite);
+               usb_serial_debug_data(debug, &port->dev, __func__,
+                                     towrite, buffer);
+               /* fill the buffer and send it */
+               usb_fill_bulk_urb(urb, port->serial->dev,
+                       usb_sndbulkpipe(port->serial->dev,
+                                       port->bulk_out_endpointAddress),
+                       buffer, towrite,
+                       usb_serial_generic_write_bulk_callback, port);
+
+               status = usb_submit_urb(urb, GFP_ATOMIC);
+               if (status) {
+                       dev_err(&port->dev,
+                               "%s - failed submitting write urb, error %d\n",
+                               __func__, status);
+                       goto error;
+               }
+
+               /* This urb is the responsibility of the host driver now */
+               usb_free_urb(urb);
+               dbg("%s write: %d", __func__, towrite);
+               count -= towrite;
+               bwrite += towrite;
+       }
+       return bwrite;
+
+error:
+       usb_free_urb(urb);
+error_no_urb:
+       kfree(buffer);
+error_no_buffer:
+       spin_lock_irqsave(&port->lock, flags);
+       port->urbs_in_flight--;
+       port->tx_bytes_flight -= towrite;
+       spin_unlock_irqrestore(&port->lock, flags);
+       return bwrite;
+}
+
 int usb_serial_generic_write(struct tty_struct *tty,
        struct usb_serial_port *port, const unsigned char *buf, int count)
 {
@@ -207,6 +290,11 @@ int usb_serial_generic_write(struct tty_struct *tty,
        /* only do something if we have a bulk out endpoint */
        if (serial->num_bulk_out) {
                unsigned long flags;
+
+               if (serial->type->max_in_flight_urbs)
+                       return usb_serial_multi_urb_write(tty, port,
+                                                         buf, count);
+
                spin_lock_irqsave(&port->lock, flags);
                if (port->write_urb_busy) {
                        spin_unlock_irqrestore(&port->lock, flags);
@@ -252,20 +340,26 @@ int usb_serial_generic_write(struct tty_struct *tty,
        /* no bulk out, so return 0 bytes written */
        return 0;
 }
+EXPORT_SYMBOL_GPL(usb_serial_generic_write);
 
 int usb_serial_generic_write_room(struct tty_struct *tty)
 {
        struct usb_serial_port *port = tty->driver_data;
        struct usb_serial *serial = port->serial;
+       unsigned long flags;
        int room = 0;
 
        dbg("%s - port %d", __func__, port->number);
-
-       /* FIXME: Locking */
-       if (serial->num_bulk_out) {
-               if (!(port->write_urb_busy))
-                       room = port->bulk_out_size;
+       spin_lock_irqsave(&port->lock, flags);
+       if (serial->type->max_in_flight_urbs) {
+               if (port->urbs_in_flight < serial->type->max_in_flight_urbs)
+                       room = port->bulk_out_size *
+                               (serial->type->max_in_flight_urbs -
+                                port->urbs_in_flight);
+       } else if (serial->num_bulk_out && !(port->write_urb_busy)) {
+               room = port->bulk_out_size;
        }
+       spin_unlock_irqrestore(&port->lock, flags);
 
        dbg("%s - returns %d", __func__, room);
        return room;
@@ -276,11 +370,16 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)
        struct usb_serial_port *port = tty->driver_data;
        struct usb_serial *serial = port->serial;
        int chars = 0;
+       unsigned long flags;
 
        dbg("%s - port %d", __func__, port->number);
 
-       /* FIXME: Locking */
-       if (serial->num_bulk_out) {
+       if (serial->type->max_in_flight_urbs) {
+               spin_lock_irqsave(&port->lock, flags);
+               chars = port->tx_bytes_flight;
+               spin_unlock_irqrestore(&port->lock, flags);
+       } else if (serial->num_bulk_out) {
+               /* FIXME: Locking */
                if (port->write_urb_busy)
                        chars = port->write_urb->transfer_buffer_length;
        }
@@ -290,7 +389,8 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)
 }
 
 
-static void resubmit_read_urb(struct usb_serial_port *port, gfp_t mem_flags)
+void usb_serial_generic_resubmit_read_urb(struct usb_serial_port *port,
+                       gfp_t mem_flags)
 {
        struct urb *urb = port->read_urb;
        struct usb_serial *serial = port->serial;
@@ -311,25 +411,28 @@ static void resubmit_read_urb(struct usb_serial_port *port, gfp_t mem_flags)
                        "%s - failed resubmitting read urb, error %d\n",
                                                        __func__, result);
 }
+EXPORT_SYMBOL_GPL(usb_serial_generic_resubmit_read_urb);
 
 /* Push data to tty layer and resubmit the bulk read URB */
 static void flush_and_resubmit_read_urb(struct usb_serial_port *port)
 {
        struct urb *urb = port->read_urb;
        struct tty_struct *tty = tty_port_tty_get(&port->port);
-       int room;
+       char *ch = (char *)urb->transfer_buffer;
+       int i;
+
+       if (!tty)
+               goto done;
 
        /* Push data to tty */
-       if (tty && urb->actual_length) {
-               room = tty_buffer_request_room(tty, urb->actual_length);
-               if (room) {
-                       tty_insert_flip_string(tty, urb->transfer_buffer, room);
-                       tty_flip_buffer_push(tty);
-               }
+       for (i = 0; i < urb->actual_length; i++, ch++) {
+               if (!usb_serial_handle_sysrq_char(port, *ch))
+                       tty_insert_flip_char(tty, *ch, TTY_NORMAL);
        }
+       tty_flip_buffer_push(tty);
        tty_kref_put(tty);
-
-       resubmit_read_urb(port, GFP_ATOMIC);
+done:
+       usb_serial_generic_resubmit_read_urb(port, GFP_ATOMIC);
 }
 
 void usb_serial_generic_read_bulk_callback(struct urb *urb)
@@ -363,12 +466,24 @@ EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback);
 
 void usb_serial_generic_write_bulk_callback(struct urb *urb)
 {
+       unsigned long flags;
        struct usb_serial_port *port = urb->context;
        int status = urb->status;
 
        dbg("%s - port %d", __func__, port->number);
 
-       port->write_urb_busy = 0;
+       if (port->serial->type->max_in_flight_urbs) {
+               spin_lock_irqsave(&port->lock, flags);
+               --port->urbs_in_flight;
+               port->tx_bytes_flight -= urb->transfer_buffer_length;
+               if (port->urbs_in_flight < 0)
+                       port->urbs_in_flight = 0;
+               spin_unlock_irqrestore(&port->lock, flags);
+       } else {
+               /* Handle the case for single urb mode */
+               port->write_urb_busy = 0;
+       }
+
        if (status) {
                dbg("%s - nonzero write bulk status received: %d",
                    __func__, status);
@@ -408,11 +523,36 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty)
 
        if (was_throttled) {
                /* Resume reading from device */
-               resubmit_read_urb(port, GFP_KERNEL);
+               usb_serial_generic_resubmit_read_urb(port, GFP_KERNEL);
+       }
+}
+
+int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch)
+{
+       if (port->sysrq && port->console) {
+               if (ch && time_before(jiffies, port->sysrq)) {
+                       handle_sysrq(ch, tty_port_tty_get(&port->port));
+                       port->sysrq = 0;
+                       return 1;
+               }
+               port->sysrq = 0;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(usb_serial_handle_sysrq_char);
+
+int usb_serial_handle_break(struct usb_serial_port *port)
+{
+       if (!port->sysrq) {
+               port->sysrq = jiffies + HZ*5;
+               return 1;
        }
+       port->sysrq = 0;
+       return 0;
 }
+EXPORT_SYMBOL_GPL(usb_serial_handle_break);
 
-void usb_serial_generic_shutdown(struct usb_serial *serial)
+void usb_serial_generic_disconnect(struct usb_serial *serial)
 {
        int i;
 
@@ -423,3 +563,7 @@ void usb_serial_generic_shutdown(struct usb_serial *serial)
                generic_cleanup(serial->port[i]);
 }
 
+void usb_serial_generic_release(struct usb_serial *serial)
+{
+       dbg("%s", __func__);
+}
index 53ef5996e33de377b6290c84e4183f2669ef646e..0191693625d6541dbe5125df9b488be237828d77 100644 (file)
@@ -224,7 +224,8 @@ static int  edge_tiocmget(struct tty_struct *tty, struct file *file);
 static int  edge_tiocmset(struct tty_struct *tty, struct file *file,
                                        unsigned int set, unsigned int clear);
 static int  edge_startup(struct usb_serial *serial);
-static void edge_shutdown(struct usb_serial *serial);
+static void edge_disconnect(struct usb_serial *serial);
+static void edge_release(struct usb_serial *serial);
 
 #include "io_tables.h" /* all of the devices that this driver supports */
 
@@ -3193,21 +3194,16 @@ static int edge_startup(struct usb_serial *serial)
 
 
 /****************************************************************************
- * edge_shutdown
+ * edge_disconnect
  *     This function is called whenever the device is removed from the usb bus.
  ****************************************************************************/
-static void edge_shutdown(struct usb_serial *serial)
+static void edge_disconnect(struct usb_serial *serial)
 {
        struct edgeport_serial *edge_serial = usb_get_serial_data(serial);
-       int i;
 
        dbg("%s", __func__);
 
        /* stop reads and writes on all ports */
-       for (i = 0; i < serial->num_ports; ++i) {
-               kfree(usb_get_serial_port_data(serial->port[i]));
-               usb_set_serial_port_data(serial->port[i],  NULL);
-       }
        /* free up our endpoint stuff */
        if (edge_serial->is_epic) {
                usb_kill_urb(edge_serial->interrupt_read_urb);
@@ -3218,9 +3214,24 @@ static void edge_shutdown(struct usb_serial *serial)
                usb_free_urb(edge_serial->read_urb);
                kfree(edge_serial->bulk_in_buffer);
        }
+}
+
+
+/****************************************************************************
+ * edge_release
+ *     This function is called when the device structure is deallocated.
+ ****************************************************************************/
+static void edge_release(struct usb_serial *serial)
+{
+       struct edgeport_serial *edge_serial = usb_get_serial_data(serial);
+       int i;
+
+       dbg("%s", __func__);
+
+       for (i = 0; i < serial->num_ports; ++i)
+               kfree(usb_get_serial_port_data(serial->port[i]));
 
        kfree(edge_serial);
-       usb_set_serial_data(serial, NULL);
 }
 
 
index 7eb9d67b81b632a20ead2479933c4e86cead3dfe..9241d314751324f65cb430ece19b6e6db373c72c 100644 (file)
@@ -117,7 +117,8 @@ static struct usb_serial_driver edgeport_2port_device = {
        .throttle               = edge_throttle,
        .unthrottle             = edge_unthrottle,
        .attach                 = edge_startup,
-       .shutdown               = edge_shutdown,
+       .disconnect             = edge_disconnect,
+       .release                = edge_release,
        .ioctl                  = edge_ioctl,
        .set_termios            = edge_set_termios,
        .tiocmget               = edge_tiocmget,
@@ -145,7 +146,8 @@ static struct usb_serial_driver edgeport_4port_device = {
        .throttle               = edge_throttle,
        .unthrottle             = edge_unthrottle,
        .attach                 = edge_startup,
-       .shutdown               = edge_shutdown,
+       .disconnect             = edge_disconnect,
+       .release                = edge_release,
        .ioctl                  = edge_ioctl,
        .set_termios            = edge_set_termios,
        .tiocmget               = edge_tiocmget,
@@ -173,7 +175,8 @@ static struct usb_serial_driver edgeport_8port_device = {
        .throttle               = edge_throttle,
        .unthrottle             = edge_unthrottle,
        .attach                 = edge_startup,
-       .shutdown               = edge_shutdown,
+       .disconnect             = edge_disconnect,
+       .release                = edge_release,
        .ioctl                  = edge_ioctl,
        .set_termios            = edge_set_termios,
        .tiocmget               = edge_tiocmget,
@@ -200,7 +203,8 @@ static struct usb_serial_driver epic_device = {
        .throttle               = edge_throttle,
        .unthrottle             = edge_unthrottle,
        .attach                 = edge_startup,
-       .shutdown               = edge_shutdown,
+       .disconnect             = edge_disconnect,
+       .release                = edge_release,
        .ioctl                  = edge_ioctl,
        .set_termios            = edge_set_termios,
        .tiocmget               = edge_tiocmget,
index db964db42d3c0d0c258d56395ed4f14c7fb89c61..e8bc42f92e79c599f1c35d7b21cb5b2a980aca9f 100644 (file)
@@ -2663,7 +2663,7 @@ cleanup:
        return -ENOMEM;
 }
 
-static void edge_shutdown(struct usb_serial *serial)
+static void edge_disconnect(struct usb_serial *serial)
 {
        int i;
        struct edgeport_port *edge_port;
@@ -2673,12 +2673,22 @@ static void edge_shutdown(struct usb_serial *serial)
        for (i = 0; i < serial->num_ports; ++i) {
                edge_port = usb_get_serial_port_data(serial->port[i]);
                edge_remove_sysfs_attrs(edge_port->port);
+       }
+}
+
+static void edge_release(struct usb_serial *serial)
+{
+       int i;
+       struct edgeport_port *edge_port;
+
+       dbg("%s", __func__);
+
+       for (i = 0; i < serial->num_ports; ++i) {
+               edge_port = usb_get_serial_port_data(serial->port[i]);
                edge_buf_free(edge_port->ep_out_buf);
                kfree(edge_port);
-               usb_set_serial_port_data(serial->port[i], NULL);
        }
        kfree(usb_get_serial_data(serial));
-       usb_set_serial_data(serial, NULL);
 }
 
 
@@ -2915,7 +2925,8 @@ static struct usb_serial_driver edgeport_1port_device = {
        .throttle               = edge_throttle,
        .unthrottle             = edge_unthrottle,
        .attach                 = edge_startup,
-       .shutdown               = edge_shutdown,
+       .disconnect             = edge_disconnect,
+       .release                = edge_release,
        .port_probe             = edge_create_sysfs_attrs,
        .ioctl                  = edge_ioctl,
        .set_termios            = edge_set_termios,
@@ -2944,7 +2955,8 @@ static struct usb_serial_driver edgeport_2port_device = {
        .throttle               = edge_throttle,
        .unthrottle             = edge_unthrottle,
        .attach                 = edge_startup,
-       .shutdown               = edge_shutdown,
+       .disconnect             = edge_disconnect,
+       .release                = edge_release,
        .port_probe             = edge_create_sysfs_attrs,
        .ioctl                  = edge_ioctl,
        .set_termios            = edge_set_termios,
index c610a99fa47741c51d2b9312150f9ffc05868e23..2545d45ce16f94159f32db95d43d6b628c461bd0 100644 (file)
@@ -79,7 +79,6 @@ static int  ipaq_open(struct tty_struct *tty,
 static void ipaq_close(struct usb_serial_port *port);
 static int  ipaq_calc_num_ports(struct usb_serial *serial);
 static int  ipaq_startup(struct usb_serial *serial);
-static void ipaq_shutdown(struct usb_serial *serial);
 static int ipaq_write(struct tty_struct *tty, struct usb_serial_port *port,
                        const unsigned char *buf, int count);
 static int ipaq_write_bulk(struct usb_serial_port *port,
@@ -576,7 +575,6 @@ static struct usb_serial_driver ipaq_device = {
        .close =                ipaq_close,
        .attach =               ipaq_startup,
        .calc_num_ports =       ipaq_calc_num_ports,
-       .shutdown =             ipaq_shutdown,
        .write =                ipaq_write,
        .write_room =           ipaq_write_room,
        .chars_in_buffer =      ipaq_chars_in_buffer,
@@ -990,11 +988,6 @@ static int ipaq_startup(struct usb_serial *serial)
        return usb_reset_configuration(serial->dev);
 }
 
-static void ipaq_shutdown(struct usb_serial *serial)
-{
-       dbg("%s", __func__);
-}
-
 static int __init ipaq_init(void)
 {
        int retval;
index 76a3cc327bb9c2d0dbfdfa0a0e0df55015e15036..96873a7a32b082ecd370e4329852a65e6b3d356b 100644 (file)
@@ -121,8 +121,8 @@ static int iuu_startup(struct usb_serial *serial)
        return 0;
 }
 
-/* Shutdown function */
-static void iuu_shutdown(struct usb_serial *serial)
+/* Release function */
+static void iuu_release(struct usb_serial *serial)
 {
        struct usb_serial_port *port = serial->port[0];
        struct iuu_private *priv = usb_get_serial_port_data(port);
@@ -1202,7 +1202,7 @@ static struct usb_serial_driver iuu_device = {
        .tiocmset = iuu_tiocmset,
        .set_termios = iuu_set_termios,
        .attach = iuu_startup,
-       .shutdown = iuu_shutdown,
+       .release = iuu_release,
 };
 
 static int __init iuu_init(void)
index f1195a98f316df62f0d465b144b32fc3f6f9da66..2594b8743d3fb340ed8a6e54dd3de4ca2e998cab 100644 (file)
@@ -2689,7 +2689,7 @@ static int keyspan_startup(struct usb_serial *serial)
        return 0;
 }
 
-static void keyspan_shutdown(struct usb_serial *serial)
+static void keyspan_disconnect(struct usb_serial *serial)
 {
        int                             i, j;
        struct usb_serial_port          *port;
@@ -2729,6 +2729,17 @@ static void keyspan_shutdown(struct usb_serial *serial)
                        usb_free_urb(p_priv->out_urbs[j]);
                }
        }
+}
+
+static void keyspan_release(struct usb_serial *serial)
+{
+       int                             i;
+       struct usb_serial_port          *port;
+       struct keyspan_serial_private   *s_priv;
+
+       dbg("%s", __func__);
+
+       s_priv = usb_get_serial_data(serial);
 
        /*  dbg("Freeing serial->private."); */
        kfree(s_priv);
index 0d4569b60768a736a1e180db3621aa9053f22e72..3107ed15af641babe6ecce65ad7c78d2a06aaacc 100644 (file)
@@ -41,7 +41,8 @@ static int  keyspan_open              (struct tty_struct *tty,
 static void keyspan_close              (struct usb_serial_port *port);
 static void keyspan_dtr_rts            (struct usb_serial_port *port, int on);
 static int  keyspan_startup            (struct usb_serial *serial);
-static void keyspan_shutdown           (struct usb_serial *serial);
+static void keyspan_disconnect         (struct usb_serial *serial);
+static void keyspan_release            (struct usb_serial *serial);
 static int  keyspan_write_room         (struct tty_struct *tty);
 
 static int  keyspan_write              (struct tty_struct *tty,
@@ -569,7 +570,8 @@ static struct usb_serial_driver keyspan_1port_device = {
        .tiocmget               = keyspan_tiocmget,
        .tiocmset               = keyspan_tiocmset,
        .attach                 = keyspan_startup,
-       .shutdown               = keyspan_shutdown,
+       .disconnect             = keyspan_disconnect,
+       .release                = keyspan_release,
 };
 
 static struct usb_serial_driver keyspan_2port_device = {
@@ -590,7 +592,8 @@ static struct usb_serial_driver keyspan_2port_device = {
        .tiocmget               = keyspan_tiocmget,
        .tiocmset               = keyspan_tiocmset,
        .attach                 = keyspan_startup,
-       .shutdown               = keyspan_shutdown,
+       .disconnect             = keyspan_disconnect,
+       .release                = keyspan_release,
 };
 
 static struct usb_serial_driver keyspan_4port_device = {
@@ -611,7 +614,8 @@ static struct usb_serial_driver keyspan_4port_device = {
        .tiocmget               = keyspan_tiocmget,
        .tiocmset               = keyspan_tiocmset,
        .attach                 = keyspan_startup,
-       .shutdown               = keyspan_shutdown,
+       .disconnect             = keyspan_disconnect,
+       .release                = keyspan_release,
 };
 
 #endif
index ab769dbea1b3e6f66d4df15ce6166caca8a17a50..d0b12e40c2b105e2b41cc44f71eba3ea04a1cc29 100644 (file)
@@ -809,7 +809,7 @@ static int keyspan_pda_startup(struct usb_serial *serial)
        return 0;
 }
 
-static void keyspan_pda_shutdown(struct usb_serial *serial)
+static void keyspan_pda_release(struct usb_serial *serial)
 {
        dbg("%s", __func__);
 
@@ -869,7 +869,7 @@ static struct usb_serial_driver keyspan_pda_device = {
        .tiocmget =             keyspan_pda_tiocmget,
        .tiocmset =             keyspan_pda_tiocmset,
        .attach =               keyspan_pda_startup,
-       .shutdown =             keyspan_pda_shutdown,
+       .release =              keyspan_pda_release,
 };
 
 
index fa817c66b3e8c827bb6ce0837591f2406dd73f70..0f44bb8e8d4f64a0400b969da4d8aa80760a318c 100644 (file)
@@ -73,7 +73,8 @@ static int debug;
  * Function prototypes
  */
 static int  klsi_105_startup(struct usb_serial *serial);
-static void klsi_105_shutdown(struct usb_serial *serial);
+static void klsi_105_disconnect(struct usb_serial *serial);
+static void klsi_105_release(struct usb_serial *serial);
 static int  klsi_105_open(struct tty_struct *tty,
                        struct usb_serial_port *port, struct file *filp);
 static void klsi_105_close(struct usb_serial_port *port);
@@ -131,7 +132,8 @@ static struct usb_serial_driver kl5kusb105d_device = {
        .tiocmget =          klsi_105_tiocmget,
        .tiocmset =          klsi_105_tiocmset,
        .attach =            klsi_105_startup,
-       .shutdown =          klsi_105_shutdown,
+       .disconnect =        klsi_105_disconnect,
+       .release =           klsi_105_release,
        .throttle =          klsi_105_throttle,
        .unthrottle =        klsi_105_unthrottle,
 };
@@ -315,7 +317,7 @@ err_cleanup:
 } /* klsi_105_startup */
 
 
-static void klsi_105_shutdown(struct usb_serial *serial)
+static void klsi_105_disconnect(struct usb_serial *serial)
 {
        int i;
 
@@ -325,33 +327,36 @@ static void klsi_105_shutdown(struct usb_serial *serial)
        for (i = 0; i < serial->num_ports; ++i) {
                struct klsi_105_private *priv =
                                usb_get_serial_port_data(serial->port[i]);
-               unsigned long flags;
 
                if (priv) {
                        /* kill our write urb pool */
                        int j;
                        struct urb **write_urbs = priv->write_urb_pool;
-                       spin_lock_irqsave(&priv->lock, flags);
 
                        for (j = 0; j < NUM_URBS; j++) {
                                if (write_urbs[j]) {
-                                       /* FIXME - uncomment the following
-                                        * usb_kill_urb call when the host
-                                        * controllers get fixed to set
-                                        * urb->dev = NULL after the urb is
-                                        * finished.  Otherwise this call
-                                        * oopses. */
-                                       /* usb_kill_urb(write_urbs[j]); */
-                                       kfree(write_urbs[j]->transfer_buffer);
+                                       usb_kill_urb(write_urbs[j]);
                                        usb_free_urb(write_urbs[j]);
                                }
                        }
-                       spin_unlock_irqrestore(&priv->lock, flags);
-                       kfree(priv);
-                       usb_set_serial_port_data(serial->port[i], NULL);
                }
        }
-} /* klsi_105_shutdown */
+} /* klsi_105_disconnect */
+
+
+static void klsi_105_release(struct usb_serial *serial)
+{
+       int i;
+
+       dbg("%s", __func__);
+
+       for (i = 0; i < serial->num_ports; ++i) {
+               struct klsi_105_private *priv =
+                               usb_get_serial_port_data(serial->port[i]);
+
+               kfree(priv);
+       }
+} /* klsi_105_release */
 
 static int  klsi_105_open(struct tty_struct *tty,
                        struct usb_serial_port *port, struct file *filp)
index 6b570498287f3f5d62d337e6a347945101b638c3..6db0e561f6805c25a032797ffd1e25bf57c5fa18 100644 (file)
@@ -69,7 +69,7 @@ static int debug;
 
 /* Function prototypes */
 static int  kobil_startup(struct usb_serial *serial);
-static void kobil_shutdown(struct usb_serial *serial);
+static void kobil_release(struct usb_serial *serial);
 static int  kobil_open(struct tty_struct *tty,
                        struct usb_serial_port *port, struct file *filp);
 static void kobil_close(struct usb_serial_port *port);
@@ -117,7 +117,7 @@ static struct usb_serial_driver kobil_device = {
        .id_table =             id_table,
        .num_ports =            1,
        .attach =               kobil_startup,
-       .shutdown =             kobil_shutdown,
+       .release =              kobil_release,
        .ioctl =                kobil_ioctl,
        .set_termios =          kobil_set_termios,
        .tiocmget =             kobil_tiocmget,
@@ -201,17 +201,13 @@ static int kobil_startup(struct usb_serial *serial)
 }
 
 
-static void kobil_shutdown(struct usb_serial *serial)
+static void kobil_release(struct usb_serial *serial)
 {
        int i;
        dbg("%s - port %d", __func__, serial->port[0]->number);
 
-       for (i = 0; i < serial->num_ports; ++i) {
-               while (serial->port[i]->port.count > 0)
-                       kobil_close(serial->port[i]);
+       for (i = 0; i < serial->num_ports; ++i)
                kfree(usb_get_serial_port_data(serial->port[i]));
-               usb_set_serial_port_data(serial->port[i], NULL);
-       }
 }
 
 
index 873795548fc0a976a5bd129e3316933c9eda069b..d8825e159aa5cfe9361b152489d79fe953f22889 100644 (file)
@@ -92,7 +92,7 @@ static int debug;
  * Function prototypes
  */
 static int  mct_u232_startup(struct usb_serial *serial);
-static void mct_u232_shutdown(struct usb_serial *serial);
+static void mct_u232_release(struct usb_serial *serial);
 static int  mct_u232_open(struct tty_struct *tty,
                        struct usb_serial_port *port, struct file *filp);
 static void mct_u232_close(struct usb_serial_port *port);
@@ -149,7 +149,7 @@ static struct usb_serial_driver mct_u232_device = {
        .tiocmget =          mct_u232_tiocmget,
        .tiocmset =          mct_u232_tiocmset,
        .attach =            mct_u232_startup,
-       .shutdown =          mct_u232_shutdown,
+       .release =           mct_u232_release,
 };
 
 
@@ -407,7 +407,7 @@ static int mct_u232_startup(struct usb_serial *serial)
 } /* mct_u232_startup */
 
 
-static void mct_u232_shutdown(struct usb_serial *serial)
+static void mct_u232_release(struct usb_serial *serial)
 {
        struct mct_u232_private *priv;
        int i;
@@ -417,12 +417,9 @@ static void mct_u232_shutdown(struct usb_serial *serial)
        for (i = 0; i < serial->num_ports; ++i) {
                /* My special items, the standard routines free my urbs */
                priv = usb_get_serial_port_data(serial->port[i]);
-               if (priv) {
-                       usb_set_serial_port_data(serial->port[i], NULL);
-                       kfree(priv);
-               }
+               kfree(priv);
        }
-} /* mct_u232_shutdown */
+} /* mct_u232_release */
 
 static int  mct_u232_open(struct tty_struct *tty,
                        struct usb_serial_port *port, struct file *filp)
index 9e1a013ee7f679177e7b588aabbb2b6534d4cda3..bfc5ce000ef92e8d664407dfd62dbf0ba4592832 100644 (file)
@@ -1521,19 +1521,16 @@ static int mos7720_startup(struct usb_serial *serial)
        return 0;
 }
 
-static void mos7720_shutdown(struct usb_serial *serial)
+static void mos7720_release(struct usb_serial *serial)
 {
        int i;
 
        /* free private structure allocated for serial port */
-       for (i = 0; i < serial->num_ports; ++i) {
+       for (i = 0; i < serial->num_ports; ++i)
                kfree(usb_get_serial_port_data(serial->port[i]));
-               usb_set_serial_port_data(serial->port[i], NULL);
-       }
 
        /* free private structure allocated for serial device */
        kfree(usb_get_serial_data(serial));
-       usb_set_serial_data(serial, NULL);
 }
 
 static struct usb_driver usb_driver = {
@@ -1558,7 +1555,7 @@ static struct usb_serial_driver moschip7720_2port_driver = {
        .throttle               = mos7720_throttle,
        .unthrottle             = mos7720_unthrottle,
        .attach                 = mos7720_startup,
-       .shutdown               = mos7720_shutdown,
+       .release                = mos7720_release,
        .ioctl                  = mos7720_ioctl,
        .set_termios            = mos7720_set_termios,
        .write                  = mos7720_write,
index 10b78a37214f6c337b1ac1bb3cb93219a9bbd3ba..c40f95c1951cf0cf17e8fedc4e8e9f4782324c67 100644 (file)
@@ -238,7 +238,7 @@ static int mos7840_set_reg_sync(struct usb_serial_port *port, __u16 reg,
 {
        struct usb_device *dev = port->serial->dev;
        val = val & 0x00ff;
-       dbg("mos7840_set_reg_sync offset is %x, value %x\n", reg, val);
+       dbg("mos7840_set_reg_sync offset is %x, value %x", reg, val);
 
        return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ,
                               MCS_WR_RTYPE, val, reg, NULL, 0,
@@ -260,7 +260,7 @@ static int mos7840_get_reg_sync(struct usb_serial_port *port, __u16 reg,
        ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
                              MCS_RD_RTYPE, 0, reg, val, VENDOR_READ_LENGTH,
                              MOS_WDR_TIMEOUT);
-       dbg("mos7840_get_reg_sync offset is %x, return val %x\n", reg, *val);
+       dbg("mos7840_get_reg_sync offset is %x, return val %x", reg, *val);
        *val = (*val) & 0x00ff;
        return ret;
 }
@@ -282,18 +282,18 @@ static int mos7840_set_uart_reg(struct usb_serial_port *port, __u16 reg,
        if (port->serial->num_ports == 4) {
                val |= (((__u16) port->number -
                                (__u16) (port->serial->minor)) + 1) << 8;
-               dbg("mos7840_set_uart_reg application number is %x\n", val);
+               dbg("mos7840_set_uart_reg application number is %x", val);
        } else {
                if (((__u16) port->number - (__u16) (port->serial->minor)) == 0) {
                        val |= (((__u16) port->number -
                              (__u16) (port->serial->minor)) + 1) << 8;
-                       dbg("mos7840_set_uart_reg application number is %x\n",
+                       dbg("mos7840_set_uart_reg application number is %x",
                            val);
                } else {
                        val |=
                            (((__u16) port->number -
                              (__u16) (port->serial->minor)) + 2) << 8;
-                       dbg("mos7840_set_uart_reg application number is %x\n",
+                       dbg("mos7840_set_uart_reg application number is %x",
                            val);
                }
        }
@@ -315,24 +315,24 @@ static int mos7840_get_uart_reg(struct usb_serial_port *port, __u16 reg,
        int ret = 0;
        __u16 Wval;
 
-       /* dbg("application number is %4x \n",
+       /* dbg("application number is %4x",
            (((__u16)port->number - (__u16)(port->serial->minor))+1)<<8); */
        /* Wval  is same as application number */
        if (port->serial->num_ports == 4) {
                Wval =
                    (((__u16) port->number - (__u16) (port->serial->minor)) +
                     1) << 8;
-               dbg("mos7840_get_uart_reg application number is %x\n", Wval);
+               dbg("mos7840_get_uart_reg application number is %x", Wval);
        } else {
                if (((__u16) port->number - (__u16) (port->serial->minor)) == 0) {
                        Wval = (((__u16) port->number -
                              (__u16) (port->serial->minor)) + 1) << 8;
-                       dbg("mos7840_get_uart_reg application number is %x\n",
+                       dbg("mos7840_get_uart_reg application number is %x",
                            Wval);
                } else {
                        Wval = (((__u16) port->number -
                              (__u16) (port->serial->minor)) + 2) << 8;
-                       dbg("mos7840_get_uart_reg application number is %x\n",
+                       dbg("mos7840_get_uart_reg application number is %x",
                            Wval);
                }
        }
@@ -346,11 +346,11 @@ static int mos7840_get_uart_reg(struct usb_serial_port *port, __u16 reg,
 static void mos7840_dump_serial_port(struct moschip_port *mos7840_port)
 {
 
-       dbg("***************************************\n");
-       dbg("SpRegOffset is %2x\n", mos7840_port->SpRegOffset);
-       dbg("ControlRegOffset is %2x \n", mos7840_port->ControlRegOffset);
-       dbg("DCRRegOffset is %2x \n", mos7840_port->DcrRegOffset);
-       dbg("***************************************\n");
+       dbg("***************************************");
+       dbg("SpRegOffset is %2x", mos7840_port->SpRegOffset);
+       dbg("ControlRegOffset is %2x", mos7840_port->ControlRegOffset);
+       dbg("DCRRegOffset is %2x", mos7840_port->DcrRegOffset);
+       dbg("***************************************");
 
 }
 
@@ -474,12 +474,12 @@ static void mos7840_control_callback(struct urb *urb)
                goto exit;
        }
 
-       dbg("%s urb buffer size is %d\n", __func__, urb->actual_length);
-       dbg("%s mos7840_port->MsrLsr is %d port %d\n", __func__,
+       dbg("%s urb buffer size is %d", __func__, urb->actual_length);
+       dbg("%s mos7840_port->MsrLsr is %d port %d", __func__,
            mos7840_port->MsrLsr, mos7840_port->port_num);
        data = urb->transfer_buffer;
        regval = (__u8) data[0];
-       dbg("%s data is %x\n", __func__, regval);
+       dbg("%s data is %x", __func__, regval);
        if (mos7840_port->MsrLsr == 0)
                mos7840_handle_new_msr(mos7840_port, regval);
        else if (mos7840_port->MsrLsr == 1)
@@ -538,7 +538,7 @@ static void mos7840_interrupt_callback(struct urb *urb)
        __u16 wval, wreg = 0;
        int status = urb->status;
 
-       dbg("%s", " : Entering\n");
+       dbg("%s", " : Entering");
 
        switch (status) {
        case 0:
@@ -570,7 +570,7 @@ static void mos7840_interrupt_callback(struct urb *urb)
         * Byte 5 FIFO status for both */
 
        if (length && length > 5) {
-               dbg("%s \n", "Wrong data !!!");
+               dbg("%s", "Wrong data !!!");
                return;
        }
 
@@ -587,17 +587,17 @@ static void mos7840_interrupt_callback(struct urb *urb)
                      (__u16) (serial->minor)) + 1) << 8;
                if (mos7840_port->open) {
                        if (sp[i] & 0x01) {
-                               dbg("SP%d No Interrupt !!!\n", i);
+                               dbg("SP%d No Interrupt !!!", i);
                        } else {
                                switch (sp[i] & 0x0f) {
                                case SERIAL_IIR_RLS:
                                        dbg("Serial Port %d: Receiver status error or ", i);
-                                       dbg("address bit detected in 9-bit mode\n");
+                                       dbg("address bit detected in 9-bit mode");
                                        mos7840_port->MsrLsr = 1;
                                        wreg = LINE_STATUS_REGISTER;
                                        break;
                                case SERIAL_IIR_MS:
-                                       dbg("Serial Port %d: Modem status change\n", i);
+                                       dbg("Serial Port %d: Modem status change", i);
                                        mos7840_port->MsrLsr = 0;
                                        wreg = MODEM_STATUS_REGISTER;
                                        break;
@@ -689,7 +689,7 @@ static void mos7840_bulk_in_callback(struct urb *urb)
 
        mos7840_port = urb->context;
        if (!mos7840_port) {
-               dbg("%s", "NULL mos7840_port pointer \n");
+               dbg("%s", "NULL mos7840_port pointer");
                mos7840_port->read_urb_busy = false;
                return;
        }
@@ -702,41 +702,41 @@ static void mos7840_bulk_in_callback(struct urb *urb)
 
        port = (struct usb_serial_port *)mos7840_port->port;
        if (mos7840_port_paranoia_check(port, __func__)) {
-               dbg("%s", "Port Paranoia failed \n");
+               dbg("%s", "Port Paranoia failed");
                mos7840_port->read_urb_busy = false;
                return;
        }
 
        serial = mos7840_get_usb_serial(port, __func__);
        if (!serial) {
-               dbg("%s\n", "Bad serial pointer ");
+               dbg("%s", "Bad serial pointer");
                mos7840_port->read_urb_busy = false;
                return;
        }
 
-       dbg("%s\n", "Entering... \n");
+       dbg("%s", "Entering... ");
 
        data = urb->transfer_buffer;
 
-       dbg("%s", "Entering ........... \n");
+       dbg("%s", "Entering ...........");
 
        if (urb->actual_length) {
                tty = tty_port_tty_get(&mos7840_port->port->port);
                if (tty) {
                        tty_buffer_request_room(tty, urb->actual_length);
                        tty_insert_flip_string(tty, data, urb->actual_length);
-                       dbg(" %s \n", data);
+                       dbg(" %s ", data);
                        tty_flip_buffer_push(tty);
                        tty_kref_put(tty);
                }
                mos7840_port->icount.rx += urb->actual_length;
                smp_wmb();
-               dbg("mos7840_port->icount.rx is %d:\n",
+               dbg("mos7840_port->icount.rx is %d:",
                    mos7840_port->icount.rx);
        }
 
        if (!mos7840_port->read_urb) {
-               dbg("%s", "URB KILLED !!!\n");
+               dbg("%s", "URB KILLED !!!");
                mos7840_port->read_urb_busy = false;
                return;
        }
@@ -777,16 +777,16 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
        spin_unlock(&mos7840_port->pool_lock);
 
        if (status) {
-               dbg("nonzero write bulk status received:%d\n", status);
+               dbg("nonzero write bulk status received:%d", status);
                return;
        }
 
        if (mos7840_port_paranoia_check(mos7840_port->port, __func__)) {
-               dbg("%s", "Port Paranoia failed \n");
+               dbg("%s", "Port Paranoia failed");
                return;
        }
 
-       dbg("%s \n", "Entering .........");
+       dbg("%s", "Entering .........");
 
        tty = tty_port_tty_get(&mos7840_port->port->port);
        if (tty && mos7840_port->open)
@@ -830,15 +830,17 @@ static int mos7840_open(struct tty_struct *tty,
        struct moschip_port *mos7840_port;
        struct moschip_port *port0;
 
+       dbg ("%s enter", __func__);
+
        if (mos7840_port_paranoia_check(port, __func__)) {
-               dbg("%s", "Port Paranoia failed \n");
+               dbg("%s", "Port Paranoia failed");
                return -ENODEV;
        }
 
        serial = port->serial;
 
        if (mos7840_serial_paranoia_check(serial, __func__)) {
-               dbg("%s", "Serial Paranoia failed \n");
+               dbg("%s", "Serial Paranoia failed");
                return -ENODEV;
        }
 
@@ -891,20 +893,20 @@ static int mos7840_open(struct tty_struct *tty,
        Data = 0x0;
        status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, &Data);
        if (status < 0) {
-               dbg("Reading Spreg failed\n");
+               dbg("Reading Spreg failed");
                return -1;
        }
        Data |= 0x80;
        status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
        if (status < 0) {
-               dbg("writing Spreg failed\n");
+               dbg("writing Spreg failed");
                return -1;
        }
 
        Data &= ~0x80;
        status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
        if (status < 0) {
-               dbg("writing Spreg failed\n");
+               dbg("writing Spreg failed");
                return -1;
        }
        /* End of block to be checked */
@@ -913,7 +915,7 @@ static int mos7840_open(struct tty_struct *tty,
        status = mos7840_get_reg_sync(port, mos7840_port->ControlRegOffset,
                                                                        &Data);
        if (status < 0) {
-               dbg("Reading Controlreg failed\n");
+               dbg("Reading Controlreg failed");
                return -1;
        }
        Data |= 0x08;           /* Driver done bit */
@@ -921,7 +923,7 @@ static int mos7840_open(struct tty_struct *tty,
        status = mos7840_set_reg_sync(port,
                                mos7840_port->ControlRegOffset, Data);
        if (status < 0) {
-               dbg("writing Controlreg failed\n");
+               dbg("writing Controlreg failed");
                return -1;
        }
        /* do register settings here */
@@ -932,21 +934,21 @@ static int mos7840_open(struct tty_struct *tty,
        Data = 0x00;
        status = mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
        if (status < 0) {
-               dbg("disableing interrupts failed\n");
+               dbg("disabling interrupts failed");
                return -1;
        }
        /* Set FIFO_CONTROL_REGISTER to the default value */
        Data = 0x00;
        status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
        if (status < 0) {
-               dbg("Writing FIFO_CONTROL_REGISTER  failed\n");
+               dbg("Writing FIFO_CONTROL_REGISTER  failed");
                return -1;
        }
 
        Data = 0xcf;
        status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
        if (status < 0) {
-               dbg("Writing FIFO_CONTROL_REGISTER  failed\n");
+               dbg("Writing FIFO_CONTROL_REGISTER  failed");
                return -1;
        }
 
@@ -1043,12 +1045,12 @@ static int mos7840_open(struct tty_struct *tty,
         * (can't set it up in mos7840_startup as the  *
         * structures were not set up at that time.)   */
 
-       dbg("port number is %d \n", port->number);
-       dbg("serial number is %d \n", port->serial->minor);
-       dbg("Bulkin endpoint is %d \n", port->bulk_in_endpointAddress);
-       dbg("BulkOut endpoint is %d \n", port->bulk_out_endpointAddress);
-       dbg("Interrupt endpoint is %d \n", port->interrupt_in_endpointAddress);
-       dbg("port's number in the device is %d\n", mos7840_port->port_num);
+       dbg("port number is %d", port->number);
+       dbg("serial number is %d", port->serial->minor);
+       dbg("Bulkin endpoint is %d", port->bulk_in_endpointAddress);
+       dbg("BulkOut endpoint is %d", port->bulk_out_endpointAddress);
+       dbg("Interrupt endpoint is %d", port->interrupt_in_endpointAddress);
+       dbg("port's number in the device is %d", mos7840_port->port_num);
        mos7840_port->read_urb = port->read_urb;
 
        /* set up our bulk in urb */
@@ -1061,7 +1063,7 @@ static int mos7840_open(struct tty_struct *tty,
                          mos7840_port->read_urb->transfer_buffer_length,
                          mos7840_bulk_in_callback, mos7840_port);
 
-       dbg("mos7840_open: bulkin endpoint is %d\n",
+       dbg("mos7840_open: bulkin endpoint is %d",
            port->bulk_in_endpointAddress);
        mos7840_port->read_urb_busy = true;
        response = usb_submit_urb(mos7840_port->read_urb, GFP_KERNEL);
@@ -1087,9 +1089,11 @@ static int mos7840_open(struct tty_struct *tty,
        mos7840_port->icount.tx = 0;
        mos7840_port->icount.rx = 0;
 
-       dbg("\n\nusb_serial serial:%p       mos7840_port:%p\n      usb_serial_port port:%p\n\n",
+       dbg("usb_serial serial:%p       mos7840_port:%p\n      usb_serial_port port:%p",
                                serial, mos7840_port, port);
 
+       dbg ("%s leave", __func__);
+
        return 0;
 
 }
@@ -1112,16 +1116,16 @@ static int mos7840_chars_in_buffer(struct tty_struct *tty)
        unsigned long flags;
        struct moschip_port *mos7840_port;
 
-       dbg("%s \n", " mos7840_chars_in_buffer:entering ...........");
+       dbg("%s", " mos7840_chars_in_buffer:entering ...........");
 
        if (mos7840_port_paranoia_check(port, __func__)) {
-               dbg("%s", "Invalid port \n");
+               dbg("%s", "Invalid port");
                return 0;
        }
 
        mos7840_port = mos7840_get_port_private(port);
        if (mos7840_port == NULL) {
-               dbg("%s \n", "mos7840_break:leaving ...........");
+               dbg("%s", "mos7840_break:leaving ...........");
                return 0;
        }
 
@@ -1148,16 +1152,16 @@ static void mos7840_close(struct usb_serial_port *port)
        int j;
        __u16 Data;
 
-       dbg("%s\n", "mos7840_close:entering...");
+       dbg("%s", "mos7840_close:entering...");
 
        if (mos7840_port_paranoia_check(port, __func__)) {
-               dbg("%s", "Port Paranoia failed \n");
+               dbg("%s", "Port Paranoia failed");
                return;
        }
 
        serial = mos7840_get_usb_serial(port, __func__);
        if (!serial) {
-               dbg("%s", "Serial Paranoia failed \n");
+               dbg("%s", "Serial Paranoia failed");
                return;
        }
 
@@ -1185,27 +1189,27 @@ static void mos7840_close(struct usb_serial_port *port)
         * and interrupt read if they exists                  */
        if (serial->dev) {
                if (mos7840_port->write_urb) {
-                       dbg("%s", "Shutdown bulk write\n");
+                       dbg("%s", "Shutdown bulk write");
                        usb_kill_urb(mos7840_port->write_urb);
                }
                if (mos7840_port->read_urb) {
-                       dbg("%s", "Shutdown bulk read\n");
+                       dbg("%s", "Shutdown bulk read");
                        usb_kill_urb(mos7840_port->read_urb);
                        mos7840_port->read_urb_busy = false;
                }
                if ((&mos7840_port->control_urb)) {
-                       dbg("%s", "Shutdown control read\n");
+                       dbg("%s", "Shutdown control read");
                        /*/      usb_kill_urb (mos7840_port->control_urb); */
                }
        }
 /*      if(mos7840_port->ctrl_buf != NULL) */
 /*              kfree(mos7840_port->ctrl_buf); */
        port0->open_ports--;
-       dbg("mos7840_num_open_ports in close%d:in port%d\n",
+       dbg("mos7840_num_open_ports in close%d:in port%d",
            port0->open_ports, port->number);
        if (port0->open_ports == 0) {
                if (serial->port[0]->interrupt_in_urb) {
-                       dbg("%s", "Shutdown interrupt_in_urb\n");
+                       dbg("%s", "Shutdown interrupt_in_urb");
                        usb_kill_urb(serial->port[0]->interrupt_in_urb);
                }
        }
@@ -1225,7 +1229,7 @@ static void mos7840_close(struct usb_serial_port *port)
 
        mos7840_port->open = 0;
 
-       dbg("%s \n", "Leaving ............");
+       dbg("%s", "Leaving ............");
 }
 
 /************************************************************************
@@ -1280,17 +1284,17 @@ static void mos7840_break(struct tty_struct *tty, int break_state)
        struct usb_serial *serial;
        struct moschip_port *mos7840_port;
 
-       dbg("%s \n", "Entering ...........");
-       dbg("mos7840_break: Start\n");
+       dbg("%s", "Entering ...........");
+       dbg("mos7840_break: Start");
 
        if (mos7840_port_paranoia_check(port, __func__)) {
-               dbg("%s", "Port Paranoia failed \n");
+               dbg("%s", "Port Paranoia failed");
                return;
        }
 
        serial = mos7840_get_usb_serial(port, __func__);
        if (!serial) {
-               dbg("%s", "Serial Paranoia failed \n");
+               dbg("%s", "Serial Paranoia failed");
                return;
        }
 
@@ -1310,7 +1314,7 @@ static void mos7840_break(struct tty_struct *tty, int break_state)
 
        /* FIXME: no locking on shadowLCR anywhere in driver */
        mos7840_port->shadowLCR = data;
-       dbg("mcs7840_break mos7840_port->shadowLCR is %x\n",
+       dbg("mcs7840_break mos7840_port->shadowLCR is %x",
            mos7840_port->shadowLCR);
        mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER,
                             mos7840_port->shadowLCR);
@@ -1334,17 +1338,17 @@ static int mos7840_write_room(struct tty_struct *tty)
        unsigned long flags;
        struct moschip_port *mos7840_port;
 
-       dbg("%s \n", " mos7840_write_room:entering ...........");
+       dbg("%s", " mos7840_write_room:entering ...........");
 
        if (mos7840_port_paranoia_check(port, __func__)) {
-               dbg("%s", "Invalid port \n");
-               dbg("%s \n", " mos7840_write_room:leaving ...........");
+               dbg("%s", "Invalid port");
+               dbg("%s", " mos7840_write_room:leaving ...........");
                return -1;
        }
 
        mos7840_port = mos7840_get_port_private(port);
        if (mos7840_port == NULL) {
-               dbg("%s \n", "mos7840_break:leaving ...........");
+               dbg("%s", "mos7840_break:leaving ...........");
                return -1;
        }
 
@@ -1384,16 +1388,16 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
        /* __u16 Data; */
        const unsigned char *current_position = data;
        unsigned char *data1;
-       dbg("%s \n", "entering ...........");
-       /* dbg("mos7840_write: mos7840_port->shadowLCR is %x\n",
+       dbg("%s", "entering ...........");
+       /* dbg("mos7840_write: mos7840_port->shadowLCR is %x",
                                        mos7840_port->shadowLCR); */
 
 #ifdef NOTMOS7840
        Data = 0x00;
        status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data);
        mos7840_port->shadowLCR = Data;
-       dbg("mos7840_write: LINE_CONTROL_REGISTER is %x\n", Data);
-       dbg("mos7840_write: mos7840_port->shadowLCR is %x\n",
+       dbg("mos7840_write: LINE_CONTROL_REGISTER is %x", Data);
+       dbg("mos7840_write: mos7840_port->shadowLCR is %x",
            mos7840_port->shadowLCR);
 
        /* Data = 0x03; */
@@ -1407,32 +1411,32 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
        /* status = mos7840_set_uart_reg(port,DIVISOR_LATCH_LSB,Data); */
        Data = 0x00;
        status = mos7840_get_uart_reg(port, DIVISOR_LATCH_LSB, &Data);
-       dbg("mos7840_write:DLL value is %x\n", Data);
+       dbg("mos7840_write:DLL value is %x", Data);
 
        Data = 0x0;
        status = mos7840_get_uart_reg(port, DIVISOR_LATCH_MSB, &Data);
-       dbg("mos7840_write:DLM value is %x\n", Data);
+       dbg("mos7840_write:DLM value is %x", Data);
 
        Data = Data & ~SERIAL_LCR_DLAB;
-       dbg("mos7840_write: mos7840_port->shadowLCR is %x\n",
+       dbg("mos7840_write: mos7840_port->shadowLCR is %x",
            mos7840_port->shadowLCR);
        status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
 #endif
 
        if (mos7840_port_paranoia_check(port, __func__)) {
-               dbg("%s", "Port Paranoia failed \n");
+               dbg("%s", "Port Paranoia failed");
                return -1;
        }
 
        serial = port->serial;
        if (mos7840_serial_paranoia_check(serial, __func__)) {
-               dbg("%s", "Serial Paranoia failed \n");
+               dbg("%s", "Serial Paranoia failed");
                return -1;
        }
 
        mos7840_port = mos7840_get_port_private(port);
        if (mos7840_port == NULL) {
-               dbg("%s", "mos7840_port is NULL\n");
+               dbg("%s", "mos7840_port is NULL");
                return -1;
        }
 
@@ -1444,7 +1448,7 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
                if (!mos7840_port->busy[i]) {
                        mos7840_port->busy[i] = 1;
                        urb = mos7840_port->write_urb_pool[i];
-                       dbg("\nURB:%d", i);
+                       dbg("URB:%d", i);
                        break;
                }
        }
@@ -1479,7 +1483,7 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
                          mos7840_bulk_out_data_callback, mos7840_port);
 
        data1 = urb->transfer_buffer;
-       dbg("\nbulkout endpoint is %d", port->bulk_out_endpointAddress);
+       dbg("bulkout endpoint is %d", port->bulk_out_endpointAddress);
 
        /* send it down the pipe */
        status = usb_submit_urb(urb, GFP_ATOMIC);
@@ -1494,7 +1498,7 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
        bytes_sent = transfer_size;
        mos7840_port->icount.tx += transfer_size;
        smp_wmb();
-       dbg("mos7840_port->icount.tx is %d:\n", mos7840_port->icount.tx);
+       dbg("mos7840_port->icount.tx is %d:", mos7840_port->icount.tx);
 exit:
        return bytes_sent;
 
@@ -1513,11 +1517,11 @@ static void mos7840_throttle(struct tty_struct *tty)
        int status;
 
        if (mos7840_port_paranoia_check(port, __func__)) {
-               dbg("%s", "Invalid port \n");
+               dbg("%s", "Invalid port");
                return;
        }
 
-       dbg("- port %d\n", port->number);
+       dbg("- port %d", port->number);
 
        mos7840_port = mos7840_get_port_private(port);
 
@@ -1525,11 +1529,11 @@ static void mos7840_throttle(struct tty_struct *tty)
                return;
 
        if (!mos7840_port->open) {
-               dbg("%s\n", "port not opened");
+               dbg("%s", "port not opened");
                return;
        }
 
-       dbg("%s", "Entering .......... \n");
+       dbg("%s", "Entering ..........");
 
        /* if we are implementing XON/XOFF, send the stop character */
        if (I_IXOFF(tty)) {
@@ -1563,7 +1567,7 @@ static void mos7840_unthrottle(struct tty_struct *tty)
        struct moschip_port *mos7840_port = mos7840_get_port_private(port);
 
        if (mos7840_port_paranoia_check(port, __func__)) {
-               dbg("%s", "Invalid port \n");
+               dbg("%s", "Invalid port");
                return;
        }
 
@@ -1575,7 +1579,7 @@ static void mos7840_unthrottle(struct tty_struct *tty)
                return;
        }
 
-       dbg("%s", "Entering .......... \n");
+       dbg("%s", "Entering ..........");
 
        /* if we are implementing XON/XOFF, send the start character */
        if (I_IXOFF(tty)) {
@@ -1660,7 +1664,7 @@ static int mos7840_tiocmset(struct tty_struct *tty, struct file *file,
 
        status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mcr);
        if (status < 0) {
-               dbg("setting MODEM_CONTROL_REGISTER Failed\n");
+               dbg("setting MODEM_CONTROL_REGISTER Failed");
                return status;
        }
 
@@ -1729,11 +1733,11 @@ static int mos7840_calc_baud_rate_divisor(int baudRate, int *divisor,
                        custom++;
                *divisor = custom;
 
-               dbg(" Baud %d = %d\n", baudrate, custom);
+               dbg(" Baud %d = %d", baudrate, custom);
                return 0;
        }
 
-       dbg("%s\n", " Baud calculation Failed...");
+       dbg("%s", " Baud calculation Failed...");
        return -1;
 #endif
 }
@@ -1759,16 +1763,16 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port,
 
        port = (struct usb_serial_port *)mos7840_port->port;
        if (mos7840_port_paranoia_check(port, __func__)) {
-               dbg("%s", "Invalid port \n");
+               dbg("%s", "Invalid port");
                return -1;
        }
 
        if (mos7840_serial_paranoia_check(port->serial, __func__)) {
-               dbg("%s", "Invalid Serial \n");
+               dbg("%s", "Invalid Serial");
                return -1;
        }
 
-       dbg("%s", "Entering .......... \n");
+       dbg("%s", "Entering ..........");
 
        number = mos7840_port->port->number - mos7840_port->port->serial->minor;
 
@@ -1784,7 +1788,7 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port,
                status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
                                                                        Data);
                if (status < 0) {
-                       dbg("Writing spreg failed in set_serial_baud\n");
+                       dbg("Writing spreg failed in set_serial_baud");
                        return -1;
                }
 #endif
@@ -1797,7 +1801,7 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port,
                status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
                                                                        Data);
                if (status < 0) {
-                       dbg("Writing spreg failed in set_serial_baud\n");
+                       dbg("Writing spreg failed in set_serial_baud");
                        return -1;
                }
 #endif
@@ -1812,14 +1816,14 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port,
                status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset,
                                                                 &Data);
                if (status < 0) {
-                       dbg("reading spreg failed in set_serial_baud\n");
+                       dbg("reading spreg failed in set_serial_baud");
                        return -1;
                }
                Data = (Data & 0x8f) | clk_sel_val;
                status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset,
                                                                Data);
                if (status < 0) {
-                       dbg("Writing spreg failed in set_serial_baud\n");
+                       dbg("Writing spreg failed in set_serial_baud");
                        return -1;
                }
                /* Calculate the Divisor */
@@ -1835,11 +1839,11 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port,
 
                /* Write the divisor */
                Data = (unsigned char)(divisor & 0xff);
-               dbg("set_serial_baud Value to write DLL is %x\n", Data);
+               dbg("set_serial_baud Value to write DLL is %x", Data);
                mos7840_set_uart_reg(port, DIVISOR_LATCH_LSB, Data);
 
                Data = (unsigned char)((divisor & 0xff00) >> 8);
-               dbg("set_serial_baud Value to write DLM is %x\n", Data);
+               dbg("set_serial_baud Value to write DLM is %x", Data);
                mos7840_set_uart_reg(port, DIVISOR_LATCH_MSB, Data);
 
                /* Disable access to divisor latch */
@@ -1877,12 +1881,12 @@ static void mos7840_change_port_settings(struct tty_struct *tty,
        port = (struct usb_serial_port *)mos7840_port->port;
 
        if (mos7840_port_paranoia_check(port, __func__)) {
-               dbg("%s", "Invalid port \n");
+               dbg("%s", "Invalid port");
                return;
        }
 
        if (mos7840_serial_paranoia_check(port->serial, __func__)) {
-               dbg("%s", "Invalid Serial \n");
+               dbg("%s", "Invalid Serial");
                return;
        }
 
@@ -1895,7 +1899,7 @@ static void mos7840_change_port_settings(struct tty_struct *tty,
                return;
        }
 
-       dbg("%s", "Entering .......... \n");
+       dbg("%s", "Entering ..........");
 
        lData = LCR_BITS_8;
        lStop = LCR_STOP_1;
@@ -1955,7 +1959,7 @@ static void mos7840_change_port_settings(struct tty_struct *tty,
            ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
        mos7840_port->shadowLCR |= (lData | lParity | lStop);
 
-       dbg("mos7840_change_port_settings mos7840_port->shadowLCR is %x\n",
+       dbg("mos7840_change_port_settings mos7840_port->shadowLCR is %x",
            mos7840_port->shadowLCR);
        /* Disable Interrupts */
        Data = 0x00;
@@ -1997,7 +2001,7 @@ static void mos7840_change_port_settings(struct tty_struct *tty,
 
        if (!baud) {
                /* pick a default, any default... */
-               dbg("%s\n", "Picked default baud...");
+               dbg("%s", "Picked default baud...");
                baud = 9600;
        }
 
@@ -2020,7 +2024,7 @@ static void mos7840_change_port_settings(struct tty_struct *tty,
        }
        wake_up(&mos7840_port->delta_msr_wait);
        mos7840_port->delta_msr_cond = 1;
-       dbg("mos7840_change_port_settings mos7840_port->shadowLCR is End %x\n",
+       dbg("mos7840_change_port_settings mos7840_port->shadowLCR is End %x",
            mos7840_port->shadowLCR);
 
        return;
@@ -2040,16 +2044,16 @@ static void mos7840_set_termios(struct tty_struct *tty,
        unsigned int cflag;
        struct usb_serial *serial;
        struct moschip_port *mos7840_port;
-       dbg("mos7840_set_termios: START\n");
+       dbg("mos7840_set_termios: START");
        if (mos7840_port_paranoia_check(port, __func__)) {
-               dbg("%s", "Invalid port \n");
+               dbg("%s", "Invalid port");
                return;
        }
 
        serial = port->serial;
 
        if (mos7840_serial_paranoia_check(serial, __func__)) {
-               dbg("%s", "Invalid Serial \n");
+               dbg("%s", "Invalid Serial");
                return;
        }
 
@@ -2063,7 +2067,7 @@ static void mos7840_set_termios(struct tty_struct *tty,
                return;
        }
 
-       dbg("%s\n", "setting termios - ");
+       dbg("%s", "setting termios - ");
 
        cflag = tty->termios->c_cflag;
 
@@ -2078,7 +2082,7 @@ static void mos7840_set_termios(struct tty_struct *tty,
        mos7840_change_port_settings(tty, mos7840_port, old_termios);
 
        if (!mos7840_port->read_urb) {
-               dbg("%s", "URB KILLED !!!!!\n");
+               dbg("%s", "URB KILLED !!!!!");
                return;
        }
 
@@ -2144,7 +2148,7 @@ static int mos7840_set_modem_info(struct moschip_port *mos7840_port,
 
        port = (struct usb_serial_port *)mos7840_port->port;
        if (mos7840_port_paranoia_check(port, __func__)) {
-               dbg("%s", "Invalid port \n");
+               dbg("%s", "Invalid port");
                return -1;
        }
 
@@ -2189,7 +2193,7 @@ static int mos7840_set_modem_info(struct moschip_port *mos7840_port,
        status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
        unlock_kernel();
        if (status < 0) {
-               dbg("setting MODEM_CONTROL_REGISTER Failed\n");
+               dbg("setting MODEM_CONTROL_REGISTER Failed");
                return -1;
        }
 
@@ -2274,7 +2278,7 @@ static int mos7840_ioctl(struct tty_struct *tty, struct file *file,
        int mosret = 0;
 
        if (mos7840_port_paranoia_check(port, __func__)) {
-               dbg("%s", "Invalid port \n");
+               dbg("%s", "Invalid port");
                return -1;
        }
 
@@ -2374,9 +2378,8 @@ static int mos7840_calc_num_ports(struct usb_serial *serial)
 {
        int mos7840_num_ports = 0;
 
-       dbg("numberofendpoints: %d \n",
-           (int)serial->interface->cur_altsetting->desc.bNumEndpoints);
-       dbg("numberofendpoints: %d \n",
+       dbg("numberofendpoints: cur %d, alt %d",
+           (int)serial->interface->cur_altsetting->desc.bNumEndpoints,
            (int)serial->interface->altsetting->desc.bNumEndpoints);
        if (serial->interface->cur_altsetting->desc.bNumEndpoints == 5) {
                mos7840_num_ports = serial->num_ports = 2;
@@ -2385,7 +2388,7 @@ static int mos7840_calc_num_ports(struct usb_serial *serial)
                serial->num_bulk_out = 4;
                mos7840_num_ports = serial->num_ports = 4;
        }
-
+       dbg ("mos7840_num_ports = %d", mos7840_num_ports);
        return mos7840_num_ports;
 }
 
@@ -2400,22 +2403,24 @@ static int mos7840_startup(struct usb_serial *serial)
        int i, status;
 
        __u16 Data;
-       dbg("%s \n", " mos7840_startup :entering..........");
+       dbg("%s", "mos7840_startup :Entering..........");
 
        if (!serial) {
-               dbg("%s\n", "Invalid Handler");
+               dbg("%s", "Invalid Handler");
                return -1;
        }
 
        dev = serial->dev;
 
-       dbg("%s\n", "Entering...");
+       dbg("%s", "Entering...");
+       dbg ("mos7840_startup: serial = %p", serial);
 
        /* we set up the pointers to the endpoints in the mos7840_open *
         * function, as the structures aren't created yet.             */
 
        /* set up port private structures */
        for (i = 0; i < serial->num_ports; ++i) {
+               dbg ("mos7840_startup: configuring port %d............", i);
                mos7840_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL);
                if (mos7840_port == NULL) {
                        dev_err(&dev->dev, "%s - Out of memory\n", __func__);
@@ -2473,10 +2478,10 @@ static int mos7840_startup(struct usb_serial *serial)
                status = mos7840_get_reg_sync(serial->port[i],
                                 mos7840_port->ControlRegOffset, &Data);
                if (status < 0) {
-                       dbg("Reading ControlReg failed status-0x%x\n", status);
+                       dbg("Reading ControlReg failed status-0x%x", status);
                        break;
                } else
-                       dbg("ControlReg Reading success val is %x, status%d\n",
+                       dbg("ControlReg Reading success val is %x, status%d",
                            Data, status);
                Data |= 0x08;   /* setting driver done bit */
                Data |= 0x04;   /* sp1_bit to have cts change reflect in
@@ -2486,10 +2491,10 @@ static int mos7840_startup(struct usb_serial *serial)
                status = mos7840_set_reg_sync(serial->port[i],
                                         mos7840_port->ControlRegOffset, Data);
                if (status < 0) {
-                       dbg("Writing ControlReg failed(rx_disable) status-0x%x\n", status);
+                       dbg("Writing ControlReg failed(rx_disable) status-0x%x", status);
                        break;
                } else
-                       dbg("ControlReg Writing success(rx_disable) status%d\n",
+                       dbg("ControlReg Writing success(rx_disable) status%d",
                            status);
 
                /* Write default values in DCR (i.e 0x01 in DCR0, 0x05 in DCR2
@@ -2498,48 +2503,48 @@ static int mos7840_startup(struct usb_serial *serial)
                status = mos7840_set_reg_sync(serial->port[i],
                         (__u16) (mos7840_port->DcrRegOffset + 0), Data);
                if (status < 0) {
-                       dbg("Writing DCR0 failed status-0x%x\n", status);
+                       dbg("Writing DCR0 failed status-0x%x", status);
                        break;
                } else
-                       dbg("DCR0 Writing success status%d\n", status);
+                       dbg("DCR0 Writing success status%d", status);
 
                Data = 0x05;
                status = mos7840_set_reg_sync(serial->port[i],
                         (__u16) (mos7840_port->DcrRegOffset + 1), Data);
                if (status < 0) {
-                       dbg("Writing DCR1 failed status-0x%x\n", status);
+                       dbg("Writing DCR1 failed status-0x%x", status);
                        break;
                } else
-                       dbg("DCR1 Writing success status%d\n", status);
+                       dbg("DCR1 Writing success status%d", status);
 
                Data = 0x24;
                status = mos7840_set_reg_sync(serial->port[i],
                         (__u16) (mos7840_port->DcrRegOffset + 2), Data);
                if (status < 0) {
-                       dbg("Writing DCR2 failed status-0x%x\n", status);
+                       dbg("Writing DCR2 failed status-0x%x", status);
                        break;
                } else
-                       dbg("DCR2 Writing success status%d\n", status);
+                       dbg("DCR2 Writing success status%d", status);
 
                /* write values in clkstart0x0 and clkmulti 0x20 */
                Data = 0x0;
                status = mos7840_set_reg_sync(serial->port[i],
                                         CLK_START_VALUE_REGISTER, Data);
                if (status < 0) {
-                       dbg("Writing CLK_START_VALUE_REGISTER failed status-0x%x\n", status);
+                       dbg("Writing CLK_START_VALUE_REGISTER failed status-0x%x", status);
                        break;
                } else
-                       dbg("CLK_START_VALUE_REGISTER Writing success status%d\n", status);
+                       dbg("CLK_START_VALUE_REGISTER Writing success status%d", status);
 
                Data = 0x20;
                status = mos7840_set_reg_sync(serial->port[i],
                                        CLK_MULTI_REGISTER, Data);
                if (status < 0) {
-                       dbg("Writing CLK_MULTI_REGISTER failed status-0x%x\n",
+                       dbg("Writing CLK_MULTI_REGISTER failed status-0x%x",
                            status);
                        goto error;
                } else
-                       dbg("CLK_MULTI_REGISTER Writing success status%d\n",
+                       dbg("CLK_MULTI_REGISTER Writing success status%d",
                            status);
 
                /* write value 0x0 to scratchpad register */
@@ -2547,11 +2552,11 @@ static int mos7840_startup(struct usb_serial *serial)
                status = mos7840_set_uart_reg(serial->port[i],
                                                SCRATCH_PAD_REGISTER, Data);
                if (status < 0) {
-                       dbg("Writing SCRATCH_PAD_REGISTER failed status-0x%x\n",
+                       dbg("Writing SCRATCH_PAD_REGISTER failed status-0x%x",
                            status);
                        break;
                } else
-                       dbg("SCRATCH_PAD_REGISTER Writing success status%d\n",
+                       dbg("SCRATCH_PAD_REGISTER Writing success status%d",
                            status);
 
                /* Zero Length flag register */
@@ -2562,30 +2567,30 @@ static int mos7840_startup(struct usb_serial *serial)
                        status = mos7840_set_reg_sync(serial->port[i],
                                      (__u16) (ZLP_REG1 +
                                      ((__u16)mos7840_port->port_num)), Data);
-                       dbg("ZLIP offset%x\n",
+                       dbg("ZLIP offset %x",
                            (__u16) (ZLP_REG1 +
                                        ((__u16) mos7840_port->port_num)));
                        if (status < 0) {
-                               dbg("Writing ZLP_REG%d failed status-0x%x\n",
+                               dbg("Writing ZLP_REG%d failed status-0x%x",
                                    i + 2, status);
                                break;
                        } else
-                               dbg("ZLP_REG%d Writing success status%d\n",
+                               dbg("ZLP_REG%d Writing success status%d",
                                    i + 2, status);
                } else {
                        Data = 0xff;
                        status = mos7840_set_reg_sync(serial->port[i],
                              (__u16) (ZLP_REG1 +
                              ((__u16)mos7840_port->port_num) - 0x1), Data);
-                       dbg("ZLIP offset%x\n",
+                       dbg("ZLIP offset %x",
                            (__u16) (ZLP_REG1 +
                                     ((__u16) mos7840_port->port_num) - 0x1));
                        if (status < 0) {
-                               dbg("Writing ZLP_REG%d failed status-0x%x\n",
+                               dbg("Writing ZLP_REG%d failed status-0x%x",
                                    i + 1, status);
                                break;
                        } else
-                               dbg("ZLP_REG%d Writing success status%d\n",
+                               dbg("ZLP_REG%d Writing success status%d",
                                    i + 1, status);
 
                }
@@ -2599,15 +2604,16 @@ static int mos7840_startup(struct usb_serial *serial)
                        goto error;
                }
        }
+       dbg ("mos7840_startup: all ports configured...........");
 
        /* Zero Length flag enable */
        Data = 0x0f;
        status = mos7840_set_reg_sync(serial->port[0], ZLP_REG5, Data);
        if (status < 0) {
-               dbg("Writing ZLP_REG5 failed status-0x%x\n", status);
+               dbg("Writing ZLP_REG5 failed status-0x%x", status);
                goto error;
        } else
-               dbg("ZLP_REG5 Writing success status%d\n", status);
+               dbg("ZLP_REG5 Writing success status%d", status);
 
        /* setting configuration feature to one */
        usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
@@ -2627,19 +2633,19 @@ error:
 }
 
 /****************************************************************************
- * mos7840_shutdown
+ * mos7840_disconnect
  *     This function is called whenever the device is removed from the usb bus.
  ****************************************************************************/
 
-static void mos7840_shutdown(struct usb_serial *serial)
+static void mos7840_disconnect(struct usb_serial *serial)
 {
        int i;
        unsigned long flags;
        struct moschip_port *mos7840_port;
-       dbg("%s \n", " shutdown :entering..........");
+       dbg("%s", " disconnect :entering..........");
 
        if (!serial) {
-               dbg("%s", "Invalid Handler \n");
+               dbg("%s", "Invalid Handler");
                return;
        }
 
@@ -2656,14 +2662,45 @@ static void mos7840_shutdown(struct usb_serial *serial)
                        mos7840_port->zombie = 1;
                        spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
                        usb_kill_urb(mos7840_port->control_urb);
+               }
+       }
+
+       dbg("%s", "Thank u :: ");
+
+}
+
+/****************************************************************************
+ * mos7840_release
+ *     This function is called when the usb_serial structure is freed.
+ ****************************************************************************/
+
+static void mos7840_release(struct usb_serial *serial)
+{
+       int i;
+       struct moschip_port *mos7840_port;
+       dbg("%s", " release :entering..........");
+
+       if (!serial) {
+               dbg("%s", "Invalid Handler");
+               return;
+       }
+
+       /* check for the ports to be closed,close the ports and disconnect */
+
+       /* free private structure allocated for serial port  *
+        * stop reads and writes on all ports                */
+
+       for (i = 0; i < serial->num_ports; ++i) {
+               mos7840_port = mos7840_get_port_private(serial->port[i]);
+               dbg("mos7840_port %d = %p", i, mos7840_port);
+               if (mos7840_port) {
                        kfree(mos7840_port->ctrl_buf);
                        kfree(mos7840_port->dr);
                        kfree(mos7840_port);
                }
-               mos7840_set_port_private(serial->port[i], NULL);
        }
 
-       dbg("%s\n", "Thank u :: ");
+       dbg("%s", "Thank u :: ");
 
 }
 
@@ -2701,7 +2738,8 @@ static struct usb_serial_driver moschip7840_4port_device = {
        .tiocmget = mos7840_tiocmget,
        .tiocmset = mos7840_tiocmset,
        .attach = mos7840_startup,
-       .shutdown = mos7840_shutdown,
+       .disconnect = mos7840_disconnect,
+       .release = mos7840_release,
        .read_bulk_callback = mos7840_bulk_in_callback,
        .read_int_callback = mos7840_interrupt_callback,
 };
@@ -2714,7 +2752,7 @@ static int __init moschip7840_init(void)
 {
        int retval;
 
-       dbg("%s \n", " mos7840_init :entering..........");
+       dbg("%s", " mos7840_init :entering..........");
 
        /* Register with the usb serial */
        retval = usb_serial_register(&moschip7840_4port_device);
@@ -2722,14 +2760,14 @@ static int __init moschip7840_init(void)
        if (retval)
                goto failed_port_device_register;
 
-       dbg("%s\n", "Entring...");
+       dbg("%s", "Entering...");
        printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
               DRIVER_DESC "\n");
 
        /* Register with the usb */
        retval = usb_register(&io_driver);
        if (retval == 0) {
-               dbg("%s\n", "Leaving...");
+               dbg("%s", "Leaving...");
                return 0;
        }
        usb_serial_deregister(&moschip7840_4port_device);
@@ -2744,13 +2782,13 @@ failed_port_device_register:
 static void __exit moschip7840_exit(void)
 {
 
-       dbg("%s \n", " mos7840_exit :entering..........");
+       dbg("%s", " mos7840_exit :entering..........");
 
        usb_deregister(&io_driver);
 
        usb_serial_deregister(&moschip7840_4port_device);
 
-       dbg("%s\n", "Entring...");
+       dbg("%s", "Entering...");
 }
 
 module_init(moschip7840_init);
index 1104617334f50d9ff4e9afbbe3d3b21934f92cc3..56857ddbd70be66aa33931376fd20e0607869883 100644 (file)
@@ -72,7 +72,8 @@ static void omninet_write_bulk_callback(struct urb *urb);
 static int  omninet_write(struct tty_struct *tty, struct usb_serial_port *port,
                                const unsigned char *buf, int count);
 static int  omninet_write_room(struct tty_struct *tty);
-static void omninet_shutdown(struct usb_serial *serial);
+static void omninet_disconnect(struct usb_serial *serial);
+static void omninet_release(struct usb_serial *serial);
 static int omninet_attach(struct usb_serial *serial);
 
 static struct usb_device_id id_table[] = {
@@ -108,7 +109,8 @@ static struct usb_serial_driver zyxel_omninet_device = {
        .write_room =           omninet_write_room,
        .read_bulk_callback =   omninet_read_bulk_callback,
        .write_bulk_callback =  omninet_write_bulk_callback,
-       .shutdown =             omninet_shutdown,
+       .disconnect =           omninet_disconnect,
+       .release =              omninet_release,
 };
 
 
@@ -345,13 +347,22 @@ static void omninet_write_bulk_callback(struct urb *urb)
 }
 
 
-static void omninet_shutdown(struct usb_serial *serial)
+static void omninet_disconnect(struct usb_serial *serial)
 {
        struct usb_serial_port *wport = serial->port[1];
-       struct usb_serial_port *port = serial->port[0];
+
        dbg("%s", __func__);
 
        usb_kill_urb(wport->write_urb);
+}
+
+
+static void omninet_release(struct usb_serial *serial)
+{
+       struct usb_serial_port *port = serial->port[0];
+
+       dbg("%s", __func__);
+
        kfree(usb_get_serial_port_data(port));
 }
 
index c20480aa975558c9fdac755fe0323991e6c1b4f6..336bba79ad32d634dd6679ec075a54574ea45526 100644 (file)
@@ -463,7 +463,7 @@ error:
        return retval;
 }
 
-static void opticon_shutdown(struct usb_serial *serial)
+static void opticon_disconnect(struct usb_serial *serial)
 {
        struct opticon_private *priv = usb_get_serial_data(serial);
 
@@ -471,9 +471,16 @@ static void opticon_shutdown(struct usb_serial *serial)
 
        usb_kill_urb(priv->bulk_read_urb);
        usb_free_urb(priv->bulk_read_urb);
+}
+
+static void opticon_release(struct usb_serial *serial)
+{
+       struct opticon_private *priv = usb_get_serial_data(serial);
+
+       dbg("%s", __func__);
+
        kfree(priv->bulk_in_buffer);
        kfree(priv);
-       usb_set_serial_data(serial, NULL);
 }
 
 static int opticon_suspend(struct usb_interface *intf, pm_message_t message)
@@ -524,7 +531,8 @@ static struct usb_serial_driver opticon_device = {
        .close =                opticon_close,
        .write =                opticon_write,
        .write_room =           opticon_write_room,
-       .shutdown =             opticon_shutdown,
+       .disconnect =           opticon_disconnect,
+       .release =              opticon_release,
        .throttle =             opticon_throttle,
        .unthrottle =           opticon_unthrottle,
        .ioctl =                opticon_ioctl,
index a16d69fadba1cd9fa7088b9baa3a598b6402c2d9..575816e6ba371fb4ef5fbeeba3668e559b86bfe2 100644 (file)
 #include <linux/usb/serial.h>
 
 /* Function prototypes */
+static int  option_probe(struct usb_serial *serial,
+                       const struct usb_device_id *id);
 static int  option_open(struct tty_struct *tty, struct usb_serial_port *port,
                                                        struct file *filp);
 static void option_close(struct usb_serial_port *port);
 static void option_dtr_rts(struct usb_serial_port *port, int on);
 
 static int  option_startup(struct usb_serial *serial);
-static void option_shutdown(struct usb_serial *serial);
+static void option_disconnect(struct usb_serial *serial);
+static void option_release(struct usb_serial *serial);
 static int  option_write_room(struct tty_struct *tty);
 
 static void option_instat_callback(struct urb *urb);
@@ -202,9 +205,9 @@ static int  option_resume(struct usb_serial *serial);
 #define NOVATELWIRELESS_PRODUCT_MC727          0x4100
 #define NOVATELWIRELESS_PRODUCT_MC950D         0x4400
 #define NOVATELWIRELESS_PRODUCT_U727           0x5010
+#define NOVATELWIRELESS_PRODUCT_MC760          0x6000
 
 /* FUTURE NOVATEL PRODUCTS */
-#define NOVATELWIRELESS_PRODUCT_EVDO_FULLSPEED 0X6000
 #define NOVATELWIRELESS_PRODUCT_EVDO_HIGHSPEED 0X6001
 #define NOVATELWIRELESS_PRODUCT_HSPA_FULLSPEED 0X7000
 #define NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED 0X7001
@@ -305,6 +308,10 @@ static int  option_resume(struct usb_serial *serial);
 #define DLINK_PRODUCT_DWM_652                  0x3e04
 
 
+/* TOSHIBA PRODUCTS */
+#define TOSHIBA_VENDOR_ID                      0x0930
+#define TOSHIBA_PRODUCT_HSDPA_MINICARD         0x1302
+
 static struct usb_device_id option_ids[] = {
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
@@ -422,7 +429,7 @@ static struct usb_device_id option_ids[] = {
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC950D) }, /* Novatel MC930D/MC950D */
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC727) }, /* Novatel MC727/U727/USB727 */
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U727) }, /* Novatel MC727/U727/USB727 */
-       { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_FULLSPEED) }, /* Novatel EVDO product */
+       { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC760) }, /* Novatel MC760/U760/USB760 */
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_FULLSPEED) }, /* Novatel HSPA product */
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_FULLSPEED) }, /* Novatel EVDO Embedded product */
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED) }, /* Novatel HSPA Embedded product */
@@ -523,6 +530,7 @@ static struct usb_device_id option_ids[] = {
        { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) },
        { USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) },
        { USB_DEVICE(0x1da5, 0x4515) }, /* BenQ H20 */
+       { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_HSDPA_MINICARD ) }, /* Toshiba 3G HSDPA == Novatel Expedite EU870D MiniCard */
        { } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
@@ -550,6 +558,7 @@ static struct usb_serial_driver option_1port_device = {
        .usb_driver        = &option_driver,
        .id_table          = option_ids,
        .num_ports         = 1,
+       .probe             = option_probe,
        .open              = option_open,
        .close             = option_close,
        .dtr_rts           = option_dtr_rts,
@@ -560,7 +569,8 @@ static struct usb_serial_driver option_1port_device = {
        .tiocmget          = option_tiocmget,
        .tiocmset          = option_tiocmset,
        .attach            = option_startup,
-       .shutdown          = option_shutdown,
+       .disconnect        = option_disconnect,
+       .release           = option_release,
        .read_int_callback = option_instat_callback,
        .suspend           = option_suspend,
        .resume            = option_resume,
@@ -626,6 +636,18 @@ static void __exit option_exit(void)
 module_init(option_init);
 module_exit(option_exit);
 
+static int option_probe(struct usb_serial *serial,
+                       const struct usb_device_id *id)
+{
+       /* D-Link DWM 652 still exposes CD-Rom emulation interface in modem mode */
+       if (serial->dev->descriptor.idVendor == DLINK_VENDOR_ID &&
+               serial->dev->descriptor.idProduct == DLINK_PRODUCT_DWM_652 &&
+               serial->interface->cur_altsetting->desc.bInterfaceClass == 0x8)
+               return -ENODEV;
+
+       return 0;
+}
+
 static void option_set_termios(struct tty_struct *tty,
                struct usb_serial_port *port, struct ktermios *old_termios)
 {
@@ -1129,7 +1151,14 @@ static void stop_read_write_urbs(struct usb_serial *serial)
        }
 }
 
-static void option_shutdown(struct usb_serial *serial)
+static void option_disconnect(struct usb_serial *serial)
+{
+       dbg("%s", __func__);
+
+       stop_read_write_urbs(serial);
+}
+
+static void option_release(struct usb_serial *serial)
 {
        int i, j;
        struct usb_serial_port *port;
@@ -1137,8 +1166,6 @@ static void option_shutdown(struct usb_serial *serial)
 
        dbg("%s", __func__);
 
-       stop_read_write_urbs(serial);
-
        /* Now free them */
        for (i = 0; i < serial->num_ports; ++i) {
                port = serial->port[i];
index 7de54781fe614e96d32ee69327822f02416c3801..3cece27325e71d90c7042aabfd812d70b2d158d4 100644 (file)
@@ -159,7 +159,7 @@ static int oti6858_tiocmget(struct tty_struct *tty, struct file *file);
 static int oti6858_tiocmset(struct tty_struct *tty, struct file *file,
                                unsigned int set, unsigned int clear);
 static int oti6858_startup(struct usb_serial *serial);
-static void oti6858_shutdown(struct usb_serial *serial);
+static void oti6858_release(struct usb_serial *serial);
 
 /* functions operating on buffers */
 static struct oti6858_buf *oti6858_buf_alloc(unsigned int size);
@@ -194,7 +194,7 @@ static struct usb_serial_driver oti6858_device = {
        .write_room =           oti6858_write_room,
        .chars_in_buffer =      oti6858_chars_in_buffer,
        .attach =               oti6858_startup,
-       .shutdown =             oti6858_shutdown,
+       .release =              oti6858_release,
 };
 
 struct oti6858_private {
@@ -782,7 +782,7 @@ static int oti6858_ioctl(struct tty_struct *tty, struct file *file,
 }
 
 
-static void oti6858_shutdown(struct usb_serial *serial)
+static void oti6858_release(struct usb_serial *serial)
 {
        struct oti6858_private *priv;
        int i;
@@ -794,7 +794,6 @@ static void oti6858_shutdown(struct usb_serial *serial)
                if (priv) {
                        oti6858_buf_free(priv->buf);
                        kfree(priv);
-                       usb_set_serial_port_data(serial->port[i], NULL);
                }
        }
 }
index e02dc3d643c7ae1279f467b21584e2899a82dfb7..ec6c132a25b56f0a63ffa3b0b3a702594d1097b3 100644 (file)
@@ -878,7 +878,7 @@ static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
                dbg("%s - error sending break = %d", __func__, result);
 }
 
-static void pl2303_shutdown(struct usb_serial *serial)
+static void pl2303_release(struct usb_serial *serial)
 {
        int i;
        struct pl2303_private *priv;
@@ -890,7 +890,6 @@ static void pl2303_shutdown(struct usb_serial *serial)
                if (priv) {
                        pl2303_buf_free(priv->buf);
                        kfree(priv);
-                       usb_set_serial_port_data(serial->port[i], NULL);
                }
        }
 }
@@ -927,6 +926,8 @@ static void pl2303_update_line_status(struct usb_serial_port *port,
        spin_lock_irqsave(&priv->lock, flags);
        priv->line_status = data[status_idx];
        spin_unlock_irqrestore(&priv->lock, flags);
+       if (priv->line_status & UART_BREAK_ERROR)
+               usb_serial_handle_break(port);
        wake_up_interruptible(&priv->delta_msr_wait);
 }
 
@@ -1037,7 +1038,8 @@ static void pl2303_read_bulk_callback(struct urb *urb)
                if (line_status & UART_OVERRUN_ERROR)
                        tty_insert_flip_char(tty, 0, TTY_OVERRUN);
                for (i = 0; i < urb->actual_length; ++i)
-                       tty_insert_flip_char(tty, data[i], tty_flag);
+                       if (!usb_serial_handle_sysrq_char(port, data[i]))
+                               tty_insert_flip_char(tty, data[i], tty_flag);
                tty_flip_buffer_push(tty);
        }
        tty_kref_put(tty);
@@ -1120,7 +1122,7 @@ static struct usb_serial_driver pl2303_device = {
        .write_room =           pl2303_write_room,
        .chars_in_buffer =      pl2303_chars_in_buffer,
        .attach =               pl2303_startup,
-       .shutdown =             pl2303_shutdown,
+       .release =              pl2303_release,
 };
 
 static int __init pl2303_init(void)
index 17ac34f4d66823deb49f02a571a09f28de07fe0a..032f7aeb40a42b17b71b1f4c2ae7b3d1ff221640 100644 (file)
@@ -1,7 +1,10 @@
 /*
   USB Driver for Sierra Wireless
 
-  Copyright (C) 2006, 2007, 2008  Kevin Lloyd <klloyd@sierrawireless.com>
+  Copyright (C) 2006, 2007, 2008  Kevin Lloyd <klloyd@sierrawireless.com>,
+
+  Copyright (C) 2008, 2009  Elina Pasheva, Matthew Safar, Rory Filer
+                       <linux@sierrawireless.com>
 
   IMPORTANT DISCLAIMER: This driver is not commercially supported by
   Sierra Wireless. Use at your own risk.
@@ -14,8 +17,8 @@
   Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
 */
 
-#define DRIVER_VERSION "v.1.3.3"
-#define DRIVER_AUTHOR "Kevin Lloyd <klloyd@sierrawireless.com>"
+#define DRIVER_VERSION "v.1.3.7"
+#define DRIVER_AUTHOR "Kevin Lloyd, Elina Pasheva, Matthew Safar, Rory Filer"
 #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
 
 #include <linux/kernel.h>
 #define SWIMS_USB_REQUEST_SetPower     0x00
 #define SWIMS_USB_REQUEST_SetNmea      0x07
 
-#define N_IN_URB       4
-#define N_OUT_URB      4
+#define N_IN_URB       8
+#define N_OUT_URB      64
 #define IN_BUFLEN      4096
 
+#define MAX_TRANSFER           (PAGE_SIZE - 512)
+/* MAX_TRANSFER is chosen so that the VM is not stressed by
+   allocations > PAGE_SIZE and the number of packets in a page
+   is an integer 512 is the largest possible packet on EHCI */
+
 static int debug;
 static int nmea;
 
@@ -46,7 +54,7 @@ struct sierra_iface_info {
 static int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
 {
        int result;
-       dev_dbg(&udev->dev, "%s", __func__);
+       dev_dbg(&udev->dev, "%s\n", __func__);
        result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
                        SWIMS_USB_REQUEST_SetPower,     /* __u8 request      */
                        USB_TYPE_VENDOR,                /* __u8 request type */
@@ -61,7 +69,7 @@ static int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
 static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable)
 {
        int result;
-       dev_dbg(&udev->dev, "%s", __func__);
+       dev_dbg(&udev->dev, "%s\n", __func__);
        result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
                        SWIMS_USB_REQUEST_SetNmea,      /* __u8 request      */
                        USB_TYPE_VENDOR,                /* __u8 request type */
@@ -75,18 +83,22 @@ static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable)
 
 static int sierra_calc_num_ports(struct usb_serial *serial)
 {
-       int result;
-       int *num_ports = usb_get_serial_data(serial);
-       dev_dbg(&serial->dev->dev, "%s", __func__);
+       int num_ports = 0;
+       u8 ifnum, numendpoints;
 
-       result = *num_ports;
+       dev_dbg(&serial->dev->dev, "%s\n", __func__);
 
-       if (result) {
-               kfree(num_ports);
-               usb_set_serial_data(serial, NULL);
-       }
+       ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
+       numendpoints = serial->interface->cur_altsetting->desc.bNumEndpoints;
 
-       return result;
+       /* Dummy interface present on some SKUs should be ignored */
+       if (ifnum == 0x99)
+               num_ports = 0;
+       else if (numendpoints <= 3)
+               num_ports = 1;
+       else
+               num_ports = (numendpoints-1)/2;
+       return num_ports;
 }
 
 static int is_blacklisted(const u8 ifnum,
@@ -111,7 +123,7 @@ static int sierra_calc_interface(struct usb_serial *serial)
        int interface;
        struct usb_interface *p_interface;
        struct usb_host_interface *p_host_interface;
-       dev_dbg(&serial->dev->dev, "%s", __func__);
+       dev_dbg(&serial->dev->dev, "%s\n", __func__);
 
        /* Get the interface structure pointer from the serial struct */
        p_interface = serial->interface;
@@ -132,23 +144,12 @@ static int sierra_probe(struct usb_serial *serial,
 {
        int result = 0;
        struct usb_device *udev;
-       int *num_ports;
        u8 ifnum;
-       u8 numendpoints;
 
-       dev_dbg(&serial->dev->dev, "%s", __func__);
-
-       num_ports = kmalloc(sizeof(*num_ports), GFP_KERNEL);
-       if (!num_ports)
-               return -ENOMEM;
-
-       ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
-       numendpoints = serial->interface->cur_altsetting->desc.bNumEndpoints;
        udev = serial->dev;
+       dev_dbg(&udev->dev, "%s\n", __func__);
 
-       /* Figure out the interface number from the serial structure */
        ifnum = sierra_calc_interface(serial);
-
        /*
         * If this interface supports more than 1 alternate
         * select the 2nd one
@@ -160,20 +161,6 @@ static int sierra_probe(struct usb_serial *serial,
                usb_set_interface(udev, ifnum, 1);
        }
 
-       /* Dummy interface present on some SKUs should be ignored */
-       if (ifnum == 0x99)
-               *num_ports = 0;
-       else if (numendpoints <= 3)
-               *num_ports = 1;
-       else
-               *num_ports = (numendpoints-1)/2;
-
-       /*
-        * save off our num_ports info so that we can use it in the
-        * calc_num_ports callback
-        */
-       usb_set_serial_data(serial, (void *)num_ports);
-
        /* ifnum could have changed - by calling usb_set_interface */
        ifnum = sierra_calc_interface(serial);
 
@@ -289,7 +276,7 @@ static int sierra_send_setup(struct usb_serial_port *port)
        __u16 interface = 0;
        int val = 0;
 
-       dev_dbg(&port->dev, "%s", __func__);
+       dev_dbg(&port->dev, "%s\n", __func__);
 
        portdata = usb_get_serial_port_data(port);
 
@@ -332,7 +319,7 @@ static int sierra_send_setup(struct usb_serial_port *port)
 static void sierra_set_termios(struct tty_struct *tty,
                struct usb_serial_port *port, struct ktermios *old_termios)
 {
-       dev_dbg(&port->dev, "%s", __func__);
+       dev_dbg(&port->dev, "%s\n", __func__);
        tty_termios_copy_hw(tty->termios, old_termios);
        sierra_send_setup(port);
 }
@@ -343,7 +330,7 @@ static int sierra_tiocmget(struct tty_struct *tty, struct file *file)
        unsigned int value;
        struct sierra_port_private *portdata;
 
-       dev_dbg(&port->dev, "%s", __func__);
+       dev_dbg(&port->dev, "%s\n", __func__);
        portdata = usb_get_serial_port_data(port);
 
        value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
@@ -394,14 +381,14 @@ static void sierra_outdat_callback(struct urb *urb)
        int status = urb->status;
        unsigned long flags;
 
-       dev_dbg(&port->dev, "%s - port %d", __func__, port->number);
+       dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number);
 
        /* free up the transfer buffer, as usb_free_urb() does not do this */
        kfree(urb->transfer_buffer);
 
        if (status)
                dev_dbg(&port->dev, "%s - nonzero write bulk status "
-                   "received: %d", __func__, status);
+                   "received: %d\n", __func__, status);
 
        spin_lock_irqsave(&portdata->lock, flags);
        --portdata->outstanding_urbs;
@@ -419,50 +406,61 @@ static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port,
        unsigned long flags;
        unsigned char *buffer;
        struct urb *urb;
-       int status;
+       size_t writesize = min((size_t)count, (size_t)MAX_TRANSFER);
+       int retval = 0;
+
+       /* verify that we actually have some data to write */
+       if (count == 0)
+               return 0;
 
        portdata = usb_get_serial_port_data(port);
 
-       dev_dbg(&port->dev, "%s: write (%d chars)", __func__, count);
+       dev_dbg(&port->dev, "%s: write (%zd bytes)\n", __func__, writesize);
 
        spin_lock_irqsave(&portdata->lock, flags);
+       dev_dbg(&port->dev, "%s - outstanding_urbs: %d\n", __func__,
+               portdata->outstanding_urbs);
        if (portdata->outstanding_urbs > N_OUT_URB) {
                spin_unlock_irqrestore(&portdata->lock, flags);
                dev_dbg(&port->dev, "%s - write limit hit\n", __func__);
                return 0;
        }
        portdata->outstanding_urbs++;
+       dev_dbg(&port->dev, "%s - 1, outstanding_urbs: %d\n", __func__,
+               portdata->outstanding_urbs);
        spin_unlock_irqrestore(&portdata->lock, flags);
 
-       buffer = kmalloc(count, GFP_ATOMIC);
+       buffer = kmalloc(writesize, GFP_ATOMIC);
        if (!buffer) {
                dev_err(&port->dev, "out of memory\n");
-               count = -ENOMEM;
+               retval = -ENOMEM;
                goto error_no_buffer;
        }
 
        urb = usb_alloc_urb(0, GFP_ATOMIC);
        if (!urb) {
                dev_err(&port->dev, "no more free urbs\n");
-               count = -ENOMEM;
+               retval = -ENOMEM;
                goto error_no_urb;
        }
 
-       memcpy(buffer, buf, count);
+       memcpy(buffer, buf, writesize);
 
-       usb_serial_debug_data(debug, &port->dev, __func__, count, buffer);
+       usb_serial_debug_data(debug, &port->dev, __func__, writesize, buffer);
 
        usb_fill_bulk_urb(urb, serial->dev,
                          usb_sndbulkpipe(serial->dev,
                                          port->bulk_out_endpointAddress),
-                         buffer, count, sierra_outdat_callback, port);
+                         buffer, writesize, sierra_outdat_callback, port);
+
+       /* Handle the need to send a zero length packet */
+       urb->transfer_flags |= URB_ZERO_PACKET;
 
        /* send it down the pipe */
-       status = usb_submit_urb(urb, GFP_ATOMIC);
-       if (status) {
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
+       if (retval) {
                dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed "
-                       "with status = %d\n", __func__, status);
-               count = status;
+                       "with status = %d\n", __func__, retval);
                goto error;
        }
 
@@ -470,7 +468,7 @@ static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port,
         * really free it when it is finished with it */
        usb_free_urb(urb);
 
-       return count;
+       return writesize;
 error:
        usb_free_urb(urb);
 error_no_urb:
@@ -478,8 +476,10 @@ error_no_urb:
 error_no_buffer:
        spin_lock_irqsave(&portdata->lock, flags);
        --portdata->outstanding_urbs;
+       dev_dbg(&port->dev, "%s - 2. outstanding_urbs: %d\n", __func__,
+               portdata->outstanding_urbs);
        spin_unlock_irqrestore(&portdata->lock, flags);
-       return count;
+       return retval;
 }
 
 static void sierra_indat_callback(struct urb *urb)
@@ -491,33 +491,39 @@ static void sierra_indat_callback(struct urb *urb)
        unsigned char *data = urb->transfer_buffer;
        int status = urb->status;
 
-       dbg("%s: %p", __func__, urb);
-
        endpoint = usb_pipeendpoint(urb->pipe);
-       port =  urb->context;
+       port = urb->context;
+
+       dev_dbg(&port->dev, "%s: %p\n", __func__, urb);
 
        if (status) {
                dev_dbg(&port->dev, "%s: nonzero status: %d on"
-                   " endpoint %02x.", __func__, status, endpoint);
+                       " endpoint %02x\n", __func__, status, endpoint);
        } else {
                if (urb->actual_length) {
                        tty = tty_port_tty_get(&port->port);
+
                        tty_buffer_request_room(tty, urb->actual_length);
                        tty_insert_flip_string(tty, data, urb->actual_length);
                        tty_flip_buffer_push(tty);
+
                        tty_kref_put(tty);
-               } else
+                       usb_serial_debug_data(debug, &port->dev, __func__,
+                               urb->actual_length, data);
+               } else {
                        dev_dbg(&port->dev, "%s: empty read urb"
-                               " received", __func__);
-
-               /* Resubmit urb so we continue receiving */
-               if (port->port.count && status != -ESHUTDOWN && status != -EPERM) {
-                       err = usb_submit_urb(urb, GFP_ATOMIC);
-                       if (err)
-                               dev_err(&port->dev, "resubmit read urb failed."
-                                       "(%d)\n", err);
+                               " received\n", __func__);
                }
        }
+
+       /* Resubmit urb so we continue receiving */
+       if (port->port.count && status != -ESHUTDOWN && status != -EPERM) {
+               err = usb_submit_urb(urb, GFP_ATOMIC);
+               if (err)
+                       dev_err(&port->dev, "resubmit read urb failed."
+                               "(%d)\n", err);
+       }
+
        return;
 }
 
@@ -529,8 +535,7 @@ static void sierra_instat_callback(struct urb *urb)
        struct sierra_port_private *portdata = usb_get_serial_port_data(port);
        struct usb_serial *serial = port->serial;
 
-       dev_dbg(&port->dev, "%s", __func__);
-       dev_dbg(&port->dev, "%s: urb %p port %p has data %p", __func__,
+       dev_dbg(&port->dev, "%s: urb %p port %p has data %p\n", __func__,
                urb, port, portdata);
 
        if (status == 0) {
@@ -550,7 +555,7 @@ static void sierra_instat_callback(struct urb *urb)
                                        sizeof(struct usb_ctrlrequest));
                        struct tty_struct *tty;
 
-                       dev_dbg(&port->dev, "%s: signal x%x", __func__,
+                       dev_dbg(&port->dev, "%s: signal x%x\n", __func__,
                                signals);
 
                        old_dcd_state = portdata->dcd_state;
@@ -565,20 +570,20 @@ static void sierra_instat_callback(struct urb *urb)
                                tty_hangup(tty);
                        tty_kref_put(tty);
                } else {
-                       dev_dbg(&port->dev, "%s: type %x req %x",
+                       dev_dbg(&port->dev, "%s: type %x req %x\n",
                                __func__, req_pkt->bRequestType,
                                req_pkt->bRequest);
                }
        } else
-               dev_dbg(&port->dev, "%s: error %d", __func__, status);
+               dev_dbg(&port->dev, "%s: error %d\n", __func__, status);
 
        /* Resubmit urb so we continue receiving IRQ data */
-       if (status != -ESHUTDOWN) {
+       if (port->port.count && status != -ESHUTDOWN && status != -ENOENT) {
                urb->dev = serial->dev;
                err = usb_submit_urb(urb, GFP_ATOMIC);
                if (err)
-                       dev_dbg(&port->dev, "%s: resubmit intr urb "
-                               "failed. (%d)", __func__, err);
+                       dev_err(&port->dev, "%s: resubmit intr urb "
+                               "failed. (%d)\n", __func__, err);
        }
 }
 
@@ -588,7 +593,7 @@ static int sierra_write_room(struct tty_struct *tty)
        struct sierra_port_private *portdata = usb_get_serial_port_data(port);
        unsigned long flags;
 
-       dev_dbg(&port->dev, "%s - port %d", __func__, port->number);
+       dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number);
 
        /* try to give a good number back based on if we have any free urbs at
         * this point in time */
@@ -729,7 +734,7 @@ static int sierra_open(struct tty_struct *tty,
 
        portdata = usb_get_serial_port_data(port);
 
-       dev_dbg(&port->dev, "%s", __func__);
+       dev_dbg(&port->dev, "%s\n", __func__);
 
        /* Set some sane defaults */
        portdata->rts_state = 1;
@@ -782,7 +787,7 @@ static int sierra_startup(struct usb_serial *serial)
        struct sierra_port_private *portdata;
        int i;
 
-       dev_dbg(&serial->dev->dev, "%s", __func__);
+       dev_dbg(&serial->dev->dev, "%s\n", __func__);
 
        /* Set Device mode to D0 */
        sierra_set_power_state(serial->dev, 0x0000);
@@ -797,7 +802,7 @@ static int sierra_startup(struct usb_serial *serial)
                portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
                if (!portdata) {
                        dev_dbg(&port->dev, "%s: kmalloc for "
-                               "sierra_port_private (%d) failed!.",
+                               "sierra_port_private (%d) failed!.\n",
                                __func__, i);
                        return -ENOMEM;
                }
@@ -809,13 +814,13 @@ static int sierra_startup(struct usb_serial *serial)
        return 0;
 }
 
-static void sierra_shutdown(struct usb_serial *serial)
+static void sierra_disconnect(struct usb_serial *serial)
 {
        int i;
        struct usb_serial_port *port;
        struct sierra_port_private *portdata;
 
-       dev_dbg(&serial->dev->dev, "%s", __func__);
+       dev_dbg(&serial->dev->dev, "%s\n", __func__);
 
        for (i = 0; i < serial->num_ports; ++i) {
                port = serial->port[i];
@@ -848,7 +853,7 @@ static struct usb_serial_driver sierra_device = {
        .tiocmget          = sierra_tiocmget,
        .tiocmset          = sierra_tiocmset,
        .attach            = sierra_startup,
-       .shutdown          = sierra_shutdown,
+       .disconnect        = sierra_disconnect,
        .read_int_callback = sierra_instat_callback,
 };
 
index 8f7ed8f13996185857021d7d2f730c08f60b2403..3c249d8e8b8eb356fef7aaee52ef2e0157994a01 100644 (file)
@@ -356,7 +356,7 @@ cleanup:
 }
 
 /* call when the device plug out. free all the memory alloced by probe */
-static void spcp8x5_shutdown(struct usb_serial *serial)
+static void spcp8x5_release(struct usb_serial *serial)
 {
        int i;
        struct spcp8x5_private *priv;
@@ -366,7 +366,6 @@ static void spcp8x5_shutdown(struct usb_serial *serial)
                if (priv) {
                        free_ringbuf(priv->buf);
                        kfree(priv);
-                       usb_set_serial_port_data(serial->port[i] , NULL);
                }
        }
 }
@@ -1020,7 +1019,7 @@ static struct usb_serial_driver spcp8x5_device = {
        .write_bulk_callback    = spcp8x5_write_bulk_callback,
        .chars_in_buffer        = spcp8x5_chars_in_buffer,
        .attach                 = spcp8x5_startup,
-       .shutdown               = spcp8x5_shutdown,
+       .release                = spcp8x5_release,
 };
 
 static int __init spcp8x5_init(void)
index 8b07ebc6baeb4e40ba036e07cacee5414b508628..6157fac9366b708c1a390c87fe46c21ab4dda91d 100644 (file)
@@ -267,7 +267,7 @@ error:
        return retval;
 }
 
-static void symbol_shutdown(struct usb_serial *serial)
+static void symbol_disconnect(struct usb_serial *serial)
 {
        struct symbol_private *priv = usb_get_serial_data(serial);
 
@@ -275,9 +275,16 @@ static void symbol_shutdown(struct usb_serial *serial)
 
        usb_kill_urb(priv->int_urb);
        usb_free_urb(priv->int_urb);
+}
+
+static void symbol_release(struct usb_serial *serial)
+{
+       struct symbol_private *priv = usb_get_serial_data(serial);
+
+       dbg("%s", __func__);
+
        kfree(priv->int_buffer);
        kfree(priv);
-       usb_set_serial_data(serial, NULL);
 }
 
 static struct usb_driver symbol_driver = {
@@ -299,7 +306,8 @@ static struct usb_serial_driver symbol_device = {
        .attach =               symbol_startup,
        .open =                 symbol_open,
        .close =                symbol_close,
-       .shutdown =             symbol_shutdown,
+       .disconnect =           symbol_disconnect,
+       .release =              symbol_release,
        .throttle =             symbol_throttle,
        .unthrottle =           symbol_unthrottle,
 };
index 42cb04c403beee3900e6fa33451913d0e0a3b29e..991d8232e3765c39de562ec8e09181d0e8d4c547 100644 (file)
@@ -97,7 +97,7 @@ struct ti_device {
 /* Function Declarations */
 
 static int ti_startup(struct usb_serial *serial);
-static void ti_shutdown(struct usb_serial *serial);
+static void ti_release(struct usb_serial *serial);
 static int ti_open(struct tty_struct *tty, struct usb_serial_port *port,
                struct file *file);
 static void ti_close(struct usb_serial_port *port);
@@ -230,7 +230,7 @@ static struct usb_serial_driver ti_1port_device = {
        .id_table               = ti_id_table_3410,
        .num_ports              = 1,
        .attach                 = ti_startup,
-       .shutdown               = ti_shutdown,
+       .release                = ti_release,
        .open                   = ti_open,
        .close                  = ti_close,
        .write                  = ti_write,
@@ -258,7 +258,7 @@ static struct usb_serial_driver ti_2port_device = {
        .id_table               = ti_id_table_5052,
        .num_ports              = 2,
        .attach                 = ti_startup,
-       .shutdown               = ti_shutdown,
+       .release                = ti_release,
        .open                   = ti_open,
        .close                  = ti_close,
        .write                  = ti_write,
@@ -473,7 +473,7 @@ free_tdev:
 }
 
 
-static void ti_shutdown(struct usb_serial *serial)
+static void ti_release(struct usb_serial *serial)
 {
        int i;
        struct ti_device *tdev = usb_get_serial_data(serial);
@@ -486,12 +486,10 @@ static void ti_shutdown(struct usb_serial *serial)
                if (tport) {
                        ti_buf_free(tport->tp_write_buf);
                        kfree(tport);
-                       usb_set_serial_port_data(serial->port[i], NULL);
                }
        }
 
        kfree(tdev);
-       usb_set_serial_data(serial, NULL);
 }
 
 
index 1967a7edc10c51fab8263aafc43a425a2b28e686..d595aa5586a733003532e6f0a7a95e051e3ce659 100644 (file)
@@ -141,6 +141,14 @@ static void destroy_serial(struct kref *kref)
        if (serial->minor != SERIAL_TTY_NO_MINOR)
                return_serial(serial);
 
+       serial->type->release(serial);
+
+       for (i = 0; i < serial->num_ports; ++i) {
+               port = serial->port[i];
+               if (port)
+                       put_device(&port->dev);
+       }
+
        /* If this is a "fake" port, we have to clean it up here, as it will
         * not get cleaned up in port_release() as it was never registered with
         * the driver core */
@@ -148,9 +156,8 @@ static void destroy_serial(struct kref *kref)
                for (i = serial->num_ports;
                                        i < serial->num_port_pointers; ++i) {
                        port = serial->port[i];
-                       if (!port)
-                               continue;
-                       port_free(port);
+                       if (port)
+                               port_free(port);
                }
        }
 
@@ -1046,10 +1053,15 @@ int usb_serial_probe(struct usb_interface *interface,
 
                dev_set_name(&port->dev, "ttyUSB%d", port->number);
                dbg ("%s - registering %s", __func__, dev_name(&port->dev));
+               port->dev_state = PORT_REGISTERING;
                retval = device_register(&port->dev);
-               if (retval)
+               if (retval) {
                        dev_err(&port->dev, "Error registering port device, "
                                "continuing\n");
+                       port->dev_state = PORT_UNREGISTERED;
+               } else {
+                       port->dev_state = PORT_REGISTERED;
+               }
        }
 
        usb_serial_console_init(debug, minor);
@@ -1113,10 +1125,6 @@ void usb_serial_disconnect(struct usb_interface *interface)
        serial->disconnected = 1;
        mutex_unlock(&serial->disc_mutex);
 
-       /* Unfortunately, many of the sub-drivers expect the port structures
-        * to exist when their shutdown method is called, so we have to go
-        * through this awkward two-step unregistration procedure.
-        */
        for (i = 0; i < serial->num_ports; ++i) {
                port = serial->port[i];
                if (port) {
@@ -1130,17 +1138,25 @@ void usb_serial_disconnect(struct usb_interface *interface)
                        }
                        kill_traffic(port);
                        cancel_work_sync(&port->work);
-                       device_del(&port->dev);
-               }
-       }
-       serial->type->shutdown(serial);
-       for (i = 0; i < serial->num_ports; ++i) {
-               port = serial->port[i];
-               if (port) {
-                       put_device(&port->dev);
-                       serial->port[i] = NULL;
+                       if (port->dev_state == PORT_REGISTERED) {
+
+                               /* Make sure the port is bound so that the
+                                * driver's port_remove method is called.
+                                */
+                               if (!port->dev.driver) {
+                                       int rc;
+
+                                       port->dev.driver =
+                                                       &serial->type->driver;
+                                       rc = device_bind_driver(&port->dev);
+                               }
+                               port->dev_state = PORT_UNREGISTERING;
+                               device_del(&port->dev);
+                               port->dev_state = PORT_UNREGISTERED;
+                       }
                }
        }
+       serial->type->disconnect(serial);
 
        /* let the last holder of this object
         * cause it to be cleaned up */
@@ -1318,7 +1334,8 @@ static void fixup_generic(struct usb_serial_driver *device)
        set_to_generic_if_null(device, chars_in_buffer);
        set_to_generic_if_null(device, read_bulk_callback);
        set_to_generic_if_null(device, write_bulk_callback);
-       set_to_generic_if_null(device, shutdown);
+       set_to_generic_if_null(device, disconnect);
+       set_to_generic_if_null(device, release);
 }
 
 int usb_serial_register(struct usb_serial_driver *driver)
index 6c9cbb59552a72626181b7ba6b5e9ee3811a1938..614800972dc3bb20f67431fd65c3b0ed9bf9146f 100644 (file)
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 
+#define URB_DEBUG_MAX_IN_FLIGHT_URBS   4000
 #define USB_DEBUG_MAX_PACKET_SIZE      8
+#define USB_DEBUG_BRK_SIZE             8
+static char USB_DEBUG_BRK[USB_DEBUG_BRK_SIZE] = {
+       0x00,
+       0xff,
+       0x01,
+       0xfe,
+       0x00,
+       0xfe,
+       0x01,
+       0xff,
+};
 
 static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x0525, 0x127a) },
@@ -38,6 +50,32 @@ static int usb_debug_open(struct tty_struct *tty, struct usb_serial_port *port,
        return usb_serial_generic_open(tty, port, filp);
 }
 
+/* This HW really does not support a serial break, so one will be
+ * emulated when ever the break state is set to true.
+ */
+static void usb_debug_break_ctl(struct tty_struct *tty, int break_state)
+{
+       struct usb_serial_port *port = tty->driver_data;
+       if (!break_state)
+               return;
+       usb_serial_generic_write(tty, port, USB_DEBUG_BRK, USB_DEBUG_BRK_SIZE);
+}
+
+static void usb_debug_read_bulk_callback(struct urb *urb)
+{
+       struct usb_serial_port *port = urb->context;
+
+       if (urb->actual_length == USB_DEBUG_BRK_SIZE &&
+           memcmp(urb->transfer_buffer, USB_DEBUG_BRK,
+                  USB_DEBUG_BRK_SIZE) == 0) {
+               usb_serial_handle_break(port);
+               usb_serial_generic_resubmit_read_urb(port, GFP_ATOMIC);
+               return;
+       }
+
+       usb_serial_generic_read_bulk_callback(urb);
+}
+
 static struct usb_serial_driver debug_device = {
        .driver = {
                .owner =        THIS_MODULE,
@@ -46,6 +84,9 @@ static struct usb_serial_driver debug_device = {
        .id_table =             id_table,
        .num_ports =            1,
        .open =                 usb_debug_open,
+       .max_in_flight_urbs =   URB_DEBUG_MAX_IN_FLIGHT_URBS,
+       .break_ctl =            usb_debug_break_ctl,
+       .read_bulk_callback =   usb_debug_read_bulk_callback,
 };
 
 static int __init debug_init(void)
index b15f1c0e1d4acba4adcbadf66ac98a9870e8c994..f5d0f64dcc52ee2c0a38e7d86b47a76181e197dc 100644 (file)
@@ -47,7 +47,7 @@ static void visor_unthrottle(struct tty_struct *tty);
 static int  visor_probe(struct usb_serial *serial,
                                        const struct usb_device_id *id);
 static int  visor_calc_num_ports(struct usb_serial *serial);
-static void visor_shutdown(struct usb_serial *serial);
+static void visor_release(struct usb_serial *serial);
 static void visor_write_bulk_callback(struct urb *urb);
 static void visor_read_bulk_callback(struct urb *urb);
 static void visor_read_int_callback(struct urb *urb);
@@ -202,7 +202,7 @@ static struct usb_serial_driver handspring_device = {
        .attach =               treo_attach,
        .probe =                visor_probe,
        .calc_num_ports =       visor_calc_num_ports,
-       .shutdown =             visor_shutdown,
+       .release =              visor_release,
        .write =                visor_write,
        .write_room =           visor_write_room,
        .write_bulk_callback =  visor_write_bulk_callback,
@@ -227,7 +227,7 @@ static struct usb_serial_driver clie_5_device = {
        .attach =               clie_5_attach,
        .probe =                visor_probe,
        .calc_num_ports =       visor_calc_num_ports,
-       .shutdown =             visor_shutdown,
+       .release =              visor_release,
        .write =                visor_write,
        .write_room =           visor_write_room,
        .write_bulk_callback =  visor_write_bulk_callback,
@@ -918,7 +918,7 @@ static int clie_5_attach(struct usb_serial *serial)
        return generic_startup(serial);
 }
 
-static void visor_shutdown(struct usb_serial *serial)
+static void visor_release(struct usb_serial *serial)
 {
        struct visor_private *priv;
        int i;
@@ -927,10 +927,7 @@ static void visor_shutdown(struct usb_serial *serial)
 
        for (i = 0; i < serial->num_ports; i++) {
                priv = usb_get_serial_port_data(serial->port[i]);
-               if (priv) {
-                       usb_set_serial_port_data(serial->port[i], NULL);
-                       kfree(priv);
-               }
+               kfree(priv);
        }
 }
 
index 7c7295d09f344cf7b4b167346e140e75d6394207..8d126dd7a02e4ebf423b54bf4064599721fb98b2 100644 (file)
@@ -144,7 +144,7 @@ static int  whiteheat_firmware_attach(struct usb_serial *serial);
 
 /* function prototypes for the Connect Tech WhiteHEAT serial converter */
 static int  whiteheat_attach(struct usb_serial *serial);
-static void whiteheat_shutdown(struct usb_serial *serial);
+static void whiteheat_release(struct usb_serial *serial);
 static int  whiteheat_open(struct tty_struct *tty,
                        struct usb_serial_port *port, struct file *filp);
 static void whiteheat_close(struct usb_serial_port *port);
@@ -189,7 +189,7 @@ static struct usb_serial_driver whiteheat_device = {
        .id_table =             id_table_std,
        .num_ports =            4,
        .attach =               whiteheat_attach,
-       .shutdown =             whiteheat_shutdown,
+       .release =              whiteheat_release,
        .open =                 whiteheat_open,
        .close =                whiteheat_close,
        .write =                whiteheat_write,
@@ -617,7 +617,7 @@ no_command_buffer:
 }
 
 
-static void whiteheat_shutdown(struct usb_serial *serial)
+static void whiteheat_release(struct usb_serial *serial)
 {
        struct usb_serial_port *command_port;
        struct usb_serial_port *port;
index 2dd9bd4bff56edceec8962d79ba17f72efad8854..ec17c96371afc7a71297ef8e8cbfd17299a0c5e3 100644 (file)
@@ -52,7 +52,7 @@ int usb_stor_euscsi_init(struct us_data *us)
        us->iobuf[0] = 0x1;
        result = usb_stor_control_msg(us, us->send_ctrl_pipe,
                        0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR,
-                       0x01, 0x0, us->iobuf, 0x1, 5*HZ);
+                       0x01, 0x0, us->iobuf, 0x1, 5000);
        US_DEBUGP("-- result is %d\n", result);
 
        return 0;
@@ -80,14 +80,16 @@ int usb_stor_ucr61s2b_init(struct us_data *us)
 
        res = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, bcb,
                        US_BULK_CB_WRAP_LEN, &partial);
-       if(res)
-               return res;
+       if (res)
+               return -EIO;
 
        US_DEBUGP("Getting status packet...\n");
        res = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
                        US_BULK_CS_WRAP_LEN, &partial);
+       if (res)
+               return -EIO;
 
-       return (res ? -1 : 0);
+       return 0;
 }
 
 /* This places the HUAWEI E220 devices in multi-port mode */
@@ -99,6 +101,6 @@ int usb_stor_huawei_e220_init(struct us_data *us)
                                      USB_REQ_SET_FEATURE,
                                      USB_TYPE_STANDARD | USB_RECIP_DEVICE,
                                      0x01, 0x0, NULL, 0x0, 1000);
-       US_DEBUGP("usb_control_msg performing result is %d\n", result);
-       return (result ? 0 : -1);
+       US_DEBUGP("Huawei mode set result is %d\n", result);
+       return (result ? 0 : -ENODEV);
 }
index 353f922939a4cd8a6e78c04aae37b328b4ce6176..d41cc0a970f79a147660da239bdc014612396354 100644 (file)
@@ -37,7 +37,7 @@ MODULE_PARM_DESC(option_zero_cd, "ZeroCD mode (1=Force Modem (default),"
 
 #define RESPONSE_LEN 1024
 
-static int option_rezero(struct us_data *us, int ep_in, int ep_out)
+static int option_rezero(struct us_data *us)
 {
        const unsigned char rezero_msg[] = {
          0x55, 0x53, 0x42, 0x43, 0x78, 0x56, 0x34, 0x12,
@@ -54,10 +54,10 @@ static int option_rezero(struct us_data *us, int ep_in, int ep_out)
        if (buffer == NULL)
                return USB_STOR_TRANSPORT_ERROR;
 
-       memcpy(buffer, rezero_msg, sizeof (rezero_msg));
+       memcpy(buffer, rezero_msg, sizeof(rezero_msg));
        result = usb_stor_bulk_transfer_buf(us,
-                       usb_sndbulkpipe(us->pusb_dev, ep_out),
-                       buffer, sizeof (rezero_msg), NULL);
+                       us->send_bulk_pipe,
+                       buffer, sizeof(rezero_msg), NULL);
        if (result != USB_STOR_XFER_GOOD) {
                result = USB_STOR_XFER_ERROR;
                goto out;
@@ -66,9 +66,15 @@ static int option_rezero(struct us_data *us, int ep_in, int ep_out)
        /* Some of the devices need to be asked for a response, but we don't
         * care what that response is.
         */
-       result = usb_stor_bulk_transfer_buf(us,
-                       usb_sndbulkpipe(us->pusb_dev, ep_out),
+       usb_stor_bulk_transfer_buf(us,
+                       us->recv_bulk_pipe,
                        buffer, RESPONSE_LEN, NULL);
+
+       /* Read the CSW */
+       usb_stor_bulk_transfer_buf(us,
+                       us->recv_bulk_pipe,
+                       buffer, 13, NULL);
+
        result = USB_STOR_XFER_GOOD;
 
 out:
@@ -76,63 +82,75 @@ out:
        return result;
 }
 
-int option_ms_init(struct us_data *us)
+static int option_inquiry(struct us_data *us)
 {
-       struct usb_device *udev;
-       struct usb_interface *intf;
-       struct usb_host_interface *iface_desc;
-       struct usb_endpoint_descriptor *endpoint = NULL;
-       u8 ep_in = 0, ep_out = 0;
-       int ep_in_size = 0, ep_out_size = 0;
-       int i, result;
-
-       udev = us->pusb_dev;
-       intf = us->pusb_intf;
-
-       /* Ensure it's really a ZeroCD device; devices that are already
-        * in modem mode return 0xFF for class, subclass, and protocol.
-        */
-       if (udev->descriptor.bDeviceClass != 0 ||
-           udev->descriptor.bDeviceSubClass != 0 ||
-           udev->descriptor.bDeviceProtocol != 0)
-               return USB_STOR_TRANSPORT_GOOD;
+       const unsigned char inquiry_msg[] = {
+         0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78,
+         0x24, 0x00, 0x00, 0x00, 0x80, 0x00, 0x06, 0x12,
+         0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00,
+         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+       };
+       char *buffer;
+       int result;
 
-       US_DEBUGP("Option MS: option_ms_init called\n");
+       US_DEBUGP("Option MS: %s", "device inquiry for vendor name\n");
 
-       /* Find the right mass storage interface */
-       iface_desc = intf->cur_altsetting;
-       if (iface_desc->desc.bInterfaceClass != 0x8 ||
-           iface_desc->desc.bInterfaceSubClass != 0x6 ||
-           iface_desc->desc.bInterfaceProtocol != 0x50) {
-               US_DEBUGP("Option MS: mass storage interface not found, no action "
-                         "required\n");
-               return USB_STOR_TRANSPORT_GOOD;
-       }
+       buffer = kzalloc(0x24, GFP_KERNEL);
+       if (buffer == NULL)
+               return USB_STOR_TRANSPORT_ERROR;
 
-       /* Find the mass storage bulk endpoints */
-       for (i = 0; i < iface_desc->desc.bNumEndpoints && (!ep_in_size || !ep_out_size); ++i) {
-               endpoint = &iface_desc->endpoint[i].desc;
-
-               if (usb_endpoint_is_bulk_in(endpoint)) {
-                       ep_in = usb_endpoint_num(endpoint);
-                       ep_in_size = le16_to_cpu(endpoint->wMaxPacketSize);
-               } else if (usb_endpoint_is_bulk_out(endpoint)) {
-                       ep_out = usb_endpoint_num(endpoint);
-                       ep_out_size = le16_to_cpu(endpoint->wMaxPacketSize);
-               }
+       memcpy(buffer, inquiry_msg, sizeof(inquiry_msg));
+       result = usb_stor_bulk_transfer_buf(us,
+                       us->send_bulk_pipe,
+                       buffer, sizeof(inquiry_msg), NULL);
+       if (result != USB_STOR_XFER_GOOD) {
+               result = USB_STOR_XFER_ERROR;
+               goto out;
        }
 
-       /* Can't find the mass storage endpoints */
-       if (!ep_in_size || !ep_out_size) {
-               US_DEBUGP("Option MS: mass storage endpoints not found, no action "
-                         "required\n");
-               return USB_STOR_TRANSPORT_GOOD;
+       result = usb_stor_bulk_transfer_buf(us,
+                       us->recv_bulk_pipe,
+                       buffer, 0x24, NULL);
+       if (result != USB_STOR_XFER_GOOD) {
+               result = USB_STOR_XFER_ERROR;
+               goto out;
        }
 
+       result = memcmp(buffer+8, "Option", 6);
+
+       /* Read the CSW */
+       usb_stor_bulk_transfer_buf(us,
+                       us->recv_bulk_pipe,
+                       buffer, 13, NULL);
+
+out:
+       kfree(buffer);
+       return result;
+}
+
+
+int option_ms_init(struct us_data *us)
+{
+       int result;
+
+       US_DEBUGP("Option MS: option_ms_init called\n");
+
+       /* Additional test for vendor information via INQUIRY,
+        * because some vendor/product IDs are ambiguous
+        */
+       result = option_inquiry(us);
+       if (result != 0) {
+               US_DEBUGP("Option MS: vendor is not Option or not determinable,"
+                         " no action taken\n");
+               return 0;
+       } else
+               US_DEBUGP("Option MS: this is a genuine Option device,"
+                         " proceeding\n");
+
        /* Force Modem mode */
        if (option_zero_cd == ZCD_FORCE_MODEM) {
                US_DEBUGP("Option MS: %s", "Forcing Modem Mode\n");
-               result = option_rezero(us, ep_in, ep_out);
+               result = option_rezero(us);
                if (result != USB_STOR_XFER_GOOD)
                        US_DEBUGP("Option MS: Failed to switch to modem mode.\n");
                return -EIO;
@@ -142,6 +160,6 @@ int option_ms_init(struct us_data *us)
                          " requests it\n");
        }
 
-       return USB_STOR_TRANSPORT_GOOD;
+       return 0;
 }
 
index 4359a2cb42df396d8e7996761814ff40755846dd..4395c4100ec2096313933d029e8b25191eefe6c9 100644 (file)
@@ -202,6 +202,6 @@ int sierra_ms_init(struct us_data *us)
 complete:
        result = device_create_file(&us->pusb_intf->dev, &dev_attr_truinst);
 
-       return USB_STOR_TRANSPORT_GOOD;
+       return 0;
 }
 
index 4b8b69045fe6073f26193bed04b1aef818a14fb6..1b9c5dd0fb27b00904c1cb9357f0402c9e12a323 100644 (file)
@@ -1385,7 +1385,7 @@ UNUSUAL_DEV(  0x10d6, 0x2200, 0x0100, 0x0100,
 UNUSUAL_DEV(  0x1186, 0x3e04, 0x0000, 0x0000,
            "D-Link",
            "USB Mass Storage",
-           US_SC_DEVICE, US_PR_DEVICE, option_ms_init, 0),
+           US_SC_DEVICE, US_PR_DEVICE, option_ms_init, US_FL_IGNORE_DEVICE),
 
 /* Reported by Kevin Lloyd <linux@sierrawireless.com>
  * Entry is needed for the initializer function override,
index 2b5a691064b719fcfa94fdb4bcac82bf0fb26205..932ffdbf86d98b542d3efe05087903926584a86d 100644 (file)
@@ -2104,6 +2104,7 @@ config FB_MB862XX_LIME
        bool "Lime GDC"
        depends on FB_MB862XX
        depends on OF && !FB_MB862XX_PCI_GDC
+       depends on PPC
        select FB_FOREIGN_ENDIAN
        select FB_LITTLE_ENDIAN
        ---help---
index 6995fe1e86d4aae1ad5abd6535e65572f1a59316..0bcc59eb37fa3787b39164a938199f2e1e0ea8ea 100644 (file)
@@ -859,43 +859,6 @@ acornfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
        return 0;
 }
 
-/*
- * Note that we are entered with the kernel locked.
- */
-static int
-acornfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
-{
-       unsigned long off, start;
-       u32 len;
-
-       off = vma->vm_pgoff << PAGE_SHIFT;
-
-       start = info->fix.smem_start;
-       len = PAGE_ALIGN(start & ~PAGE_MASK) + info->fix.smem_len;
-       start &= PAGE_MASK;
-       if ((vma->vm_end - vma->vm_start + off) > len)
-               return -EINVAL;
-       off += start;
-       vma->vm_pgoff = off >> PAGE_SHIFT;
-
-       /* This is an IO map - tell maydump to skip this VMA */
-       vma->vm_flags |= VM_IO;
-
-       vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
-
-       /*
-        * Don't alter the page protection flags; we want to keep the area
-        * cached for better performance.  This does mean that we may miss
-        * some updates to the screen occasionally, but process switches
-        * should cause the caches and buffers to be flushed often enough.
-        */
-       if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
-                               vma->vm_end - vma->vm_start,
-                               vma->vm_page_prot))
-               return -EAGAIN;
-       return 0;
-}
-
 static struct fb_ops acornfb_ops = {
        .owner          = THIS_MODULE,
        .fb_check_var   = acornfb_check_var,
@@ -905,7 +868,6 @@ static struct fb_ops acornfb_ops = {
        .fb_fillrect    = cfb_fillrect,
        .fb_copyarea    = cfb_copyarea,
        .fb_imageblit   = cfb_imageblit,
-       .fb_mmap        = acornfb_mmap,
 };
 
 /*
index 2fb63f6ea2f167fcdc1d5148e896fff00f415127..5afd64482f5584fd7c03f0d6267875da6eb3f16f 100644 (file)
@@ -345,7 +345,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
        dev_dbg(dev, "  bpp:        %u\n", var->bits_per_pixel);
        dev_dbg(dev, "  clk:        %lu KHz\n", clk_value_khz);
 
-       if ((PICOS2KHZ(var->pixclock) * var->bits_per_pixel / 8) > clk_value_khz) {
+       if (PICOS2KHZ(var->pixclock) > clk_value_khz) {
                dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(var->pixclock));
                return -EINVAL;
        }
index 97a1f095f327115524bdb9fcd55da6162d8497d2..515cf1978d19ef21fc5062471e1357826e4da8c6 100644 (file)
@@ -213,7 +213,6 @@ static void radeon_pm_disable_dynamic_mode(struct radeonfb_info *rinfo)
                         PIXCLKS_CNTL__R300_PIXCLK_TRANS_ALWAYS_ONb     |
                         PIXCLKS_CNTL__R300_PIXCLK_TVO_ALWAYS_ONb       |
                         PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb          |
-                        PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb          |
                         PIXCLKS_CNTL__R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF);
                 OUTPLL(pllPIXCLKS_CNTL, tmp);
 
@@ -395,7 +394,7 @@ static void radeon_pm_enable_dynamic_mode(struct radeonfb_info *rinfo)
                        PIXCLKS_CNTL__R300_PIXCLK_TRANS_ALWAYS_ONb      |
                        PIXCLKS_CNTL__R300_PIXCLK_TVO_ALWAYS_ONb        |
                        PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb           |
-                       PIXCLKS_CNTL__R300_P2G2CLK_ALWAYS_ONb);
+                       PIXCLKS_CNTL__R300_P2G2CLK_DAC_ALWAYS_ONb);
                OUTPLL(pllPIXCLKS_CNTL, tmp);
 
                tmp = INPLL(pllMCLK_MISC);
index 37e60b1d2ed953ff963820e8f386985d973b5fa7..e49ae5edcc008fcc6a698ad07388de8199ea4278 100644 (file)
@@ -323,7 +323,6 @@ static int bfin_bf54x_fb_release(struct fb_info *info, int user)
                bfin_write_EPPI0_CONTROL(0);
                SSYNC();
                disable_dma(CH_EPPI0);
-               memset(fbi->fb_buffer, 0, info->fix.smem_len);
        }
 
        spin_unlock(&fbi->lock);
@@ -530,7 +529,7 @@ static irqreturn_t bfin_bf54x_irq_error(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static int __init bfin_bf54x_probe(struct platform_device *pdev)
+static int __devinit bfin_bf54x_probe(struct platform_device *pdev)
 {
        struct bfin_bf54xfb_info *info;
        struct fb_info *fbinfo;
@@ -626,14 +625,12 @@ static int __init bfin_bf54x_probe(struct platform_device *pdev)
                goto out3;
        }
 
-       memset(info->fb_buffer, 0, fbinfo->fix.smem_len);
-
        fbinfo->screen_base = (void *)info->fb_buffer;
        fbinfo->fix.smem_start = (int)info->fb_buffer;
 
        fbinfo->fbops = &bfin_bf54x_fb_ops;
 
-       fbinfo->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
+       fbinfo->pseudo_palette = kzalloc(sizeof(u32) * 16, GFP_KERNEL);
        if (!fbinfo->pseudo_palette) {
                printk(KERN_ERR DRIVER_NAME
                       "Fail to allocate pseudo_palette\n");
@@ -642,8 +639,6 @@ static int __init bfin_bf54x_probe(struct platform_device *pdev)
                goto out4;
        }
 
-       memset(fbinfo->pseudo_palette, 0, sizeof(u32) * 16);
-
        if (fb_alloc_cmap(&fbinfo->cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0)
            < 0) {
                printk(KERN_ERR DRIVER_NAME
@@ -712,7 +707,7 @@ out1:
        return ret;
 }
 
-static int bfin_bf54x_remove(struct platform_device *pdev)
+static int __devexit bfin_bf54x_remove(struct platform_device *pdev)
 {
 
        struct fb_info *fbinfo = platform_get_drvdata(pdev);
@@ -781,7 +776,7 @@ static int bfin_bf54x_resume(struct platform_device *pdev)
 
 static struct platform_driver bfin_bf54x_driver = {
        .probe = bfin_bf54x_probe,
-       .remove = bfin_bf54x_remove,
+       .remove = __devexit_p(bfin_bf54x_remove),
        .suspend = bfin_bf54x_suspend,
        .resume = bfin_bf54x_resume,
        .driver = {
@@ -790,7 +785,7 @@ static struct platform_driver bfin_bf54x_driver = {
                   },
 };
 
-static int __devinit bfin_bf54x_driver_init(void)
+static int __init bfin_bf54x_driver_init(void)
 {
        return platform_driver_register(&bfin_bf54x_driver);
 }
index 90cfddabf1f7618548275f99ec292f5f6573b8e6..5cc36cfbf07be275ce2b8ea92104c41e4bda1996 100644 (file)
@@ -242,7 +242,6 @@ static int bfin_t350mcqb_fb_release(struct fb_info *info, int user)
                SSYNC();
                disable_dma(CH_PPI);
                bfin_t350mcqb_stop_timers();
-               memset(fbi->fb_buffer, 0, info->fix.smem_len);
        }
 
        spin_unlock(&fbi->lock);
@@ -527,8 +526,6 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
                goto out3;
        }
 
-       memset(info->fb_buffer, 0, fbinfo->fix.smem_len);
-
        fbinfo->screen_base = (void *)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET;
        fbinfo->fix.smem_start = (int)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET;
 
@@ -602,7 +599,7 @@ out1:
        return ret;
 }
 
-static int bfin_t350mcqb_remove(struct platform_device *pdev)
+static int __devexit bfin_t350mcqb_remove(struct platform_device *pdev)
 {
 
        struct fb_info *fbinfo = platform_get_drvdata(pdev);
@@ -637,9 +634,6 @@ static int bfin_t350mcqb_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM
 static int bfin_t350mcqb_suspend(struct platform_device *pdev, pm_message_t state)
 {
-       struct fb_info *fbinfo = platform_get_drvdata(pdev);
-       struct bfin_t350mcqbfb_info *info = fbinfo->par;
-
        bfin_t350mcqb_disable_ppi();
        disable_dma(CH_PPI);
        bfin_write_PPI_STATUS(0xFFFF);
@@ -649,9 +643,6 @@ static int bfin_t350mcqb_suspend(struct platform_device *pdev, pm_message_t stat
 
 static int bfin_t350mcqb_resume(struct platform_device *pdev)
 {
-       struct fb_info *fbinfo = platform_get_drvdata(pdev);
-       struct bfin_t350mcqbfb_info *info = fbinfo->par;
-
        enable_dma(CH_PPI);
        bfin_t350mcqb_enable_ppi();
 
@@ -664,7 +655,7 @@ static int bfin_t350mcqb_resume(struct platform_device *pdev)
 
 static struct platform_driver bfin_t350mcqb_driver = {
        .probe = bfin_t350mcqb_probe,
-       .remove = bfin_t350mcqb_remove,
+       .remove = __devexit_p(bfin_t350mcqb_remove),
        .suspend = bfin_t350mcqb_suspend,
        .resume = bfin_t350mcqb_resume,
        .driver = {
@@ -673,7 +664,7 @@ static struct platform_driver bfin_t350mcqb_driver = {
                   },
 };
 
-static int __devinit bfin_t350mcqb_driver_init(void)
+static int __init bfin_t350mcqb_driver_init(void)
 {
        return platform_driver_register(&bfin_t350mcqb_driver);
 }
index 1e35ba6f18e01ef44eeda30e5685a9eb2f556317..b0b147cb4cb3aae5a0090e38145f8b48d1b0e25b 100644 (file)
@@ -111,9 +111,7 @@ struct bw2_par {
        u32                     flags;
 #define BW2_FLAG_BLANKED       0x00000001
 
-       unsigned long           physbase;
        unsigned long           which_io;
-       unsigned long           fbsize;
 };
 
 /**
@@ -167,17 +165,15 @@ static int bw2_mmap(struct fb_info *info, struct vm_area_struct *vma)
        struct bw2_par *par = (struct bw2_par *)info->par;
 
        return sbusfb_mmap_helper(bw2_mmap_map,
-                                 par->physbase, par->fbsize,
+                                 info->fix.smem_start, info->fix.smem_len,
                                  par->which_io,
                                  vma);
 }
 
 static int bw2_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
-       struct bw2_par *par = (struct bw2_par *) info->par;
-
        return sbusfb_ioctl_helper(cmd, arg, info,
-                                  FBTYPE_SUN2BW, 1, par->fbsize);
+                                  FBTYPE_SUN2BW, 1, info->fix.smem_len);
 }
 
 /*
@@ -294,7 +290,7 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id *
 
        spin_lock_init(&par->lock);
 
-       par->physbase = op->resource[0].start;
+       info->fix.smem_start = op->resource[0].start;
        par->which_io = op->resource[0].flags & IORESOURCE_BITS;
 
        sbusfb_fill_var(&info->var, dp, 1);
@@ -317,13 +313,13 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id *
                        goto out_unmap_regs;
        }
 
-       par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
+       info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);
 
        info->flags = FBINFO_DEFAULT;
        info->fbops = &bw2_ops;
 
        info->screen_base = of_ioremap(&op->resource[0], 0,
-                                      par->fbsize, "bw2 ram");
+                                      info->fix.smem_len, "bw2 ram");
        if (!info->screen_base)
                goto out_unmap_regs;
 
@@ -338,12 +334,12 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id *
        dev_set_drvdata(&op->dev, info);
 
        printk(KERN_INFO "%s: bwtwo at %lx:%lx\n",
-              dp->full_name, par->which_io, par->physbase);
+              dp->full_name, par->which_io, info->fix.smem_start);
 
        return 0;
 
 out_unmap_screen:
-       of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
+       of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len);
 
 out_unmap_regs:
        of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs));
@@ -363,7 +359,7 @@ static int __devexit bw2_remove(struct of_device *op)
        unregister_framebuffer(info);
 
        of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs));
-       of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
+       of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len);
 
        framebuffer_release(info);
 
index c7ff3c1a266a3611c2081e71e56bbb29264eaa0b..0c02f8ec4bf3dafe14965025a3a1121e19ab4dfd 100644 (file)
@@ -562,7 +562,7 @@ static int __devinit alloc_carmine_fb(void __iomem *regs, void __iomem *smem_bas
        if (ret < 0)
                goto err_free_fb;
 
-       if (fb_mode > ARRAY_SIZE(carmine_modedb))
+       if (fb_mode >= ARRAY_SIZE(carmine_modedb))
                fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE;
 
        par->cur_mode = par->new_mode = ~0;
index a2d1882791a58e11956b250afbca92fa520b9e79..fe45a3b8d0e060141e8a7cef3d7702fff15a44fa 100644 (file)
@@ -196,9 +196,7 @@ struct cg14_par {
        u32                     flags;
 #define CG14_FLAG_BLANKED      0x00000001
 
-       unsigned long           physbase;
        unsigned long           iospace;
-       unsigned long           fbsize;
 
        struct sbus_mmap_map    mmap_map[CG14_MMAP_ENTRIES];
 
@@ -271,7 +269,7 @@ static int cg14_mmap(struct fb_info *info, struct vm_area_struct *vma)
        struct cg14_par *par = (struct cg14_par *) info->par;
 
        return sbusfb_mmap_helper(par->mmap_map,
-                                 par->physbase, par->fbsize,
+                                 info->fix.smem_start, info->fix.smem_len,
                                  par->iospace, vma);
 }
 
@@ -343,7 +341,8 @@ static int cg14_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 
        default:
                ret = sbusfb_ioctl_helper(cmd, arg, info,
-                                         FBTYPE_MDICOLOR, 8, par->fbsize);
+                                         FBTYPE_MDICOLOR, 8,
+                                         info->fix.smem_len);
                break;
        };
 
@@ -462,7 +461,7 @@ static void cg14_unmap_regs(struct of_device *op, struct fb_info *info,
                           par->cursor, sizeof(struct cg14_cursor));
        if (info->screen_base)
                of_iounmap(&op->resource[1],
-                          info->screen_base, par->fbsize);
+                          info->screen_base, info->fix.smem_len);
 }
 
 static int __devinit cg14_probe(struct of_device *op, const struct of_device_id *match)
@@ -488,14 +487,14 @@ static int __devinit cg14_probe(struct of_device *op, const struct of_device_id
 
        linebytes = of_getintprop_default(dp, "linebytes",
                                          info->var.xres);
-       par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
+       info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);
 
        if (!strcmp(dp->parent->name, "sbus") ||
            !strcmp(dp->parent->name, "sbi")) {
-               par->physbase = op->resource[0].start;
+               info->fix.smem_start = op->resource[0].start;
                par->iospace = op->resource[0].flags & IORESOURCE_BITS;
        } else {
-               par->physbase = op->resource[1].start;
+               info->fix.smem_start = op->resource[1].start;
                par->iospace = op->resource[0].flags & IORESOURCE_BITS;
        }
 
@@ -507,7 +506,7 @@ static int __devinit cg14_probe(struct of_device *op, const struct of_device_id
                                 sizeof(struct cg14_cursor), "cg14 cursor");
 
        info->screen_base = of_ioremap(&op->resource[1], 0,
-                                      par->fbsize, "cg14 ram");
+                                      info->fix.smem_len, "cg14 ram");
 
        if (!par->regs || !par->clut || !par->cursor || !info->screen_base)
                goto out_unmap_regs;
@@ -557,7 +556,7 @@ static int __devinit cg14_probe(struct of_device *op, const struct of_device_id
 
        printk(KERN_INFO "%s: cgfourteen at %lx:%lx, %dMB\n",
               dp->full_name,
-              par->iospace, par->physbase,
+              par->iospace, info->fix.smem_start,
               par->ramsize >> 20);
 
        return 0;
index 99f87fb61d0558e816541fe0f133f79c2700decc..b2319fa7286f8c77d8649ff4892f02ace8fb45e0 100644 (file)
@@ -118,9 +118,7 @@ struct cg3_par {
 #define CG3_FLAG_BLANKED       0x00000001
 #define CG3_FLAG_RDI           0x00000002
 
-       unsigned long           physbase;
        unsigned long           which_io;
-       unsigned long           fbsize;
 };
 
 /**
@@ -231,17 +229,15 @@ static int cg3_mmap(struct fb_info *info, struct vm_area_struct *vma)
        struct cg3_par *par = (struct cg3_par *)info->par;
 
        return sbusfb_mmap_helper(cg3_mmap_map,
-                                 par->physbase, par->fbsize,
+                                 info->fix.smem_start, info->fix.smem_len,
                                  par->which_io,
                                  vma);
 }
 
 static int cg3_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
-       struct cg3_par *par = (struct cg3_par *) info->par;
-
        return sbusfb_ioctl_helper(cmd, arg, info,
-                                  FBTYPE_SUN3COLOR, 8, par->fbsize);
+                                  FBTYPE_SUN3COLOR, 8, info->fix.smem_len);
 }
 
 /*
@@ -368,7 +364,7 @@ static int __devinit cg3_probe(struct of_device *op,
 
        spin_lock_init(&par->lock);
 
-       par->physbase = op->resource[0].start;
+       info->fix.smem_start = op->resource[0].start;
        par->which_io = op->resource[0].flags & IORESOURCE_BITS;
 
        sbusfb_fill_var(&info->var, dp, 8);
@@ -382,7 +378,7 @@ static int __devinit cg3_probe(struct of_device *op,
 
        linebytes = of_getintprop_default(dp, "linebytes",
                                          info->var.xres);
-       par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
+       info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);
 
        par->regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET,
                               sizeof(struct cg3_regs), "cg3 regs");
@@ -392,7 +388,7 @@ static int __devinit cg3_probe(struct of_device *op,
        info->flags = FBINFO_DEFAULT;
        info->fbops = &cg3_ops;
        info->screen_base = of_ioremap(&op->resource[0], CG3_RAM_OFFSET,
-                                      par->fbsize, "cg3 ram");
+                                      info->fix.smem_len, "cg3 ram");
        if (!info->screen_base)
                goto out_unmap_regs;
 
@@ -418,7 +414,7 @@ static int __devinit cg3_probe(struct of_device *op,
        dev_set_drvdata(&op->dev, info);
 
        printk(KERN_INFO "%s: cg3 at %lx:%lx\n",
-              dp->full_name, par->which_io, par->physbase);
+              dp->full_name, par->which_io, info->fix.smem_start);
 
        return 0;
 
@@ -426,7 +422,7 @@ out_dealloc_cmap:
        fb_dealloc_cmap(&info->cmap);
 
 out_unmap_screen:
-       of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
+       of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len);
 
 out_unmap_regs:
        of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs));
@@ -447,7 +443,7 @@ static int __devexit cg3_remove(struct of_device *op)
        fb_dealloc_cmap(&info->cmap);
 
        of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs));
-       of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
+       of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len);
 
        framebuffer_release(info);
 
index 940ec04f0f1be22665c99e548eaf9392a2fa13b1..0d47c6030e3d084011d697bf7aefe34d6f02021f 100644 (file)
@@ -263,9 +263,7 @@ struct cg6_par {
        u32                     flags;
 #define CG6_FLAG_BLANKED       0x00000001
 
-       unsigned long           physbase;
        unsigned long           which_io;
-       unsigned long           fbsize;
 };
 
 static int cg6_sync(struct fb_info *info)
@@ -596,16 +594,14 @@ static int cg6_mmap(struct fb_info *info, struct vm_area_struct *vma)
        struct cg6_par *par = (struct cg6_par *)info->par;
 
        return sbusfb_mmap_helper(cg6_mmap_map,
-                                 par->physbase, par->fbsize,
+                                 info->fix.smem_start, info->fix.smem_len,
                                  par->which_io, vma);
 }
 
 static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
-       struct cg6_par *par = (struct cg6_par *)info->par;
-
        return sbusfb_ioctl_helper(cmd, arg, info,
-                                  FBTYPE_SUNFAST_COLOR, 8, par->fbsize);
+                                  FBTYPE_SUNFAST_COLOR, 8, info->fix.smem_len);
 }
 
 /*
@@ -631,12 +627,12 @@ static void __devinit cg6_init_fix(struct fb_info *info, int linebytes)
                break;
        };
        if (((conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK) >= 11) {
-               if (par->fbsize <= 0x100000)
+               if (info->fix.smem_len <= 0x100000)
                        cg6_card_name = "TGX";
                else
                        cg6_card_name = "TGX+";
        } else {
-               if (par->fbsize <= 0x100000)
+               if (info->fix.smem_len <= 0x100000)
                        cg6_card_name = "GX";
                else
                        cg6_card_name = "GX+";
@@ -738,7 +734,8 @@ static void cg6_unmap_regs(struct of_device *op, struct fb_info *info,
                of_iounmap(&op->resource[0], par->fhc, sizeof(u32));
 
        if (info->screen_base)
-               of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
+               of_iounmap(&op->resource[0], info->screen_base,
+                          info->fix.smem_len);
 }
 
 static int __devinit cg6_probe(struct of_device *op,
@@ -759,7 +756,7 @@ static int __devinit cg6_probe(struct of_device *op,
 
        spin_lock_init(&par->lock);
 
-       par->physbase = op->resource[0].start;
+       info->fix.smem_start = op->resource[0].start;
        par->which_io = op->resource[0].flags & IORESOURCE_BITS;
 
        sbusfb_fill_var(&info->var, dp, 8);
@@ -769,11 +766,11 @@ static int __devinit cg6_probe(struct of_device *op,
 
        linebytes = of_getintprop_default(dp, "linebytes",
                                          info->var.xres);
-       par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
+       info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);
 
        dblbuf = of_getintprop_default(dp, "dblbuf", 0);
        if (dblbuf)
-               par->fbsize *= 4;
+               info->fix.smem_len *= 4;
 
        par->fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET,
                                4096, "cgsix fbc");
@@ -792,7 +789,7 @@ static int __devinit cg6_probe(struct of_device *op,
        info->fbops = &cg6_ops;
 
        info->screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET,
-                                       par->fbsize, "cgsix ram");
+                                       info->fix.smem_len, "cgsix ram");
        if (!par->fbc || !par->tec || !par->thc ||
            !par->bt || !par->fhc || !info->screen_base)
                goto out_unmap_regs;
@@ -817,7 +814,7 @@ static int __devinit cg6_probe(struct of_device *op,
 
        printk(KERN_INFO "%s: CGsix [%s] at %lx:%lx\n",
               dp->full_name, info->fix.id,
-              par->which_io, par->physbase);
+              par->which_io, info->fix.smem_start);
 
        return 0;
 
index 777389c40988812c29f5ad31c7c04cc700f6f690..57b9d276497ed07e485311f38e95c6ef86af870e 100644 (file)
@@ -414,7 +414,6 @@ chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
        }
 
        pci_set_drvdata(dp, p);
-       p->device = &dp->dev;
 
        init_chips(p, addr);
 
index 8dea2bc927054783658183f662d9644e2eb27efc..eb12182b20598861937b46496b8716efcae1e366 100644 (file)
@@ -280,6 +280,9 @@ static int __init efifb_probe(struct platform_device *dev)
        info->pseudo_palette = info->par;
        info->par = NULL;
 
+       info->aperture_base = efifb_fix.smem_start;
+       info->aperture_size = size_total;
+
        info->screen_base = ioremap(efifb_fix.smem_start, efifb_fix.smem_len);
        if (!info->screen_base) {
                printk(KERN_ERR "efifb: abort, cannot ioremap video memory "
@@ -337,7 +340,7 @@ static int __init efifb_probe(struct platform_device *dev)
        info->fbops = &efifb_ops;
        info->var = efifb_defined;
        info->fix = efifb_fix;
-       info->flags = FBINFO_FLAG_DEFAULT;
+       info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE;
 
        if ((err = fb_alloc_cmap(&info->cmap, 256, 0)) < 0) {
                printk(KERN_ERR "efifb: cannot allocate colormap\n");
index d412a1ddc12fabb50df8562af40b5df25351d2bd..f8a09bf8d0cdecb0963116a4fb7a7d3793ed798d 100644 (file)
@@ -1462,6 +1462,16 @@ static int fb_check_foreignness(struct fb_info *fi)
        return 0;
 }
 
+static bool fb_do_apertures_overlap(struct fb_info *gen, struct fb_info *hw)
+{
+       /* is the generic aperture base the same as the HW one */
+       if (gen->aperture_base == hw->aperture_base)
+               return true;
+       /* is the generic aperture base inside the hw base->hw base+size */
+       if (gen->aperture_base > hw->aperture_base && gen->aperture_base <= hw->aperture_base + hw->aperture_size)
+               return true;
+       return false;
+}
 /**
  *     register_framebuffer - registers a frame buffer device
  *     @fb_info: frame buffer info structure
@@ -1485,6 +1495,23 @@ register_framebuffer(struct fb_info *fb_info)
        if (fb_check_foreignness(fb_info))
                return -ENOSYS;
 
+       /* check all firmware fbs and kick off if the base addr overlaps */
+       for (i = 0 ; i < FB_MAX; i++) {
+               if (!registered_fb[i])
+                       continue;
+
+               if (registered_fb[i]->flags & FBINFO_MISC_FIRMWARE) {
+                       if (fb_do_apertures_overlap(registered_fb[i], fb_info)) {
+                               printk(KERN_ERR "fb: conflicting fb hw usage "
+                                      "%s vs %s - removing generic driver\n",
+                                      fb_info->fix.id,
+                                      registered_fb[i]->fix.id);
+                               unregister_framebuffer(registered_fb[i]);
+                               break;
+                       }
+               }
+       }
+
        num_registered_fb++;
        for (i = 0 ; i < FB_MAX; i++)
                if (!registered_fb[i])
@@ -1586,6 +1613,10 @@ unregister_framebuffer(struct fb_info *fb_info)
        device_destroy(fb_class, MKDEV(FB_MAJOR, i));
        event.info = fb_info;
        fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
+
+       /* this may free fb info */
+       if (fb_info->fbops->fb_destroy)
+               fb_info->fbops->fb_destroy(fb_info);
 done:
        return ret;
 }
index 3a81060137a22bd29176d885a2cec1facf3c599b..15d200109446aa577f77f0d12d9f2cd66d04f6f2 100644 (file)
@@ -395,17 +395,16 @@ int __init igafb_init(void)
        /* We leak a reference here but as it cannot be unloaded this is
           fine. If you write unload code remember to free it in unload */
        
-       size = sizeof(struct fb_info) + sizeof(struct iga_par) + sizeof(u32)*16;
+       size = sizeof(struct iga_par) + sizeof(u32)*16;
 
-        info = kzalloc(size, GFP_ATOMIC);
+       info = framebuffer_alloc(size, &pdev->dev);
         if (!info) {
                 printk("igafb_init: can't alloc fb_info\n");
                 pci_dev_put(pdev);
                 return -ENOMEM;
         }
 
-       par = (struct iga_par *) (info + 1);
-       
+       par = info->par;
 
        if ((addr = pdev->resource[0].start) == 0) {
                 printk("igafb_init: no memory start\n");
@@ -526,7 +525,6 @@ int __init igafb_init(void)
        info->var = default_var;
        info->fix = igafb_fix;
        info->pseudo_palette = (void *)(par + 1);
-       info->device = &pdev->dev;
 
        if (!iga_init(info, par)) {
                iounmap((void *)par->io_base);
index ace14fe02fc4f49348024b1d1bc964cccffecbdc..0cafd642fbc0f57b5eaee3fe85a60895c30e1d8d 100644 (file)
@@ -1365,6 +1365,11 @@ static int intelfb_set_par(struct fb_info *info)
        DBG_MSG("intelfb_set_par (%dx%d-%d)\n", info->var.xres,
                info->var.yres, info->var.bits_per_pixel);
 
+       /*
+        * Disable VCO prior to timing register change.
+        */
+       OUTREG(DPLL_A, INREG(DPLL_A) & ~DPLL_VCO_ENABLE);
+
        intelfb_blank(FB_BLANK_POWERDOWN, info);
 
        if (ACCEL(dinfo, info))
index 7c7e8c2da9d911081f68d3b94d46f2effd69e496..e145e2d16fe37414d40e7c1ce4df3831b3752ddc 100644 (file)
@@ -191,9 +191,7 @@ struct leo_par {
        u32                     flags;
 #define LEO_FLAG_BLANKED       0x00000001
 
-       unsigned long           physbase;
        unsigned long           which_io;
-       unsigned long           fbsize;
 };
 
 static void leo_wait(struct leo_lx_krn __iomem *lx_krn)
@@ -420,16 +418,14 @@ static int leo_mmap(struct fb_info *info, struct vm_area_struct *vma)
        struct leo_par *par = (struct leo_par *)info->par;
 
        return sbusfb_mmap_helper(leo_mmap_map,
-                                 par->physbase, par->fbsize,
+                                 info->fix.smem_start, info->fix.smem_len,
                                  par->which_io, vma);
 }
 
 static int leo_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
-       struct leo_par *par = (struct leo_par *) info->par;
-
        return sbusfb_ioctl_helper(cmd, arg, info,
-                                  FBTYPE_SUNLEO, 32, par->fbsize);
+                                  FBTYPE_SUNLEO, 32, info->fix.smem_len);
 }
 
 /*
@@ -569,7 +565,7 @@ static int __devinit leo_probe(struct of_device *op,
 
        spin_lock_init(&par->lock);
 
-       par->physbase = op->resource[0].start;
+       info->fix.smem_start = op->resource[0].start;
        par->which_io = op->resource[0].flags & IORESOURCE_BITS;
 
        sbusfb_fill_var(&info->var, dp, 32);
@@ -577,7 +573,7 @@ static int __devinit leo_probe(struct of_device *op,
 
        linebytes = of_getintprop_default(dp, "linebytes",
                                          info->var.xres);
-       par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
+       info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);
 
        par->lc_ss0_usr =
                of_ioremap(&op->resource[0], LEO_OFF_LC_SS0_USR,
@@ -627,7 +623,7 @@ static int __devinit leo_probe(struct of_device *op,
 
        printk(KERN_INFO "%s: leo at %lx:%lx\n",
               dp->full_name,
-              par->which_io, par->physbase);
+              par->which_io, info->fix.smem_start);
 
        return 0;
 
index b91251d1fe41c9e254ebfb51320545754d45c305..3b437813584cec4f3d73ba5364353ac4a5cbb29b 100644 (file)
@@ -37,22 +37,24 @@ extra-y += $(call logo-cfiles,_clut224,ppm)
 # Gray 256
 extra-y += $(call logo-cfiles,_gray256,pgm)
 
+pnmtologo := scripts/pnmtologo
+
 # Create commands like "pnmtologo -t mono -n logo_mac_mono -o ..."
 quiet_cmd_logo = LOGO    $@
-       cmd_logo = scripts/pnmtologo \
+       cmd_logo = $(pnmtologo) \
                        -t $(patsubst $*_%,%,$(notdir $(basename $<))) \
                        -n $(notdir $(basename $<)) -o $@ $<
 
-$(obj)/%_mono.c: $(src)/%_mono.pbm FORCE
+$(obj)/%_mono.c: $(src)/%_mono.pbm $(pnmtologo) FORCE
        $(call if_changed,logo)
 
-$(obj)/%_vga16.c: $(src)/%_vga16.ppm FORCE
+$(obj)/%_vga16.c: $(src)/%_vga16.ppm $(pnmtologo) FORCE
        $(call if_changed,logo)
 
-$(obj)/%_clut224.c: $(src)/%_clut224.ppm FORCE
+$(obj)/%_clut224.c: $(src)/%_clut224.ppm $(pnmtologo) FORCE
        $(call if_changed,logo)
 
-$(obj)/%_gray256.c: $(src)/%_gray256.pgm FORCE
+$(obj)/%_gray256.c: $(src)/%_gray256.pgm $(pnmtologo) FORCE
        $(call if_changed,logo)
 
 # Files generated that shall be removed upon make clean
index 2e85a2b52d05feada5f9c7a056d8c2575f5c9ba1..ea7a8ccc830c8659f23b13dc98db761b89a6c0da 100644 (file)
 #include <asm/bootinfo.h>
 #endif
 
-extern const struct linux_logo logo_linux_mono;
-extern const struct linux_logo logo_linux_vga16;
-extern const struct linux_logo logo_linux_clut224;
-extern const struct linux_logo logo_blackfin_vga16;
-extern const struct linux_logo logo_blackfin_clut224;
-extern const struct linux_logo logo_dec_clut224;
-extern const struct linux_logo logo_mac_clut224;
-extern const struct linux_logo logo_parisc_clut224;
-extern const struct linux_logo logo_sgi_clut224;
-extern const struct linux_logo logo_sun_clut224;
-extern const struct linux_logo logo_superh_mono;
-extern const struct linux_logo logo_superh_vga16;
-extern const struct linux_logo logo_superh_clut224;
-extern const struct linux_logo logo_m32r_clut224;
-
 static int nologo;
 module_param(nologo, bool, 0);
 MODULE_PARM_DESC(nologo, "Disables startup logo");
index fb64234a3825a2a9d1ee7f24e52e7cd75b969713..a28e3cfbbf707964099cbf6d04a97eb6a6db2860 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
-#if defined(CONFIG_PPC_OF)
+#if defined(CONFIG_OF)
 #include <linux/of_platform.h>
 #endif
 #include "mb862xxfb.h"
index 16186240c5f22ba47b63971847ba6e2384515d27..34e4e79951696bd5ac805cb69fea5780e84018c2 100644 (file)
@@ -264,6 +264,14 @@ static const struct fb_videomode modedb[] = {
        /* 1280x800, 60 Hz, 47.403 kHz hsync, WXGA 16:10 aspect ratio */
        NULL, 60, 1280, 800, 12048, 200, 64, 24, 1, 136, 3,
        0, FB_VMODE_NONINTERLACED
+    }, {
+       /* 720x576i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */
+       NULL, 50, 720, 576, 74074, 64, 16, 39, 5, 64, 5,
+       0, FB_VMODE_INTERLACED
+    }, {
+       /* 800x520i @ 50 Hz, 15.625 kHz hsync (PAL RGB) */
+       NULL, 50, 800, 520, 58823, 144, 64, 72, 28, 80, 5,
+       0, FB_VMODE_INTERLACED
     },
 };
 
index e1d9eeb1aeafe432f1e240e4bf30d895cc72c80d..4d8c54c23dd7e320289fadec313d52ec5f333392 100644 (file)
@@ -378,7 +378,6 @@ static void __init offb_init_fb(const char *name, const char *full_name,
        struct fb_fix_screeninfo *fix;
        struct fb_var_screeninfo *var;
        struct fb_info *info;
-       int size;
 
        if (!request_mem_region(res_start, res_size, "offb"))
                return;
@@ -393,15 +392,12 @@ static void __init offb_init_fb(const char *name, const char *full_name,
                return;
        }
 
-       size = sizeof(struct fb_info) + sizeof(u32) * 16;
-
-       info = kmalloc(size, GFP_ATOMIC);
+       info = framebuffer_alloc(sizeof(u32) * 16, NULL);
        
        if (info == 0) {
                release_mem_region(res_start, res_size);
                return;
        }
-       memset(info, 0, size);
 
        fix = &info->fix;
        var = &info->var;
@@ -497,7 +493,7 @@ static void __init offb_init_fb(const char *name, const char *full_name,
                iounmap(par->cmap_adr);
                par->cmap_adr = NULL;
                iounmap(info->screen_base);
-               kfree(info);
+               framebuffer_release(info);
                release_mem_region(res_start, res_size);
                return;
        }
index 7000f2cd58542e54668d58ecb3374e5c6c23d3fb..7fa4ab01b0d36281536875ed1d28e68606d78984 100644 (file)
@@ -134,9 +134,7 @@ struct p9100_par {
        u32                     flags;
 #define P9100_FLAG_BLANKED     0x00000001
 
-       unsigned long           physbase;
        unsigned long           which_io;
-       unsigned long           fbsize;
 };
 
 /**
@@ -224,18 +222,16 @@ static int p9100_mmap(struct fb_info *info, struct vm_area_struct *vma)
        struct p9100_par *par = (struct p9100_par *)info->par;
 
        return sbusfb_mmap_helper(p9100_mmap_map,
-                                 par->physbase, par->fbsize,
+                                 info->fix.smem_start, info->fix.smem_len,
                                  par->which_io, vma);
 }
 
 static int p9100_ioctl(struct fb_info *info, unsigned int cmd,
                       unsigned long arg)
 {
-       struct p9100_par *par = (struct p9100_par *) info->par;
-
        /* Make it look like a cg3. */
        return sbusfb_ioctl_helper(cmd, arg, info,
-                                  FBTYPE_SUN3COLOR, 8, par->fbsize);
+                                  FBTYPE_SUN3COLOR, 8, info->fix.smem_len);
 }
 
 /*
@@ -271,7 +267,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id
        spin_lock_init(&par->lock);
 
        /* This is the framebuffer and the only resource apps can mmap.  */
-       par->physbase = op->resource[2].start;
+       info->fix.smem_start = op->resource[2].start;
        par->which_io = op->resource[2].flags & IORESOURCE_BITS;
 
        sbusfb_fill_var(&info->var, dp, 8);
@@ -280,7 +276,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id
        info->var.blue.length = 8;
 
        linebytes = of_getintprop_default(dp, "linebytes", info->var.xres);
-       par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
+       info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);
 
        par->regs = of_ioremap(&op->resource[0], 0,
                               sizeof(struct p9100_regs), "p9100 regs");
@@ -290,7 +286,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id
        info->flags = FBINFO_DEFAULT;
        info->fbops = &p9100_ops;
        info->screen_base = of_ioremap(&op->resource[2], 0,
-                                      par->fbsize, "p9100 ram");
+                                      info->fix.smem_len, "p9100 ram");
        if (!info->screen_base)
                goto out_unmap_regs;
 
@@ -311,7 +307,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id
 
        printk(KERN_INFO "%s: p9100 at %lx:%lx\n",
               dp->full_name,
-              par->which_io, par->physbase);
+              par->which_io, info->fix.smem_start);
 
        return 0;
 
@@ -319,7 +315,7 @@ out_dealloc_cmap:
        fb_dealloc_cmap(&info->cmap);
 
 out_unmap_screen:
-       of_iounmap(&op->resource[2], info->screen_base, par->fbsize);
+       of_iounmap(&op->resource[2], info->screen_base, info->fix.smem_len);
 
 out_unmap_regs:
        of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs));
@@ -340,7 +336,7 @@ static int __devexit p9100_remove(struct of_device *op)
        fb_dealloc_cmap(&info->cmap);
 
        of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs));
-       of_iounmap(&op->resource[2], info->screen_base, par->fbsize);
+       of_iounmap(&op->resource[2], info->screen_base, info->fix.smem_len);
 
        framebuffer_release(info);
 
index c6dd924976a4f105457bd15c205a2938a07eeee3..36436ee6c1a4f58076b56b9c99f9e6568e613f3a 100644 (file)
@@ -1748,7 +1748,7 @@ static void __devexit pm2fb_remove(struct pci_dev *pdev)
        pci_set_drvdata(pdev, NULL);
        fb_dealloc_cmap(&info->cmap);
        kfree(info->pixmap.addr);
-       kfree(info);
+       framebuffer_release(info);
 }
 
 static struct pci_device_id pm2fb_id_table[] = {
index e00c1dff55de24316d905750619781960328968c..c0af638fe702441c4095d168f4b464769296274c 100644 (file)
 #include <linux/init.h>
 
 #include <asm/abs_addr.h>
+#include <asm/iommu.h>
 #include <asm/lv1call.h>
 #include <asm/ps3av.h>
 #include <asm/ps3fb.h>
 #include <asm/ps3.h>
+#include <asm/ps3gpu.h>
 
 
 #define DEVICE_NAME            "ps3fb"
 
-#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC   0x101
-#define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP   0x102
-#define L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP       0x600
-#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT                0x601
-#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC   0x602
-
-#define L1GPU_FB_BLIT_WAIT_FOR_COMPLETION      (1ULL << 32)
-
-#define L1GPU_DISPLAY_SYNC_HSYNC               1
-#define L1GPU_DISPLAY_SYNC_VSYNC               2
-
 #define GPU_CMD_BUF_SIZE                       (2 * 1024 * 1024)
 #define GPU_FB_START                           (64 * 1024)
 #define GPU_IOIF                               (0x0d000000UL)
@@ -462,33 +453,27 @@ static void ps3fb_sync_image(struct device *dev, u64 frame_offset,
        src_offset += GPU_FB_START;
 
        mutex_lock(&ps3_gpu_mutex);
-       status = lv1_gpu_context_attribute(ps3fb.context_handle,
-                                          L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
-                                          dst_offset, GPU_IOIF + src_offset,
-                                          L1GPU_FB_BLIT_WAIT_FOR_COMPLETION |
-                                          (width << 16) | height,
-                                          line_length);
+       status = lv1_gpu_fb_blit(ps3fb.context_handle, dst_offset,
+                                GPU_IOIF + src_offset,
+                                L1GPU_FB_BLIT_WAIT_FOR_COMPLETION |
+                                (width << 16) | height,
+                                line_length);
        mutex_unlock(&ps3_gpu_mutex);
 
        if (status)
-               dev_err(dev,
-                       "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n",
-                       __func__, status);
+               dev_err(dev, "%s: lv1_gpu_fb_blit failed: %d\n", __func__,
+                       status);
 #ifdef HEAD_A
-       status = lv1_gpu_context_attribute(ps3fb.context_handle,
-                                          L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
-                                          0, frame_offset, 0, 0);
+       status = lv1_gpu_display_flip(ps3fb.context_handle, 0, frame_offset);
        if (status)
-               dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
-                       __func__, status);
+               dev_err(dev, "%s: lv1_gpu_display_flip failed: %d\n", __func__,
+                       status);
 #endif
 #ifdef HEAD_B
-       status = lv1_gpu_context_attribute(ps3fb.context_handle,
-                                          L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
-                                          1, frame_offset, 0, 0);
+       status = lv1_gpu_display_flip(ps3fb.context_handle, 1, frame_offset);
        if (status)
-               dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
-                       __func__, status);
+               dev_err(dev, "%s: lv1_gpu_display_flip failed: %d\n", __func__,
+                       status);
 #endif
 }
 
@@ -956,73 +941,6 @@ static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr)
 }
 
 
-static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo,
-                               struct device *dev)
-{
-       int error;
-
-       dev_dbg(dev, "version_driver:%x\n", dinfo->version_driver);
-       dev_dbg(dev, "irq outlet:%x\n", dinfo->irq.irq_outlet);
-       dev_dbg(dev,
-               "version_gpu: %x memory_size: %x ch: %x core_freq: %d "
-               "mem_freq:%d\n",
-               dinfo->version_gpu, dinfo->memory_size, dinfo->hardware_channel,
-               dinfo->nvcore_frequency/1000000, dinfo->memory_frequency/1000000);
-
-       if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) {
-               dev_err(dev, "%s: version_driver err:%x\n", __func__,
-                       dinfo->version_driver);
-               return -EINVAL;
-       }
-
-       error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet,
-                                  &ps3fb.irq_no);
-       if (error) {
-               dev_err(dev, "%s: ps3_alloc_irq failed %d\n", __func__, error);
-               return error;
-       }
-
-       error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED,
-                           DEVICE_NAME, dev);
-       if (error) {
-               dev_err(dev, "%s: request_irq failed %d\n", __func__, error);
-               ps3_irq_plug_destroy(ps3fb.irq_no);
-               return error;
-       }
-
-       dinfo->irq.mask = (1 << GPU_INTR_STATUS_VSYNC_1) |
-                         (1 << GPU_INTR_STATUS_FLIP_1);
-       return 0;
-}
-
-static int ps3fb_xdr_settings(u64 xdr_lpar, struct device *dev)
-{
-       int status;
-
-       status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF,
-                                      xdr_lpar, ps3fb_videomemory.size, 0);
-       if (status) {
-               dev_err(dev, "%s: lv1_gpu_context_iomap failed: %d\n",
-                       __func__, status);
-               return -ENXIO;
-       }
-       dev_dbg(dev, "video:%p ioif:%lx lpar:%llx size:%lx\n",
-               ps3fb_videomemory.address, GPU_IOIF, xdr_lpar,
-               ps3fb_videomemory.size);
-
-       status = lv1_gpu_context_attribute(ps3fb.context_handle,
-                                          L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP,
-                                          xdr_lpar, GPU_CMD_BUF_SIZE,
-                                          GPU_IOIF, 0);
-       if (status) {
-               dev_err(dev,
-                       "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n",
-                       __func__, status);
-               return -ENXIO;
-       }
-       return 0;
-}
-
 static struct fb_ops ps3fb_ops = {
        .fb_open        = ps3fb_open,
        .fb_release     = ps3fb_release,
@@ -1048,49 +966,18 @@ static struct fb_fix_screeninfo ps3fb_fix __initdata = {
        .accel =        FB_ACCEL_NONE,
 };
 
-static int ps3fb_set_sync(struct device *dev)
-{
-       int status;
-
-#ifdef HEAD_A
-       status = lv1_gpu_context_attribute(0x0,
-                                          L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
-                                          0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
-       if (status) {
-               dev_err(dev,
-                       "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: "
-                       "%d\n",
-                       __func__, status);
-               return -1;
-       }
-#endif
-#ifdef HEAD_B
-       status = lv1_gpu_context_attribute(0x0,
-                                          L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
-                                          1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
-
-       if (status) {
-               dev_err(dev,
-                       "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: "
-                       "%d\n",
-                       __func__, status);
-               return -1;
-       }
-#endif
-       return 0;
-}
-
 static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
 {
        struct fb_info *info;
        struct ps3fb_par *par;
-       int retval = -ENOMEM;
+       int retval;
        u64 ddr_lpar = 0;
        u64 lpar_dma_control = 0;
        u64 lpar_driver_info = 0;
        u64 lpar_reports = 0;
        u64 lpar_reports_size = 0;
        u64 xdr_lpar;
+       struct gpu_driver_info *dinfo;
        void *fb_start;
        int status;
        struct task_struct *task;
@@ -1101,8 +988,8 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
                return -ENOMEM;
        }
 
-       status = ps3_open_hv_device(dev);
-       if (status) {
+       retval = ps3_open_hv_device(dev);
+       if (retval) {
                dev_err(&dev->core, "%s: ps3_open_hv_device failed\n",
                        __func__);
                goto err;
@@ -1116,7 +1003,24 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
        atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */
        init_waitqueue_head(&ps3fb.wait_vsync);
 
-       ps3fb_set_sync(&dev->core);
+#ifdef HEAD_A
+       status = lv1_gpu_display_sync(0x0, 0, L1GPU_DISPLAY_SYNC_VSYNC);
+       if (status) {
+               dev_err(&dev->core, "%s: lv1_gpu_display_sync failed: %d\n",
+                       __func__, status);
+               retval = -ENODEV;
+               goto err_close_device;
+       }
+#endif
+#ifdef HEAD_B
+       status = lv1_gpu_display_sync(0x0, 1, L1GPU_DISPLAY_SYNC_VSYNC);
+       if (status) {
+               dev_err(&dev->core, "%s: lv1_gpu_display_sync failed: %d\n",
+                       __func__, status);
+               retval = -ENODEV;
+               goto err_close_device;
+       }
+#endif
 
        max_ps3fb_size = _ALIGN_UP(GPU_IOIF, 256*1024*1024) - GPU_IOIF;
        if (ps3fb_videomemory.size > max_ps3fb_size) {
@@ -1131,7 +1035,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
        if (status) {
                dev_err(&dev->core, "%s: lv1_gpu_memory_allocate failed: %d\n",
                        __func__, status);
-               goto err;
+               goto err_close_device;
        }
        dev_dbg(&dev->core, "ddr:lpar:0x%llx\n", ddr_lpar);
 
@@ -1141,33 +1045,85 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
                                          &lpar_reports, &lpar_reports_size);
        if (status) {
                dev_err(&dev->core,
-                       "%s: lv1_gpu_context_attribute failed: %d\n", __func__,
+                       "%s: lv1_gpu_context_allocate failed: %d\n", __func__,
                        status);
                goto err_gpu_memory_free;
        }
 
        /* vsync interrupt */
-       ps3fb.dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024);
-       if (!ps3fb.dinfo) {
+       dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024);
+       if (!dinfo) {
                dev_err(&dev->core, "%s: ioremap failed\n", __func__);
                goto err_gpu_context_free;
        }
 
-       retval = ps3fb_vsync_settings(ps3fb.dinfo, &dev->core);
-       if (retval)
+       ps3fb.dinfo = dinfo;
+       dev_dbg(&dev->core, "version_driver:%x\n", dinfo->version_driver);
+       dev_dbg(&dev->core, "irq outlet:%x\n", dinfo->irq.irq_outlet);
+       dev_dbg(&dev->core, "version_gpu: %x memory_size: %x ch: %x "
+               "core_freq: %d mem_freq:%d\n", dinfo->version_gpu,
+               dinfo->memory_size, dinfo->hardware_channel,
+               dinfo->nvcore_frequency/1000000,
+               dinfo->memory_frequency/1000000);
+
+       if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) {
+               dev_err(&dev->core, "%s: version_driver err:%x\n", __func__,
+                       dinfo->version_driver);
+               retval = -EINVAL;
+               goto err_iounmap_dinfo;
+       }
+
+       retval = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet,
+                                   &ps3fb.irq_no);
+       if (retval) {
+               dev_err(&dev->core, "%s: ps3_alloc_irq failed %d\n", __func__,
+                       retval);
                goto err_iounmap_dinfo;
+       }
+
+       retval = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt,
+                            IRQF_DISABLED, DEVICE_NAME, &dev->core);
+       if (retval) {
+               dev_err(&dev->core, "%s: request_irq failed %d\n", __func__,
+                       retval);
+               goto err_destroy_plug;
+       }
+
+       dinfo->irq.mask = (1 << GPU_INTR_STATUS_VSYNC_1) |
+                         (1 << GPU_INTR_STATUS_FLIP_1);
 
        /* Clear memory to prevent kernel info leakage into userspace */
        memset(ps3fb_videomemory.address, 0, ps3fb_videomemory.size);
 
        xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address));
-       retval = ps3fb_xdr_settings(xdr_lpar, &dev->core);
-       if (retval)
+
+       status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF,
+                                      xdr_lpar, ps3fb_videomemory.size,
+                                      CBE_IOPTE_PP_W | CBE_IOPTE_PP_R |
+                                      CBE_IOPTE_M);
+       if (status) {
+               dev_err(&dev->core, "%s: lv1_gpu_context_iomap failed: %d\n",
+                       __func__, status);
+               retval =  -ENXIO;
                goto err_free_irq;
+       }
+
+       dev_dbg(&dev->core, "video:%p ioif:%lx lpar:%llx size:%lx\n",
+               ps3fb_videomemory.address, GPU_IOIF, xdr_lpar,
+               ps3fb_videomemory.size);
+
+       status = lv1_gpu_fb_setup(ps3fb.context_handle, xdr_lpar,
+                                 GPU_CMD_BUF_SIZE, GPU_IOIF);
+       if (status) {
+               dev_err(&dev->core, "%s: lv1_gpu_fb_setup failed: %d\n",
+                       __func__, status);
+               retval = -ENXIO;
+               goto err_context_unmap;
+       }
 
        info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core);
        if (!info)
-               goto err_free_irq;
+               goto err_context_fb_close;
 
        par = info->par;
        par->mode_id = ~ps3fb_mode;     /* != ps3fb_mode, to trigger change */
@@ -1210,7 +1166,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
        if (retval < 0)
                goto err_fb_dealloc;
 
-       dev->core.driver_data = info;
+       ps3_system_bus_set_drvdata(dev, info);
 
        dev_info(info->device, "%s %s, using %u KiB of video memory\n",
                 dev_driver_string(info->dev), dev_name(info->dev),
@@ -1232,8 +1188,14 @@ err_fb_dealloc:
        fb_dealloc_cmap(&info->cmap);
 err_framebuffer_release:
        framebuffer_release(info);
+err_context_fb_close:
+       lv1_gpu_fb_close(ps3fb.context_handle);
+err_context_unmap:
+       lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar,
+                             ps3fb_videomemory.size, CBE_IOPTE_M);
 err_free_irq:
        free_irq(ps3fb.irq_no, &dev->core);
+err_destroy_plug:
        ps3_irq_plug_destroy(ps3fb.irq_no);
 err_iounmap_dinfo:
        iounmap((u8 __force __iomem *)ps3fb.dinfo);
@@ -1241,14 +1203,16 @@ err_gpu_context_free:
        lv1_gpu_context_free(ps3fb.context_handle);
 err_gpu_memory_free:
        lv1_gpu_memory_free(ps3fb.memory_handle);
+err_close_device:
+       ps3_close_hv_device(dev);
 err:
        return retval;
 }
 
 static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
 {
-       int status;
-       struct fb_info *info = dev->core.driver_data;
+       struct fb_info *info = ps3_system_bus_get_drvdata(dev);
+       u64 xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address));
 
        dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__);
 
@@ -1268,20 +1232,14 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
                unregister_framebuffer(info);
                fb_dealloc_cmap(&info->cmap);
                framebuffer_release(info);
-               info = dev->core.driver_data = NULL;
+               ps3_system_bus_set_drvdata(dev, NULL);
        }
        iounmap((u8 __force __iomem *)ps3fb.dinfo);
-
-       status = lv1_gpu_context_free(ps3fb.context_handle);
-       if (status)
-               dev_dbg(&dev->core, "lv1_gpu_context_free failed: %d\n",
-                       status);
-
-       status = lv1_gpu_memory_free(ps3fb.memory_handle);
-       if (status)
-               dev_dbg(&dev->core, "lv1_gpu_memory_free failed: %d\n",
-                       status);
-
+       lv1_gpu_fb_close(ps3fb.context_handle);
+       lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar,
+                             ps3fb_videomemory.size, CBE_IOPTE_M);
+       lv1_gpu_context_free(ps3fb.context_handle);
+       lv1_gpu_memory_free(ps3fb.memory_handle);
        ps3_close_hv_device(dev);
        dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
 
index 0726aecf3b7e084c87f6abdc66ca44f4c16cb631..0deb0a8867b74af88560e7f867f36c262084f17a 100644 (file)
@@ -2,6 +2,7 @@
  *
  * (c) 2004 Simtec Electronics
  * (c) 2005 Thibaut VARENE <varenet@parisc-linux.org>
+ * (c) 2009 Kristoffer Ericson <kristoffer.ericson@gmail.com>
  *
  * Driver for Epson S1D13xxx series framebuffer chips
  *
  *  linux/drivers/video/epson1355fb.c
  *  linux/drivers/video/epson/s1d13xxxfb.c (2.4 driver by Epson)
  *
- * Note, currently only tested on S1D13806 with 16bit CRT.
- * As such, this driver might still contain some hardcoded bits relating to
- * S1D13806.
- * Making it work on other S1D13XXX chips should merely be a matter of adding
- * a few switch()s, some missing glue here and there maybe, and split header
- * files.
- *
  * TODO: - handle dual screen display (CRT and LCD at the same time).
  *      - check_var(), mode change, etc.
- *      - PM untested.
- *      - Accelerated interfaces.
- *      - Probably not SMP safe :)
+ *      - probably not SMP safe :)
+ *       - support all bitblt operations on all cards
  *
  * 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
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
-
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
 #include <linux/fb.h>
+#include <linux/spinlock_types.h>
+#include <linux/spinlock.h>
 
 #include <asm/io.h>
 
 #include <video/s1d13xxxfb.h>
 
-#define PFX "s1d13xxxfb: "
+#define PFX    "s1d13xxxfb: "
+#define BLIT   "s1d13xxxfb_bitblt: "
 
+/*
+ * set this to enable debugging on general functions
+ */
 #if 0
 #define dbg(fmt, args...) do { printk(KERN_INFO fmt, ## args); } while(0)
 #else
 #endif
 
 /*
- * List of card production ids
+ * set this to enable debugging on 2D acceleration
+ */
+#if 0
+#define dbg_blit(fmt, args...) do { printk(KERN_INFO BLIT fmt, ## args); } while (0)
+#else
+#define dbg_blit(fmt, args...) do { } while (0)
+#endif
+
+/*
+ * we make sure only one bitblt operation is running
+ */
+static DEFINE_SPINLOCK(s1d13xxxfb_bitblt_lock);
+
+/*
+ * list of card production ids
  */
 static const int s1d13xxxfb_prod_ids[] = {
        S1D13505_PROD_ID,
@@ -69,7 +81,7 @@ static const char *s1d13xxxfb_prod_names[] = {
 };
 
 /*
- * Here we define the default struct fb_fix_screeninfo
+ * here we define the default struct fb_fix_screeninfo
  */
 static struct fb_fix_screeninfo __devinitdata s1d13xxxfb_fix = {
        .id             = S1D_FBID,
@@ -145,8 +157,10 @@ crt_enable(struct s1d13xxxfb_par *par, int enable)
        s1d13xxxfb_writereg(par, S1DREG_COM_DISP_MODE, mode);
 }
 
-/* framebuffer control routines */
 
+/*************************************************************
+ framebuffer control functions
+ *************************************************************/
 static inline void
 s1d13xxxfb_setup_pseudocolour(struct fb_info *info)
 {
@@ -242,13 +256,13 @@ s1d13xxxfb_set_par(struct fb_info *info)
 }
 
 /**
- *     s1d13xxxfb_setcolreg - sets a color register.
- *      @regno: Which register in the CLUT we are programming
- *      @red: The red value which can be up to 16 bits wide
+ *     s1d13xxxfb_setcolreg - sets a color register.
+ *     @regno: Which register in the CLUT we are programming
+ *     @red: The red value which can be up to 16 bits wide
  *     @green: The green value which can be up to 16 bits wide
  *     @blue:  The blue value which can be up to 16 bits wide.
  *     @transp: If supported the alpha value which can be up to 16 bits wide.
- *      @info: frame buffer info structure
+ *     @info: frame buffer info structure
  *
  *     Returns negative errno on error, or zero on success.
  */
@@ -351,15 +365,15 @@ s1d13xxxfb_blank(int blank_mode, struct fb_info *info)
 }
 
 /**
- *      s1d13xxxfb_pan_display - Pans the display.
- *      @var: frame buffer variable screen structure
- *      @info: frame buffer structure that represents a single frame buffer
+ *     s1d13xxxfb_pan_display - Pans the display.
+ *     @var: frame buffer variable screen structure
+ *     @info: frame buffer structure that represents a single frame buffer
  *
  *     Pan (or wrap, depending on the `vmode' field) the display using the
- *     `yoffset' field of the `var' structure (`xoffset'  not yet supported).
- *     If the values don't fit, return -EINVAL.
+ *     `yoffset' field of the `var' structure (`xoffset'  not yet supported).
+ *     If the values don't fit, return -EINVAL.
  *
- *      Returns negative errno on error, or zero on success.
+ *     Returns negative errno on error, or zero on success.
  */
 static int
 s1d13xxxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
@@ -390,8 +404,259 @@ s1d13xxxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
        return 0;
 }
 
-/* framebuffer information structures */
+/************************************************************
+ functions to handle bitblt acceleration
+ ************************************************************/
+
+/**
+ *     bltbit_wait_bitset - waits for change in register value
+ *     @info : framebuffer structure
+ *     @bit  : value expected in register
+ *     @timeout : ...
+ *
+ *     waits until value changes INTO bit
+ */
+static u8
+bltbit_wait_bitset(struct fb_info *info, u8 bit, int timeout)
+{
+       while (!(s1d13xxxfb_readreg(info->par, S1DREG_BBLT_CTL0) & bit)) {
+               udelay(10);
+               if (!--timeout) {
+                       dbg_blit("wait_bitset timeout\n");
+                       break;
+               }
+       }
+
+       return timeout;
+}
+
+/**
+ *     bltbit_wait_bitclear - waits for change in register value
+ *     @info : frambuffer structure
+ *     @bit  : value currently in register
+ *     @timeout : ...
+ *
+ *     waits until value changes FROM bit
+ *
+ */
+static u8
+bltbit_wait_bitclear(struct fb_info *info, u8 bit, int timeout)
+{
+       while (s1d13xxxfb_readreg(info->par, S1DREG_BBLT_CTL0) & bit) {
+               udelay(10);
+               if (!--timeout) {
+                       dbg_blit("wait_bitclear timeout\n");
+                       break;
+               }
+       }
+
+       return timeout;
+}
+
+/**
+ *     bltbit_fifo_status - checks the current status of the fifo
+ *     @info : framebuffer structure
+ *
+ *     returns number of free words in buffer
+ */
+static u8
+bltbit_fifo_status(struct fb_info *info)
+{
+       u8 status;
 
+       status = s1d13xxxfb_readreg(info->par, S1DREG_BBLT_CTL0);
+
+       /* its empty so room for 16 words */
+       if (status & BBLT_FIFO_EMPTY)
+               return 16;
+
+       /* its full so we dont want to add */
+       if (status & BBLT_FIFO_FULL)
+               return 0;
+
+       /* its atleast half full but we can add one atleast */
+       if (status & BBLT_FIFO_NOT_FULL)
+               return 1;
+
+       return 0;
+}
+
+/*
+ *     s1d13xxxfb_bitblt_copyarea - accelerated copyarea function
+ *     @info : framebuffer structure
+ *     @area : fb_copyarea structure
+ *
+ *     supports (atleast) S1D13506
+ *
+ */
+static void
+s1d13xxxfb_bitblt_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+       u32 dst, src;
+       u32 stride;
+       u16 reverse = 0;
+       u16 sx = area->sx, sy = area->sy;
+       u16 dx = area->dx, dy = area->dy;
+       u16 width = area->width, height = area->height;
+       u16 bpp;
+
+       spin_lock(&s1d13xxxfb_bitblt_lock);
+
+       /* bytes per xres line */
+       bpp = (info->var.bits_per_pixel >> 3);
+       stride = bpp * info->var.xres;
+
+       /* reverse, calculate the last pixel in rectangle */
+       if ((dy > sy) || ((dy == sy) && (dx >= sx))) {
+               dst = (((dy + height - 1) * stride) + (bpp * (dx + width - 1)));
+               src = (((sy + height - 1) * stride) + (bpp * (sx + width - 1)));
+               reverse = 1;
+       /* not reverse, calculate the first pixel in rectangle */
+       } else { /* (y * xres) + (bpp * x) */
+               dst = (dy * stride) + (bpp * dx);
+               src = (sy * stride) + (bpp * sx);
+       }
+
+       /* set source adress */
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_SRC_START0, (src & 0xff));
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_SRC_START1, (src >> 8) & 0x00ff);
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_SRC_START2, (src >> 16) & 0x00ff);
+
+       /* set destination adress */
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START0, (dst & 0xff));
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START1, (dst >> 8) & 0x00ff);
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START2, (dst >> 16) & 0x00ff);
+
+       /* program height and width */
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_WIDTH0, (width & 0xff) - 1);
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_WIDTH1, (width >> 8));
+
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_HEIGHT0, (height & 0xff) - 1);
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_HEIGHT1, (height >> 8));
+
+       /* negative direction ROP */
+       if (reverse == 1) {
+               dbg_blit("(copyarea) negative rop\n");
+               s1d13xxxfb_writereg(info->par, S1DREG_BBLT_OP, 0x03);
+       } else /* positive direction ROP */ {
+               s1d13xxxfb_writereg(info->par, S1DREG_BBLT_OP, 0x02);
+               dbg_blit("(copyarea) positive rop\n");
+       }
+
+       /* set for rectangel mode and not linear */
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL0, 0x0);
+
+       /* setup the bpp 1 = 16bpp, 0 = 8bpp*/
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL1, (bpp >> 1));
+
+       /* set words per xres */
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_MEM_OFF0, (stride >> 1) & 0xff);
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_MEM_OFF1, (stride >> 9));
+
+       dbg_blit("(copyarea) dx=%d, dy=%d\n", dx, dy);
+       dbg_blit("(copyarea) sx=%d, sy=%d\n", sx, sy);
+       dbg_blit("(copyarea) width=%d, height=%d\n", width - 1, height - 1);
+       dbg_blit("(copyarea) stride=%d\n", stride);
+       dbg_blit("(copyarea) bpp=%d=0x0%d, mem_offset1=%d, mem_offset2=%d\n", bpp, (bpp >> 1),
+               (stride >> 1) & 0xff, stride >> 9);
+
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CC_EXP, 0x0c);
+
+       /* initialize the engine */
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL0, 0x80);
+
+       /* wait to complete */
+       bltbit_wait_bitclear(info, 0x80, 8000);
+
+       spin_unlock(&s1d13xxxfb_bitblt_lock);
+}
+
+/**
+ *
+ *     s1d13xxxfb_bitblt_solidfill - accelerated solidfill function
+ *     @info : framebuffer structure
+ *     @rect : fb_fillrect structure
+ *
+ *     supports (atleast 13506)
+ *
+ **/
+static void
+s1d13xxxfb_bitblt_solidfill(struct fb_info *info, const struct fb_fillrect *rect)
+{
+       u32 screen_stride, dest;
+       u32 fg;
+       u16 bpp = (info->var.bits_per_pixel >> 3);
+
+       /* grab spinlock */
+       spin_lock(&s1d13xxxfb_bitblt_lock);
+
+       /* bytes per x width */
+       screen_stride = (bpp * info->var.xres);
+
+       /* bytes to starting point */
+       dest = ((rect->dy * screen_stride) + (bpp * rect->dx));
+
+       dbg_blit("(solidfill) dx=%d, dy=%d, stride=%d, dest=%d\n"
+                "(solidfill) : rect_width=%d, rect_height=%d\n",
+                               rect->dx, rect->dy, screen_stride, dest,
+                               rect->width - 1, rect->height - 1);
+
+       dbg_blit("(solidfill) : xres=%d, yres=%d, bpp=%d\n",
+                               info->var.xres, info->var.yres,
+                               info->var.bits_per_pixel);
+       dbg_blit("(solidfill) : rop=%d\n", rect->rop);
+
+       /* We split the destination into the three registers */
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START0, (dest & 0x00ff));
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START1, ((dest >> 8) & 0x00ff));
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_DST_START2, ((dest >> 16) & 0x00ff));
+
+       /* give information regarding rectangel width */
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_WIDTH0, ((rect->width) & 0x00ff) - 1);
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_WIDTH1, (rect->width >> 8));
+
+       /* give information regarding rectangel height */
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_HEIGHT0, ((rect->height) & 0x00ff) - 1);
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_HEIGHT1, (rect->height >> 8));
+
+       if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
+               info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+               fg = ((u32 *)info->pseudo_palette)[rect->color];
+               dbg_blit("(solidfill) truecolor/directcolor\n");
+               dbg_blit("(solidfill) pseudo_palette[%d] = %d\n", rect->color, fg);
+       } else {
+               fg = rect->color;
+               dbg_blit("(solidfill) color = %d\n", rect->color);
+       }
+
+       /* set foreground color */
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_FGC0, (fg & 0xff));
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_FGC1, (fg >> 8) & 0xff);
+
+       /* set rectangual region of memory (rectangle and not linear) */
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL0, 0x0);
+
+       /* set operation mode SOLID_FILL */
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_OP, BBLT_SOLID_FILL);
+
+       /* set bits per pixel (1 = 16bpp, 0 = 8bpp) */
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL1, (info->var.bits_per_pixel >> 4));
+
+       /* set the memory offset for the bblt in word sizes */
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_MEM_OFF0, (screen_stride >> 1) & 0x00ff);
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_MEM_OFF1, (screen_stride >> 9));
+
+       /* and away we go.... */
+       s1d13xxxfb_writereg(info->par, S1DREG_BBLT_CTL0, 0x80);
+
+       /* wait until its done */
+       bltbit_wait_bitclear(info, 0x80, 8000);
+
+       /* let others play */
+       spin_unlock(&s1d13xxxfb_bitblt_lock);
+}
+
+/* framebuffer information structures */
 static struct fb_ops s1d13xxxfb_fbops = {
        .owner          = THIS_MODULE,
        .fb_set_par     = s1d13xxxfb_set_par,
@@ -400,7 +665,7 @@ static struct fb_ops s1d13xxxfb_fbops = {
 
        .fb_pan_display = s1d13xxxfb_pan_display,
 
-       /* to be replaced by any acceleration we can */
+       /* gets replaced at chip detection time */
        .fb_fillrect    = cfb_fillrect,
        .fb_copyarea    = cfb_copyarea,
        .fb_imageblit   = cfb_imageblit,
@@ -412,9 +677,9 @@ static int s1d13xxxfb_width_tab[2][4] __devinitdata = {
 };
 
 /**
- *      s1d13xxxfb_fetch_hw_state - Configure the framebuffer according to
+ *     s1d13xxxfb_fetch_hw_state - Configure the framebuffer according to
  *     hardware setup.
- *      @info: frame buffer structure
+ *     @info: frame buffer structure
  *
  *     We setup the framebuffer structures according to the current
  *     hardware setup. On some machines, the BIOS will have filled
@@ -569,7 +834,6 @@ s1d13xxxfb_probe(struct platform_device *pdev)
        if (pdata && pdata->platform_init_video)
                pdata->platform_init_video();
 
-
        if (pdev->num_resources != 2) {
                dev_err(&pdev->dev, "invalid num_resources: %i\n",
                       pdev->num_resources);
@@ -655,16 +919,27 @@ s1d13xxxfb_probe(struct platform_device *pdev)
 
        info->fix = s1d13xxxfb_fix;
        info->fix.mmio_start = pdev->resource[1].start;
-       info->fix.mmio_len = pdev->resource[1].end - pdev->resource[1].start +1;
+       info->fix.mmio_len = pdev->resource[1].end - pdev->resource[1].start + 1;
        info->fix.smem_start = pdev->resource[0].start;
-       info->fix.smem_len = pdev->resource[0].end - pdev->resource[0].start +1;
+       info->fix.smem_len = pdev->resource[0].end - pdev->resource[0].start + 1;
 
        printk(KERN_INFO PFX "regs mapped at 0x%p, fb %d KiB mapped at 0x%p\n",
               default_par->regs, info->fix.smem_len / 1024, info->screen_base);
 
        info->par = default_par;
-       info->fbops = &s1d13xxxfb_fbops;
        info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+       info->fbops = &s1d13xxxfb_fbops;
+
+       switch(prod_id) {
+       case S1D13506_PROD_ID:  /* activate acceleration */
+               s1d13xxxfb_fbops.fb_fillrect = s1d13xxxfb_bitblt_solidfill;
+               s1d13xxxfb_fbops.fb_copyarea = s1d13xxxfb_bitblt_copyarea;
+               info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN |
+                       FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_COPYAREA;
+               break;
+       default:
+               break;
+       }
 
        /* perform "manual" chip initialization, if needed */
        if (pdata && pdata->initregs)
index d3a568e6b169c4d1a0a122880dfb4a0b3a5bb9ac..43680e545427f190b432252acb6bfe518219f089 100644 (file)
@@ -358,9 +358,16 @@ static int s3c_fb_set_par(struct fb_info *info)
        writel(data, regs + VIDOSD_B(win_no));
 
        data = var->xres * var->yres;
+
+       u32 osdc_data = 0;
+
+       osdc_data = VIDISD14C_ALPHA1_R(0xf) |
+               VIDISD14C_ALPHA1_G(0xf) |
+               VIDISD14C_ALPHA1_B(0xf);
+
        if (s3c_fb_has_osd_d(win_no)) {
                writel(data, regs + VIDOSD_D(win_no));
-               writel(0, regs + VIDOSD_C(win_no));
+               writel(osdc_data, regs + VIDOSD_C(win_no));
        } else
                writel(data, regs + VIDOSD_C(win_no));
 
@@ -409,8 +416,12 @@ static int s3c_fb_set_par(struct fb_info *info)
                                data |= WINCON1_BPPMODE_19BPP_A1666;
                        else
                                data |= WINCON1_BPPMODE_18BPP_666;
-               } else if (var->transp.length != 0)
-                       data |= WINCON1_BPPMODE_25BPP_A1888;
+               } else if (var->transp.length == 1)
+                       data |= WINCON1_BPPMODE_25BPP_A1888
+                               | WINCON1_BLD_PIX;
+               else if (var->transp.length == 4)
+                       data |= WINCON1_BPPMODE_28BPP_A4888
+                               | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL;
                else
                        data |= WINCON0_BPPMODE_24BPP_888;
 
@@ -418,6 +429,20 @@ static int s3c_fb_set_par(struct fb_info *info)
                break;
        }
 
+       /* It has no color key control register for window0 */
+       if (win_no > 0) {
+               u32 keycon0_data = 0, keycon1_data = 0;
+
+               keycon0_data = ~(WxKEYCON0_KEYBL_EN |
+                               WxKEYCON0_KEYEN_F |
+                               WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0);
+
+               keycon1_data = WxKEYCON1_COLVAL(0xffffff);
+
+               writel(keycon0_data, regs + WxKEYCONy(win_no-1, 0));
+               writel(keycon1_data, regs + WxKEYCONy(win_no-1, 1));
+       }
+
        writel(data, regs + WINCON(win_no));
        writel(0x0, regs + WINxMAP(win_no));
 
@@ -700,9 +725,12 @@ static void s3c_fb_free_memory(struct s3c_fb *sfb, struct s3c_fb_win *win)
  */
 static void s3c_fb_release_win(struct s3c_fb *sfb, struct s3c_fb_win *win)
 {
-       fb_dealloc_cmap(&win->fbinfo->cmap);
-       unregister_framebuffer(win->fbinfo);
-       s3c_fb_free_memory(sfb, win);
+       if (win->fbinfo) {
+               unregister_framebuffer(win->fbinfo);
+               fb_dealloc_cmap(&win->fbinfo->cmap);
+               s3c_fb_free_memory(sfb, win);
+               framebuffer_release(win->fbinfo);
+       }
 }
 
 /**
@@ -753,7 +781,7 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
        ret = s3c_fb_alloc_memory(sfb, win);
        if (ret) {
                dev_err(sfb->dev, "failed to allocate display memory\n");
-               goto err_framebuffer;
+               return ret;
        }
 
        /* setup the r/b/g positions for the window's palette */
@@ -776,7 +804,7 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
        ret = s3c_fb_check_var(&fbinfo->var, fbinfo);
        if (ret < 0) {
                dev_err(sfb->dev, "check_var failed on initial video params\n");
-               goto err_alloc_mem;
+               return ret;
        }
 
        /* create initial colour map */
@@ -796,20 +824,13 @@ static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
        ret = register_framebuffer(fbinfo);
        if (ret < 0) {
                dev_err(sfb->dev, "failed to register framebuffer\n");
-               goto err_alloc_mem;
+               return ret;
        }
 
        *res = win;
        dev_info(sfb->dev, "window %d: fb %s\n", win_no, fbinfo->fix.id);
 
        return 0;
-
-err_alloc_mem:
-       s3c_fb_free_memory(sfb, win);
-
-err_framebuffer:
-       unregister_framebuffer(fbinfo);
-       return ret;
 }
 
 /**
index b0b4513ba53784014c6bf0c6c60fc576d7f054f7..7da0027e2409f498ac88a175c78e1fb9f0f4b30e 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/cpufreq.h>
 
 #include <asm/io.h>
 #include <asm/div64.h>
@@ -89,7 +90,7 @@ static void s3c2410fb_set_lcdaddr(struct fb_info *info)
 static unsigned int s3c2410fb_calc_pixclk(struct s3c2410fb_info *fbi,
                                          unsigned long pixclk)
 {
-       unsigned long clk = clk_get_rate(fbi->clk);
+       unsigned long clk = fbi->clk_rate;
        unsigned long long div;
 
        /* pixclk is in picoseconds, our clock is in Hz
@@ -758,6 +759,57 @@ static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_CPU_FREQ
+
+static int s3c2410fb_cpufreq_transition(struct notifier_block *nb,
+                                       unsigned long val, void *data)
+{
+       struct cpufreq_freqs *freqs = data;
+       struct s3c2410fb_info *info;
+       struct fb_info *fbinfo;
+       long delta_f;
+
+       info = container_of(nb, struct s3c2410fb_info, freq_transition);
+       fbinfo = platform_get_drvdata(to_platform_device(info->dev));
+
+       /* work out change, <0 for speed-up */
+       delta_f = info->clk_rate - clk_get_rate(info->clk);
+
+       if ((val == CPUFREQ_POSTCHANGE && delta_f > 0) ||
+           (val == CPUFREQ_PRECHANGE && delta_f < 0)) {
+               info->clk_rate = clk_get_rate(info->clk);
+               s3c2410fb_activate_var(fbinfo);
+       }
+
+       return 0;
+}
+
+static inline int s3c2410fb_cpufreq_register(struct s3c2410fb_info *info)
+{
+       info->freq_transition.notifier_call = s3c2410fb_cpufreq_transition;
+
+       return cpufreq_register_notifier(&info->freq_transition,
+                                        CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info)
+{
+       cpufreq_unregister_notifier(&info->freq_transition,
+                                   CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+#else
+static inline int s3c2410fb_cpufreq_register(struct s3c2410fb_info *info)
+{
+       return 0;
+}
+
+static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info)
+{
+}
+#endif
+
+
 static char driver_name[] = "s3c2410fb";
 
 static int __init s3c24xxfb_probe(struct platform_device *pdev,
@@ -875,6 +927,8 @@ static int __init s3c24xxfb_probe(struct platform_device *pdev,
 
        msleep(1);
 
+       info->clk_rate = clk_get_rate(info->clk);
+
        /* find maximum required memory size for display */
        for (i = 0; i < mach_info->num_displays; i++) {
                unsigned long smem_len = mach_info->displays[i].xres;
@@ -904,11 +958,17 @@ static int __init s3c24xxfb_probe(struct platform_device *pdev,
 
        s3c2410fb_check_var(&fbinfo->var, fbinfo);
 
+       ret = s3c2410fb_cpufreq_register(info);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to register cpufreq\n");
+               goto free_video_memory;
+       }
+
        ret = register_framebuffer(fbinfo);
        if (ret < 0) {
                printk(KERN_ERR "Failed to register framebuffer device: %d\n",
                        ret);
-               goto free_video_memory;
+               goto free_cpufreq;
        }
 
        /* create device files */
@@ -922,6 +982,8 @@ static int __init s3c24xxfb_probe(struct platform_device *pdev,
 
        return 0;
 
+ free_cpufreq:
+       s3c2410fb_cpufreq_deregister(info);
 free_video_memory:
        s3c2410fb_unmap_video_memory(fbinfo);
 release_clock:
@@ -961,6 +1023,7 @@ static int s3c2410fb_remove(struct platform_device *pdev)
        int irq;
 
        unregister_framebuffer(fbinfo);
+       s3c2410fb_cpufreq_deregister(info);
 
        s3c2410fb_lcd_enable(info, 0);
        msleep(1);
index 9a6ba3e9d1b823bf7a9dc7db874cc37e7c26645f..47a17bd2301169d9368d041b83d2b2b9d80835bf 100644 (file)
@@ -29,8 +29,13 @@ struct s3c2410fb_info {
        enum s3c_drv_type       drv_type;
        struct s3c2410fb_hw     regs;
 
+       unsigned long           clk_rate;
        unsigned int            palette_ready;
 
+#ifdef CONFIG_CPU_FREQ
+       struct notifier_block   freq_transition;
+#endif
+
        /* keep these registers in case we need to re-write palette */
        u32                     palette_buffer[256];
        u32                     pseudo_pal[16];
index 7e17ee95a97aa41b4a990ac395453ad19e10d4da..7072d19080d584dbaf2f754dd31c177251932de4 100644 (file)
@@ -5928,7 +5928,7 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                if(pci_enable_device(pdev)) {
                        if(ivideo->nbridge) pci_dev_put(ivideo->nbridge);
                        pci_set_drvdata(pdev, NULL);
-                       kfree(sis_fb_info);
+                       framebuffer_release(sis_fb_info);
                        return -EIO;
                }
        }
@@ -6134,7 +6134,7 @@ error_3:  vfree(ivideo->bios_abase);
                pci_set_drvdata(pdev, NULL);
                if(!ivideo->sisvga_enabled)
                        pci_disable_device(pdev);
-               kfree(sis_fb_info);
+               framebuffer_release(sis_fb_info);
                return ret;
        }
 
index eabaad765aebcdf1e975c8d68108e098a330175d..eec9dcb7f59976f2a9fe337322fb82724a4ed5fe 100644 (file)
@@ -1380,7 +1380,7 @@ stifb_cleanup(void)
                                if (info->screen_base)
                                        iounmap(info->screen_base);
                        fb_dealloc_cmap(&info->cmap);
-                       kfree(info); 
+                       framebuffer_release(info);
                }
                sti->info = NULL;
        }
index 643afbfe8277bfe9bf03bf35a80c5d4a83e98841..45b883598bf02739083c19ba32106fe527dda081 100644 (file)
@@ -116,17 +116,16 @@ struct tcx_par {
        u32                     flags;
 #define TCX_FLAG_BLANKED       0x00000001
 
-       unsigned long           physbase;
        unsigned long           which_io;
-       unsigned long           fbsize;
 
        struct sbus_mmap_map    mmap_map[TCX_MMAP_ENTRIES];
        int                     lowdepth;
 };
 
 /* Reset control plane so that WID is 8-bit plane. */
-static void __tcx_set_control_plane(struct tcx_par *par)
+static void __tcx_set_control_plane(struct fb_info *info)
 {
+       struct tcx_par *par = info->par;
        u32 __iomem *p, *pend;
 
        if (par->lowdepth)
@@ -135,7 +134,7 @@ static void __tcx_set_control_plane(struct tcx_par *par)
        p = par->cplane;
        if (p == NULL)
                return;
-       for (pend = p + par->fbsize; p < pend; p++) {
+       for (pend = p + info->fix.smem_len; p < pend; p++) {
                u32 tmp = sbus_readl(p);
 
                tmp &= 0xffffff;
@@ -149,7 +148,7 @@ static void tcx_reset(struct fb_info *info)
        unsigned long flags;
 
        spin_lock_irqsave(&par->lock, flags);
-       __tcx_set_control_plane(par);
+       __tcx_set_control_plane(info);
        spin_unlock_irqrestore(&par->lock, flags);
 }
 
@@ -304,7 +303,7 @@ static int tcx_mmap(struct fb_info *info, struct vm_area_struct *vma)
        struct tcx_par *par = (struct tcx_par *)info->par;
 
        return sbusfb_mmap_helper(par->mmap_map,
-                                 par->physbase, par->fbsize,
+                                 info->fix.smem_start, info->fix.smem_len,
                                  par->which_io, vma);
 }
 
@@ -316,7 +315,7 @@ static int tcx_ioctl(struct fb_info *info, unsigned int cmd,
        return sbusfb_ioctl_helper(cmd, arg, info,
                                   FBTYPE_TCXCOLOR,
                                   (par->lowdepth ? 8 : 24),
-                                  par->fbsize);
+                                  info->fix.smem_len);
 }
 
 /*
@@ -358,10 +357,10 @@ static void tcx_unmap_regs(struct of_device *op, struct fb_info *info,
                           par->bt, sizeof(struct bt_regs));
        if (par->cplane)
                of_iounmap(&op->resource[4],
-                          par->cplane, par->fbsize * sizeof(u32));
+                          par->cplane, info->fix.smem_len * sizeof(u32));
        if (info->screen_base)
                of_iounmap(&op->resource[0],
-                          info->screen_base, par->fbsize);
+                          info->screen_base, info->fix.smem_len);
 }
 
 static int __devinit tcx_probe(struct of_device *op,
@@ -391,7 +390,7 @@ static int __devinit tcx_probe(struct of_device *op,
 
        linebytes = of_getintprop_default(dp, "linebytes",
                                          info->var.xres);
-       par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
+       info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);
 
        par->tec = of_ioremap(&op->resource[7], 0,
                                  sizeof(struct tcx_tec), "tcx tec");
@@ -400,7 +399,7 @@ static int __devinit tcx_probe(struct of_device *op,
        par->bt = of_ioremap(&op->resource[8], 0,
                                 sizeof(struct bt_regs), "tcx dac");
        info->screen_base = of_ioremap(&op->resource[0], 0,
-                                          par->fbsize, "tcx ram");
+                                          info->fix.smem_len, "tcx ram");
        if (!par->tec || !par->thc ||
            !par->bt || !info->screen_base)
                goto out_unmap_regs;
@@ -408,7 +407,7 @@ static int __devinit tcx_probe(struct of_device *op,
        memcpy(&par->mmap_map, &__tcx_mmap_map, sizeof(par->mmap_map));
        if (!par->lowdepth) {
                par->cplane = of_ioremap(&op->resource[4], 0,
-                                            par->fbsize * sizeof(u32),
+                                            info->fix.smem_len * sizeof(u32),
                                             "tcx cplane");
                if (!par->cplane)
                        goto out_unmap_regs;
@@ -419,7 +418,7 @@ static int __devinit tcx_probe(struct of_device *op,
                par->mmap_map[6].size = SBUS_MMAP_EMPTY;
        }
 
-       par->physbase = op->resource[0].start;
+       info->fix.smem_start = op->resource[0].start;
        par->which_io = op->resource[0].flags & IORESOURCE_BITS;
 
        for (i = 0; i < TCX_MMAP_ENTRIES; i++) {
@@ -473,7 +472,7 @@ static int __devinit tcx_probe(struct of_device *op,
        printk(KERN_INFO "%s: TCX at %lx:%lx, %s\n",
               dp->full_name,
               par->which_io,
-              par->physbase,
+              info->fix.smem_start,
               par->lowdepth ? "8-bit only" : "24-bit depth");
 
        return 0;
index 89f231dc443f0b191701cae247aca0f29c4785f2..ff43c8885028e2f20eb928cc2119977373a3d135 100644 (file)
@@ -1315,7 +1315,6 @@ static int __devinit tdfxfb_setup_i2c_bus(struct tdfxfb_i2c_chan *chan,
 
        strlcpy(chan->adapter.name, name, sizeof(chan->adapter.name));
        chan->adapter.owner             = THIS_MODULE;
-       chan->adapter.class             = I2C_CLASS_TV_ANALOG;
        chan->adapter.algo_data         = &chan->algo;
        chan->adapter.dev.parent        = dev;
        chan->algo.setsda               = tdfxfb_i2c_setsda;
index d6856f43d241df13d14ab43113c9472387ecbdef..bd37ee1f6a251bce027920a4eab805b0bbcfc3de 100644 (file)
@@ -174,8 +174,17 @@ static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green,
        return err;
 }
 
+static void vesafb_destroy(struct fb_info *info)
+{
+       if (info->screen_base)
+               iounmap(info->screen_base);
+       release_mem_region(info->aperture_base, info->aperture_size);
+       framebuffer_release(info);
+}
+
 static struct fb_ops vesafb_ops = {
        .owner          = THIS_MODULE,
+       .fb_destroy     = vesafb_destroy,
        .fb_setcolreg   = vesafb_setcolreg,
        .fb_pan_display = vesafb_pan_display,
        .fb_fillrect    = cfb_fillrect,
@@ -286,6 +295,10 @@ static int __init vesafb_probe(struct platform_device *dev)
        info->pseudo_palette = info->par;
        info->par = NULL;
 
+       /* set vesafb aperture size for generic probing */
+       info->aperture_base = screen_info.lfb_base;
+       info->aperture_size = size_total;
+
        info->screen_base = ioremap(vesafb_fix.smem_start, vesafb_fix.smem_len);
        if (!info->screen_base) {
                printk(KERN_ERR
@@ -437,7 +450,7 @@ static int __init vesafb_probe(struct platform_device *dev)
        info->fbops = &vesafb_ops;
        info->var = vesafb_defined;
        info->fix = vesafb_fix;
-       info->flags = FBINFO_FLAG_DEFAULT |
+       info->flags = FBINFO_FLAG_DEFAULT | FBINFO_MISC_FIRMWARE |
                (ypan ? FBINFO_HWACCEL_YPAN : 0);
 
        if (!ypan)
index 2493f05e9f6176588c0f0fc3471097f62c8ae68d..15502d5e3641890f1f6646cc661b5e26d4755753 100644 (file)
@@ -384,7 +384,7 @@ static int __devinit xenfb_probe(struct xenbus_device *dev,
                fb_size = XENFB_DEFAULT_FB_LEN;
        }
 
-       dev->dev.driver_data = info;
+       dev_set_drvdata(&dev->dev, info);
        info->xbdev = dev;
        info->irq = -1;
        info->x1 = info->y1 = INT_MAX;
@@ -503,7 +503,7 @@ xenfb_make_preferred_console(void)
 
 static int xenfb_resume(struct xenbus_device *dev)
 {
-       struct xenfb_info *info = dev->dev.driver_data;
+       struct xenfb_info *info = dev_get_drvdata(&dev->dev);
 
        xenfb_disconnect_backend(info);
        xenfb_init_shared_page(info, info->fb_info);
@@ -512,7 +512,7 @@ static int xenfb_resume(struct xenbus_device *dev)
 
 static int xenfb_remove(struct xenbus_device *dev)
 {
-       struct xenfb_info *info = dev->dev.driver_data;
+       struct xenfb_info *info = dev_get_drvdata(&dev->dev);
 
        xenfb_disconnect_backend(info);
        if (info->fb_info) {
@@ -621,7 +621,7 @@ static void xenfb_disconnect_backend(struct xenfb_info *info)
 static void xenfb_backend_changed(struct xenbus_device *dev,
                                  enum xenbus_state backend_state)
 {
-       struct xenfb_info *info = dev->dev.driver_data;
+       struct xenfb_info *info = dev_get_drvdata(&dev->dev);
        int val;
 
        switch (backend_state) {
diff --git a/drivers/vlynq/Kconfig b/drivers/vlynq/Kconfig
new file mode 100644 (file)
index 0000000..f654221
--- /dev/null
@@ -0,0 +1,20 @@
+menu "TI VLYNQ"
+
+config VLYNQ
+       bool "TI VLYNQ bus support"
+       depends on AR7 && EXPERIMENTAL
+       help
+         Support for Texas Instruments(R) VLYNQ bus.
+         The VLYNQ bus is a high-speed, serial and packetized
+         data bus which allows external peripherals of a SoC
+         to appear into the system's main memory.
+
+         If unsure, say N
+
+config VLYNQ_DEBUG
+       bool "VLYNQ bus debug"
+       depends on VLYNQ && KERNEL_DEBUG
+       help
+         Turn on VLYNQ bus debugging.
+
+endmenu
diff --git a/drivers/vlynq/Makefile b/drivers/vlynq/Makefile
new file mode 100644 (file)
index 0000000..b3f6114
--- /dev/null
@@ -0,0 +1,5 @@
+#
+# Makefile for kernel vlynq drivers
+#
+
+obj-$(CONFIG_VLYNQ) += vlynq.o
diff --git a/drivers/vlynq/vlynq.c b/drivers/vlynq/vlynq.c
new file mode 100644 (file)
index 0000000..7335433
--- /dev/null
@@ -0,0 +1,814 @@
+/*
+ * Copyright (C) 2006, 2007 Eugene Konev <ejka@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Parts of the VLYNQ specification can be found here:
+ * http://www.ti.com/litv/pdf/sprue36a
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include <linux/vlynq.h>
+
+#define VLYNQ_CTRL_PM_ENABLE           0x80000000
+#define VLYNQ_CTRL_CLOCK_INT           0x00008000
+#define VLYNQ_CTRL_CLOCK_DIV(x)                (((x) & 7) << 16)
+#define VLYNQ_CTRL_INT_LOCAL           0x00004000
+#define VLYNQ_CTRL_INT_ENABLE          0x00002000
+#define VLYNQ_CTRL_INT_VECTOR(x)       (((x) & 0x1f) << 8)
+#define VLYNQ_CTRL_INT2CFG             0x00000080
+#define VLYNQ_CTRL_RESET               0x00000001
+
+#define VLYNQ_CTRL_CLOCK_MASK          (0x7 << 16)
+
+#define VLYNQ_INT_OFFSET               0x00000014
+#define VLYNQ_REMOTE_OFFSET            0x00000080
+
+#define VLYNQ_STATUS_LINK              0x00000001
+#define VLYNQ_STATUS_LERROR            0x00000080
+#define VLYNQ_STATUS_RERROR            0x00000100
+
+#define VINT_ENABLE                    0x00000100
+#define VINT_TYPE_EDGE                 0x00000080
+#define VINT_LEVEL_LOW                 0x00000040
+#define VINT_VECTOR(x)                 ((x) & 0x1f)
+#define VINT_OFFSET(irq)               (8 * ((irq) % 4))
+
+#define VLYNQ_AUTONEGO_V2              0x00010000
+
+struct vlynq_regs {
+       u32 revision;
+       u32 control;
+       u32 status;
+       u32 int_prio;
+       u32 int_status;
+       u32 int_pending;
+       u32 int_ptr;
+       u32 tx_offset;
+       struct vlynq_mapping rx_mapping[4];
+       u32 chip;
+       u32 autonego;
+       u32 unused[6];
+       u32 int_device[8];
+};
+
+#ifdef VLYNQ_DEBUG
+static void vlynq_dump_regs(struct vlynq_device *dev)
+{
+       int i;
+
+       printk(KERN_DEBUG "VLYNQ local=%p remote=%p\n",
+                       dev->local, dev->remote);
+       for (i = 0; i < 32; i++) {
+               printk(KERN_DEBUG "VLYNQ: local %d: %08x\n",
+                       i + 1, ((u32 *)dev->local)[i]);
+               printk(KERN_DEBUG "VLYNQ: remote %d: %08x\n",
+                       i + 1, ((u32 *)dev->remote)[i]);
+       }
+}
+
+static void vlynq_dump_mem(u32 *base, int count)
+{
+       int i;
+
+       for (i = 0; i < (count + 3) / 4; i++) {
+               if (i % 4 == 0)
+                       printk(KERN_DEBUG "\nMEM[0x%04x]:", i * 4);
+               printk(KERN_DEBUG " 0x%08x", *(base + i));
+       }
+       printk(KERN_DEBUG "\n");
+}
+#endif
+
+/* Check the VLYNQ link status with a given device */
+static int vlynq_linked(struct vlynq_device *dev)
+{
+       int i;
+
+       for (i = 0; i < 100; i++)
+               if (readl(&dev->local->status) & VLYNQ_STATUS_LINK)
+                       return 1;
+               else
+                       cpu_relax();
+
+       return 0;
+}
+
+static void vlynq_reset(struct vlynq_device *dev)
+{
+       writel(readl(&dev->local->control) | VLYNQ_CTRL_RESET,
+                       &dev->local->control);
+
+       /* Wait for the devices to finish resetting */
+       msleep(5);
+
+       /* Remove reset bit */
+       writel(readl(&dev->local->control) & ~VLYNQ_CTRL_RESET,
+                       &dev->local->control);
+
+       /* Give some time for the devices to settle */
+       msleep(5);
+}
+
+static void vlynq_irq_unmask(unsigned int irq)
+{
+       u32 val;
+       struct vlynq_device *dev = get_irq_chip_data(irq);
+       int virq;
+
+       BUG_ON(!dev);
+       virq = irq - dev->irq_start;
+       val = readl(&dev->remote->int_device[virq >> 2]);
+       val |= (VINT_ENABLE | virq) << VINT_OFFSET(virq);
+       writel(val, &dev->remote->int_device[virq >> 2]);
+}
+
+static void vlynq_irq_mask(unsigned int irq)
+{
+       u32 val;
+       struct vlynq_device *dev = get_irq_chip_data(irq);
+       int virq;
+
+       BUG_ON(!dev);
+       virq = irq - dev->irq_start;
+       val = readl(&dev->remote->int_device[virq >> 2]);
+       val &= ~(VINT_ENABLE << VINT_OFFSET(virq));
+       writel(val, &dev->remote->int_device[virq >> 2]);
+}
+
+static int vlynq_irq_type(unsigned int irq, unsigned int flow_type)
+{
+       u32 val;
+       struct vlynq_device *dev = get_irq_chip_data(irq);
+       int virq;
+
+       BUG_ON(!dev);
+       virq = irq - dev->irq_start;
+       val = readl(&dev->remote->int_device[virq >> 2]);
+       switch (flow_type & IRQ_TYPE_SENSE_MASK) {
+       case IRQ_TYPE_EDGE_RISING:
+       case IRQ_TYPE_EDGE_FALLING:
+       case IRQ_TYPE_EDGE_BOTH:
+               val |= VINT_TYPE_EDGE << VINT_OFFSET(virq);
+               val &= ~(VINT_LEVEL_LOW << VINT_OFFSET(virq));
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               val &= ~(VINT_TYPE_EDGE << VINT_OFFSET(virq));
+               val &= ~(VINT_LEVEL_LOW << VINT_OFFSET(virq));
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               val &= ~(VINT_TYPE_EDGE << VINT_OFFSET(virq));
+               val |= VINT_LEVEL_LOW << VINT_OFFSET(virq);
+               break;
+       default:
+               return -EINVAL;
+       }
+       writel(val, &dev->remote->int_device[virq >> 2]);
+       return 0;
+}
+
+static void vlynq_local_ack(unsigned int irq)
+{
+       struct vlynq_device *dev = get_irq_chip_data(irq);
+
+       u32 status = readl(&dev->local->status);
+
+       pr_debug("%s: local status: 0x%08x\n",
+                      dev_name(&dev->dev), status);
+       writel(status, &dev->local->status);
+}
+
+static void vlynq_remote_ack(unsigned int irq)
+{
+       struct vlynq_device *dev = get_irq_chip_data(irq);
+
+       u32 status = readl(&dev->remote->status);
+
+       pr_debug("%s: remote status: 0x%08x\n",
+                      dev_name(&dev->dev), status);
+       writel(status, &dev->remote->status);
+}
+
+static irqreturn_t vlynq_irq(int irq, void *dev_id)
+{
+       struct vlynq_device *dev = dev_id;
+       u32 status;
+       int virq = 0;
+
+       status = readl(&dev->local->int_status);
+       writel(status, &dev->local->int_status);
+
+       if (unlikely(!status))
+               spurious_interrupt();
+
+       while (status) {
+               if (status & 1)
+                       do_IRQ(dev->irq_start + virq);
+               status >>= 1;
+               virq++;
+       }
+
+       return IRQ_HANDLED;
+}
+
+static struct irq_chip vlynq_irq_chip = {
+       .name = "vlynq",
+       .unmask = vlynq_irq_unmask,
+       .mask = vlynq_irq_mask,
+       .set_type = vlynq_irq_type,
+};
+
+static struct irq_chip vlynq_local_chip = {
+       .name = "vlynq local error",
+       .unmask = vlynq_irq_unmask,
+       .mask = vlynq_irq_mask,
+       .ack = vlynq_local_ack,
+};
+
+static struct irq_chip vlynq_remote_chip = {
+       .name = "vlynq local error",
+       .unmask = vlynq_irq_unmask,
+       .mask = vlynq_irq_mask,
+       .ack = vlynq_remote_ack,
+};
+
+static int vlynq_setup_irq(struct vlynq_device *dev)
+{
+       u32 val;
+       int i, virq;
+
+       if (dev->local_irq == dev->remote_irq) {
+               printk(KERN_ERR
+                      "%s: local vlynq irq should be different from remote\n",
+                      dev_name(&dev->dev));
+               return -EINVAL;
+       }
+
+       /* Clear local and remote error bits */
+       writel(readl(&dev->local->status), &dev->local->status);
+       writel(readl(&dev->remote->status), &dev->remote->status);
+
+       /* Now setup interrupts */
+       val = VLYNQ_CTRL_INT_VECTOR(dev->local_irq);
+       val |= VLYNQ_CTRL_INT_ENABLE | VLYNQ_CTRL_INT_LOCAL |
+               VLYNQ_CTRL_INT2CFG;
+       val |= readl(&dev->local->control);
+       writel(VLYNQ_INT_OFFSET, &dev->local->int_ptr);
+       writel(val, &dev->local->control);
+
+       val = VLYNQ_CTRL_INT_VECTOR(dev->remote_irq);
+       val |= VLYNQ_CTRL_INT_ENABLE;
+       val |= readl(&dev->remote->control);
+       writel(VLYNQ_INT_OFFSET, &dev->remote->int_ptr);
+       writel(val, &dev->remote->int_ptr);
+       writel(val, &dev->remote->control);
+
+       for (i = dev->irq_start; i <= dev->irq_end; i++) {
+               virq = i - dev->irq_start;
+               if (virq == dev->local_irq) {
+                       set_irq_chip_and_handler(i, &vlynq_local_chip,
+                                                handle_level_irq);
+                       set_irq_chip_data(i, dev);
+               } else if (virq == dev->remote_irq) {
+                       set_irq_chip_and_handler(i, &vlynq_remote_chip,
+                                                handle_level_irq);
+                       set_irq_chip_data(i, dev);
+               } else {
+                       set_irq_chip_and_handler(i, &vlynq_irq_chip,
+                                                handle_simple_irq);
+                       set_irq_chip_data(i, dev);
+                       writel(0, &dev->remote->int_device[virq >> 2]);
+               }
+       }
+
+       if (request_irq(dev->irq, vlynq_irq, IRQF_SHARED, "vlynq", dev)) {
+               printk(KERN_ERR "%s: request_irq failed\n",
+                                       dev_name(&dev->dev));
+               return -EAGAIN;
+       }
+
+       return 0;
+}
+
+static void vlynq_device_release(struct device *dev)
+{
+       struct vlynq_device *vdev = to_vlynq_device(dev);
+       kfree(vdev);
+}
+
+static int vlynq_device_match(struct device *dev,
+                             struct device_driver *drv)
+{
+       struct vlynq_device *vdev = to_vlynq_device(dev);
+       struct vlynq_driver *vdrv = to_vlynq_driver(drv);
+       struct vlynq_device_id *ids = vdrv->id_table;
+
+       while (ids->id) {
+               if (ids->id == vdev->dev_id) {
+                       vdev->divisor = ids->divisor;
+                       vlynq_set_drvdata(vdev, ids);
+                       printk(KERN_INFO "Driver found for VLYNQ "
+                               "device: %08x\n", vdev->dev_id);
+                       return 1;
+               }
+               printk(KERN_DEBUG "Not using the %08x VLYNQ device's driver"
+                       " for VLYNQ device: %08x\n", ids->id, vdev->dev_id);
+               ids++;
+       }
+       return 0;
+}
+
+static int vlynq_device_probe(struct device *dev)
+{
+       struct vlynq_device *vdev = to_vlynq_device(dev);
+       struct vlynq_driver *drv = to_vlynq_driver(dev->driver);
+       struct vlynq_device_id *id = vlynq_get_drvdata(vdev);
+       int result = -ENODEV;
+
+       if (drv->probe)
+               result = drv->probe(vdev, id);
+       if (result)
+               put_device(dev);
+       return result;
+}
+
+static int vlynq_device_remove(struct device *dev)
+{
+       struct vlynq_driver *drv = to_vlynq_driver(dev->driver);
+
+       if (drv->remove)
+               drv->remove(to_vlynq_device(dev));
+
+       return 0;
+}
+
+int __vlynq_register_driver(struct vlynq_driver *driver, struct module *owner)
+{
+       driver->driver.name = driver->name;
+       driver->driver.bus = &vlynq_bus_type;
+       return driver_register(&driver->driver);
+}
+EXPORT_SYMBOL(__vlynq_register_driver);
+
+void vlynq_unregister_driver(struct vlynq_driver *driver)
+{
+       driver_unregister(&driver->driver);
+}
+EXPORT_SYMBOL(vlynq_unregister_driver);
+
+/*
+ * A VLYNQ remote device can clock the VLYNQ bus master
+ * using a dedicated clock line. In that case, both the
+ * remove device and the bus master should have the same
+ * serial clock dividers configured. Iterate through the
+ * 8 possible dividers until we actually link with the
+ * device.
+ */
+static int __vlynq_try_remote(struct vlynq_device *dev)
+{
+       int i;
+
+       vlynq_reset(dev);
+       for (i = dev->dev_id ? vlynq_rdiv2 : vlynq_rdiv8; dev->dev_id ?
+                       i <= vlynq_rdiv8 : i >= vlynq_rdiv2;
+               dev->dev_id ? i++ : i--) {
+
+               if (!vlynq_linked(dev))
+                       break;
+
+               writel((readl(&dev->remote->control) &
+                               ~VLYNQ_CTRL_CLOCK_MASK) |
+                               VLYNQ_CTRL_CLOCK_INT |
+                               VLYNQ_CTRL_CLOCK_DIV(i - vlynq_rdiv1),
+                               &dev->remote->control);
+               writel((readl(&dev->local->control)
+                               & ~(VLYNQ_CTRL_CLOCK_INT |
+                               VLYNQ_CTRL_CLOCK_MASK)) |
+                               VLYNQ_CTRL_CLOCK_DIV(i - vlynq_rdiv1),
+                               &dev->local->control);
+
+               if (vlynq_linked(dev)) {
+                       printk(KERN_DEBUG
+                               "%s: using remote clock divisor %d\n",
+                               dev_name(&dev->dev), i - vlynq_rdiv1 + 1);
+                       dev->divisor = i;
+                       return 0;
+               } else {
+                       vlynq_reset(dev);
+               }
+       }
+
+       return -ENODEV;
+}
+
+/*
+ * A VLYNQ remote device can be clocked by the VLYNQ bus
+ * master using a dedicated clock line. In that case, only
+ * the bus master configures the serial clock divider.
+ * Iterate through the 8 possible dividers until we
+ * actually get a link with the device.
+ */
+static int __vlynq_try_local(struct vlynq_device *dev)
+{
+       int i;
+
+       vlynq_reset(dev);
+
+       for (i = dev->dev_id ? vlynq_ldiv2 : vlynq_ldiv8; dev->dev_id ?
+                       i <= vlynq_ldiv8 : i >= vlynq_ldiv2;
+               dev->dev_id ? i++ : i--) {
+
+               writel((readl(&dev->local->control) &
+                               ~VLYNQ_CTRL_CLOCK_MASK) |
+                               VLYNQ_CTRL_CLOCK_INT |
+                               VLYNQ_CTRL_CLOCK_DIV(i - vlynq_ldiv1),
+                               &dev->local->control);
+
+               if (vlynq_linked(dev)) {
+                       printk(KERN_DEBUG
+                               "%s: using local clock divisor %d\n",
+                               dev_name(&dev->dev), i - vlynq_ldiv1 + 1);
+                       dev->divisor = i;
+                       return 0;
+               } else {
+                       vlynq_reset(dev);
+               }
+       }
+
+       return -ENODEV;
+}
+
+/*
+ * When using external clocking method, serial clock
+ * is supplied by an external oscillator, therefore we
+ * should mask the local clock bit in the clock control
+ * register for both the bus master and the remote device.
+ */
+static int __vlynq_try_external(struct vlynq_device *dev)
+{
+       vlynq_reset(dev);
+       if (!vlynq_linked(dev))
+               return -ENODEV;
+
+       writel((readl(&dev->remote->control) &
+                       ~VLYNQ_CTRL_CLOCK_INT),
+                       &dev->remote->control);
+
+       writel((readl(&dev->local->control) &
+                       ~VLYNQ_CTRL_CLOCK_INT),
+                       &dev->local->control);
+
+       if (vlynq_linked(dev)) {
+               printk(KERN_DEBUG "%s: using external clock\n",
+                       dev_name(&dev->dev));
+                       dev->divisor = vlynq_div_external;
+               return 0;
+       }
+
+       return -ENODEV;
+}
+
+static int __vlynq_enable_device(struct vlynq_device *dev)
+{
+       int result;
+       struct plat_vlynq_ops *ops = dev->dev.platform_data;
+
+       result = ops->on(dev);
+       if (result)
+               return result;
+
+       switch (dev->divisor) {
+       case vlynq_div_external:
+       case vlynq_div_auto:
+               /* When the device is brought from reset it should have clock
+                * generation negotiated by hardware.
+                * Check which device is generating clocks and perform setup
+                * accordingly */
+               if (vlynq_linked(dev) && readl(&dev->remote->control) &
+                  VLYNQ_CTRL_CLOCK_INT) {
+                       if (!__vlynq_try_remote(dev) ||
+                               !__vlynq_try_local(dev)  ||
+                               !__vlynq_try_external(dev))
+                               return 0;
+               } else {
+                       if (!__vlynq_try_external(dev) ||
+                               !__vlynq_try_local(dev)    ||
+                               !__vlynq_try_remote(dev))
+                               return 0;
+               }
+               break;
+       case vlynq_ldiv1:
+       case vlynq_ldiv2:
+       case vlynq_ldiv3:
+       case vlynq_ldiv4:
+       case vlynq_ldiv5:
+       case vlynq_ldiv6:
+       case vlynq_ldiv7:
+       case vlynq_ldiv8:
+               writel(VLYNQ_CTRL_CLOCK_INT |
+                       VLYNQ_CTRL_CLOCK_DIV(dev->divisor -
+                       vlynq_ldiv1), &dev->local->control);
+               writel(0, &dev->remote->control);
+               if (vlynq_linked(dev)) {
+                       printk(KERN_DEBUG
+                               "%s: using local clock divisor %d\n",
+                               dev_name(&dev->dev),
+                               dev->divisor - vlynq_ldiv1 + 1);
+                       return 0;
+               }
+               break;
+       case vlynq_rdiv1:
+       case vlynq_rdiv2:
+       case vlynq_rdiv3:
+       case vlynq_rdiv4:
+       case vlynq_rdiv5:
+       case vlynq_rdiv6:
+       case vlynq_rdiv7:
+       case vlynq_rdiv8:
+               writel(0, &dev->local->control);
+               writel(VLYNQ_CTRL_CLOCK_INT |
+                       VLYNQ_CTRL_CLOCK_DIV(dev->divisor -
+                       vlynq_rdiv1), &dev->remote->control);
+               if (vlynq_linked(dev)) {
+                       printk(KERN_DEBUG
+                               "%s: using remote clock divisor %d\n",
+                               dev_name(&dev->dev),
+                               dev->divisor - vlynq_rdiv1 + 1);
+                       return 0;
+               }
+               break;
+       }
+
+       ops->off(dev);
+       return -ENODEV;
+}
+
+int vlynq_enable_device(struct vlynq_device *dev)
+{
+       struct plat_vlynq_ops *ops = dev->dev.platform_data;
+       int result = -ENODEV;
+
+       result = __vlynq_enable_device(dev);
+       if (result)
+               return result;
+
+       result = vlynq_setup_irq(dev);
+       if (result)
+               ops->off(dev);
+
+       dev->enabled = !result;
+       return result;
+}
+EXPORT_SYMBOL(vlynq_enable_device);
+
+
+void vlynq_disable_device(struct vlynq_device *dev)
+{
+       struct plat_vlynq_ops *ops = dev->dev.platform_data;
+
+       dev->enabled = 0;
+       free_irq(dev->irq, dev);
+       ops->off(dev);
+}
+EXPORT_SYMBOL(vlynq_disable_device);
+
+int vlynq_set_local_mapping(struct vlynq_device *dev, u32 tx_offset,
+                           struct vlynq_mapping *mapping)
+{
+       int i;
+
+       if (!dev->enabled)
+               return -ENXIO;
+
+       writel(tx_offset, &dev->local->tx_offset);
+       for (i = 0; i < 4; i++) {
+               writel(mapping[i].offset, &dev->local->rx_mapping[i].offset);
+               writel(mapping[i].size, &dev->local->rx_mapping[i].size);
+       }
+       return 0;
+}
+EXPORT_SYMBOL(vlynq_set_local_mapping);
+
+int vlynq_set_remote_mapping(struct vlynq_device *dev, u32 tx_offset,
+                            struct vlynq_mapping *mapping)
+{
+       int i;
+
+       if (!dev->enabled)
+               return -ENXIO;
+
+       writel(tx_offset, &dev->remote->tx_offset);
+       for (i = 0; i < 4; i++) {
+               writel(mapping[i].offset, &dev->remote->rx_mapping[i].offset);
+               writel(mapping[i].size, &dev->remote->rx_mapping[i].size);
+       }
+       return 0;
+}
+EXPORT_SYMBOL(vlynq_set_remote_mapping);
+
+int vlynq_set_local_irq(struct vlynq_device *dev, int virq)
+{
+       int irq = dev->irq_start + virq;
+       if (dev->enabled)
+               return -EBUSY;
+
+       if ((irq < dev->irq_start) || (irq > dev->irq_end))
+               return -EINVAL;
+
+       if (virq == dev->remote_irq)
+               return -EINVAL;
+
+       dev->local_irq = virq;
+
+       return 0;
+}
+EXPORT_SYMBOL(vlynq_set_local_irq);
+
+int vlynq_set_remote_irq(struct vlynq_device *dev, int virq)
+{
+       int irq = dev->irq_start + virq;
+       if (dev->enabled)
+               return -EBUSY;
+
+       if ((irq < dev->irq_start) || (irq > dev->irq_end))
+               return -EINVAL;
+
+       if (virq == dev->local_irq)
+               return -EINVAL;
+
+       dev->remote_irq = virq;
+
+       return 0;
+}
+EXPORT_SYMBOL(vlynq_set_remote_irq);
+
+static int vlynq_probe(struct platform_device *pdev)
+{
+       struct vlynq_device *dev;
+       struct resource *regs_res, *mem_res, *irq_res;
+       int len, result;
+
+       regs_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+       if (!regs_res)
+               return -ENODEV;
+
+       mem_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem");
+       if (!mem_res)
+               return -ENODEV;
+
+       irq_res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "devirq");
+       if (!irq_res)
+               return -ENODEV;
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               printk(KERN_ERR
+                      "vlynq: failed to allocate device structure\n");
+               return -ENOMEM;
+       }
+
+       dev->id = pdev->id;
+       dev->dev.bus = &vlynq_bus_type;
+       dev->dev.parent = &pdev->dev;
+       dev_set_name(&dev->dev, "vlynq%d", dev->id);
+       dev->dev.platform_data = pdev->dev.platform_data;
+       dev->dev.release = vlynq_device_release;
+
+       dev->regs_start = regs_res->start;
+       dev->regs_end = regs_res->end;
+       dev->mem_start = mem_res->start;
+       dev->mem_end = mem_res->end;
+
+       len = regs_res->end - regs_res->start;
+       if (!request_mem_region(regs_res->start, len, dev_name(&dev->dev))) {
+               printk(KERN_ERR "%s: Can't request vlynq registers\n",
+                      dev_name(&dev->dev));
+               result = -ENXIO;
+               goto fail_request;
+       }
+
+       dev->local = ioremap(regs_res->start, len);
+       if (!dev->local) {
+               printk(KERN_ERR "%s: Can't remap vlynq registers\n",
+                      dev_name(&dev->dev));
+               result = -ENXIO;
+               goto fail_remap;
+       }
+
+       dev->remote = (struct vlynq_regs *)((void *)dev->local +
+                                           VLYNQ_REMOTE_OFFSET);
+
+       dev->irq = platform_get_irq_byname(pdev, "irq");
+       dev->irq_start = irq_res->start;
+       dev->irq_end = irq_res->end;
+       dev->local_irq = dev->irq_end - dev->irq_start;
+       dev->remote_irq = dev->local_irq - 1;
+
+       if (device_register(&dev->dev))
+               goto fail_register;
+       platform_set_drvdata(pdev, dev);
+
+       printk(KERN_INFO "%s: regs 0x%p, irq %d, mem 0x%p\n",
+              dev_name(&dev->dev), (void *)dev->regs_start, dev->irq,
+              (void *)dev->mem_start);
+
+       dev->dev_id = 0;
+       dev->divisor = vlynq_div_auto;
+       result = __vlynq_enable_device(dev);
+       if (result == 0) {
+               dev->dev_id = readl(&dev->remote->chip);
+               ((struct plat_vlynq_ops *)(dev->dev.platform_data))->off(dev);
+       }
+       if (dev->dev_id)
+               printk(KERN_INFO "Found a VLYNQ device: %08x\n", dev->dev_id);
+
+       return 0;
+
+fail_register:
+       iounmap(dev->local);
+fail_remap:
+fail_request:
+       release_mem_region(regs_res->start, len);
+       kfree(dev);
+       return result;
+}
+
+static int vlynq_remove(struct platform_device *pdev)
+{
+       struct vlynq_device *dev = platform_get_drvdata(pdev);
+
+       device_unregister(&dev->dev);
+       iounmap(dev->local);
+       release_mem_region(dev->regs_start, dev->regs_end - dev->regs_start);
+
+       kfree(dev);
+
+       return 0;
+}
+
+static struct platform_driver vlynq_platform_driver = {
+       .driver.name = "vlynq",
+       .probe = vlynq_probe,
+       .remove = __devexit_p(vlynq_remove),
+};
+
+struct bus_type vlynq_bus_type = {
+       .name = "vlynq",
+       .match = vlynq_device_match,
+       .probe = vlynq_device_probe,
+       .remove = vlynq_device_remove,
+};
+EXPORT_SYMBOL(vlynq_bus_type);
+
+static int __devinit vlynq_init(void)
+{
+       int res = 0;
+
+       res = bus_register(&vlynq_bus_type);
+       if (res)
+               goto fail_bus;
+
+       res = platform_driver_register(&vlynq_platform_driver);
+       if (res)
+               goto fail_platform;
+
+       return 0;
+
+fail_platform:
+       bus_unregister(&vlynq_bus_type);
+fail_bus:
+       return res;
+}
+
+static void __devexit vlynq_exit(void)
+{
+       platform_driver_unregister(&vlynq_platform_driver);
+       bus_unregister(&vlynq_bus_type);
+}
+
+module_init(vlynq_init);
+module_exit(vlynq_exit);
index 525da2e8f73be1da26f67be2c1630b6f20518ac0..4044f163035f6d77734c404ca3a5ee8ab6bb55e8 100644 (file)
@@ -39,6 +39,13 @@ config FS_POSIX_ACL
        bool
        default n
 
+source "fs/xfs/Kconfig"
+source "fs/gfs2/Kconfig"
+source "fs/ocfs2/Kconfig"
+source "fs/btrfs/Kconfig"
+
+endif # BLOCK
+
 config FILE_LOCKING
        bool "Enable POSIX file locking API" if EMBEDDED
        default y
@@ -47,13 +54,6 @@ config FILE_LOCKING
           for filesystems like NFS and for the flock() system
           call. Disabling this option saves about 11k.
 
-source "fs/xfs/Kconfig"
-source "fs/gfs2/Kconfig"
-source "fs/ocfs2/Kconfig"
-source "fs/btrfs/Kconfig"
-
-endif # BLOCK
-
 source "fs/notify/Kconfig"
 
 source "fs/quota/Kconfig"
index 2d33a5f7d218ad75cf26ec973f10e5958fc5a57d..0dd4dafee10b391f7d92b89f8c4e491ed5f09810 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/errno.h>
+#include <rxrpc/packet.h>
 #include "internal.h"
 #include "afs_fs.h"
 
@@ -54,6 +55,21 @@ int afs_abort_to_error(u32 abort_code)
        case 0x2f6df24:         return -ENOLCK;
        case 0x2f6df26:         return -ENOTEMPTY;
        case 0x2f6df78:         return -EDQUOT;
+
+       case RXKADINCONSISTENCY: return -EPROTO;
+       case RXKADPACKETSHORT:  return -EPROTO;
+       case RXKADLEVELFAIL:    return -EKEYREJECTED;
+       case RXKADTICKETLEN:    return -EKEYREJECTED;
+       case RXKADOUTOFSEQUENCE: return -EPROTO;
+       case RXKADNOAUTH:       return -EKEYREJECTED;
+       case RXKADBADKEY:       return -EKEYREJECTED;
+       case RXKADBADTICKET:    return -EKEYREJECTED;
+       case RXKADUNKNOWNKEY:   return -EKEYREJECTED;
+       case RXKADEXPIRED:      return -EKEYEXPIRED;
+       case RXKADSEALEDINCON:  return -EKEYREJECTED;
+       case RXKADDATALEN:      return -EKEYREJECTED;
+       case RXKADILLEGALLEVEL: return -EKEYREJECTED;
+
        default:                return -EREMOTEIO;
        }
 }
index ec2a7431e458b52c89795f6ba9c01a2efe8aa254..6e689208def255c946cf39d1f44c562aedf51448 100644 (file)
@@ -65,6 +65,8 @@ static int afs_vlocation_access_vl_by_name(struct afs_vlocation *vl,
                                goto out;
                        goto rotate;
                case -ENOMEDIUM:
+               case -EKEYREJECTED:
+               case -EKEYEXPIRED:
                        goto out;
                default:
                        ret = -EIO;
index 9367b6297d84c819c1c42abef581ed39c0093b78..89cd2deeb4aff144d1ee4355e6e57b4c9ec3aaeb 100644 (file)
@@ -513,7 +513,7 @@ befs_utf2nls(struct super_block *sb, const char *in,
 {
        struct nls_table *nls = BEFS_SB(sb)->nls;
        int i, o;
-       wchar_t uni;
+       unicode_t uni;
        int unilen, utflen;
        char *result;
        /* The utf8->nls conversion won't make the final nls string bigger
@@ -539,16 +539,16 @@ befs_utf2nls(struct super_block *sb, const char *in,
        for (i = o = 0; i < in_len; i += utflen, o += unilen) {
 
                /* convert from UTF-8 to Unicode */
-               utflen = utf8_mbtowc(&uni, &in[i], in_len - i);
-               if (utflen < 0) {
+               utflen = utf8_to_utf32(&in[i], in_len - i, &uni);
+               if (utflen < 0)
                        goto conv_err;
-               }
 
                /* convert from Unicode to nls */
+               if (uni > MAX_WCHAR_T)
+                       goto conv_err;
                unilen = nls->uni2char(uni, &result[o], in_len - o);
-               if (unilen < 0) {
+               if (unilen < 0)
                        goto conv_err;
-               }
        }
        result[o] = '\0';
        *out_len = o;
@@ -619,15 +619,13 @@ befs_nls2utf(struct super_block *sb, const char *in,
 
                /* convert from nls to unicode */
                unilen = nls->char2uni(&in[i], in_len - i, &uni);
-               if (unilen < 0) {
+               if (unilen < 0)
                        goto conv_err;
-               }
 
                /* convert from unicode to UTF-8 */
-               utflen = utf8_wctomb(&result[o], uni, 3);
-               if (utflen <= 0) {
+               utflen = utf32_to_utf8(uni, &result[o], 3);
+               if (utflen <= 0)
                        goto conv_err;
-               }
        }
 
        result[o] = '\0';
index 5f80848c320c7a66c6425e75aea21533607134fa..24c9140435323e4caabbdf00156efd0060d1be55 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -25,7 +25,6 @@
 #include <linux/module.h>
 #include <linux/mempool.h>
 #include <linux/workqueue.h>
-#include <linux/blktrace_api.h>
 #include <scsi/sg.h>           /* for struct sg_iovec */
 
 #include <trace/events/block.h>
index 0d50d49d990ab858d1a00b24a7a9fdbdcc7e7b4b..d28d29c95f7ca23a91e9ccf3c306840484ea29ed 100644 (file)
@@ -42,6 +42,8 @@
 static struct extent_io_ops btree_extent_io_ops;
 static void end_workqueue_fn(struct btrfs_work *work);
 
+static atomic_t btrfs_bdi_num = ATOMIC_INIT(0);
+
 /*
  * end_io_wq structs are used to do processing in task context when an IO is
  * complete.  This is used during reads to verify checksums, and it is used
@@ -1342,12 +1344,25 @@ static void btrfs_unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
        free_extent_map(em);
 }
 
+/*
+ * If this fails, caller must call bdi_destroy() to get rid of the
+ * bdi again.
+ */
 static int setup_bdi(struct btrfs_fs_info *info, struct backing_dev_info *bdi)
 {
-       bdi_init(bdi);
+       int err;
+
+       bdi->capabilities = BDI_CAP_MAP_COPY;
+       err = bdi_init(bdi);
+       if (err)
+               return err;
+
+       err = bdi_register(bdi, NULL, "btrfs-%d",
+                               atomic_inc_return(&btrfs_bdi_num));
+       if (err)
+               return err;
+
        bdi->ra_pages   = default_backing_dev_info.ra_pages;
-       bdi->state              = 0;
-       bdi->capabilities       = default_backing_dev_info.capabilities;
        bdi->unplug_io_fn       = btrfs_unplug_io_fn;
        bdi->unplug_io_data     = info;
        bdi->congested_fn       = btrfs_congested_fn;
@@ -1569,7 +1584,8 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        fs_info->sb = sb;
        fs_info->max_extent = (u64)-1;
        fs_info->max_inline = 8192 * 1024;
-       setup_bdi(fs_info, &fs_info->bdi);
+       if (setup_bdi(fs_info, &fs_info->bdi))
+               goto fail_bdi;
        fs_info->btree_inode = new_inode(sb);
        fs_info->btree_inode->i_ino = 1;
        fs_info->btree_inode->i_nlink = 1;
@@ -1946,8 +1962,8 @@ fail_iput:
 
        btrfs_close_devices(fs_info->fs_devices);
        btrfs_mapping_tree_free(&fs_info->mapping_tree);
+fail_bdi:
        bdi_destroy(&fs_info->bdi);
-
 fail:
        kfree(extent_root);
        kfree(tree_root);
index 2e177d7f4bb949ac92405bbaaa5f2452d8657e2e..4e83457ea253e798ccfc8cb1d493ad7e48daa2bd 100644 (file)
@@ -543,13 +543,13 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans,
                        btrfs_free_log(trans, root);
                        btrfs_update_reloc_root(trans, root);
 
-                       if (root->commit_root == root->node)
-                               continue;
-
-                       free_extent_buffer(root->commit_root);
-                       root->commit_root = btrfs_root_node(root);
+                       if (root->commit_root != root->node) {
+                               free_extent_buffer(root->commit_root);
+                               root->commit_root = btrfs_root_node(root);
+                               btrfs_set_root_node(&root->root_item,
+                                                   root->node);
+                       }
 
-                       btrfs_set_root_node(&root->root_item, root->node);
                        err = btrfs_update_root(trans, fs_info->tree_root,
                                                &root->root_key,
                                                &root->root_item);
index 33a90120f6ad11673bb869f5526db633d9cfac24..4d74fc72c195daf72e9d9b8ec9a56e62a51f0227 100644 (file)
@@ -67,6 +67,8 @@ static int debugfs_u8_get(void *data, u64 *val)
        return 0;
 }
 DEFINE_SIMPLE_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_u8_ro, debugfs_u8_get, NULL, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_u8_wo, NULL, debugfs_u8_set, "%llu\n");
 
 /**
  * debugfs_create_u8 - create a debugfs file that is used to read and write an unsigned 8-bit value
@@ -95,6 +97,13 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%llu\n");
 struct dentry *debugfs_create_u8(const char *name, mode_t mode,
                                 struct dentry *parent, u8 *value)
 {
+       /* if there are no write bits set, make read only */
+       if (!(mode & S_IWUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_u8_ro);
+       /* if there are no read bits set, make write only */
+       if (!(mode & S_IRUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_u8_wo);
+
        return debugfs_create_file(name, mode, parent, value, &fops_u8);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_u8);
@@ -110,6 +119,8 @@ static int debugfs_u16_get(void *data, u64 *val)
        return 0;
 }
 DEFINE_SIMPLE_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_u16_ro, debugfs_u16_get, NULL, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_u16_wo, NULL, debugfs_u16_set, "%llu\n");
 
 /**
  * debugfs_create_u16 - create a debugfs file that is used to read and write an unsigned 16-bit value
@@ -138,6 +149,13 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u16, debugfs_u16_get, debugfs_u16_set, "%llu\n");
 struct dentry *debugfs_create_u16(const char *name, mode_t mode,
                                  struct dentry *parent, u16 *value)
 {
+       /* if there are no write bits set, make read only */
+       if (!(mode & S_IWUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_u16_ro);
+       /* if there are no read bits set, make write only */
+       if (!(mode & S_IRUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_u16_wo);
+
        return debugfs_create_file(name, mode, parent, value, &fops_u16);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_u16);
@@ -153,6 +171,8 @@ static int debugfs_u32_get(void *data, u64 *val)
        return 0;
 }
 DEFINE_SIMPLE_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_u32_ro, debugfs_u32_get, NULL, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_u32_wo, NULL, debugfs_u32_set, "%llu\n");
 
 /**
  * debugfs_create_u32 - create a debugfs file that is used to read and write an unsigned 32-bit value
@@ -181,6 +201,13 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%llu\n");
 struct dentry *debugfs_create_u32(const char *name, mode_t mode,
                                 struct dentry *parent, u32 *value)
 {
+       /* if there are no write bits set, make read only */
+       if (!(mode & S_IWUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_u32_ro);
+       /* if there are no read bits set, make write only */
+       if (!(mode & S_IRUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_u32_wo);
+
        return debugfs_create_file(name, mode, parent, value, &fops_u32);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_u32);
@@ -197,6 +224,8 @@ static int debugfs_u64_get(void *data, u64 *val)
        return 0;
 }
 DEFINE_SIMPLE_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_u64_ro, debugfs_u64_get, NULL, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n");
 
 /**
  * debugfs_create_u64 - create a debugfs file that is used to read and write an unsigned 64-bit value
@@ -225,15 +254,28 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%llu\n");
 struct dentry *debugfs_create_u64(const char *name, mode_t mode,
                                 struct dentry *parent, u64 *value)
 {
+       /* if there are no write bits set, make read only */
+       if (!(mode & S_IWUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_u64_ro);
+       /* if there are no read bits set, make write only */
+       if (!(mode & S_IRUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_u64_wo);
+
        return debugfs_create_file(name, mode, parent, value, &fops_u64);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_u64);
 
 DEFINE_SIMPLE_ATTRIBUTE(fops_x8, debugfs_u8_get, debugfs_u8_set, "0x%02llx\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_x8_ro, debugfs_u8_get, NULL, "0x%02llx\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_x8_wo, NULL, debugfs_u8_set, "0x%02llx\n");
 
 DEFINE_SIMPLE_ATTRIBUTE(fops_x16, debugfs_u16_get, debugfs_u16_set, "0x%04llx\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_x16_ro, debugfs_u16_get, NULL, "0x%04llx\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_x16_wo, NULL, debugfs_u16_set, "0x%04llx\n");
 
 DEFINE_SIMPLE_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%08llx\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_x32_ro, debugfs_u32_get, NULL, "0x%08llx\n");
+DEFINE_SIMPLE_ATTRIBUTE(fops_x32_wo, NULL, debugfs_u32_set, "0x%08llx\n");
 
 /*
  * debugfs_create_x{8,16,32} - create a debugfs file that is used to read and write an unsigned {8,16,32}-bit value
@@ -256,6 +298,13 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_x32, debugfs_u32_get, debugfs_u32_set, "0x%08llx\n"
 struct dentry *debugfs_create_x8(const char *name, mode_t mode,
                                 struct dentry *parent, u8 *value)
 {
+       /* if there are no write bits set, make read only */
+       if (!(mode & S_IWUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_x8_ro);
+       /* if there are no read bits set, make write only */
+       if (!(mode & S_IRUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_x8_wo);
+
        return debugfs_create_file(name, mode, parent, value, &fops_x8);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_x8);
@@ -273,6 +322,13 @@ EXPORT_SYMBOL_GPL(debugfs_create_x8);
 struct dentry *debugfs_create_x16(const char *name, mode_t mode,
                                 struct dentry *parent, u16 *value)
 {
+       /* if there are no write bits set, make read only */
+       if (!(mode & S_IWUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_x16_ro);
+       /* if there are no read bits set, make write only */
+       if (!(mode & S_IRUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_x16_wo);
+
        return debugfs_create_file(name, mode, parent, value, &fops_x16);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_x16);
@@ -290,6 +346,13 @@ EXPORT_SYMBOL_GPL(debugfs_create_x16);
 struct dentry *debugfs_create_x32(const char *name, mode_t mode,
                                 struct dentry *parent, u32 *value)
 {
+       /* if there are no write bits set, make read only */
+       if (!(mode & S_IWUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_x32_ro);
+       /* if there are no read bits set, make write only */
+       if (!(mode & S_IRUGO))
+               return debugfs_create_file(name, mode, parent, value, &fops_x32_wo);
+
        return debugfs_create_file(name, mode, parent, value, &fops_x32);
 }
 EXPORT_SYMBOL_GPL(debugfs_create_x32);
@@ -419,7 +482,7 @@ static const struct file_operations fops_blob = {
 };
 
 /**
- * debugfs_create_blob - create a debugfs file that is used to read and write a binary blob
+ * debugfs_create_blob - create a debugfs file that is used to read a binary blob
  * @name: a pointer to a string containing the name of the file to create.
  * @mode: the permission that the file should have
  * @parent: a pointer to the parent dentry for this file.  This should be a
index 0662ba6de85a46040ac83b87d66562146a009811..d22438ef7674870ad4987b9c2eb11555057e4dc8 100644 (file)
@@ -403,6 +403,7 @@ void debugfs_remove_recursive(struct dentry *dentry)
                }
                child = list_entry(parent->d_subdirs.next, struct dentry,
                                d_u.d_child);
+ next_sibling:
 
                /*
                 * If "child" isn't empty, walk down the tree and
@@ -416,6 +417,16 @@ void debugfs_remove_recursive(struct dentry *dentry)
                }
                __debugfs_remove(child, parent);
                if (parent->d_subdirs.next == &child->d_u.d_child) {
+                       /*
+                        * Try the next sibling.
+                        */
+                       if (child->d_u.d_child.next != &parent->d_subdirs) {
+                               child = list_entry(child->d_u.d_child.next,
+                                                  struct dentry,
+                                                  d_u.d_child);
+                               goto next_sibling;
+                       }
+
                        /*
                         * Avoid infinite loop if we fail to remove
                         * one dentry.
index b6a719a909f8eee1829764ea770e879c1c9c73fe..a2edb79134472170e95d5fe835e7ad6a783e00db 100644 (file)
@@ -24,7 +24,7 @@ static void drop_pagecache_sb(struct super_block *sb)
                        continue;
                __iget(inode);
                spin_unlock(&inode_lock);
-               __invalidate_mapping_pages(inode->i_mapping, 0, -1, true);
+               invalidate_mapping_pages(inode->i_mapping, 0, -1);
                iput(toput_inode);
                toput_inode = inode;
                spin_lock(&inode_lock);
index b4260229808790859871d7cf0e013cdf2601116c..923990e4f16e13b4ebc2f9f9435aee64b24633f8 100644 (file)
@@ -241,7 +241,7 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus)
        while (*fclus < cluster) {
                /* prevent the infinite loop of cluster chain */
                if (*fclus > limit) {
-                       fat_fs_panic(sb, "%s: detected the cluster chain loop"
+                       fat_fs_error(sb, "%s: detected the cluster chain loop"
                                     " (i_pos %lld)", __func__,
                                     MSDOS_I(inode)->i_pos);
                        nr = -EIO;
@@ -252,7 +252,7 @@ int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus)
                if (nr < 0)
                        goto out;
                else if (nr == FAT_ENT_FREE) {
-                       fat_fs_panic(sb, "%s: invalid cluster chain"
+                       fat_fs_error(sb, "%s: invalid cluster chain"
                                     " (i_pos %lld)", __func__,
                                     MSDOS_I(inode)->i_pos);
                        nr = -EIO;
@@ -285,7 +285,7 @@ static int fat_bmap_cluster(struct inode *inode, int cluster)
        if (ret < 0)
                return ret;
        else if (ret == FAT_ENT_EOF) {
-               fat_fs_panic(sb, "%s: request beyond EOF (i_pos %lld)",
+               fat_fs_error(sb, "%s: request beyond EOF (i_pos %lld)",
                             __func__, MSDOS_I(inode)->i_pos);
                return -EIO;
        }
index f3500294eec583a04b908e8013880a177a849f76..38ff75a0fe22d3b8764e9be001dd57857c5abe66 100644 (file)
 #include <asm/uaccess.h>
 #include "fat.h"
 
+/*
+ * Maximum buffer size of short name.
+ * [(MSDOS_NAME + '.') * max one char + nul]
+ * For msdos style, ['.' (hidden) + MSDOS_NAME + '.' + nul]
+ */
+#define FAT_MAX_SHORT_SIZE     ((MSDOS_NAME + 1) * NLS_MAX_CHARSET_SIZE + 1)
+/*
+ * Maximum buffer size of unicode chars from slots.
+ * [(max longname slots * 13 (size in a slot) + nul) * sizeof(wchar_t)]
+ */
+#define FAT_MAX_UNI_CHARS      ((MSDOS_SLOTS - 1) * 13 + 1)
+#define FAT_MAX_UNI_SIZE       (FAT_MAX_UNI_CHARS * sizeof(wchar_t))
+
 static inline loff_t fat_make_i_pos(struct super_block *sb,
                                    struct buffer_head *bh,
                                    struct msdos_dir_entry *de)
@@ -171,7 +184,8 @@ static inline int fat_uni_to_x8(struct msdos_sb_info *sbi, const wchar_t *uni,
                                unsigned char *buf, int size)
 {
        if (sbi->options.utf8)
-               return utf8_wcstombs(buf, uni, size);
+               return utf16s_to_utf8s(uni, FAT_MAX_UNI_CHARS,
+                               UTF16_HOST_ENDIAN, buf, size);
        else
                return uni16_to_x8(buf, uni, size, sbi->options.unicode_xlate,
                                   sbi->nls_io);
@@ -324,19 +338,6 @@ parse_long:
        return 0;
 }
 
-/*
- * Maximum buffer size of short name.
- * [(MSDOS_NAME + '.') * max one char + nul]
- * For msdos style, ['.' (hidden) + MSDOS_NAME + '.' + nul]
- */
-#define FAT_MAX_SHORT_SIZE     ((MSDOS_NAME + 1) * NLS_MAX_CHARSET_SIZE + 1)
-/*
- * Maximum buffer size of unicode chars from slots.
- * [(max longname slots * 13 (size in a slot) + nul) * sizeof(wchar_t)]
- */
-#define FAT_MAX_UNI_CHARS      ((MSDOS_SLOTS - 1) * 13 + 1)
-#define FAT_MAX_UNI_SIZE       (FAT_MAX_UNI_CHARS * sizeof(wchar_t))
-
 /*
  * Return values: negative -> error, 0 -> not found, positive -> found,
  * value is the total amount of slots, including the shortname entry.
@@ -1334,7 +1335,7 @@ found:
                        goto error_remove;
                }
                if (dir->i_size & (sbi->cluster_size - 1)) {
-                       fat_fs_panic(sb, "Odd directory size");
+                       fat_fs_error(sb, "Odd directory size");
                        dir->i_size = (dir->i_size + sbi->cluster_size - 1)
                                & ~((loff_t)sbi->cluster_size - 1);
                }
index e4d88527b5dd924c51186e43872127dca36ad7ee..adb0e72a176dd42bb8bdd1b4d099e021a02b02b1 100644 (file)
 #define VFAT_SFN_CREATE_WIN95  0x0100 /* emulate win95 rule for create */
 #define VFAT_SFN_CREATE_WINNT  0x0200 /* emulate winnt rule for create */
 
+#define FAT_ERRORS_CONT                1      /* ignore error and continue */
+#define FAT_ERRORS_PANIC       2      /* panic on error */
+#define FAT_ERRORS_RO          3      /* remount r/o on error */
+
 struct fat_mount_options {
        uid_t fs_uid;
        gid_t fs_gid;
@@ -26,6 +30,7 @@ struct fat_mount_options {
        char *iocharset;          /* Charset used for filename input/display */
        unsigned short shortname; /* flags for shortname display/create rule */
        unsigned char name_check; /* r = relaxed, n = normal, s = strict */
+       unsigned char errors;     /* On error: continue, panic, remount-ro */
        unsigned short allow_utime;/* permission for setting the [am]time */
        unsigned quiet:1,         /* set = fake successful chmods and chowns */
                 showexec:1,      /* set = only set x bit for com/exe/bat */
@@ -316,7 +321,7 @@ extern int fat_fill_super(struct super_block *sb, void *data, int silent,
 extern int fat_flush_inodes(struct super_block *sb, struct inode *i1,
                            struct inode *i2);
 /* fat/misc.c */
-extern void fat_fs_panic(struct super_block *s, const char *fmt, ...)
+extern void fat_fs_error(struct super_block *s, const char *fmt, ...)
        __attribute__ ((format (printf, 2, 3))) __cold;
 extern void fat_clusters_flush(struct super_block *sb);
 extern int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster);
index 618f5305c2e4f298bdb9742c5f5038ff57e9c22f..a81037721a6f12cb7e11d85f188c408ae2907699 100644 (file)
@@ -348,7 +348,7 @@ int fat_ent_read(struct inode *inode, struct fat_entry *fatent, int entry)
 
        if (entry < FAT_START_ENT || sbi->max_cluster <= entry) {
                fatent_brelse(fatent);
-               fat_fs_panic(sb, "invalid access to FAT (entry 0x%08x)", entry);
+               fat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", entry);
                return -EIO;
        }
 
@@ -560,7 +560,7 @@ int fat_free_clusters(struct inode *inode, int cluster)
                        err = cluster;
                        goto error;
                } else if (cluster == FAT_ENT_FREE) {
-                       fat_fs_panic(sb, "%s: deleting FAT entry beyond EOF",
+                       fat_fs_error(sb, "%s: deleting FAT entry beyond EOF",
                                     __func__);
                        err = -EIO;
                        goto error;
index e955a56b4e5ea0455c27782ce754d0734691ef49..b28ea646ff607cfdbe0f1ebda29158b5feadef88 100644 (file)
 #include <linux/security.h>
 #include "fat.h"
 
-int fat_generic_ioctl(struct inode *inode, struct file *filp,
-                     unsigned int cmd, unsigned long arg)
+static int fat_ioctl_get_attributes(struct inode *inode, u32 __user *user_attr)
 {
+       u32 attr;
+
+       mutex_lock(&inode->i_mutex);
+       attr = fat_make_attrs(inode);
+       mutex_unlock(&inode->i_mutex);
+
+       return put_user(attr, user_attr);
+}
+
+static int fat_ioctl_set_attributes(struct file *file, u32 __user *user_attr)
+{
+       struct inode *inode = file->f_path.dentry->d_inode;
        struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
-       u32 __user *user_attr = (u32 __user *)arg;
+       int is_dir = S_ISDIR(inode->i_mode);
+       u32 attr, oldattr;
+       struct iattr ia;
+       int err;
 
-       switch (cmd) {
-       case FAT_IOCTL_GET_ATTRIBUTES:
-       {
-               u32 attr;
+       err = get_user(attr, user_attr);
+       if (err)
+               goto out;
 
-               mutex_lock(&inode->i_mutex);
-               attr = fat_make_attrs(inode);
-               mutex_unlock(&inode->i_mutex);
+       mutex_lock(&inode->i_mutex);
+       err = mnt_want_write(file->f_path.mnt);
+       if (err)
+               goto out_unlock_inode;
 
-               return put_user(attr, user_attr);
+       /*
+        * ATTR_VOLUME and ATTR_DIR cannot be changed; this also
+        * prevents the user from turning us into a VFAT
+        * longname entry.  Also, we obviously can't set
+        * any of the NTFS attributes in the high 24 bits.
+        */
+       attr &= 0xff & ~(ATTR_VOLUME | ATTR_DIR);
+       /* Merge in ATTR_VOLUME and ATTR_DIR */
+       attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) |
+               (is_dir ? ATTR_DIR : 0);
+       oldattr = fat_make_attrs(inode);
+
+       /* Equivalent to a chmod() */
+       ia.ia_valid = ATTR_MODE | ATTR_CTIME;
+       ia.ia_ctime = current_fs_time(inode->i_sb);
+       if (is_dir)
+               ia.ia_mode = fat_make_mode(sbi, attr, S_IRWXUGO);
+       else {
+               ia.ia_mode = fat_make_mode(sbi, attr,
+                       S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO));
        }
-       case FAT_IOCTL_SET_ATTRIBUTES:
-       {
-               u32 attr, oldattr;
-               int err, is_dir = S_ISDIR(inode->i_mode);
-               struct iattr ia;
 
-               err = get_user(attr, user_attr);
-               if (err)
-                       return err;
+       /* The root directory has no attributes */
+       if (inode->i_ino == MSDOS_ROOT_INO && attr != ATTR_DIR) {
+               err = -EINVAL;
+               goto out_drop_write;
+       }
 
-               mutex_lock(&inode->i_mutex);
-
-               err = mnt_want_write(filp->f_path.mnt);
-               if (err)
-                       goto up_no_drop_write;
-
-               /*
-                * ATTR_VOLUME and ATTR_DIR cannot be changed; this also
-                * prevents the user from turning us into a VFAT
-                * longname entry.  Also, we obviously can't set
-                * any of the NTFS attributes in the high 24 bits.
-                */
-               attr &= 0xff & ~(ATTR_VOLUME | ATTR_DIR);
-               /* Merge in ATTR_VOLUME and ATTR_DIR */
-               attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) |
-                       (is_dir ? ATTR_DIR : 0);
-               oldattr = fat_make_attrs(inode);
-
-               /* Equivalent to a chmod() */
-               ia.ia_valid = ATTR_MODE | ATTR_CTIME;
-               ia.ia_ctime = current_fs_time(inode->i_sb);
-               if (is_dir)
-                       ia.ia_mode = fat_make_mode(sbi, attr, S_IRWXUGO);
-               else {
-                       ia.ia_mode = fat_make_mode(sbi, attr,
-                               S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO));
-               }
+       if (sbi->options.sys_immutable &&
+           ((attr | oldattr) & ATTR_SYS) &&
+           !capable(CAP_LINUX_IMMUTABLE)) {
+               err = -EPERM;
+               goto out_drop_write;
+       }
 
-               /* The root directory has no attributes */
-               if (inode->i_ino == MSDOS_ROOT_INO && attr != ATTR_DIR) {
-                       err = -EINVAL;
-                       goto up;
-               }
+       /*
+        * The security check is questionable...  We single
+        * out the RO attribute for checking by the security
+        * module, just because it maps to a file mode.
+        */
+       err = security_inode_setattr(file->f_path.dentry, &ia);
+       if (err)
+               goto out_drop_write;
 
-               if (sbi->options.sys_immutable) {
-                       if ((attr | oldattr) & ATTR_SYS) {
-                               if (!capable(CAP_LINUX_IMMUTABLE)) {
-                                       err = -EPERM;
-                                       goto up;
-                               }
-                       }
-               }
+       /* This MUST be done before doing anything irreversible... */
+       err = fat_setattr(file->f_path.dentry, &ia);
+       if (err)
+               goto out_drop_write;
+
+       fsnotify_change(file->f_path.dentry, ia.ia_valid);
+       if (sbi->options.sys_immutable) {
+               if (attr & ATTR_SYS)
+                       inode->i_flags |= S_IMMUTABLE;
+               else
+                       inode->i_flags &= S_IMMUTABLE;
+       }
 
-               /*
-                * The security check is questionable...  We single
-                * out the RO attribute for checking by the security
-                * module, just because it maps to a file mode.
-                */
-               err = security_inode_setattr(filp->f_path.dentry, &ia);
-               if (err)
-                       goto up;
-
-               /* This MUST be done before doing anything irreversible... */
-               err = fat_setattr(filp->f_path.dentry, &ia);
-               if (err)
-                       goto up;
-
-               fsnotify_change(filp->f_path.dentry, ia.ia_valid);
-               if (sbi->options.sys_immutable) {
-                       if (attr & ATTR_SYS)
-                               inode->i_flags |= S_IMMUTABLE;
-                       else
-                               inode->i_flags &= S_IMMUTABLE;
-               }
+       fat_save_attrs(inode, attr);
+       mark_inode_dirty(inode);
+out_drop_write:
+       mnt_drop_write(file->f_path.mnt);
+out_unlock_inode:
+       mutex_unlock(&inode->i_mutex);
+out:
+       return err;
+}
 
-               fat_save_attrs(inode, attr);
-               mark_inode_dirty(inode);
-up:
-               mnt_drop_write(filp->f_path.mnt);
-up_no_drop_write:
-               mutex_unlock(&inode->i_mutex);
-               return err;
-       }
+int fat_generic_ioctl(struct inode *inode, struct file *filp,
+                     unsigned int cmd, unsigned long arg)
+{
+       u32 __user *user_attr = (u32 __user *)arg;
+
+       switch (cmd) {
+       case FAT_IOCTL_GET_ATTRIBUTES:
+               return fat_ioctl_get_attributes(inode, user_attr);
+       case FAT_IOCTL_SET_ATTRIBUTES:
+               return fat_ioctl_set_attributes(filp, user_attr);
        default:
                return -ENOTTY; /* Inappropriate ioctl for device */
        }
@@ -225,7 +231,7 @@ static int fat_free(struct inode *inode, int skip)
                        fatent_brelse(&fatent);
                        return 0;
                } else if (ret == FAT_ENT_FREE) {
-                       fat_fs_panic(sb,
+                       fat_fs_error(sb,
                                     "%s: invalid cluster chain (i_pos %lld)",
                                     __func__, MSDOS_I(inode)->i_pos);
                        ret = -EIO;
index 51a5ecf9000ad3b95e187d0f2edac858cb164c89..304b411cb8bca697dca036fe386c8ace977305b6 100644 (file)
@@ -76,7 +76,7 @@ static inline int __fat_get_block(struct inode *inode, sector_t iblock,
                return 0;
 
        if (iblock != MSDOS_I(inode)->mmu_private >> sb->s_blocksize_bits) {
-               fat_fs_panic(sb, "corrupted file size (i_pos %lld, %lld)",
+               fat_fs_error(sb, "corrupted file size (i_pos %lld, %lld)",
                        MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private);
                return -EIO;
        }
@@ -856,6 +856,12 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt)
                seq_puts(m, ",flush");
        if (opts->tz_utc)
                seq_puts(m, ",tz=UTC");
+       if (opts->errors == FAT_ERRORS_CONT)
+               seq_puts(m, ",errors=continue");
+       else if (opts->errors == FAT_ERRORS_PANIC)
+               seq_puts(m, ",errors=panic");
+       else
+               seq_puts(m, ",errors=remount-ro");
 
        return 0;
 }
@@ -868,7 +874,8 @@ enum {
        Opt_charset, Opt_shortname_lower, Opt_shortname_win95,
        Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes,
        Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes,
-       Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err,
+       Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont,
+       Opt_err_panic, Opt_err_ro, Opt_err,
 };
 
 static const match_table_t fat_tokens = {
@@ -891,6 +898,11 @@ static const match_table_t fat_tokens = {
        {Opt_showexec, "showexec"},
        {Opt_debug, "debug"},
        {Opt_immutable, "sys_immutable"},
+       {Opt_flush, "flush"},
+       {Opt_tz_utc, "tz=UTC"},
+       {Opt_err_cont, "errors=continue"},
+       {Opt_err_panic, "errors=panic"},
+       {Opt_err_ro, "errors=remount-ro"},
        {Opt_obsolate, "conv=binary"},
        {Opt_obsolate, "conv=text"},
        {Opt_obsolate, "conv=auto"},
@@ -902,8 +914,6 @@ static const match_table_t fat_tokens = {
        {Opt_obsolate, "cvf_format=%20s"},
        {Opt_obsolate, "cvf_options=%100s"},
        {Opt_obsolate, "posix"},
-       {Opt_flush, "flush"},
-       {Opt_tz_utc, "tz=UTC"},
        {Opt_err, NULL},
 };
 static const match_table_t msdos_tokens = {
@@ -973,6 +983,7 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
        opts->numtail = 1;
        opts->usefree = opts->nocase = 0;
        opts->tz_utc = 0;
+       opts->errors = FAT_ERRORS_RO;
        *debug = 0;
 
        if (!options)
@@ -1065,6 +1076,15 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
                case Opt_tz_utc:
                        opts->tz_utc = 1;
                        break;
+               case Opt_err_cont:
+                       opts->errors = FAT_ERRORS_CONT;
+                       break;
+               case Opt_err_panic:
+                       opts->errors = FAT_ERRORS_PANIC;
+                       break;
+               case Opt_err_ro:
+                       opts->errors = FAT_ERRORS_RO;
+                       break;
 
                /* msdos specific */
                case Opt_dots:
index ac39ebcc149676b9eb35c15c8ddcff722f43a69f..a6c20473dfd75bd83d2d6caf1d4685078c687fb4 100644 (file)
 #include "fat.h"
 
 /*
- * fat_fs_panic reports a severe file system problem and sets the file system
- * read-only. The file system can be made writable again by remounting it.
+ * fat_fs_error reports a file system problem that might indicate fa data
+ * corruption/inconsistency. Depending on 'errors' mount option the
+ * panic() is called, or error message is printed FAT and nothing is done,
+ * or filesystem is remounted read-only (default behavior).
+ * In case the file system is remounted read-only, it can be made writable
+ * again by remounting it.
  */
-void fat_fs_panic(struct super_block *s, const char *fmt, ...)
+void fat_fs_error(struct super_block *s, const char *fmt, ...)
 {
+       struct fat_mount_options *opts = &MSDOS_SB(s)->options;
        va_list args;
 
-       printk(KERN_ERR "FAT: Filesystem panic (dev %s)\n", s->s_id);
+       printk(KERN_ERR "FAT: Filesystem error (dev %s)\n", s->s_id);
 
        printk(KERN_ERR "    ");
        va_start(args, fmt);
@@ -27,13 +32,14 @@ void fat_fs_panic(struct super_block *s, const char *fmt, ...)
        va_end(args);
        printk("\n");
 
-       if (!(s->s_flags & MS_RDONLY)) {
+       if (opts->errors == FAT_ERRORS_PANIC)
+               panic("    FAT fs panic from previous error\n");
+       else if (opts->errors == FAT_ERRORS_RO && !(s->s_flags & MS_RDONLY)) {
                s->s_flags |= MS_RDONLY;
                printk(KERN_ERR "    File system has been set read-only\n");
        }
 }
-
-EXPORT_SYMBOL_GPL(fat_fs_panic);
+EXPORT_SYMBOL_GPL(fat_fs_error);
 
 /* Flushes the number of free clusters on FAT32 */
 /* XXX: Need to write one per FSINFO block.  Currently only writes 1 */
@@ -124,7 +130,7 @@ int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster)
                        mark_inode_dirty(inode);
        }
        if (new_fclus != (inode->i_blocks >> (sbi->cluster_bits - 9))) {
-               fat_fs_panic(sb, "clusters badly computed (%d != %llu)",
+               fat_fs_error(sb, "clusters badly computed (%d != %llu)",
                             new_fclus,
                             (llu)(inode->i_blocks >> (sbi->cluster_bits - 9)));
                fat_cache_inval_inode(inode);
index 20f522861355ae9439e5ed10303af53d8ab4c22d..82f88733b681accfa68bdeb86bed85734b9fcc6e 100644 (file)
@@ -608,7 +608,7 @@ error_inode:
                sinfo.bh = NULL;
        }
        if (corrupt < 0) {
-               fat_fs_panic(new_dir->i_sb,
+               fat_fs_error(new_dir->i_sb,
                             "%s: Filesystem corrupted (i_pos %lld)",
                             __func__, sinfo.i_pos);
        }
index b50ecbe97f83d09a412390c96a750facfcf603e9..73471b7ecc8c2bd90591f43391afaaeacf6c39af 100644 (file)
@@ -502,11 +502,11 @@ xlate_to_uni(const unsigned char *name, int len, unsigned char *outname,
        if (utf8) {
                int name_len = strlen(name);
 
-               *outlen = utf8_mbstowcs((wchar_t *)outname, name, PATH_MAX);
+               *outlen = utf8s_to_utf16s(name, PATH_MAX, (wchar_t *) outname);
 
                /*
                 * We stripped '.'s before and set len appropriately,
-                * but utf8_mbstowcs doesn't care about len
+                * but utf8s_to_utf16s doesn't care about len
                 */
                *outlen -= (name_len - len);
 
@@ -1030,7 +1030,7 @@ error_inode:
                sinfo.bh = NULL;
        }
        if (corrupt < 0) {
-               fat_fs_panic(new_dir->i_sb,
+               fat_fs_error(new_dir->i_sb,
                             "%s: Filesystem corrupted (i_pos %lld)",
                             __func__, sinfo.i_pos);
        }
index 1ad703150dee08d9bec6c481f480b99ae7b149d5..a040b764f8e38b6a5067642713d4f9c6e9dc92ba 100644 (file)
@@ -198,15 +198,19 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
 }
 
 static void f_modown(struct file *filp, struct pid *pid, enum pid_type type,
-                     uid_t uid, uid_t euid, int force)
+                     int force)
 {
        write_lock_irq(&filp->f_owner.lock);
        if (force || !filp->f_owner.pid) {
                put_pid(filp->f_owner.pid);
                filp->f_owner.pid = get_pid(pid);
                filp->f_owner.pid_type = type;
-               filp->f_owner.uid = uid;
-               filp->f_owner.euid = euid;
+
+               if (pid) {
+                       const struct cred *cred = current_cred();
+                       filp->f_owner.uid = cred->uid;
+                       filp->f_owner.euid = cred->euid;
+               }
        }
        write_unlock_irq(&filp->f_owner.lock);
 }
@@ -214,14 +218,13 @@ static void f_modown(struct file *filp, struct pid *pid, enum pid_type type,
 int __f_setown(struct file *filp, struct pid *pid, enum pid_type type,
                int force)
 {
-       const struct cred *cred = current_cred();
        int err;
-       
+
        err = security_file_set_fowner(filp);
        if (err)
                return err;
 
-       f_modown(filp, pid, type, cred->uid, cred->euid, force);
+       f_modown(filp, pid, type, force);
        return 0;
 }
 EXPORT_SYMBOL(__f_setown);
@@ -247,7 +250,7 @@ EXPORT_SYMBOL(f_setown);
 
 void f_delown(struct file *filp)
 {
-       f_modown(filp, NULL, PIDTYPE_PID, 0, 0, 1);
+       f_modown(filp, NULL, PIDTYPE_PID, 1);
 }
 
 pid_t f_getown(struct file *filp)
@@ -425,14 +428,20 @@ static inline int sigio_perm(struct task_struct *p,
 }
 
 static void send_sigio_to_task(struct task_struct *p,
-                              struct fown_struct *fown, 
+                              struct fown_struct *fown,
                               int fd,
                               int reason)
 {
-       if (!sigio_perm(p, fown, fown->signum))
+       /*
+        * F_SETSIG can change ->signum lockless in parallel, make
+        * sure we read it once and use the same value throughout.
+        */
+       int signum = ACCESS_ONCE(fown->signum);
+
+       if (!sigio_perm(p, fown, signum))
                return;
 
-       switch (fown->signum) {
+       switch (signum) {
                siginfo_t si;
                default:
                        /* Queue a rt signal with the appropriate fd as its
@@ -441,7 +450,7 @@ static void send_sigio_to_task(struct task_struct *p,
                           delivered even if we can't queue.  Failure to
                           queue in this case _should_ be reported; we fall
                           back to SIGIO in that case. --sct */
-                       si.si_signo = fown->signum;
+                       si.si_signo = signum;
                        si.si_errno = 0;
                        si.si_code  = reason;
                        /* Make sure we are called with one of the POLL_*
@@ -453,7 +462,7 @@ static void send_sigio_to_task(struct task_struct *p,
                        else
                                si.si_band = band_table[reason - POLL_IN];
                        si.si_fd    = fd;
-                       if (!group_send_sig_info(fown->signum, &si, p))
+                       if (!group_send_sig_info(signum, &si, p))
                                break;
                /* fall-through: fall back on the old plain SIGIO signal */
                case 0:
index 40308e98c6a44f9763354b375ba4c51bb569607a..caf049146ca27a537a7dddc4a38ba02f085a6b35 100644 (file)
@@ -321,7 +321,7 @@ __sync_single_inode(struct inode *inode, struct writeback_control *wbc)
 
        spin_lock(&inode_lock);
        inode->i_state &= ~I_SYNC;
-       if (!(inode->i_state & I_FREEING)) {
+       if (!(inode->i_state & (I_FREEING | I_CLEAR))) {
                if (!(inode->i_state & I_DIRTY) &&
                    mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) {
                        /*
@@ -492,7 +492,7 @@ void generic_sync_sb_inodes(struct super_block *sb,
                        break;
                }
 
-               if (inode->i_state & I_NEW) {
+               if (inode->i_state & (I_NEW | I_WILL_FREE)) {
                        requeue_io(inode);
                        continue;
                }
@@ -523,7 +523,7 @@ void generic_sync_sb_inodes(struct super_block *sb,
                if (current_is_pdflush() && !writeback_acquire(bdi))
                        break;
 
-               BUG_ON(inode->i_state & I_FREEING);
+               BUG_ON(inode->i_state & (I_FREEING | I_CLEAR));
                __iget(inode);
                pages_skipped = wbc->pages_skipped;
                __writeback_single_inode(inode, wbc);
index 92c14b850e9cadeaf2179ca012130cfa6b744204..a048de81c09318ae5ccd092f5675649a50a7025b 100644 (file)
@@ -37,37 +37,6 @@ uni16_to_x8(unsigned char *ascii, __be16 *uni, int len, struct nls_table *nls)
        return (op - ascii);
 }
 
-/* Convert big endian wide character string to utf8 */
-static int
-wcsntombs_be(__u8 *s, const __u8 *pwcs, int inlen, int maxlen)
-{
-       const __u8 *ip;
-       __u8 *op;
-       int size;
-       __u16 c;
-
-       op = s;
-       ip = pwcs;
-       while ((*ip || ip[1]) && (maxlen > 0) && (inlen > 0)) {
-               c = (*ip << 8) | ip[1];
-               if (c > 0x7f) {
-                       size = utf8_wctomb(op, c, maxlen);
-                       if (size == -1) {
-                               /* Ignore character and move on */
-                               maxlen--;
-                       } else {
-                               op += size;
-                               maxlen -= size;
-                       }
-               } else {
-                       *op++ = (__u8) c;
-               }
-               ip += 2;
-               inlen--;
-       }
-       return (op - s);
-}
-
 int
 get_joliet_filename(struct iso_directory_record * de, unsigned char *outname, struct inode * inode)
 {
@@ -79,8 +48,9 @@ get_joliet_filename(struct iso_directory_record * de, unsigned char *outname, st
        nls = ISOFS_SB(inode->i_sb)->s_nls_iocharset;
 
        if (utf8) {
-               len = wcsntombs_be(outname, de->name,
-                               de->name_len[0] >> 1, PAGE_SIZE);
+               len = utf16s_to_utf8s((const wchar_t *) de->name,
+                               de->name_len[0] >> 1, UTF16_BIG_ENDIAN,
+                               outname, PAGE_SIZE);
        } else {
                len = uni16_to_x8(outname, (__be16 *) de->name,
                                de->name_len[0] >> 1, nls);
index bbbd5f202e3740d7e735449eb8e6e9626d56e4f1..41d6045dbeb08b5db952e9945a054bf722470451 100644 (file)
@@ -391,6 +391,7 @@ int extHint(struct inode *ip, s64 offset, xad_t * xp)
                }
                XADaddress(xp, xaddr);
                XADlength(xp, xlen);
+               XADoffset(xp, prev);
                /*
                 * only preserve the abnr flag within the xad flags
                 * of the returned hint.
index 97645f112114e0c2f1aa4304a1f85046ec66ebb6..0ec6237a5970f162e0ed0d72b33fa9f1e15a7b86 100644 (file)
@@ -1113,11 +1113,13 @@ ncp__io2vol(struct ncp_server *server, unsigned char *vname, unsigned int *vlen,
 
                if (NCP_IS_FLAG(server, NCP_FLAG_UTF8)) {
                        int k;
+                       unicode_t u;
 
-                       k = utf8_mbtowc(&ec, iname, iname_end - iname);
-                       if (k < 0)
+                       k = utf8_to_utf32(iname, iname_end - iname, &u);
+                       if (k < 0 || u > MAX_WCHAR_T)
                                return -EINVAL;
                        iname += k;
+                       ec = u;
                } else {
                        if (*iname == NCP_ESC) {
                                int k;
@@ -1214,7 +1216,7 @@ ncp__vol2io(struct ncp_server *server, unsigned char *iname, unsigned int *ilen,
                if (NCP_IS_FLAG(server, NCP_FLAG_UTF8)) {
                        int k;
 
-                       k = utf8_wctomb(iname, ec, iname_end - iname);
+                       k = utf32_to_utf8(ec, iname, iname_end - iname);
                        if (k < 0) {
                                err = -ENAMETOOLONG;
                                goto quit;
index a2ab2529b5ca4ee1c1ac2b8e3889e4651bb8f1ac..ceda50aad73cc5a3bc93baeaaa7771ebd7a0f00f 100644 (file)
@@ -31,7 +31,7 @@ static inline void nfs_inc_server_stats(const struct nfs_server *server,
        cpu = get_cpu();
        iostats = per_cpu_ptr(server->io_stats, cpu);
        iostats->events[stat]++;
-       put_cpu_no_resched();
+       put_cpu();
 }
 
 static inline void nfs_inc_stats(const struct inode *inode,
@@ -50,7 +50,7 @@ static inline void nfs_add_server_stats(const struct nfs_server *server,
        cpu = get_cpu();
        iostats = per_cpu_ptr(server->io_stats, cpu);
        iostats->bytes[stat] += addend;
-       put_cpu_no_resched();
+       put_cpu();
 }
 
 static inline void nfs_add_stats(const struct inode *inode,
@@ -71,7 +71,7 @@ static inline void nfs_add_fscache_stats(struct inode *inode,
        cpu = get_cpu();
        iostats = per_cpu_ptr(NFS_SERVER(inode)->io_stats, cpu);
        iostats->fscache[stat] += addend;
-       put_cpu_no_resched();
+       put_cpu();
 }
 #endif
 
index 9b0efdad89100bd60e5a15954b67ca83495cad56..477d37d83b316367e1ac04fb31ba98e375a37b1a 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/errno.h>
 #include <linux/kmod.h>
 #include <linux/spinlock.h>
+#include <asm/byteorder.h>
 
 static struct nls_table default_table;
 static struct nls_table *tables = &default_table;
@@ -43,10 +44,17 @@ static const struct utf8_table utf8_table[] =
     {0,                                                       /* end of table    */}
 };
 
-int
-utf8_mbtowc(wchar_t *p, const __u8 *s, int n)
+#define UNICODE_MAX    0x0010ffff
+#define PLANE_SIZE     0x00010000
+
+#define SURROGATE_MASK 0xfffff800
+#define SURROGATE_PAIR 0x0000d800
+#define SURROGATE_LOW  0x00000400
+#define SURROGATE_BITS 0x000003ff
+
+int utf8_to_utf32(const u8 *s, int len, unicode_t *pu)
 {
-       long l;
+       unsigned long l;
        int c0, c, nc;
        const struct utf8_table *t;
   
@@ -57,12 +65,13 @@ utf8_mbtowc(wchar_t *p, const __u8 *s, int n)
                nc++;
                if ((c0 & t->cmask) == t->cval) {
                        l &= t->lmask;
-                       if (l < t->lval)
+                       if (l < t->lval || l > UNICODE_MAX ||
+                                       (l & SURROGATE_MASK) == SURROGATE_PAIR)
                                return -1;
-                       *p = l;
+                       *pu = (unicode_t) l;
                        return nc;
                }
-               if (n <= nc)
+               if (len <= nc)
                        return -1;
                s++;
                c = (*s ^ 0x80) & 0xFF;
@@ -72,90 +81,133 @@ utf8_mbtowc(wchar_t *p, const __u8 *s, int n)
        }
        return -1;
 }
+EXPORT_SYMBOL(utf8_to_utf32);
 
-int
-utf8_mbstowcs(wchar_t *pwcs, const __u8 *s, int n)
+int utf32_to_utf8(unicode_t u, u8 *s, int maxlen)
 {
-       __u16 *op;
-       const __u8 *ip;
-       int size;
-
-       op = pwcs;
-       ip = s;
-       while (*ip && n > 0) {
-               if (*ip & 0x80) {
-                       size = utf8_mbtowc(op, ip, n);
-                       if (size == -1) {
-                               /* Ignore character and move on */
-                               ip++;
-                               n--;
-                       } else {
-                               op++;
-                               ip += size;
-                               n -= size;
-                       }
-               } else {
-                       *op++ = *ip++;
-                       n--;
-               }
-       }
-       return (op - pwcs);
-}
-
-int
-utf8_wctomb(__u8 *s, wchar_t wc, int maxlen)
-{
-       long l;
+       unsigned long l;
        int c, nc;
        const struct utf8_table *t;
-  
+
        if (!s)
                return 0;
-  
-       l = wc;
+
+       l = u;
+       if (l > UNICODE_MAX || (l & SURROGATE_MASK) == SURROGATE_PAIR)
+               return -1;
+
        nc = 0;
        for (t = utf8_table; t->cmask && maxlen; t++, maxlen--) {
                nc++;
                if (l <= t->lmask) {
                        c = t->shift;
-                       *s = t->cval | (l >> c);
+                       *s = (u8) (t->cval | (l >> c));
                        while (c > 0) {
                                c -= 6;
                                s++;
-                               *s = 0x80 | ((l >> c) & 0x3F);
+                               *s = (u8) (0x80 | ((l >> c) & 0x3F));
                        }
                        return nc;
                }
        }
        return -1;
 }
+EXPORT_SYMBOL(utf32_to_utf8);
 
-int
-utf8_wcstombs(__u8 *s, const wchar_t *pwcs, int maxlen)
+int utf8s_to_utf16s(const u8 *s, int len, wchar_t *pwcs)
 {
-       const __u16 *ip;
-       __u8 *op;
+       u16 *op;
        int size;
+       unicode_t u;
+
+       op = pwcs;
+       while (*s && len > 0) {
+               if (*s & 0x80) {
+                       size = utf8_to_utf32(s, len, &u);
+                       if (size < 0) {
+                               /* Ignore character and move on */
+                               size = 1;
+                       } else if (u >= PLANE_SIZE) {
+                               u -= PLANE_SIZE;
+                               *op++ = (wchar_t) (SURROGATE_PAIR |
+                                               ((u >> 10) & SURROGATE_BITS));
+                               *op++ = (wchar_t) (SURROGATE_PAIR |
+                                               SURROGATE_LOW |
+                                               (u & SURROGATE_BITS));
+                       } else {
+                               *op++ = (wchar_t) u;
+                       }
+                       s += size;
+                       len -= size;
+               } else {
+                       *op++ = *s++;
+                       len--;
+               }
+       }
+       return op - pwcs;
+}
+EXPORT_SYMBOL(utf8s_to_utf16s);
+
+static inline unsigned long get_utf16(unsigned c, enum utf16_endian endian)
+{
+       switch (endian) {
+       default:
+               return c;
+       case UTF16_LITTLE_ENDIAN:
+               return __le16_to_cpu(c);
+       case UTF16_BIG_ENDIAN:
+               return __be16_to_cpu(c);
+       }
+}
+
+int utf16s_to_utf8s(const wchar_t *pwcs, int len, enum utf16_endian endian,
+               u8 *s, int maxlen)
+{
+       u8 *op;
+       int size;
+       unsigned long u, v;
 
        op = s;
-       ip = pwcs;
-       while (*ip && maxlen > 0) {
-               if (*ip > 0x7f) {
-                       size = utf8_wctomb(op, *ip, maxlen);
+       while (len > 0 && maxlen > 0) {
+               u = get_utf16(*pwcs, endian);
+               if (!u)
+                       break;
+               pwcs++;
+               len--;
+               if (u > 0x7f) {
+                       if ((u & SURROGATE_MASK) == SURROGATE_PAIR) {
+                               if (u & SURROGATE_LOW) {
+                                       /* Ignore character and move on */
+                                       continue;
+                               }
+                               if (len <= 0)
+                                       break;
+                               v = get_utf16(*pwcs, endian);
+                               if ((v & SURROGATE_MASK) != SURROGATE_PAIR ||
+                                               !(v & SURROGATE_LOW)) {
+                                       /* Ignore character and move on */
+                                       continue;
+                               }
+                               u = PLANE_SIZE + ((u & SURROGATE_BITS) << 10)
+                                               + (v & SURROGATE_BITS);
+                               pwcs++;
+                               len--;
+                       }
+                       size = utf32_to_utf8(u, op, maxlen);
                        if (size == -1) {
                                /* Ignore character and move on */
-                               maxlen--;
                        } else {
                                op += size;
                                maxlen -= size;
                        }
                } else {
-                       *op++ = (__u8) *ip;
+                       *op++ = (u8) u;
+                       maxlen--;
                }
-               ip++;
        }
-       return (op - s);
+       return op - s;
 }
+EXPORT_SYMBOL(utf16s_to_utf8s);
 
 int register_nls(struct nls_table * nls)
 {
@@ -467,9 +519,5 @@ EXPORT_SYMBOL(unregister_nls);
 EXPORT_SYMBOL(unload_nls);
 EXPORT_SYMBOL(load_nls);
 EXPORT_SYMBOL(load_nls_default);
-EXPORT_SYMBOL(utf8_mbtowc);
-EXPORT_SYMBOL(utf8_mbstowcs);
-EXPORT_SYMBOL(utf8_wctomb);
-EXPORT_SYMBOL(utf8_wcstombs);
 
 MODULE_LICENSE("Dual BSD/GPL");
index aa2c42fdd977d8ed481e9e303382e608d1f6a9d8..0d60a44acacd42b7eee10349a672a9ec9a74240a 100644 (file)
@@ -15,7 +15,11 @@ static int uni2char(wchar_t uni, unsigned char *out, int boundlen)
 {
        int n;
 
-       if ( (n = utf8_wctomb(out, uni, boundlen)) == -1) {
+       if (boundlen <= 0)
+               return -ENAMETOOLONG;
+
+       n = utf32_to_utf8(uni, out, boundlen);
+       if (n < 0) {
                *out = '?';
                return -EINVAL;
        }
@@ -25,11 +29,14 @@ static int uni2char(wchar_t uni, unsigned char *out, int boundlen)
 static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni)
 {
        int n;
+       unicode_t u;
 
-       if ( (n = utf8_mbtowc(uni, rawstring, boundlen)) == -1) {
+       n = utf8_to_utf32(rawstring, boundlen, &u);
+       if (n < 0 || u > MAX_WCHAR_T) {
                *uni = 0x003f;  /* ? */
-               n = -EINVAL;
+               return -EINVAL;
        }
+       *uni = (wchar_t) u;
        return n;
 }
 
index 82c5085559c6796332f97bfe3064861c5cc46aad..9938034762cca7867007dc841af663b0f097c574 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/pagemap.h>
 #include <linux/quotaops.h>
 #include <linux/slab.h>
+#include <linux/log2.h>
 
 #include "aops.h"
 #include "attrib.h"
@@ -1570,7 +1571,7 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi)
        ntfs_debug("Index collation rule is 0x%x.",
                        le32_to_cpu(ir->collation_rule));
        ni->itype.index.block_size = le32_to_cpu(ir->index_block_size);
-       if (ni->itype.index.block_size & (ni->itype.index.block_size - 1)) {
+       if (!is_power_of_2(ni->itype.index.block_size)) {
                ntfs_error(vi->i_sb, "Index block size (%u) is not a power of "
                                "two.", ni->itype.index.block_size);
                goto unm_err_out;
index d7932e95b1fdfe09ad3e46c78799aa1304d87dc5..89b02985c054e7d05fdf0b147ecf970b7d498e22 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/highmem.h>
 #include <linux/buffer_head.h>
 #include <linux/bitops.h>
+#include <linux/log2.h>
 
 #include "attrib.h"
 #include "aops.h"
@@ -65,7 +66,7 @@ static bool ntfs_check_restart_page_header(struct inode *vi,
                        logfile_log_page_size < NTFS_BLOCK_SIZE ||
                        logfile_system_page_size &
                        (logfile_system_page_size - 1) ||
-                       logfile_log_page_size & (logfile_log_page_size - 1)) {
+                       !is_power_of_2(logfile_log_page_size)) {
                ntfs_error(vi->i_sb, "$LogFile uses unsupported page size.");
                return false;
        }
index 678a067d9251f12424ee9486cc81960749bc33ec..9edcde4974aa22a37841d8b22aac86c7e435cea6 100644 (file)
@@ -475,6 +475,12 @@ struct ocfs2_path {
 #define path_leaf_el(_path) ((_path)->p_node[(_path)->p_tree_depth].el)
 #define path_num_items(_path) ((_path)->p_tree_depth + 1)
 
+static int ocfs2_find_path(struct inode *inode, struct ocfs2_path *path,
+                          u32 cpos);
+static void ocfs2_adjust_rightmost_records(struct inode *inode,
+                                          handle_t *handle,
+                                          struct ocfs2_path *path,
+                                          struct ocfs2_extent_rec *insert_rec);
 /*
  * Reset the actual path elements so that we can re-use the structure
  * to build another path. Generally, this involves freeing the buffer
@@ -1012,6 +1018,54 @@ static inline u32 ocfs2_sum_rightmost_rec(struct ocfs2_extent_list  *el)
                ocfs2_rec_clusters(el, &el->l_recs[i]);
 }
 
+/*
+ * Change range of the branches in the right most path according to the leaf
+ * extent block's rightmost record.
+ */
+static int ocfs2_adjust_rightmost_branch(handle_t *handle,
+                                        struct inode *inode,
+                                        struct ocfs2_extent_tree *et)
+{
+       int status;
+       struct ocfs2_path *path = NULL;
+       struct ocfs2_extent_list *el;
+       struct ocfs2_extent_rec *rec;
+
+       path = ocfs2_new_path_from_et(et);
+       if (!path) {
+               status = -ENOMEM;
+               return status;
+       }
+
+       status = ocfs2_find_path(inode, path, UINT_MAX);
+       if (status < 0) {
+               mlog_errno(status);
+               goto out;
+       }
+
+       status = ocfs2_extend_trans(handle, path_num_items(path) +
+                                   handle->h_buffer_credits);
+       if (status < 0) {
+               mlog_errno(status);
+               goto out;
+       }
+
+       status = ocfs2_journal_access_path(inode, handle, path);
+       if (status < 0) {
+               mlog_errno(status);
+               goto out;
+       }
+
+       el = path_leaf_el(path);
+       rec = &el->l_recs[le32_to_cpu(el->l_next_free_rec) - 1];
+
+       ocfs2_adjust_rightmost_records(inode, handle, path, rec);
+
+out:
+       ocfs2_free_path(path);
+       return status;
+}
+
 /*
  * Add an entire tree branch to our inode. eb_bh is the extent block
  * to start at, if we don't want to start the branch at the dinode
@@ -1038,7 +1092,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
        struct ocfs2_extent_block *eb;
        struct ocfs2_extent_list  *eb_el;
        struct ocfs2_extent_list  *el;
-       u32 new_cpos;
+       u32 new_cpos, root_end;
 
        mlog_entry_void();
 
@@ -1055,6 +1109,27 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
 
        new_blocks = le16_to_cpu(el->l_tree_depth);
 
+       eb = (struct ocfs2_extent_block *)(*last_eb_bh)->b_data;
+       new_cpos = ocfs2_sum_rightmost_rec(&eb->h_list);
+       root_end = ocfs2_sum_rightmost_rec(et->et_root_el);
+
+       /*
+        * If there is a gap before the root end and the real end
+        * of the righmost leaf block, we need to remove the gap
+        * between new_cpos and root_end first so that the tree
+        * is consistent after we add a new branch(it will start
+        * from new_cpos).
+        */
+       if (root_end > new_cpos) {
+               mlog(0, "adjust the cluster end from %u to %u\n",
+                    root_end, new_cpos);
+               status = ocfs2_adjust_rightmost_branch(handle, inode, et);
+               if (status) {
+                       mlog_errno(status);
+                       goto bail;
+               }
+       }
+
        /* allocate the number of new eb blocks we need */
        new_eb_bhs = kcalloc(new_blocks, sizeof(struct buffer_head *),
                             GFP_KERNEL);
@@ -1071,9 +1146,6 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
                goto bail;
        }
 
-       eb = (struct ocfs2_extent_block *)(*last_eb_bh)->b_data;
-       new_cpos = ocfs2_sum_rightmost_rec(&eb->h_list);
-
        /* Note: new_eb_bhs[new_blocks - 1] is the guy which will be
         * linked with the rest of the tree.
         * conversly, new_eb_bhs[0] is the new bottommost leaf.
index 2a947c44e5949173817d36716ffb3c7b8bbdeec8..a1163b8b417c5cbf4ac5e1dcaf522f34a300a22b 100644 (file)
@@ -22,6 +22,9 @@
 #include <linux/crc32.h>
 #include <linux/buffer_head.h>
 #include <linux/bitops.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/fs.h>
 #include <asm/byteorder.h>
 
 #include <cluster/masklog.h>
@@ -222,6 +225,155 @@ void ocfs2_hamming_fix_block(void *data, unsigned int blocksize,
        ocfs2_hamming_fix(data, blocksize * 8, 0, fix);
 }
 
+
+/*
+ * Debugfs handling.
+ */
+
+#ifdef CONFIG_DEBUG_FS
+
+static int blockcheck_u64_get(void *data, u64 *val)
+{
+       *val = *(u64 *)data;
+       return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(blockcheck_fops, blockcheck_u64_get, NULL, "%llu\n");
+
+static struct dentry *blockcheck_debugfs_create(const char *name,
+                                               struct dentry *parent,
+                                               u64 *value)
+{
+       return debugfs_create_file(name, S_IFREG | S_IRUSR, parent, value,
+                                  &blockcheck_fops);
+}
+
+static void ocfs2_blockcheck_debug_remove(struct ocfs2_blockcheck_stats *stats)
+{
+       if (stats) {
+               debugfs_remove(stats->b_debug_check);
+               stats->b_debug_check = NULL;
+               debugfs_remove(stats->b_debug_failure);
+               stats->b_debug_failure = NULL;
+               debugfs_remove(stats->b_debug_recover);
+               stats->b_debug_recover = NULL;
+               debugfs_remove(stats->b_debug_dir);
+               stats->b_debug_dir = NULL;
+       }
+}
+
+static int ocfs2_blockcheck_debug_install(struct ocfs2_blockcheck_stats *stats,
+                                         struct dentry *parent)
+{
+       int rc = -EINVAL;
+
+       if (!stats)
+               goto out;
+
+       stats->b_debug_dir = debugfs_create_dir("blockcheck", parent);
+       if (!stats->b_debug_dir)
+               goto out;
+
+       stats->b_debug_check =
+               blockcheck_debugfs_create("blocks_checked",
+                                         stats->b_debug_dir,
+                                         &stats->b_check_count);
+
+       stats->b_debug_failure =
+               blockcheck_debugfs_create("checksums_failed",
+                                         stats->b_debug_dir,
+                                         &stats->b_failure_count);
+
+       stats->b_debug_recover =
+               blockcheck_debugfs_create("ecc_recoveries",
+                                         stats->b_debug_dir,
+                                         &stats->b_recover_count);
+       if (stats->b_debug_check && stats->b_debug_failure &&
+           stats->b_debug_recover)
+               rc = 0;
+
+out:
+       if (rc)
+               ocfs2_blockcheck_debug_remove(stats);
+       return rc;
+}
+#else
+static inline int ocfs2_blockcheck_debug_install(struct ocfs2_blockcheck_stats *stats,
+                                                struct dentry *parent)
+{
+       return 0;
+}
+
+static inline void ocfs2_blockcheck_debug_remove(struct ocfs2_blockcheck_stats *stats)
+{
+}
+#endif  /* CONFIG_DEBUG_FS */
+
+/* Always-called wrappers for starting and stopping the debugfs files */
+int ocfs2_blockcheck_stats_debugfs_install(struct ocfs2_blockcheck_stats *stats,
+                                          struct dentry *parent)
+{
+       return ocfs2_blockcheck_debug_install(stats, parent);
+}
+
+void ocfs2_blockcheck_stats_debugfs_remove(struct ocfs2_blockcheck_stats *stats)
+{
+       ocfs2_blockcheck_debug_remove(stats);
+}
+
+static void ocfs2_blockcheck_inc_check(struct ocfs2_blockcheck_stats *stats)
+{
+       u64 new_count;
+
+       if (!stats)
+               return;
+
+       spin_lock(&stats->b_lock);
+       stats->b_check_count++;
+       new_count = stats->b_check_count;
+       spin_unlock(&stats->b_lock);
+
+       if (!new_count)
+               mlog(ML_NOTICE, "Block check count has wrapped\n");
+}
+
+static void ocfs2_blockcheck_inc_failure(struct ocfs2_blockcheck_stats *stats)
+{
+       u64 new_count;
+
+       if (!stats)
+               return;
+
+       spin_lock(&stats->b_lock);
+       stats->b_failure_count++;
+       new_count = stats->b_failure_count;
+       spin_unlock(&stats->b_lock);
+
+       if (!new_count)
+               mlog(ML_NOTICE, "Checksum failure count has wrapped\n");
+}
+
+static void ocfs2_blockcheck_inc_recover(struct ocfs2_blockcheck_stats *stats)
+{
+       u64 new_count;
+
+       if (!stats)
+               return;
+
+       spin_lock(&stats->b_lock);
+       stats->b_recover_count++;
+       new_count = stats->b_recover_count;
+       spin_unlock(&stats->b_lock);
+
+       if (!new_count)
+               mlog(ML_NOTICE, "ECC recovery count has wrapped\n");
+}
+
+
+
+/*
+ * These are the low-level APIs for using the ocfs2_block_check structure.
+ */
+
 /*
  * This function generates check information for a block.
  * data is the block to be checked.  bc is a pointer to the
@@ -266,12 +418,15 @@ void ocfs2_block_check_compute(void *data, size_t blocksize,
  * Again, the data passed in should be the on-disk endian.
  */
 int ocfs2_block_check_validate(void *data, size_t blocksize,
-                              struct ocfs2_block_check *bc)
+                              struct ocfs2_block_check *bc,
+                              struct ocfs2_blockcheck_stats *stats)
 {
        int rc = 0;
        struct ocfs2_block_check check;
        u32 crc, ecc;
 
+       ocfs2_blockcheck_inc_check(stats);
+
        check.bc_crc32e = le32_to_cpu(bc->bc_crc32e);
        check.bc_ecc = le16_to_cpu(bc->bc_ecc);
 
@@ -282,6 +437,7 @@ int ocfs2_block_check_validate(void *data, size_t blocksize,
        if (crc == check.bc_crc32e)
                goto out;
 
+       ocfs2_blockcheck_inc_failure(stats);
        mlog(ML_ERROR,
             "CRC32 failed: stored: %u, computed %u.  Applying ECC.\n",
             (unsigned int)check.bc_crc32e, (unsigned int)crc);
@@ -292,8 +448,10 @@ int ocfs2_block_check_validate(void *data, size_t blocksize,
 
        /* And check the crc32 again */
        crc = crc32_le(~0, data, blocksize);
-       if (crc == check.bc_crc32e)
+       if (crc == check.bc_crc32e) {
+               ocfs2_blockcheck_inc_recover(stats);
                goto out;
+       }
 
        mlog(ML_ERROR, "Fixed CRC32 failed: stored: %u, computed %u\n",
             (unsigned int)check.bc_crc32e, (unsigned int)crc);
@@ -366,7 +524,8 @@ void ocfs2_block_check_compute_bhs(struct buffer_head **bhs, int nr,
  * Again, the data passed in should be the on-disk endian.
  */
 int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
-                                  struct ocfs2_block_check *bc)
+                                  struct ocfs2_block_check *bc,
+                                  struct ocfs2_blockcheck_stats *stats)
 {
        int i, rc = 0;
        struct ocfs2_block_check check;
@@ -377,6 +536,8 @@ int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
        if (!nr)
                return 0;
 
+       ocfs2_blockcheck_inc_check(stats);
+
        check.bc_crc32e = le32_to_cpu(bc->bc_crc32e);
        check.bc_ecc = le16_to_cpu(bc->bc_ecc);
 
@@ -388,6 +549,7 @@ int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
        if (crc == check.bc_crc32e)
                goto out;
 
+       ocfs2_blockcheck_inc_failure(stats);
        mlog(ML_ERROR,
             "CRC32 failed: stored: %u, computed %u.  Applying ECC.\n",
             (unsigned int)check.bc_crc32e, (unsigned int)crc);
@@ -416,8 +578,10 @@ int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
        /* And check the crc32 again */
        for (i = 0, crc = ~0; i < nr; i++)
                crc = crc32_le(crc, bhs[i]->b_data, bhs[i]->b_size);
-       if (crc == check.bc_crc32e)
+       if (crc == check.bc_crc32e) {
+               ocfs2_blockcheck_inc_recover(stats);
                goto out;
+       }
 
        mlog(ML_ERROR, "Fixed CRC32 failed: stored: %u, computed %u\n",
             (unsigned int)check.bc_crc32e, (unsigned int)crc);
@@ -448,9 +612,11 @@ int ocfs2_validate_meta_ecc(struct super_block *sb, void *data,
                            struct ocfs2_block_check *bc)
 {
        int rc = 0;
+       struct ocfs2_super *osb = OCFS2_SB(sb);
 
-       if (ocfs2_meta_ecc(OCFS2_SB(sb)))
-               rc = ocfs2_block_check_validate(data, sb->s_blocksize, bc);
+       if (ocfs2_meta_ecc(osb))
+               rc = ocfs2_block_check_validate(data, sb->s_blocksize, bc,
+                                               &osb->osb_ecc_stats);
 
        return rc;
 }
@@ -468,9 +634,11 @@ int ocfs2_validate_meta_ecc_bhs(struct super_block *sb,
                                struct ocfs2_block_check *bc)
 {
        int rc = 0;
+       struct ocfs2_super *osb = OCFS2_SB(sb);
 
-       if (ocfs2_meta_ecc(OCFS2_SB(sb)))
-               rc = ocfs2_block_check_validate_bhs(bhs, nr, bc);
+       if (ocfs2_meta_ecc(osb))
+               rc = ocfs2_block_check_validate_bhs(bhs, nr, bc,
+                                                   &osb->osb_ecc_stats);
 
        return rc;
 }
index 70ec3feda32f88d48512864ff79859bdf1af6cd6..d4b69febf70a212a8534d4d4219844f667d9b320 100644 (file)
 #define OCFS2_BLOCKCHECK_H
 
 
+/* Count errors and error correction from blockcheck.c */
+struct ocfs2_blockcheck_stats {
+       spinlock_t b_lock;
+       u64 b_check_count;      /* Number of blocks we've checked */
+       u64 b_failure_count;    /* Number of failed checksums */
+       u64 b_recover_count;    /* Number of blocks fixed by ecc */
+
+       /*
+        * debugfs entries, used if this is passed to
+        * ocfs2_blockcheck_stats_debugfs_install()
+        */
+       struct dentry *b_debug_dir;     /* Parent of the debugfs  files */
+       struct dentry *b_debug_check;   /* Exposes b_check_count */
+       struct dentry *b_debug_failure; /* Exposes b_failure_count */
+       struct dentry *b_debug_recover; /* Exposes b_recover_count */
+};
+
+
 /* High level block API */
 void ocfs2_compute_meta_ecc(struct super_block *sb, void *data,
                            struct ocfs2_block_check *bc);
@@ -37,11 +55,18 @@ int ocfs2_validate_meta_ecc_bhs(struct super_block *sb,
 void ocfs2_block_check_compute(void *data, size_t blocksize,
                               struct ocfs2_block_check *bc);
 int ocfs2_block_check_validate(void *data, size_t blocksize,
-                              struct ocfs2_block_check *bc);
+                              struct ocfs2_block_check *bc,
+                              struct ocfs2_blockcheck_stats *stats);
 void ocfs2_block_check_compute_bhs(struct buffer_head **bhs, int nr,
                                   struct ocfs2_block_check *bc);
 int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
-                                  struct ocfs2_block_check *bc);
+                                  struct ocfs2_block_check *bc,
+                                  struct ocfs2_blockcheck_stats *stats);
+
+/* Debug Initialization */
+int ocfs2_blockcheck_stats_debugfs_install(struct ocfs2_blockcheck_stats *stats,
+                                          struct dentry *parent);
+void ocfs2_blockcheck_stats_debugfs_remove(struct ocfs2_blockcheck_stats *stats);
 
 /*
  * Hamming code functions
index 7e72a81bc2d4e1923f23debe1d371da66e42c72b..696c32e507160d80fde6d0fed3fd7b5724c3d6dc 100644 (file)
  * only emit the appropriage printk() when the caller passes in a constant
  * mask, as is almost always the case.
  *
- * All this bitmask nonsense is hidden from the /proc interface so that Joel
- * doesn't have an aneurism.  Reading the file gives a straight forward
- * indication of which bits are on or off:
- *     ENTRY off
- *     EXIT off
+ * All this bitmask nonsense is managed from the files under
+ * /sys/fs/o2cb/logmask/.  Reading the files gives a straightforward
+ * indication of which bits are allowed (allow) or denied (off/deny).
+ *     ENTRY deny
+ *     EXIT deny
  *     TCP off
  *     MSG off
  *     SOCKET off
- *     ERROR off
- *     NOTICE on
+ *     ERROR allow
+ *     NOTICE allow
  *
  * Writing changes the state of a given bit and requires a strictly formatted
  * single write() call:
  *
- *     write(fd, "ENTRY on", 8);
+ *     write(fd, "allow", 5);
  *
- * would turn the entry bit on.  "1" is also accepted in the place of "on", and
- * "off" and "0" behave as expected.
+ * Echoing allow/deny/off string into the logmask files can flip the bits
+ * on or off as expected; here is the bash script for example:
  *
- * Some trivial shell can flip all the bits on or off:
+ * log_mask="/sys/fs/o2cb/log_mask"
+ * for node in ENTRY EXIT TCP MSG SOCKET ERROR NOTICE; do
+ *     echo allow >"$log_mask"/"$node"
+ * done
  *
- * log_mask="/proc/fs/ocfs2_nodemanager/log_mask"
- * cat $log_mask | (
- *     while read bit status; do
- *             # $1 is "on" or "off", say
- *             echo "$bit $1" > $log_mask
- *     done
- * )
+ * The debugfs.ocfs2 tool can also flip the bits with the -l option:
+ *
+ * debugfs.ocfs2 -l TCP allow
  */
 
 /* for task_struct */
index 9fbe849f634419d9f5418d6097e789906ba460b1..334f231a422c732db5a9364596f9d9655f5dee79 100644 (file)
@@ -974,7 +974,7 @@ static int o2net_tx_can_proceed(struct o2net_node *nn,
 int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec,
                           size_t caller_veclen, u8 target_node, int *status)
 {
-       int ret, error = 0;
+       int ret;
        struct o2net_msg *msg = NULL;
        size_t veclen, caller_bytes = 0;
        struct kvec *vec = NULL;
@@ -1015,10 +1015,7 @@ int o2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec,
 
        o2net_set_nst_sock_time(&nst);
 
-       ret = wait_event_interruptible(nn->nn_sc_wq,
-                                      o2net_tx_can_proceed(nn, &sc, &error));
-       if (!ret && error)
-               ret = error;
+       wait_event(nn->nn_sc_wq, o2net_tx_can_proceed(nn, &sc, &ret));
        if (ret)
                goto out;
 
index c5752305627c669359f6e6cd688b9f3eecbb6958..b358f3bf896dbb5bf299fe7976397994c59c6b8d 100644 (file)
@@ -2900,6 +2900,8 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
        alloc = ocfs2_clusters_for_bytes(sb, bytes);
        dx_alloc = 0;
 
+       down_write(&oi->ip_alloc_sem);
+
        if (ocfs2_supports_indexed_dirs(osb)) {
                credits += ocfs2_add_dir_index_credits(sb);
 
@@ -2940,8 +2942,6 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
                goto out;
        }
 
-       down_write(&oi->ip_alloc_sem);
-
        /*
         * Prepare for worst case allocation scenario of two separate
         * extents in the unindexed tree.
@@ -2953,7 +2953,7 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
        if (IS_ERR(handle)) {
                ret = PTR_ERR(handle);
                mlog_errno(ret);
-               goto out_sem;
+               goto out;
        }
 
        if (vfs_dq_alloc_space_nodirty(dir,
@@ -3172,10 +3172,8 @@ out_commit:
 
        ocfs2_commit_trans(osb, handle);
 
-out_sem:
-       up_write(&oi->ip_alloc_sem);
-
 out:
+       up_write(&oi->ip_alloc_sem);
        if (data_ac)
                ocfs2_free_alloc_context(data_ac);
        if (meta_ac)
@@ -3322,11 +3320,15 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
                brelse(new_bh);
                new_bh = NULL;
 
+               down_write(&OCFS2_I(dir)->ip_alloc_sem);
+               drop_alloc_sem = 1;
                dir_i_size = i_size_read(dir);
                credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS;
                goto do_extend;
        }
 
+       down_write(&OCFS2_I(dir)->ip_alloc_sem);
+       drop_alloc_sem = 1;
        dir_i_size = i_size_read(dir);
        mlog(0, "extending dir %llu (i_size = %lld)\n",
             (unsigned long long)OCFS2_I(dir)->ip_blkno, dir_i_size);
@@ -3370,9 +3372,6 @@ do_extend:
                credits++; /* For attaching the new dirent block to the
                            * dx_root */
 
-       down_write(&OCFS2_I(dir)->ip_alloc_sem);
-       drop_alloc_sem = 1;
-
        handle = ocfs2_start_trans(osb, credits);
        if (IS_ERR(handle)) {
                status = PTR_ERR(handle);
@@ -3435,10 +3434,10 @@ bail_bh:
        *new_de_bh = new_bh;
        get_bh(*new_de_bh);
 bail:
-       if (drop_alloc_sem)
-               up_write(&OCFS2_I(dir)->ip_alloc_sem);
        if (handle)
                ocfs2_commit_trans(osb, handle);
+       if (drop_alloc_sem)
+               up_write(&OCFS2_I(dir)->ip_alloc_sem);
 
        if (data_ac)
                ocfs2_free_alloc_context(data_ac);
index e15fc7d50827019fe974b9bb61b8f5dd7312665a..6cdeaa76f27fec651b0c14f40a48e31f3aa8f71e 100644 (file)
@@ -248,6 +248,10 @@ static struct ocfs2_lock_res_ops ocfs2_nfs_sync_lops = {
        .flags          = 0,
 };
 
+static struct ocfs2_lock_res_ops ocfs2_orphan_scan_lops = {
+       .flags          = LOCK_TYPE_REQUIRES_REFRESH|LOCK_TYPE_USES_LVB,
+};
+
 static struct ocfs2_lock_res_ops ocfs2_dentry_lops = {
        .get_osb        = ocfs2_get_dentry_osb,
        .post_unlock    = ocfs2_dentry_post_unlock,
@@ -637,6 +641,19 @@ static void ocfs2_nfs_sync_lock_res_init(struct ocfs2_lock_res *res,
                                   &ocfs2_nfs_sync_lops, osb);
 }
 
+static void ocfs2_orphan_scan_lock_res_init(struct ocfs2_lock_res *res,
+                                           struct ocfs2_super *osb)
+{
+       struct ocfs2_orphan_scan_lvb *lvb;
+
+       ocfs2_lock_res_init_once(res);
+       ocfs2_build_lock_name(OCFS2_LOCK_TYPE_ORPHAN_SCAN, 0, 0, res->l_name);
+       ocfs2_lock_res_init_common(osb, res, OCFS2_LOCK_TYPE_ORPHAN_SCAN,
+                                  &ocfs2_orphan_scan_lops, osb);
+       lvb = ocfs2_dlm_lvb(&res->l_lksb);
+       lvb->lvb_version = OCFS2_ORPHAN_LVB_VERSION;
+}
+
 void ocfs2_file_lock_res_init(struct ocfs2_lock_res *lockres,
                              struct ocfs2_file_private *fp)
 {
@@ -2352,6 +2369,37 @@ void ocfs2_inode_unlock(struct inode *inode,
        mlog_exit_void();
 }
 
+int ocfs2_orphan_scan_lock(struct ocfs2_super *osb, u32 *seqno, int ex)
+{
+       struct ocfs2_lock_res *lockres;
+       struct ocfs2_orphan_scan_lvb *lvb;
+       int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR;
+       int status = 0;
+
+       lockres = &osb->osb_orphan_scan.os_lockres;
+       status = ocfs2_cluster_lock(osb, lockres, level, 0, 0);
+       if (status < 0)
+               return status;
+
+       lvb = ocfs2_dlm_lvb(&lockres->l_lksb);
+       if (lvb->lvb_version == OCFS2_ORPHAN_LVB_VERSION)
+               *seqno = be32_to_cpu(lvb->lvb_os_seqno);
+       return status;
+}
+
+void ocfs2_orphan_scan_unlock(struct ocfs2_super *osb, u32 seqno, int ex)
+{
+       struct ocfs2_lock_res *lockres;
+       struct ocfs2_orphan_scan_lvb *lvb;
+       int level = ex ? DLM_LOCK_EX : DLM_LOCK_PR;
+
+       lockres = &osb->osb_orphan_scan.os_lockres;
+       lvb = ocfs2_dlm_lvb(&lockres->l_lksb);
+       lvb->lvb_version = OCFS2_ORPHAN_LVB_VERSION;
+       lvb->lvb_os_seqno = cpu_to_be32(seqno);
+       ocfs2_cluster_unlock(osb, lockres, level);
+}
+
 int ocfs2_super_lock(struct ocfs2_super *osb,
                     int ex)
 {
@@ -2842,6 +2890,7 @@ local:
        ocfs2_super_lock_res_init(&osb->osb_super_lockres, osb);
        ocfs2_rename_lock_res_init(&osb->osb_rename_lockres, osb);
        ocfs2_nfs_sync_lock_res_init(&osb->osb_nfs_sync_lockres, osb);
+       ocfs2_orphan_scan_lock_res_init(&osb->osb_orphan_scan.os_lockres, osb);
 
        osb->cconn = conn;
 
@@ -2878,6 +2927,7 @@ void ocfs2_dlm_shutdown(struct ocfs2_super *osb,
        ocfs2_lock_res_free(&osb->osb_super_lockres);
        ocfs2_lock_res_free(&osb->osb_rename_lockres);
        ocfs2_lock_res_free(&osb->osb_nfs_sync_lockres);
+       ocfs2_lock_res_free(&osb->osb_orphan_scan.os_lockres);
 
        ocfs2_cluster_disconnect(osb->cconn, hangup_pending);
        osb->cconn = NULL;
@@ -3061,6 +3111,7 @@ static void ocfs2_drop_osb_locks(struct ocfs2_super *osb)
        ocfs2_simple_drop_lockres(osb, &osb->osb_super_lockres);
        ocfs2_simple_drop_lockres(osb, &osb->osb_rename_lockres);
        ocfs2_simple_drop_lockres(osb, &osb->osb_nfs_sync_lockres);
+       ocfs2_simple_drop_lockres(osb, &osb->osb_orphan_scan.os_lockres);
 }
 
 int ocfs2_drop_inode_locks(struct inode *inode)
index e1fd5721cd7f15da6e844579e1964d691af597fe..31b90d7b8f51f0dc449da138e8e7b14f118aabb4 100644 (file)
@@ -62,6 +62,14 @@ struct ocfs2_qinfo_lvb {
        __be32  lvb_free_entry;
 };
 
+#define OCFS2_ORPHAN_LVB_VERSION 1
+
+struct ocfs2_orphan_scan_lvb {
+       __u8    lvb_version;
+       __u8    lvb_reserved[3];
+       __be32  lvb_os_seqno;
+};
+
 /* ocfs2_inode_lock_full() 'arg_flags' flags */
 /* don't wait on recovery. */
 #define OCFS2_META_LOCK_RECOVERY       (0x01)
@@ -113,6 +121,9 @@ int ocfs2_super_lock(struct ocfs2_super *osb,
                     int ex);
 void ocfs2_super_unlock(struct ocfs2_super *osb,
                        int ex);
+int ocfs2_orphan_scan_lock(struct ocfs2_super *osb, u32 *seqno, int ex);
+void ocfs2_orphan_scan_unlock(struct ocfs2_super *osb, u32 seqno, int ex);
+
 int ocfs2_rename_lock(struct ocfs2_super *osb);
 void ocfs2_rename_unlock(struct ocfs2_super *osb);
 int ocfs2_nfs_sync_lock(struct ocfs2_super *osb, int ex);
index c2a87c885b73672db90e52aae9497c34842d1c65..07267e0da909410294a3f330eb08fea5d1feefb8 100644 (file)
@@ -187,6 +187,9 @@ static int ocfs2_sync_file(struct file *file,
        if (err)
                goto bail;
 
+       if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
+               goto bail;
+
        journal = osb->journal->j_journal;
        err = jbd2_journal_force_commit(journal);
 
@@ -894,9 +897,9 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
        struct ocfs2_super *osb = OCFS2_SB(sb);
        struct buffer_head *bh = NULL;
        handle_t *handle = NULL;
-       int locked[MAXQUOTAS] = {0, 0};
-       int credits, qtype;
-       struct ocfs2_mem_dqinfo *oinfo;
+       int qtype;
+       struct dquot *transfer_from[MAXQUOTAS] = { };
+       struct dquot *transfer_to[MAXQUOTAS] = { };
 
        mlog_entry("(0x%p, '%.*s')\n", dentry,
                   dentry->d_name.len, dentry->d_name.name);
@@ -969,30 +972,37 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
 
        if ((attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
            (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
-               credits = OCFS2_INODE_UPDATE_CREDITS;
+               /*
+                * Gather pointers to quota structures so that allocation /
+                * freeing of quota structures happens here and not inside
+                * vfs_dq_transfer() where we have problems with lock ordering
+                */
                if (attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid
                    && OCFS2_HAS_RO_COMPAT_FEATURE(sb,
                    OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) {
-                       oinfo = sb_dqinfo(sb, USRQUOTA)->dqi_priv;
-                       status = ocfs2_lock_global_qf(oinfo, 1);
-                       if (status < 0)
+                       transfer_to[USRQUOTA] = dqget(sb, attr->ia_uid,
+                                                     USRQUOTA);
+                       transfer_from[USRQUOTA] = dqget(sb, inode->i_uid,
+                                                       USRQUOTA);
+                       if (!transfer_to[USRQUOTA] || !transfer_from[USRQUOTA]) {
+                               status = -ESRCH;
                                goto bail_unlock;
-                       credits += ocfs2_calc_qinit_credits(sb, USRQUOTA) +
-                               ocfs2_calc_qdel_credits(sb, USRQUOTA);
-                       locked[USRQUOTA] = 1;
+                       }
                }
                if (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid
                    && OCFS2_HAS_RO_COMPAT_FEATURE(sb,
                    OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) {
-                       oinfo = sb_dqinfo(sb, GRPQUOTA)->dqi_priv;
-                       status = ocfs2_lock_global_qf(oinfo, 1);
-                       if (status < 0)
+                       transfer_to[GRPQUOTA] = dqget(sb, attr->ia_gid,
+                                                     GRPQUOTA);
+                       transfer_from[GRPQUOTA] = dqget(sb, inode->i_gid,
+                                                       GRPQUOTA);
+                       if (!transfer_to[GRPQUOTA] || !transfer_from[GRPQUOTA]) {
+                               status = -ESRCH;
                                goto bail_unlock;
-                       credits += ocfs2_calc_qinit_credits(sb, GRPQUOTA) +
-                                  ocfs2_calc_qdel_credits(sb, GRPQUOTA);
-                       locked[GRPQUOTA] = 1;
+                       }
                }
-               handle = ocfs2_start_trans(osb, credits);
+               handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS +
+                                          2 * ocfs2_quota_trans_credits(sb));
                if (IS_ERR(handle)) {
                        status = PTR_ERR(handle);
                        mlog_errno(status);
@@ -1030,12 +1040,6 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
 bail_commit:
        ocfs2_commit_trans(osb, handle);
 bail_unlock:
-       for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
-               if (!locked[qtype])
-                       continue;
-               oinfo = sb_dqinfo(sb, qtype)->dqi_priv;
-               ocfs2_unlock_global_qf(oinfo, 1);
-       }
        ocfs2_inode_unlock(inode, 1);
 bail_unlock_rw:
        if (size_change)
@@ -1043,6 +1047,12 @@ bail_unlock_rw:
 bail:
        brelse(bh);
 
+       /* Release quota pointers in case we acquired them */
+       for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
+               dqput(transfer_to[qtype]);
+               dqput(transfer_from[qtype]);
+       }
+
        if (!status && attr->ia_valid & ATTR_MODE) {
                status = ocfs2_acl_chmod(inode);
                if (status < 0)
index a20a0f1e37fd18e898ade8803d19ff7489df7e85..4a3b9e6b31adcc6247dc28fea3887a426f9a09d7 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/slab.h>
 #include <linux/highmem.h>
 #include <linux/kthread.h>
+#include <linux/time.h>
+#include <linux/random.h>
 
 #define MLOG_MASK_PREFIX ML_JOURNAL
 #include <cluster/masklog.h>
@@ -52,6 +54,8 @@
 
 DEFINE_SPINLOCK(trans_inc_lock);
 
+#define ORPHAN_SCAN_SCHEDULE_TIMEOUT 300000
+
 static int ocfs2_force_read_journal(struct inode *inode);
 static int ocfs2_recover_node(struct ocfs2_super *osb,
                              int node_num, int slot_num);
@@ -1841,6 +1845,113 @@ bail:
        return status;
 }
 
+/*
+ * Scan timer should get fired every ORPHAN_SCAN_SCHEDULE_TIMEOUT. Add some
+ * randomness to the timeout to minimize multple nodes firing the timer at the
+ * same time.
+ */
+static inline unsigned long ocfs2_orphan_scan_timeout(void)
+{
+       unsigned long time;
+
+       get_random_bytes(&time, sizeof(time));
+       time = ORPHAN_SCAN_SCHEDULE_TIMEOUT + (time % 5000);
+       return msecs_to_jiffies(time);
+}
+
+/*
+ * ocfs2_queue_orphan_scan calls ocfs2_queue_recovery_completion for
+ * every slot, queuing a recovery of the slot on the ocfs2_wq thread. This
+ * is done to catch any orphans that are left over in orphan directories.
+ *
+ * ocfs2_queue_orphan_scan gets called every ORPHAN_SCAN_SCHEDULE_TIMEOUT
+ * seconds.  It gets an EX lock on os_lockres and checks sequence number
+ * stored in LVB. If the sequence number has changed, it means some other
+ * node has done the scan.  This node skips the scan and tracks the
+ * sequence number.  If the sequence number didn't change, it means a scan
+ * hasn't happened.  The node queues a scan and increments the
+ * sequence number in the LVB.
+ */
+void ocfs2_queue_orphan_scan(struct ocfs2_super *osb)
+{
+       struct ocfs2_orphan_scan *os;
+       int status, i;
+       u32 seqno = 0;
+
+       os = &osb->osb_orphan_scan;
+
+       status = ocfs2_orphan_scan_lock(osb, &seqno, DLM_LOCK_EX);
+       if (status < 0) {
+               if (status != -EAGAIN)
+                       mlog_errno(status);
+               goto out;
+       }
+
+       if (os->os_seqno != seqno) {
+               os->os_seqno = seqno;
+               goto unlock;
+       }
+
+       for (i = 0; i < osb->max_slots; i++)
+               ocfs2_queue_recovery_completion(osb->journal, i, NULL, NULL,
+                                               NULL);
+       /*
+        * We queued a recovery on orphan slots, increment the sequence
+        * number and update LVB so other node will skip the scan for a while
+        */
+       seqno++;
+       os->os_count++;
+       os->os_scantime = CURRENT_TIME;
+unlock:
+       ocfs2_orphan_scan_unlock(osb, seqno, DLM_LOCK_EX);
+out:
+       return;
+}
+
+/* Worker task that gets fired every ORPHAN_SCAN_SCHEDULE_TIMEOUT millsec */
+void ocfs2_orphan_scan_work(struct work_struct *work)
+{
+       struct ocfs2_orphan_scan *os;
+       struct ocfs2_super *osb;
+
+       os = container_of(work, struct ocfs2_orphan_scan,
+                         os_orphan_scan_work.work);
+       osb = os->os_osb;
+
+       mutex_lock(&os->os_lock);
+       ocfs2_queue_orphan_scan(osb);
+       schedule_delayed_work(&os->os_orphan_scan_work,
+                             ocfs2_orphan_scan_timeout());
+       mutex_unlock(&os->os_lock);
+}
+
+void ocfs2_orphan_scan_stop(struct ocfs2_super *osb)
+{
+       struct ocfs2_orphan_scan *os;
+
+       os = &osb->osb_orphan_scan;
+       mutex_lock(&os->os_lock);
+       cancel_delayed_work(&os->os_orphan_scan_work);
+       mutex_unlock(&os->os_lock);
+}
+
+int ocfs2_orphan_scan_init(struct ocfs2_super *osb)
+{
+       struct ocfs2_orphan_scan *os;
+
+       os = &osb->osb_orphan_scan;
+       os->os_osb = osb;
+       os->os_count = 0;
+       os->os_scantime = CURRENT_TIME;
+       mutex_init(&os->os_lock);
+
+       INIT_DELAYED_WORK(&os->os_orphan_scan_work,
+                         ocfs2_orphan_scan_work);
+       schedule_delayed_work(&os->os_orphan_scan_work,
+                             ocfs2_orphan_scan_timeout());
+       return 0;
+}
+
 struct ocfs2_orphan_filldir_priv {
        struct inode            *head;
        struct ocfs2_super      *osb;
index eb7b76331eb7733f4d9f4a5494b3509054a886b1..61045eeb3f6ea0c83f45e7e012b2aab1da34626a 100644 (file)
@@ -144,6 +144,10 @@ static inline void ocfs2_inode_set_new(struct ocfs2_super *osb,
 }
 
 /* Exported only for the journal struct init code in super.c. Do not call. */
+int ocfs2_orphan_scan_init(struct ocfs2_super *osb);
+void ocfs2_orphan_scan_stop(struct ocfs2_super *osb);
+void ocfs2_orphan_scan_exit(struct ocfs2_super *osb);
+
 void ocfs2_complete_recovery(struct work_struct *work);
 void ocfs2_wait_for_recovery(struct ocfs2_super *osb);
 
index 1386281950dbead47e4b5528cde7caae706cb3f2..18c1d9ec1c93cdc5421150e7ec39e45d4162d737 100644 (file)
@@ -47,6 +47,9 @@
 #include "ocfs2_fs.h"
 #include "ocfs2_lockid.h"
 
+/* For struct ocfs2_blockcheck_stats */
+#include "blockcheck.h"
+
 /* Most user visible OCFS2 inodes will have very few pieces of
  * metadata, but larger files (including bitmaps, etc) must be taken
  * into account when designing an access scheme. We allow a small
@@ -151,6 +154,16 @@ struct ocfs2_lock_res {
 #endif
 };
 
+struct ocfs2_orphan_scan {
+       struct mutex            os_lock;
+       struct ocfs2_super      *os_osb;
+       struct ocfs2_lock_res   os_lockres;     /* lock to synchronize scans */
+       struct delayed_work     os_orphan_scan_work;
+       struct timespec         os_scantime;  /* time this node ran the scan */
+       u32                     os_count;      /* tracks node specific scans */
+       u32                     os_seqno;       /* tracks cluster wide scans */
+};
+
 struct ocfs2_dlm_debug {
        struct kref d_refcnt;
        struct dentry *d_locking_state;
@@ -295,6 +308,7 @@ struct ocfs2_super
        struct ocfs2_dinode *local_alloc_copy;
        struct ocfs2_quota_recovery *quota_rec;
 
+       struct ocfs2_blockcheck_stats osb_ecc_stats;
        struct ocfs2_alloc_stats alloc_stats;
        char dev_str[20];               /* "major,minor" of the device */
 
@@ -341,6 +355,8 @@ struct ocfs2_super
        unsigned int                    *osb_orphan_wipes;
        wait_queue_head_t               osb_wipe_event;
 
+       struct ocfs2_orphan_scan        osb_orphan_scan;
+
        /* used to protect metaecc calculation check of xattr. */
        spinlock_t osb_xattr_lock;
 
index a53ce87481bf20b1c724d2c699fab3c52674b991..fcdba091af3dd8be6706950e83a772049bf775b1 100644 (file)
@@ -48,6 +48,7 @@ enum ocfs2_lock_type {
        OCFS2_LOCK_TYPE_FLOCK,
        OCFS2_LOCK_TYPE_QINFO,
        OCFS2_LOCK_TYPE_NFS_SYNC,
+       OCFS2_LOCK_TYPE_ORPHAN_SCAN,
        OCFS2_NUM_LOCK_TYPES
 };
 
@@ -85,6 +86,9 @@ static inline char ocfs2_lock_type_char(enum ocfs2_lock_type type)
                case OCFS2_LOCK_TYPE_NFS_SYNC:
                        c = 'Y';
                        break;
+               case OCFS2_LOCK_TYPE_ORPHAN_SCAN:
+                       c = 'P';
+                       break;
                default:
                        c = '\0';
        }
@@ -104,6 +108,7 @@ static char *ocfs2_lock_type_strings[] = {
        [OCFS2_LOCK_TYPE_OPEN] = "Open",
        [OCFS2_LOCK_TYPE_FLOCK] = "Flock",
        [OCFS2_LOCK_TYPE_QINFO] = "Quota",
+       [OCFS2_LOCK_TYPE_ORPHAN_SCAN] = "OrphanScan",
 };
 
 static inline const char *ocfs2_lock_type_string(enum ocfs2_lock_type type)
index 1ed0f7c868697c47c447ee611175f067def508dd..edfa60cd155c18e9ac67a1fe6ae1476900fed8b7 100644 (file)
@@ -421,6 +421,7 @@ int ocfs2_global_read_dquot(struct dquot *dquot)
        OCFS2_DQUOT(dquot)->dq_originodes = dquot->dq_dqb.dqb_curinodes;
        if (!dquot->dq_off) {   /* No real quota entry? */
                /* Upgrade to exclusive lock for allocation */
+               ocfs2_qinfo_unlock(info, 0);
                err = ocfs2_qinfo_lock(info, 1);
                if (err < 0)
                        goto out_qlock;
@@ -435,7 +436,8 @@ int ocfs2_global_read_dquot(struct dquot *dquot)
 out_qlock:
        if (ex)
                ocfs2_qinfo_unlock(info, 1);
-       ocfs2_qinfo_unlock(info, 0);
+       else
+               ocfs2_qinfo_unlock(info, 0);
 out:
        if (err < 0)
                mlog_errno(err);
index 07deec5e9721633e8bd88552baf840ab2cc8e2cb..5a460fa8255384f615d2dd7ca8836d3091fc58b5 100644 (file)
@@ -444,10 +444,6 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
 
        mlog_entry("ino=%lu type=%u", (unsigned long)lqinode->i_ino, type);
 
-       status = ocfs2_lock_global_qf(oinfo, 1);
-       if (status < 0)
-               goto out;
-
        list_for_each_entry_safe(rchunk, next, &(rec->r_list[type]), rc_list) {
                chunk = rchunk->rc_chunk;
                hbh = NULL;
@@ -480,12 +476,18 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
                                     type);
                                goto out_put_bh;
                        }
+                       status = ocfs2_lock_global_qf(oinfo, 1);
+                       if (status < 0) {
+                               mlog_errno(status);
+                               goto out_put_dquot;
+                       }
+
                        handle = ocfs2_start_trans(OCFS2_SB(sb),
                                                   OCFS2_QSYNC_CREDITS);
                        if (IS_ERR(handle)) {
                                status = PTR_ERR(handle);
                                mlog_errno(status);
-                               goto out_put_dquot;
+                               goto out_drop_lock;
                        }
                        mutex_lock(&sb_dqopt(sb)->dqio_mutex);
                        spin_lock(&dq_data_lock);
@@ -523,6 +525,8 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
 out_commit:
                        mutex_unlock(&sb_dqopt(sb)->dqio_mutex);
                        ocfs2_commit_trans(OCFS2_SB(sb), handle);
+out_drop_lock:
+                       ocfs2_unlock_global_qf(oinfo, 1);
 out_put_dquot:
                        dqput(dquot);
 out_put_bh:
@@ -537,8 +541,6 @@ out_put_bh:
                if (status < 0)
                        break;
        }
-       ocfs2_unlock_global_qf(oinfo, 1);
-out:
        if (status < 0)
                free_recovery_list(&(rec->r_list[type]));
        mlog_exit(status);
@@ -655,6 +657,9 @@ static int ocfs2_local_read_info(struct super_block *sb, int type)
        struct ocfs2_quota_recovery *rec;
        int locked = 0;
 
+       /* We don't need the lock and we have to acquire quota file locks
+        * which will later depend on this lock */
+       mutex_unlock(&sb_dqopt(sb)->dqio_mutex);
        info->dqi_maxblimit = 0x7fffffffffffffffLL;
        info->dqi_maxilimit = 0x7fffffffffffffffLL;
        oinfo = kmalloc(sizeof(struct ocfs2_mem_dqinfo), GFP_NOFS);
@@ -733,6 +738,7 @@ static int ocfs2_local_read_info(struct super_block *sb, int type)
                goto out_err;
        }
 
+       mutex_lock(&sb_dqopt(sb)->dqio_mutex);
        return 0;
 out_err:
        if (oinfo) {
@@ -746,6 +752,7 @@ out_err:
                kfree(oinfo);
        }
        brelse(bh);
+       mutex_lock(&sb_dqopt(sb)->dqio_mutex);
        return -1;
 }
 
index 201b40a441fe806073c03bbb9fcc046f6423def7..d33767f17ba39db14dc8725ca2494fcd6ee73222 100644 (file)
@@ -119,10 +119,12 @@ static void ocfs2_release_system_inodes(struct ocfs2_super *osb);
 static int ocfs2_check_volume(struct ocfs2_super *osb);
 static int ocfs2_verify_volume(struct ocfs2_dinode *di,
                               struct buffer_head *bh,
-                              u32 sectsize);
+                              u32 sectsize,
+                              struct ocfs2_blockcheck_stats *stats);
 static int ocfs2_initialize_super(struct super_block *sb,
                                  struct buffer_head *bh,
-                                 int sector_size);
+                                 int sector_size,
+                                 struct ocfs2_blockcheck_stats *stats);
 static int ocfs2_get_sector(struct super_block *sb,
                            struct buffer_head **bh,
                            int block,
@@ -207,6 +209,7 @@ static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len)
        int i;
        struct ocfs2_cluster_connection *cconn = osb->cconn;
        struct ocfs2_recovery_map *rm = osb->recovery_map;
+       struct ocfs2_orphan_scan *os;
 
        out += snprintf(buf + out, len - out,
                        "%10s => Id: %-s  Uuid: %-s  Gen: 0x%X  Label: %-s\n",
@@ -308,6 +311,13 @@ static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len)
                                i, osb->slot_recovery_generations[i]);
        }
 
+       os = &osb->osb_orphan_scan;
+       out += snprintf(buf + out, len - out, "Orphan Scan=> ");
+       out += snprintf(buf + out, len - out, "Local: %u  Global: %u ",
+                       os->os_count, os->os_seqno);
+       out += snprintf(buf + out, len - out, " Last Scan: %lu seconds ago\n",
+                       (get_seconds() - os->os_scantime.tv_sec));
+
        return out;
 }
 
@@ -693,7 +703,8 @@ out:
 
 static int ocfs2_sb_probe(struct super_block *sb,
                          struct buffer_head **bh,
-                         int *sector_size)
+                         int *sector_size,
+                         struct ocfs2_blockcheck_stats *stats)
 {
        int status, tmpstat;
        struct ocfs1_vol_disk_hdr *hdr;
@@ -759,7 +770,8 @@ static int ocfs2_sb_probe(struct super_block *sb,
                        goto bail;
                }
                di = (struct ocfs2_dinode *) (*bh)->b_data;
-               status = ocfs2_verify_volume(di, *bh, blksize);
+               memset(stats, 0, sizeof(struct ocfs2_blockcheck_stats));
+               status = ocfs2_verify_volume(di, *bh, blksize, stats);
                if (status >= 0)
                        goto bail;
                brelse(*bh);
@@ -965,6 +977,7 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
        struct ocfs2_super *osb = NULL;
        struct buffer_head *bh = NULL;
        char nodestr[8];
+       struct ocfs2_blockcheck_stats stats;
 
        mlog_entry("%p, %p, %i", sb, data, silent);
 
@@ -974,13 +987,13 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
        }
 
        /* probe for superblock */
-       status = ocfs2_sb_probe(sb, &bh, &sector_size);
+       status = ocfs2_sb_probe(sb, &bh, &sector_size, &stats);
        if (status < 0) {
                mlog(ML_ERROR, "superblock probe failed!\n");
                goto read_super_error;
        }
 
-       status = ocfs2_initialize_super(sb, bh, sector_size);
+       status = ocfs2_initialize_super(sb, bh, sector_size, &stats);
        osb = OCFS2_SB(sb);
        if (status < 0) {
                mlog_errno(status);
@@ -1090,6 +1103,18 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
                goto read_super_error;
        }
 
+       if (ocfs2_meta_ecc(osb)) {
+               status = ocfs2_blockcheck_stats_debugfs_install(
+                                               &osb->osb_ecc_stats,
+                                               osb->osb_debug_root);
+               if (status) {
+                       mlog(ML_ERROR,
+                            "Unable to create blockcheck statistics "
+                            "files\n");
+                       goto read_super_error;
+               }
+       }
+
        status = ocfs2_mount_volume(sb);
        if (osb->root_inode)
                inode = igrab(osb->root_inode);
@@ -1760,13 +1785,8 @@ static int ocfs2_mount_volume(struct super_block *sb)
        }
 
        status = ocfs2_truncate_log_init(osb);
-       if (status < 0) {
+       if (status < 0)
                mlog_errno(status);
-               goto leave;
-       }
-
-       if (ocfs2_mount_local(osb))
-               goto leave;
 
 leave:
        if (unlock_super)
@@ -1796,6 +1816,8 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
 
        ocfs2_truncate_log_shutdown(osb);
 
+       ocfs2_orphan_scan_stop(osb);
+
        /* This will disable recovery and flush any recovery work. */
        ocfs2_recovery_exit(osb);
 
@@ -1833,6 +1855,7 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
        if (osb->cconn)
                ocfs2_dlm_shutdown(osb, hangup_needed);
 
+       ocfs2_blockcheck_stats_debugfs_remove(&osb->osb_ecc_stats);
        debugfs_remove(osb->osb_debug_root);
 
        if (hangup_needed)
@@ -1880,7 +1903,8 @@ static int ocfs2_setup_osb_uuid(struct ocfs2_super *osb, const unsigned char *uu
 
 static int ocfs2_initialize_super(struct super_block *sb,
                                  struct buffer_head *bh,
-                                 int sector_size)
+                                 int sector_size,
+                                 struct ocfs2_blockcheck_stats *stats)
 {
        int status;
        int i, cbits, bbits;
@@ -1939,6 +1963,9 @@ static int ocfs2_initialize_super(struct super_block *sb,
        atomic_set(&osb->alloc_stats.bg_allocs, 0);
        atomic_set(&osb->alloc_stats.bg_extends, 0);
 
+       /* Copy the blockcheck stats from the superblock probe */
+       osb->osb_ecc_stats = *stats;
+
        ocfs2_init_node_maps(osb);
 
        snprintf(osb->dev_str, sizeof(osb->dev_str), "%u,%u",
@@ -1951,6 +1978,13 @@ static int ocfs2_initialize_super(struct super_block *sb,
                goto bail;
        }
 
+       status = ocfs2_orphan_scan_init(osb);
+       if (status) {
+               mlog(ML_ERROR, "Unable to initialize delayed orphan scan\n");
+               mlog_errno(status);
+               goto bail;
+       }
+
        init_waitqueue_head(&osb->checkpoint_event);
        atomic_set(&osb->needs_checkpoint, 0);
 
@@ -2169,7 +2203,8 @@ bail:
  */
 static int ocfs2_verify_volume(struct ocfs2_dinode *di,
                               struct buffer_head *bh,
-                              u32 blksz)
+                              u32 blksz,
+                              struct ocfs2_blockcheck_stats *stats)
 {
        int status = -EAGAIN;
 
@@ -2182,7 +2217,8 @@ static int ocfs2_verify_volume(struct ocfs2_dinode *di,
                    OCFS2_FEATURE_INCOMPAT_META_ECC) {
                        status = ocfs2_block_check_validate(bh->b_data,
                                                            bh->b_size,
-                                                           &di->i_check);
+                                                           &di->i_check,
+                                                           stats);
                        if (status)
                                goto out;
                }
index 15631019dc634561838919310b2566e263f1d8dc..ba320e250747fd01dedcd06a85df0d2e867dbe44 100644 (file)
@@ -3154,7 +3154,7 @@ static int ocfs2_iterate_xattr_buckets(struct inode *inode,
                     le32_to_cpu(bucket_xh(bucket)->xh_entries[0].xe_name_hash));
                if (func) {
                        ret = func(inode, bucket, para);
-                       if (ret)
+                       if (ret && ret != -ERANGE)
                                mlog_errno(ret);
                        /* Fall through to bucket_relse() */
                }
@@ -3261,7 +3261,8 @@ static int ocfs2_xattr_tree_list_index_block(struct inode *inode,
                                                  ocfs2_list_xattr_bucket,
                                                  &xl);
                if (ret) {
-                       mlog_errno(ret);
+                       if (ret != -ERANGE)
+                               mlog_errno(ret);
                        goto out;
                }
 
index 1539e630c47d524b1df251236e638dbb1e8d279b..3ce5ae9e3d2dabd36dce105ecb4545a4723c1202 100644 (file)
@@ -1006,7 +1006,12 @@ static ssize_t oom_adjust_read(struct file *file, char __user *buf,
 
        if (!task)
                return -ESRCH;
-       oom_adjust = task->oomkilladj;
+       task_lock(task);
+       if (task->mm)
+               oom_adjust = task->mm->oom_adj;
+       else
+               oom_adjust = OOM_DISABLE;
+       task_unlock(task);
        put_task_struct(task);
 
        len = snprintf(buffer, sizeof(buffer), "%i\n", oom_adjust);
@@ -1035,11 +1040,19 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
        task = get_proc_task(file->f_path.dentry->d_inode);
        if (!task)
                return -ESRCH;
-       if (oom_adjust < task->oomkilladj && !capable(CAP_SYS_RESOURCE)) {
+       task_lock(task);
+       if (!task->mm) {
+               task_unlock(task);
+               put_task_struct(task);
+               return -EINVAL;
+       }
+       if (oom_adjust < task->mm->oom_adj && !capable(CAP_SYS_RESOURCE)) {
+               task_unlock(task);
                put_task_struct(task);
                return -EACCES;
        }
-       task->oomkilladj = oom_adjust;
+       task->mm->oom_adj = oom_adjust;
+       task_unlock(task);
        put_task_struct(task);
        if (end - buffer == 0)
                return -EIO;
index c6b0302af4c40268e9511e34d16f3385f817e1d6..d5c410d47faef162d3edf1876f8582baec0936e9 100644 (file)
@@ -64,10 +64,8 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
                "Inactive(anon): %8lu kB\n"
                "Active(file):   %8lu kB\n"
                "Inactive(file): %8lu kB\n"
-#ifdef CONFIG_UNEVICTABLE_LRU
                "Unevictable:    %8lu kB\n"
                "Mlocked:        %8lu kB\n"
-#endif
 #ifdef CONFIG_HIGHMEM
                "HighTotal:      %8lu kB\n"
                "HighFree:       %8lu kB\n"
@@ -109,10 +107,8 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
                K(pages[LRU_INACTIVE_ANON]),
                K(pages[LRU_ACTIVE_FILE]),
                K(pages[LRU_INACTIVE_FILE]),
-#ifdef CONFIG_UNEVICTABLE_LRU
                K(pages[LRU_UNEVICTABLE]),
                K(global_page_state(NR_MLOCK)),
-#endif
 #ifdef CONFIG_HIGHMEM
                K(i.totalhigh),
                K(i.freehigh),
index e9983837d08d4d310701fa774057f1b66848ffb3..2707c6c7a20f0dc8bac60ad129103570b4cb10d0 100644 (file)
@@ -6,11 +6,13 @@
 #include <linux/mmzone.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/hugetlb.h>
 #include <asm/uaccess.h>
 #include "internal.h"
 
 #define KPMSIZE sizeof(u64)
 #define KPMMASK (KPMSIZE - 1)
+
 /* /proc/kpagecount - an array exposing page counts
  *
  * Each entry is a u64 representing the corresponding
@@ -32,20 +34,22 @@ static ssize_t kpagecount_read(struct file *file, char __user *buf,
                return -EINVAL;
 
        while (count > 0) {
-               ppage = NULL;
                if (pfn_valid(pfn))
                        ppage = pfn_to_page(pfn);
-               pfn++;
+               else
+                       ppage = NULL;
                if (!ppage)
                        pcount = 0;
                else
                        pcount = page_mapcount(ppage);
 
-               if (put_user(pcount, out++)) {
+               if (put_user(pcount, out)) {
                        ret = -EFAULT;
                        break;
                }
 
+               pfn++;
+               out++;
                count -= KPMSIZE;
        }
 
@@ -68,19 +72,122 @@ static const struct file_operations proc_kpagecount_operations = {
 
 /* These macros are used to decouple internal flags from exported ones */
 
-#define KPF_LOCKED     0
-#define KPF_ERROR      1
-#define KPF_REFERENCED 2
-#define KPF_UPTODATE   3
-#define KPF_DIRTY      4
-#define KPF_LRU        5
-#define KPF_ACTIVE     6
-#define KPF_SLAB       7
-#define KPF_WRITEBACK  8
-#define KPF_RECLAIM    9
-#define KPF_BUDDY     10
+#define KPF_LOCKED             0
+#define KPF_ERROR              1
+#define KPF_REFERENCED         2
+#define KPF_UPTODATE           3
+#define KPF_DIRTY              4
+#define KPF_LRU                        5
+#define KPF_ACTIVE             6
+#define KPF_SLAB               7
+#define KPF_WRITEBACK          8
+#define KPF_RECLAIM            9
+#define KPF_BUDDY              10
+
+/* 11-20: new additions in 2.6.31 */
+#define KPF_MMAP               11
+#define KPF_ANON               12
+#define KPF_SWAPCACHE          13
+#define KPF_SWAPBACKED         14
+#define KPF_COMPOUND_HEAD      15
+#define KPF_COMPOUND_TAIL      16
+#define KPF_HUGE               17
+#define KPF_UNEVICTABLE                18
+#define KPF_NOPAGE             20
+
+/* kernel hacking assistances
+ * WARNING: subject to change, never rely on them!
+ */
+#define KPF_RESERVED           32
+#define KPF_MLOCKED            33
+#define KPF_MAPPEDTODISK       34
+#define KPF_PRIVATE            35
+#define KPF_PRIVATE_2          36
+#define KPF_OWNER_PRIVATE      37
+#define KPF_ARCH               38
+#define KPF_UNCACHED           39
+
+static inline u64 kpf_copy_bit(u64 kflags, int ubit, int kbit)
+{
+       return ((kflags >> kbit) & 1) << ubit;
+}
 
-#define kpf_copy_bit(flags, dstpos, srcpos) (((flags >> srcpos) & 1) << dstpos)
+static u64 get_uflags(struct page *page)
+{
+       u64 k;
+       u64 u;
+
+       /*
+        * pseudo flag: KPF_NOPAGE
+        * it differentiates a memory hole from a page with no flags
+        */
+       if (!page)
+               return 1 << KPF_NOPAGE;
+
+       k = page->flags;
+       u = 0;
+
+       /*
+        * pseudo flags for the well known (anonymous) memory mapped pages
+        *
+        * Note that page->_mapcount is overloaded in SLOB/SLUB/SLQB, so the
+        * simple test in page_mapped() is not enough.
+        */
+       if (!PageSlab(page) && page_mapped(page))
+               u |= 1 << KPF_MMAP;
+       if (PageAnon(page))
+               u |= 1 << KPF_ANON;
+
+       /*
+        * compound pages: export both head/tail info
+        * they together define a compound page's start/end pos and order
+        */
+       if (PageHead(page))
+               u |= 1 << KPF_COMPOUND_HEAD;
+       if (PageTail(page))
+               u |= 1 << KPF_COMPOUND_TAIL;
+       if (PageHuge(page))
+               u |= 1 << KPF_HUGE;
+
+       u |= kpf_copy_bit(k, KPF_LOCKED,        PG_locked);
+
+       /*
+        * Caveats on high order pages:
+        * PG_buddy will only be set on the head page; SLUB/SLQB do the same
+        * for PG_slab; SLOB won't set PG_slab at all on compound pages.
+        */
+       u |= kpf_copy_bit(k, KPF_SLAB,          PG_slab);
+       u |= kpf_copy_bit(k, KPF_BUDDY,         PG_buddy);
+
+       u |= kpf_copy_bit(k, KPF_ERROR,         PG_error);
+       u |= kpf_copy_bit(k, KPF_DIRTY,         PG_dirty);
+       u |= kpf_copy_bit(k, KPF_UPTODATE,      PG_uptodate);
+       u |= kpf_copy_bit(k, KPF_WRITEBACK,     PG_writeback);
+
+       u |= kpf_copy_bit(k, KPF_LRU,           PG_lru);
+       u |= kpf_copy_bit(k, KPF_REFERENCED,    PG_referenced);
+       u |= kpf_copy_bit(k, KPF_ACTIVE,        PG_active);
+       u |= kpf_copy_bit(k, KPF_RECLAIM,       PG_reclaim);
+
+       u |= kpf_copy_bit(k, KPF_SWAPCACHE,     PG_swapcache);
+       u |= kpf_copy_bit(k, KPF_SWAPBACKED,    PG_swapbacked);
+
+       u |= kpf_copy_bit(k, KPF_UNEVICTABLE,   PG_unevictable);
+       u |= kpf_copy_bit(k, KPF_MLOCKED,       PG_mlocked);
+
+#ifdef CONFIG_IA64_UNCACHED_ALLOCATOR
+       u |= kpf_copy_bit(k, KPF_UNCACHED,      PG_uncached);
+#endif
+
+       u |= kpf_copy_bit(k, KPF_RESERVED,      PG_reserved);
+       u |= kpf_copy_bit(k, KPF_MAPPEDTODISK,  PG_mappedtodisk);
+       u |= kpf_copy_bit(k, KPF_PRIVATE,       PG_private);
+       u |= kpf_copy_bit(k, KPF_PRIVATE_2,     PG_private_2);
+       u |= kpf_copy_bit(k, KPF_OWNER_PRIVATE, PG_owner_priv_1);
+       u |= kpf_copy_bit(k, KPF_ARCH,          PG_arch_1);
+
+       return u;
+};
 
 static ssize_t kpageflags_read(struct file *file, char __user *buf,
                             size_t count, loff_t *ppos)
@@ -90,7 +197,6 @@ static ssize_t kpageflags_read(struct file *file, char __user *buf,
        unsigned long src = *ppos;
        unsigned long pfn;
        ssize_t ret = 0;
-       u64 kflags, uflags;
 
        pfn = src / KPMSIZE;
        count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src);
@@ -98,32 +204,18 @@ static ssize_t kpageflags_read(struct file *file, char __user *buf,
                return -EINVAL;
 
        while (count > 0) {
-               ppage = NULL;
                if (pfn_valid(pfn))
                        ppage = pfn_to_page(pfn);
-               pfn++;
-               if (!ppage)
-                       kflags = 0;
                else
-                       kflags = ppage->flags;
-
-               uflags = kpf_copy_bit(kflags, KPF_LOCKED, PG_locked) |
-                       kpf_copy_bit(kflags, KPF_ERROR, PG_error) |
-                       kpf_copy_bit(kflags, KPF_REFERENCED, PG_referenced) |
-                       kpf_copy_bit(kflags, KPF_UPTODATE, PG_uptodate) |
-                       kpf_copy_bit(kflags, KPF_DIRTY, PG_dirty) |
-                       kpf_copy_bit(kflags, KPF_LRU, PG_lru) |
-                       kpf_copy_bit(kflags, KPF_ACTIVE, PG_active) |
-                       kpf_copy_bit(kflags, KPF_SLAB, PG_slab) |
-                       kpf_copy_bit(kflags, KPF_WRITEBACK, PG_writeback) |
-                       kpf_copy_bit(kflags, KPF_RECLAIM, PG_reclaim) |
-                       kpf_copy_bit(kflags, KPF_BUDDY, PG_buddy);
-
-               if (put_user(uflags, out++)) {
+                       ppage = NULL;
+
+               if (put_user(get_uflags(ppage), out)) {
                        ret = -EFAULT;
                        break;
                }
 
+               pfn++;
+               out++;
                count -= KPMSIZE;
        }
 
index 0fe0e1469df31f386845dd443fdfe89a01543d92..d870237e42c74f018b2824304345aa44a90b8607 100644 (file)
@@ -168,7 +168,7 @@ static struct poll_table_entry *poll_get_entry(struct poll_wqueues *p)
        return table->entry++;
 }
 
-static int pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key)
+static int __pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key)
 {
        struct poll_wqueues *pwq = wait->private;
        DECLARE_WAITQUEUE(dummy_wait, pwq->polling_task);
@@ -194,6 +194,16 @@ static int pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key)
        return default_wake_function(&dummy_wait, mode, sync, key);
 }
 
+static int pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key)
+{
+       struct poll_table_entry *entry;
+
+       entry = container_of(wait, struct poll_table_entry, wait);
+       if (key && !((unsigned long)key & entry->key))
+               return 0;
+       return __pollwake(wait, mode, sync, key);
+}
+
 /* Add a new entry */
 static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
                                poll_table *p)
@@ -205,6 +215,7 @@ static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
        get_file(filp);
        entry->filp = filp;
        entry->wait_address = wait_address;
+       entry->key = p->key;
        init_waitqueue_func_entry(&entry->wait, pollwake);
        entry->wait.private = pwq;
        add_wait_queue(wait_address, &entry->wait);
@@ -362,6 +373,18 @@ get_max:
 #define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR)
 #define POLLEX_SET (POLLPRI)
 
+static inline void wait_key_set(poll_table *wait, unsigned long in,
+                               unsigned long out, unsigned long bit)
+{
+       if (wait) {
+               wait->key = POLLEX_SET;
+               if (in & bit)
+                       wait->key |= POLLIN_SET;
+               if (out & bit)
+                       wait->key |= POLLOUT_SET;
+       }
+}
+
 int do_select(int n, fd_set_bits *fds, struct timespec *end_time)
 {
        ktime_t expire, *to = NULL;
@@ -418,20 +441,25 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time)
                                if (file) {
                                        f_op = file->f_op;
                                        mask = DEFAULT_POLLMASK;
-                                       if (f_op && f_op->poll)
-                                               mask = (*f_op->poll)(file, retval ? NULL : wait);
+                                       if (f_op && f_op->poll) {
+                                               wait_key_set(wait, in, out, bit);
+                                               mask = (*f_op->poll)(file, wait);
+                                       }
                                        fput_light(file, fput_needed);
                                        if ((mask & POLLIN_SET) && (in & bit)) {
                                                res_in |= bit;
                                                retval++;
+                                               wait = NULL;
                                        }
                                        if ((mask & POLLOUT_SET) && (out & bit)) {
                                                res_out |= bit;
                                                retval++;
+                                               wait = NULL;
                                        }
                                        if ((mask & POLLEX_SET) && (ex & bit)) {
                                                res_ex |= bit;
                                                retval++;
+                                               wait = NULL;
                                        }
                                }
                        }
@@ -685,8 +713,12 @@ static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait)
                mask = POLLNVAL;
                if (file != NULL) {
                        mask = DEFAULT_POLLMASK;
-                       if (file->f_op && file->f_op->poll)
+                       if (file->f_op && file->f_op->poll) {
+                               if (pwait)
+                                       pwait->key = pollfd->events |
+                                                       POLLERR | POLLHUP;
                                mask = file->f_op->poll(file, pwait);
+                       }
                        /* Mask out unneeded events. */
                        mask &= pollfd->events | POLLERR | POLLHUP;
                        fput_light(file, fput_needed);
index a3ba217fbe74f4313a1dca88a8cc863e14766341..1d897ad808e0b1d234c302bc745a3c858848ce6b 100644 (file)
@@ -192,8 +192,11 @@ static void *sysfs_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
        int error = -ENOMEM;
        unsigned long page = get_zeroed_page(GFP_KERNEL);
-       if (page)
+       if (page) {
                error = sysfs_getlink(dentry, (char *) page); 
+               if (error < 0)
+                       free_page((unsigned long)page);
+       }
        nd_set_link(nd, error ? ERR_PTR(error) : (char *)page);
        return NULL;
 }
index 3589eab02a2f55666551e6c25393d8b740952914..3260b73abe29c322cb5f66bb5dc3337a7aedd769 100644 (file)
@@ -1937,6 +1937,9 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
        err  = bdi_init(&c->bdi);
        if (err)
                goto out_close;
+       err = bdi_register(&c->bdi, NULL, "ubifs");
+       if (err)
+               goto out_bdi;
 
        err = ubifs_parse_options(c, data, 0);
        if (err)
index 4db89e98535d25eae5be6c9496b622e1296613f7..82ec6a3c050095a018e4594fe28dec4d5408e49e 100644 (file)
@@ -47,7 +47,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20090320
+#define ACPI_CA_VERSION                 0x20090521
 
 #include "actypes.h"
 #include "actbl.h"
@@ -201,6 +201,8 @@ acpi_evaluate_object_typed(acpi_handle object,
 acpi_status
 acpi_get_object_info(acpi_handle handle, struct acpi_buffer *return_buffer);
 
+acpi_status acpi_install_method(u8 *buffer);
+
 acpi_status
 acpi_get_next_object(acpi_object_type type,
                     acpi_handle parent,
@@ -375,7 +377,7 @@ acpi_status acpi_leave_sleep_state_prep(u8 sleep_state);
 acpi_status acpi_leave_sleep_state(u8 sleep_state);
 
 /*
- * Debug output
+ * Error/Warning output
  */
 void ACPI_INTERNAL_VAR_XFACE
 acpi_error(const char *module_name,
@@ -394,6 +396,9 @@ void ACPI_INTERNAL_VAR_XFACE
 acpi_info(const char *module_name,
          u32 line_number, const char *format, ...) ACPI_PRINTF_LIKE(3);
 
+/*
+ * Debug output
+ */
 #ifdef ACPI_DEBUG_OUTPUT
 
 void ACPI_INTERNAL_VAR_XFACE
index f555d927f7c0f17bb630a2c1ca3f868205b4af68..37ba576d06e857c51a4c9b62f3d7464eee87fbd2 100644 (file)
@@ -429,20 +429,12 @@ typedef unsigned long long acpi_integer;
 
 /* Data manipulation */
 
-#define ACPI_LOWORD(l)                  ((u16)(u32)(l))
-#define ACPI_HIWORD(l)                  ((u16)((((u32)(l)) >> 16) & 0xFFFF))
-#define ACPI_LOBYTE(l)                  ((u8)(u16)(l))
-#define ACPI_HIBYTE(l)                  ((u8)((((u16)(l)) >> 8) & 0xFF))
-
-/* Full 64-bit integer must be available on both 32-bit and 64-bit platforms */
-
-struct acpi_integer_overlay {
-       u32 lo_dword;
-       u32 hi_dword;
-};
-
-#define ACPI_LODWORD(integer)           (ACPI_CAST_PTR (struct acpi_integer_overlay, &integer)->lo_dword)
-#define ACPI_HIDWORD(integer)           (ACPI_CAST_PTR (struct acpi_integer_overlay, &integer)->hi_dword)
+#define ACPI_LOBYTE(integer)            ((u8)   (u16)(integer))
+#define ACPI_HIBYTE(integer)            ((u8) (((u16)(integer)) >> 8))
+#define ACPI_LOWORD(integer)            ((u16)  (u32)(integer))
+#define ACPI_HIWORD(integer)            ((u16)(((u32)(integer)) >> 16))
+#define ACPI_LODWORD(integer64)         ((u32)  (u64)(integer64))
+#define ACPI_HIDWORD(integer64)         ((u32)(((u64)(integer64)) >> 32))
 
 #define ACPI_SET_BIT(target,bit)        ((target) |= (bit))
 #define ACPI_CLEAR_BIT(target,bit)      ((target) &= ~(bit))
index 8e2cdc57b1974f5430b4d39fe681090f9ffd0441..935c5d7fc86eb44f2050e5f21ba1aedd8ef0b930 100644 (file)
@@ -62,4 +62,8 @@
  */
 #define ACPI_UNUSED_VAR __attribute__ ((unused))
 
+#ifdef _ANSI
+#define inline
+#endif
+
 #endif                         /* __ACGCC_H__ */
index 6d49b2a498c4d5c92ae49d974be3b6a693b9bfae..fcb8e4b159b1cde3060d27fd1761c898fa0a0250 100644 (file)
@@ -1,11 +1,11 @@
 /******************************************************************************
  *
- * Name: aclinux.h - OS specific defines, etc.
+ * Name: aclinux.h - OS specific defines, etc. for Linux
  *
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2008, Intel Corp.
+ * Copyright (C) 2000 - 2009, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #ifndef __ACLINUX_H__
 #define __ACLINUX_H__
 
+/* Common (in-kernel/user-space) ACPICA configuration */
+
 #define ACPI_USE_SYSTEM_CLIBRARY
 #define ACPI_USE_DO_WHILE_0
 #define ACPI_MUTEX_TYPE             ACPI_BINARY_SEMAPHORE
 
+
 #ifdef __KERNEL__
 
 #include <linux/string.h>
 #include <linux/spinlock_types.h>
 #include <asm/current.h>
 
-/* Host-dependent types and defines */
+/* Host-dependent types and defines for in-kernel ACPICA */
 
 #define ACPI_MACHINE_WIDTH          BITS_PER_LONG
-#define acpi_cache_t                        struct kmem_cache
-#define acpi_spinlock                   spinlock_t *
 #define ACPI_EXPORT_SYMBOL(symbol)  EXPORT_SYMBOL(symbol);
 #define strtoul                     simple_strtoul
 
-#else                          /* !__KERNEL__ */
+#define acpi_cache_t                        struct kmem_cache
+#define acpi_spinlock                       spinlock_t *
+#define acpi_cpu_flags                      unsigned long
+#define acpi_thread_id                      struct task_struct *
+
+#else /* !__KERNEL__ */
 
 #include <stdarg.h>
 #include <string.h>
 #include <ctype.h>
 #include <unistd.h>
 
+/* Host-dependent types and defines for user-space ACPICA */
+
+#define ACPI_FLUSH_CPU_CACHE()
+#define acpi_thread_id                      pthread_t
+
 #if defined(__ia64__) || defined(__x86_64__)
 #define ACPI_MACHINE_WIDTH          64
 #define COMPILER_DEPENDENT_INT64    long
 #define __cdecl
 #endif
 
-#define ACPI_FLUSH_CPU_CACHE()
-#endif                         /* __KERNEL__ */
+#endif /* __KERNEL__ */
 
 /* Linux uses GCC */
 
 #include "acgcc.h"
 
-#define acpi_cpu_flags unsigned long
-
-#define acpi_thread_id struct task_struct *
 
+#ifdef __KERNEL__
+/*
+ * Overrides for in-kernel ACPICA
+ */
 static inline acpi_thread_id acpi_os_get_thread_id(void)
 {
        return current;
@@ -119,30 +130,32 @@ static inline acpi_thread_id acpi_os_get_thread_id(void)
 #include <acpi/actypes.h>
 static inline void *acpi_os_allocate(acpi_size size)
 {
-       return kmalloc(size, irqs_disabled()? GFP_ATOMIC : GFP_KERNEL);
+       return kmalloc(size, irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL);
 }
+
 static inline void *acpi_os_allocate_zeroed(acpi_size size)
 {
-       return kzalloc(size, irqs_disabled()? GFP_ATOMIC : GFP_KERNEL);
+       return kzalloc(size, irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL);
 }
 
 static inline void *acpi_os_acquire_object(acpi_cache_t * cache)
 {
        return kmem_cache_zalloc(cache,
-                                irqs_disabled()? GFP_ATOMIC : GFP_KERNEL);
+               irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL);
 }
 
-#define ACPI_ALLOCATE(a)       acpi_os_allocate(a)
-#define ACPI_ALLOCATE_ZEROED(a)        acpi_os_allocate_zeroed(a)
-#define ACPI_FREE(a)           kfree(a)
+#define ACPI_ALLOCATE(a)        acpi_os_allocate(a)
+#define ACPI_ALLOCATE_ZEROED(a) acpi_os_allocate_zeroed(a)
+#define ACPI_FREE(a)            kfree(a)
 
-/*
- * We need to show where it is safe to preempt execution of ACPICA
- */
-#define ACPI_PREEMPTION_POINT()                \
-       do {                            \
-               if (!irqs_disabled())   \
-                       cond_resched(); \
+/* Used within ACPICA to show where it is safe to preempt execution */
+
+#define ACPI_PREEMPTION_POINT() \
+       do { \
+               if (!irqs_disabled()) \
+                       cond_resched(); \
        } while (0)
 
-#endif                         /* __ACLINUX_H__ */
+#endif /* __KERNEL__ */
+
+#endif /* __ACLINUX_H__ */
diff --git a/include/asm-generic/atomic64.h b/include/asm-generic/atomic64.h
new file mode 100644 (file)
index 0000000..b18ce4f
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Generic implementation of 64-bit atomics using spinlocks,
+ * useful on processors that don't have 64-bit atomic instructions.
+ *
+ * Copyright Â© 2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _ASM_GENERIC_ATOMIC64_H
+#define _ASM_GENERIC_ATOMIC64_H
+
+typedef struct {
+       long long counter;
+} atomic64_t;
+
+#define ATOMIC64_INIT(i)       { (i) }
+
+extern long long atomic64_read(const atomic64_t *v);
+extern void     atomic64_set(atomic64_t *v, long long i);
+extern void     atomic64_add(long long a, atomic64_t *v);
+extern long long atomic64_add_return(long long a, atomic64_t *v);
+extern void     atomic64_sub(long long a, atomic64_t *v);
+extern long long atomic64_sub_return(long long a, atomic64_t *v);
+extern long long atomic64_dec_if_positive(atomic64_t *v);
+extern long long atomic64_cmpxchg(atomic64_t *v, long long o, long long n);
+extern long long atomic64_xchg(atomic64_t *v, long long new);
+extern int      atomic64_add_unless(atomic64_t *v, long long a, long long u);
+
+#define atomic64_add_negative(a, v)    (atomic64_add_return((a), (v)) < 0)
+#define atomic64_inc(v)                        atomic64_add(1LL, (v))
+#define atomic64_inc_return(v)         atomic64_add_return(1LL, (v))
+#define atomic64_inc_and_test(v)       (atomic64_inc_return(v) == 0)
+#define atomic64_sub_and_test(a, v)    (atomic64_sub_return((a), (v)) == 0)
+#define atomic64_dec(v)                        atomic64_sub(1LL, (v))
+#define atomic64_dec_return(v)         atomic64_sub_return(1LL, (v))
+#define atomic64_dec_and_test(v)       (atomic64_dec_return((v)) == 0)
+#define atomic64_inc_not_zero(v)       atomic64_add_unless((v), 1LL, 0LL)
+
+#endif  /*  _ASM_GENERIC_ATOMIC64_H  */
index 58c33055c304f65a1c6f576d1d1e8b0c8533afad..54e8b3d956b7fe9ba20082844b50237d27050681 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _ASM_GENERIC_KMAP_TYPES_H
 #define _ASM_GENERIC_KMAP_TYPES_H
 
-#ifdef CONFIG_DEBUG_HIGHMEM
+#ifdef __WITH_KM_FENCE
 # define D(n) __KM_FENCE_##n ,
 #else
 # define D(n)
index f8634ab53b8f98166a05af894d8789e790ee7435..45c18672b0936dc50c04b0cb33f105376401db2b 100644 (file)
        {0x1002, 0x940A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x940B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x940F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R600|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x94A0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x94A1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x94A0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x94A1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x94B1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x94B3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x94B5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV740|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x9456, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x945A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x945B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x9460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
-       {0x1002, 0x9462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x9462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x946A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x946B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x947A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV770|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
index fe3e3a4b4aed9257ec14a6c1e3799fd52444b90e..41862e9a4c2097bd2cae6e6a90d33b50fe8f751f 100644 (file)
@@ -496,6 +496,16 @@ typedef struct {
 #define DRM_RADEON_SETPARAM   0x19
 #define DRM_RADEON_SURF_ALLOC 0x1a
 #define DRM_RADEON_SURF_FREE  0x1b
+/* KMS ioctl */
+#define DRM_RADEON_GEM_INFO            0x1c
+#define DRM_RADEON_GEM_CREATE          0x1d
+#define DRM_RADEON_GEM_MMAP            0x1e
+#define DRM_RADEON_GEM_PREAD           0x21
+#define DRM_RADEON_GEM_PWRITE          0x22
+#define DRM_RADEON_GEM_SET_DOMAIN      0x23
+#define DRM_RADEON_GEM_WAIT_IDLE       0x24
+#define DRM_RADEON_CS                  0x26
+#define DRM_RADEON_INFO                        0x27
 
 #define DRM_IOCTL_RADEON_CP_INIT    DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CP_INIT, drm_radeon_init_t)
 #define DRM_IOCTL_RADEON_CP_START   DRM_IO(  DRM_COMMAND_BASE + DRM_RADEON_CP_START)
@@ -524,6 +534,17 @@ typedef struct {
 #define DRM_IOCTL_RADEON_SETPARAM   DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_SETPARAM, drm_radeon_setparam_t)
 #define DRM_IOCTL_RADEON_SURF_ALLOC DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_SURF_ALLOC, drm_radeon_surface_alloc_t)
 #define DRM_IOCTL_RADEON_SURF_FREE  DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_SURF_FREE, drm_radeon_surface_free_t)
+/* KMS */
+#define DRM_IOCTL_RADEON_GEM_INFO      DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_INFO, struct drm_radeon_gem_info)
+#define DRM_IOCTL_RADEON_GEM_CREATE    DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_CREATE, struct drm_radeon_gem_create)
+#define DRM_IOCTL_RADEON_GEM_MMAP      DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_MMAP, struct drm_radeon_gem_mmap)
+#define DRM_IOCTL_RADEON_GEM_PREAD     DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_PREAD, struct drm_radeon_gem_pread)
+#define DRM_IOCTL_RADEON_GEM_PWRITE    DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_PWRITE, struct drm_radeon_gem_pwrite)
+#define DRM_IOCTL_RADEON_GEM_SET_DOMAIN        DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_SET_DOMAIN, struct drm_radeon_gem_set_domain)
+#define DRM_IOCTL_RADEON_GEM_WAIT_IDLE DRM_IOW(DRM_COMMAND_BASE + DRM_RADEON_GEM_WAIT_IDLE, struct drm_radeon_gem_wait_idle)
+#define DRM_IOCTL_RADEON_CS            DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_CS, struct drm_radeon_cs)
+#define DRM_IOCTL_RADEON_INFO          DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_INFO, struct drm_radeon_info)
+
 
 typedef struct drm_radeon_init {
        enum {
@@ -682,6 +703,7 @@ typedef struct drm_radeon_indirect {
 #define RADEON_PARAM_VBLANK_CRTC           13   /* VBLANK CRTC */
 #define RADEON_PARAM_FB_LOCATION           14   /* FB location */
 #define RADEON_PARAM_NUM_GB_PIPES          15   /* num GB pipes */
+#define RADEON_PARAM_DEVICE_ID             16
 
 typedef struct drm_radeon_getparam {
        int param;
@@ -751,4 +773,112 @@ typedef struct drm_radeon_surface_free {
 #define        DRM_RADEON_VBLANK_CRTC1         1
 #define        DRM_RADEON_VBLANK_CRTC2         2
 
+/*
+ * Kernel modesetting world below.
+ */
+#define RADEON_GEM_DOMAIN_CPU          0x1
+#define RADEON_GEM_DOMAIN_GTT          0x2
+#define RADEON_GEM_DOMAIN_VRAM         0x4
+
+struct drm_radeon_gem_info {
+       uint64_t        gart_size;
+       uint64_t        vram_size;
+       uint64_t        vram_visible;
+};
+
+#define RADEON_GEM_NO_BACKING_STORE 1
+
+struct drm_radeon_gem_create {
+       uint64_t        size;
+       uint64_t        alignment;
+       uint32_t        handle;
+       uint32_t        initial_domain;
+       uint32_t        flags;
+};
+
+struct drm_radeon_gem_mmap {
+       uint32_t        handle;
+       uint32_t        pad;
+       uint64_t        offset;
+       uint64_t        size;
+       uint64_t        addr_ptr;
+};
+
+struct drm_radeon_gem_set_domain {
+       uint32_t        handle;
+       uint32_t        read_domains;
+       uint32_t        write_domain;
+};
+
+struct drm_radeon_gem_wait_idle {
+       uint32_t        handle;
+       uint32_t        pad;
+};
+
+struct drm_radeon_gem_busy {
+       uint32_t        handle;
+       uint32_t        busy;
+};
+
+struct drm_radeon_gem_pread {
+       /** Handle for the object being read. */
+       uint32_t handle;
+       uint32_t pad;
+       /** Offset into the object to read from */
+       uint64_t offset;
+       /** Length of data to read */
+       uint64_t size;
+       /** Pointer to write the data into. */
+       /* void *, but pointers are not 32/64 compatible */
+       uint64_t data_ptr;
+};
+
+struct drm_radeon_gem_pwrite {
+       /** Handle for the object being written to. */
+       uint32_t handle;
+       uint32_t pad;
+       /** Offset into the object to write to */
+       uint64_t offset;
+       /** Length of data to write */
+       uint64_t size;
+       /** Pointer to read the data from. */
+       /* void *, but pointers are not 32/64 compatible */
+       uint64_t data_ptr;
+};
+
+#define RADEON_CHUNK_ID_RELOCS 0x01
+#define RADEON_CHUNK_ID_IB     0x02
+
+struct drm_radeon_cs_chunk {
+       uint32_t                chunk_id;
+       uint32_t                length_dw;
+       uint64_t                chunk_data;
+};
+
+struct drm_radeon_cs_reloc {
+       uint32_t                handle;
+       uint32_t                read_domains;
+       uint32_t                write_domain;
+       uint32_t                flags;
+};
+
+struct drm_radeon_cs {
+       uint32_t                num_chunks;
+       uint32_t                cs_id;
+       /* this points to uint64_t * which point to cs chunks */
+       uint64_t                chunks;
+       /* updates to the limits after this CS ioctl */
+       uint64_t                gart_limit;
+       uint64_t                vram_limit;
+};
+
+#define RADEON_INFO_DEVICE_ID          0x00
+#define RADEON_INFO_NUM_GB_PIPES       0x01
+
+struct drm_radeon_info {
+       uint32_t                request;
+       uint32_t                pad;
+       uint64_t                value;
+};
+
 #endif
diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h
new file mode 100644 (file)
index 0000000..cd22ab4
--- /dev/null
@@ -0,0 +1,618 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+/*
+ * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
+ */
+
+#ifndef _TTM_BO_API_H_
+#define _TTM_BO_API_H_
+
+#include "drm_hashtab.h"
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/wait.h>
+#include <linux/mutex.h>
+#include <linux/mm.h>
+#include <linux/rbtree.h>
+#include <linux/bitmap.h>
+
+struct ttm_bo_device;
+
+struct drm_mm_node;
+
+/**
+ * struct ttm_mem_reg
+ *
+ * @mm_node: Memory manager node.
+ * @size: Requested size of memory region.
+ * @num_pages: Actual size of memory region in pages.
+ * @page_alignment: Page alignment.
+ * @placement: Placement flags.
+ *
+ * Structure indicating the placement and space resources used by a
+ * buffer object.
+ */
+
+struct ttm_mem_reg {
+       struct drm_mm_node *mm_node;
+       unsigned long size;
+       unsigned long num_pages;
+       uint32_t page_alignment;
+       uint32_t mem_type;
+       uint32_t placement;
+};
+
+/**
+ * enum ttm_bo_type
+ *
+ * @ttm_bo_type_device:        These are 'normal' buffers that can
+ * be mmapped by user space. Each of these bos occupy a slot in the
+ * device address space, that can be used for normal vm operations.
+ *
+ * @ttm_bo_type_user: These are user-space memory areas that are made
+ * available to the GPU by mapping the buffer pages into the GPU aperture
+ * space. These buffers cannot be mmaped from the device address space.
+ *
+ * @ttm_bo_type_kernel: These buffers are like ttm_bo_type_device buffers,
+ * but they cannot be accessed from user-space. For kernel-only use.
+ */
+
+enum ttm_bo_type {
+       ttm_bo_type_device,
+       ttm_bo_type_user,
+       ttm_bo_type_kernel
+};
+
+struct ttm_tt;
+
+/**
+ * struct ttm_buffer_object
+ *
+ * @bdev: Pointer to the buffer object device structure.
+ * @buffer_start: The virtual user-space start address of ttm_bo_type_user
+ * buffers.
+ * @type: The bo type.
+ * @destroy: Destruction function. If NULL, kfree is used.
+ * @num_pages: Actual number of pages.
+ * @addr_space_offset: Address space offset.
+ * @acc_size: Accounted size for this object.
+ * @kref: Reference count of this buffer object. When this refcount reaches
+ * zero, the object is put on the delayed delete list.
+ * @list_kref: List reference count of this buffer object. This member is
+ * used to avoid destruction while the buffer object is still on a list.
+ * Lru lists may keep one refcount, the delayed delete list, and kref != 0
+ * keeps one refcount. When this refcount reaches zero,
+ * the object is destroyed.
+ * @event_queue: Queue for processes waiting on buffer object status change.
+ * @lock: spinlock protecting mostly synchronization members.
+ * @proposed_placement: Proposed placement for the buffer. Changed only by the
+ * creator prior to validation as opposed to bo->mem.proposed_flags which is
+ * changed by the implementation prior to a buffer move if it wants to outsmart
+ * the buffer creator / user. This latter happens, for example, at eviction.
+ * @mem: structure describing current placement.
+ * @persistant_swap_storage: Usually the swap storage is deleted for buffers
+ * pinned in physical memory. If this behaviour is not desired, this member
+ * holds a pointer to a persistant shmem object.
+ * @ttm: TTM structure holding system pages.
+ * @evicted: Whether the object was evicted without user-space knowing.
+ * @cpu_writes: For synchronization. Number of cpu writers.
+ * @lru: List head for the lru list.
+ * @ddestroy: List head for the delayed destroy list.
+ * @swap: List head for swap LRU list.
+ * @val_seq: Sequence of the validation holding the @reserved lock.
+ * Used to avoid starvation when many processes compete to validate the
+ * buffer. This member is protected by the bo_device::lru_lock.
+ * @seq_valid: The value of @val_seq is valid. This value is protected by
+ * the bo_device::lru_lock.
+ * @reserved: Deadlock-free lock used for synchronization state transitions.
+ * @sync_obj_arg: Opaque argument to synchronization object function.
+ * @sync_obj: Pointer to a synchronization object.
+ * @priv_flags: Flags describing buffer object internal state.
+ * @vm_rb: Rb node for the vm rb tree.
+ * @vm_node: Address space manager node.
+ * @offset: The current GPU offset, which can have different meanings
+ * depending on the memory type. For SYSTEM type memory, it should be 0.
+ * @cur_placement: Hint of current placement.
+ *
+ * Base class for TTM buffer object, that deals with data placement and CPU
+ * mappings. GPU mappings are really up to the driver, but for simpler GPUs
+ * the driver can usually use the placement offset @offset directly as the
+ * GPU virtual address. For drivers implementing multiple
+ * GPU memory manager contexts, the driver should manage the address space
+ * in these contexts separately and use these objects to get the correct
+ * placement and caching for these GPU maps. This makes it possible to use
+ * these objects for even quite elaborate memory management schemes.
+ * The destroy member, the API visibility of this object makes it possible
+ * to derive driver specific types.
+ */
+
+struct ttm_buffer_object {
+       /**
+        * Members constant at init.
+        */
+
+       struct ttm_bo_device *bdev;
+       unsigned long buffer_start;
+       enum ttm_bo_type type;
+       void (*destroy) (struct ttm_buffer_object *);
+       unsigned long num_pages;
+       uint64_t addr_space_offset;
+       size_t acc_size;
+
+       /**
+       * Members not needing protection.
+       */
+
+       struct kref kref;
+       struct kref list_kref;
+       wait_queue_head_t event_queue;
+       spinlock_t lock;
+
+       /**
+        * Members protected by the bo::reserved lock.
+        */
+
+       uint32_t proposed_placement;
+       struct ttm_mem_reg mem;
+       struct file *persistant_swap_storage;
+       struct ttm_tt *ttm;
+       bool evicted;
+
+       /**
+        * Members protected by the bo::reserved lock only when written to.
+        */
+
+       atomic_t cpu_writers;
+
+       /**
+        * Members protected by the bdev::lru_lock.
+        */
+
+       struct list_head lru;
+       struct list_head ddestroy;
+       struct list_head swap;
+       uint32_t val_seq;
+       bool seq_valid;
+
+       /**
+        * Members protected by the bdev::lru_lock
+        * only when written to.
+        */
+
+       atomic_t reserved;
+
+
+       /**
+        * Members protected by the bo::lock
+        */
+
+       void *sync_obj_arg;
+       void *sync_obj;
+       unsigned long priv_flags;
+
+       /**
+        * Members protected by the bdev::vm_lock
+        */
+
+       struct rb_node vm_rb;
+       struct drm_mm_node *vm_node;
+
+
+       /**
+        * Special members that are protected by the reserve lock
+        * and the bo::lock when written to. Can be read with
+        * either of these locks held.
+        */
+
+       unsigned long offset;
+       uint32_t cur_placement;
+};
+
+/**
+ * struct ttm_bo_kmap_obj
+ *
+ * @virtual: The current kernel virtual address.
+ * @page: The page when kmap'ing a single page.
+ * @bo_kmap_type: Type of bo_kmap.
+ *
+ * Object describing a kernel mapping. Since a TTM bo may be located
+ * in various memory types with various caching policies, the
+ * mapping can either be an ioremap, a vmap, a kmap or part of a
+ * premapped region.
+ */
+
+struct ttm_bo_kmap_obj {
+       void *virtual;
+       struct page *page;
+       enum {
+               ttm_bo_map_iomap,
+               ttm_bo_map_vmap,
+               ttm_bo_map_kmap,
+               ttm_bo_map_premapped,
+       } bo_kmap_type;
+};
+
+/**
+ * ttm_bo_reference - reference a struct ttm_buffer_object
+ *
+ * @bo: The buffer object.
+ *
+ * Returns a refcounted pointer to a buffer object.
+ */
+
+static inline struct ttm_buffer_object *
+ttm_bo_reference(struct ttm_buffer_object *bo)
+{
+       kref_get(&bo->kref);
+       return bo;
+}
+
+/**
+ * ttm_bo_wait - wait for buffer idle.
+ *
+ * @bo:  The buffer object.
+ * @interruptible:  Use interruptible wait.
+ * @no_wait:  Return immediately if buffer is busy.
+ *
+ * This function must be called with the bo::mutex held, and makes
+ * sure any previous rendering to the buffer is completed.
+ * Note: It might be necessary to block validations before the
+ * wait by reserving the buffer.
+ * Returns -EBUSY if no_wait is true and the buffer is busy.
+ * Returns -ERESTART if interrupted by a signal.
+ */
+extern int ttm_bo_wait(struct ttm_buffer_object *bo, bool lazy,
+                      bool interruptible, bool no_wait);
+/**
+ * ttm_buffer_object_validate
+ *
+ * @bo: The buffer object.
+ * @proposed_placement: Proposed_placement for the buffer object.
+ * @interruptible: Sleep interruptible if sleeping.
+ * @no_wait: Return immediately if the buffer is busy.
+ *
+ * Changes placement and caching policy of the buffer object
+ * according to bo::proposed_flags.
+ * Returns
+ * -EINVAL on invalid proposed_flags.
+ * -ENOMEM on out-of-memory condition.
+ * -EBUSY if no_wait is true and buffer busy.
+ * -ERESTART if interrupted by a signal.
+ */
+extern int ttm_buffer_object_validate(struct ttm_buffer_object *bo,
+                                     uint32_t proposed_placement,
+                                     bool interruptible, bool no_wait);
+/**
+ * ttm_bo_unref
+ *
+ * @bo: The buffer object.
+ *
+ * Unreference and clear a pointer to a buffer object.
+ */
+extern void ttm_bo_unref(struct ttm_buffer_object **bo);
+
+/**
+ * ttm_bo_synccpu_write_grab
+ *
+ * @bo: The buffer object:
+ * @no_wait: Return immediately if buffer is busy.
+ *
+ * Synchronizes a buffer object for CPU RW access. This means
+ * blocking command submission that affects the buffer and
+ * waiting for buffer idle. This lock is recursive.
+ * Returns
+ * -EBUSY if the buffer is busy and no_wait is true.
+ * -ERESTART if interrupted by a signal.
+ */
+
+extern int
+ttm_bo_synccpu_write_grab(struct ttm_buffer_object *bo, bool no_wait);
+/**
+ * ttm_bo_synccpu_write_release:
+ *
+ * @bo : The buffer object.
+ *
+ * Releases a synccpu lock.
+ */
+extern void ttm_bo_synccpu_write_release(struct ttm_buffer_object *bo);
+
+/**
+ * ttm_buffer_object_init
+ *
+ * @bdev: Pointer to a ttm_bo_device struct.
+ * @bo: Pointer to a ttm_buffer_object to be initialized.
+ * @size: Requested size of buffer object.
+ * @type: Requested type of buffer object.
+ * @flags: Initial placement flags.
+ * @page_alignment: Data alignment in pages.
+ * @buffer_start: Virtual address of user space data backing a
+ * user buffer object.
+ * @interruptible: If needing to sleep to wait for GPU resources,
+ * sleep interruptible.
+ * @persistant_swap_storage: Usually the swap storage is deleted for buffers
+ * pinned in physical memory. If this behaviour is not desired, this member
+ * holds a pointer to a persistant shmem object. Typically, this would
+ * point to the shmem object backing a GEM object if TTM is used to back a
+ * GEM user interface.
+ * @acc_size: Accounted size for this object.
+ * @destroy: Destroy function. Use NULL for kfree().
+ *
+ * This function initializes a pre-allocated struct ttm_buffer_object.
+ * As this object may be part of a larger structure, this function,
+ * together with the @destroy function,
+ * enables driver-specific objects derived from a ttm_buffer_object.
+ * On successful return, the object kref and list_kref are set to 1.
+ * Returns
+ * -ENOMEM: Out of memory.
+ * -EINVAL: Invalid placement flags.
+ * -ERESTART: Interrupted by signal while sleeping waiting for resources.
+ */
+
+extern int ttm_buffer_object_init(struct ttm_bo_device *bdev,
+                                 struct ttm_buffer_object *bo,
+                                 unsigned long size,
+                                 enum ttm_bo_type type,
+                                 uint32_t flags,
+                                 uint32_t page_alignment,
+                                 unsigned long buffer_start,
+                                 bool interrubtible,
+                                 struct file *persistant_swap_storage,
+                                 size_t acc_size,
+                                 void (*destroy) (struct ttm_buffer_object *));
+/**
+ * ttm_bo_synccpu_object_init
+ *
+ * @bdev: Pointer to a ttm_bo_device struct.
+ * @bo: Pointer to a ttm_buffer_object to be initialized.
+ * @size: Requested size of buffer object.
+ * @type: Requested type of buffer object.
+ * @flags: Initial placement flags.
+ * @page_alignment: Data alignment in pages.
+ * @buffer_start: Virtual address of user space data backing a
+ * user buffer object.
+ * @interruptible: If needing to sleep while waiting for GPU resources,
+ * sleep interruptible.
+ * @persistant_swap_storage: Usually the swap storage is deleted for buffers
+ * pinned in physical memory. If this behaviour is not desired, this member
+ * holds a pointer to a persistant shmem object. Typically, this would
+ * point to the shmem object backing a GEM object if TTM is used to back a
+ * GEM user interface.
+ * @p_bo: On successful completion *p_bo points to the created object.
+ *
+ * This function allocates a ttm_buffer_object, and then calls
+ * ttm_buffer_object_init on that object.
+ * The destroy function is set to kfree().
+ * Returns
+ * -ENOMEM: Out of memory.
+ * -EINVAL: Invalid placement flags.
+ * -ERESTART: Interrupted by signal while waiting for resources.
+ */
+
+extern int ttm_buffer_object_create(struct ttm_bo_device *bdev,
+                                   unsigned long size,
+                                   enum ttm_bo_type type,
+                                   uint32_t flags,
+                                   uint32_t page_alignment,
+                                   unsigned long buffer_start,
+                                   bool interruptible,
+                                   struct file *persistant_swap_storage,
+                                   struct ttm_buffer_object **p_bo);
+
+/**
+ * ttm_bo_check_placement
+ *
+ * @bo: the buffer object.
+ * @set_flags: placement flags to set.
+ * @clr_flags: placement flags to clear.
+ *
+ * Performs minimal validity checking on an intended change of
+ * placement flags.
+ * Returns
+ * -EINVAL: Intended change is invalid or not allowed.
+ */
+
+extern int ttm_bo_check_placement(struct ttm_buffer_object *bo,
+                                 uint32_t set_flags, uint32_t clr_flags);
+
+/**
+ * ttm_bo_init_mm
+ *
+ * @bdev: Pointer to a ttm_bo_device struct.
+ * @mem_type: The memory type.
+ * @p_offset: offset for managed area in pages.
+ * @p_size: size managed area in pages.
+ *
+ * Initialize a manager for a given memory type.
+ * Note: if part of driver firstopen, it must be protected from a
+ * potentially racing lastclose.
+ * Returns:
+ * -EINVAL: invalid size or memory type.
+ * -ENOMEM: Not enough memory.
+ * May also return driver-specified errors.
+ */
+
+extern int ttm_bo_init_mm(struct ttm_bo_device *bdev, unsigned type,
+                         unsigned long p_offset, unsigned long p_size);
+/**
+ * ttm_bo_clean_mm
+ *
+ * @bdev: Pointer to a ttm_bo_device struct.
+ * @mem_type: The memory type.
+ *
+ * Take down a manager for a given memory type after first walking
+ * the LRU list to evict any buffers left alive.
+ *
+ * Normally, this function is part of lastclose() or unload(), and at that
+ * point there shouldn't be any buffers left created by user-space, since
+ * there should've been removed by the file descriptor release() method.
+ * However, before this function is run, make sure to signal all sync objects,
+ * and verify that the delayed delete queue is empty. The driver must also
+ * make sure that there are no NO_EVICT buffers present in this memory type
+ * when the call is made.
+ *
+ * If this function is part of a VT switch, the caller must make sure that
+ * there are no appications currently validating buffers before this
+ * function is called. The caller can do that by first taking the
+ * struct ttm_bo_device::ttm_lock in write mode.
+ *
+ * Returns:
+ * -EINVAL: invalid or uninitialized memory type.
+ * -EBUSY: There are still buffers left in this memory type.
+ */
+
+extern int ttm_bo_clean_mm(struct ttm_bo_device *bdev, unsigned mem_type);
+
+/**
+ * ttm_bo_evict_mm
+ *
+ * @bdev: Pointer to a ttm_bo_device struct.
+ * @mem_type: The memory type.
+ *
+ * Evicts all buffers on the lru list of the memory type.
+ * This is normally part of a VT switch or an
+ * out-of-memory-space-due-to-fragmentation handler.
+ * The caller must make sure that there are no other processes
+ * currently validating buffers, and can do that by taking the
+ * struct ttm_bo_device::ttm_lock in write mode.
+ *
+ * Returns:
+ * -EINVAL: Invalid or uninitialized memory type.
+ * -ERESTART: The call was interrupted by a signal while waiting to
+ * evict a buffer.
+ */
+
+extern int ttm_bo_evict_mm(struct ttm_bo_device *bdev, unsigned mem_type);
+
+/**
+ * ttm_kmap_obj_virtual
+ *
+ * @map: A struct ttm_bo_kmap_obj returned from ttm_bo_kmap.
+ * @is_iomem: Pointer to an integer that on return indicates 1 if the
+ * virtual map is io memory, 0 if normal memory.
+ *
+ * Returns the virtual address of a buffer object area mapped by ttm_bo_kmap.
+ * If *is_iomem is 1 on return, the virtual address points to an io memory area,
+ * that should strictly be accessed by the iowriteXX() and similar functions.
+ */
+
+static inline void *ttm_kmap_obj_virtual(struct ttm_bo_kmap_obj *map,
+                                        bool *is_iomem)
+{
+       *is_iomem = (map->bo_kmap_type == ttm_bo_map_iomap ||
+                    map->bo_kmap_type == ttm_bo_map_premapped);
+       return map->virtual;
+}
+
+/**
+ * ttm_bo_kmap
+ *
+ * @bo: The buffer object.
+ * @start_page: The first page to map.
+ * @num_pages: Number of pages to map.
+ * @map: pointer to a struct ttm_bo_kmap_obj representing the map.
+ *
+ * Sets up a kernel virtual mapping, using ioremap, vmap or kmap to the
+ * data in the buffer object. The ttm_kmap_obj_virtual function can then be
+ * used to obtain a virtual address to the data.
+ *
+ * Returns
+ * -ENOMEM: Out of memory.
+ * -EINVAL: Invalid range.
+ */
+
+extern int ttm_bo_kmap(struct ttm_buffer_object *bo, unsigned long start_page,
+                      unsigned long num_pages, struct ttm_bo_kmap_obj *map);
+
+/**
+ * ttm_bo_kunmap
+ *
+ * @map: Object describing the map to unmap.
+ *
+ * Unmaps a kernel map set up by ttm_bo_kmap.
+ */
+
+extern void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map);
+
+#if 0
+#endif
+
+/**
+ * ttm_fbdev_mmap - mmap fbdev memory backed by a ttm buffer object.
+ *
+ * @vma:       vma as input from the fbdev mmap method.
+ * @bo:        The bo backing the address space. The address space will
+ * have the same size as the bo, and start at offset 0.
+ *
+ * This function is intended to be called by the fbdev mmap method
+ * if the fbdev address space is to be backed by a bo.
+ */
+
+extern int ttm_fbdev_mmap(struct vm_area_struct *vma,
+                         struct ttm_buffer_object *bo);
+
+/**
+ * ttm_bo_mmap - mmap out of the ttm device address space.
+ *
+ * @filp:      filp as input from the mmap method.
+ * @vma:       vma as input from the mmap method.
+ * @bdev:      Pointer to the ttm_bo_device with the address space manager.
+ *
+ * This function is intended to be called by the device mmap method.
+ * if the device address space is to be backed by the bo manager.
+ */
+
+extern int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma,
+                      struct ttm_bo_device *bdev);
+
+/**
+ * ttm_bo_io
+ *
+ * @bdev:      Pointer to the struct ttm_bo_device.
+ * @filp:      Pointer to the struct file attempting to read / write.
+ * @wbuf:      User-space pointer to address of buffer to write. NULL on read.
+ * @rbuf:      User-space pointer to address of buffer to read into.
+ * Null on write.
+ * @count:     Number of bytes to read / write.
+ * @f_pos:     Pointer to current file position.
+ * @write:     1 for read, 0 for write.
+ *
+ * This function implements read / write into ttm buffer objects, and is
+ * intended to
+ * be called from the fops::read and fops::write method.
+ * Returns:
+ * See man (2) write, man(2) read. In particular,
+ * the function may return -EINTR if
+ * interrupted by a signal.
+ */
+
+extern ssize_t ttm_bo_io(struct ttm_bo_device *bdev, struct file *filp,
+                        const char __user *wbuf, char __user *rbuf,
+                        size_t count, loff_t *f_pos, bool write);
+
+extern void ttm_bo_swapout_all(struct ttm_bo_device *bdev);
+
+#endif
diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h
new file mode 100644 (file)
index 0000000..62ed733
--- /dev/null
@@ -0,0 +1,867 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2006-2009 Vmware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+/*
+ * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
+ */
+#ifndef _TTM_BO_DRIVER_H_
+#define _TTM_BO_DRIVER_H_
+
+#include "ttm/ttm_bo_api.h"
+#include "ttm/ttm_memory.h"
+#include "drm_mm.h"
+#include "linux/workqueue.h"
+#include "linux/fs.h"
+#include "linux/spinlock.h"
+
+struct ttm_backend;
+
+struct ttm_backend_func {
+       /**
+        * struct ttm_backend_func member populate
+        *
+        * @backend: Pointer to a struct ttm_backend.
+        * @num_pages: Number of pages to populate.
+        * @pages: Array of pointers to ttm pages.
+        * @dummy_read_page: Page to be used instead of NULL pages in the
+        * array @pages.
+        *
+        * Populate the backend with ttm pages. Depending on the backend,
+        * it may or may not copy the @pages array.
+        */
+       int (*populate) (struct ttm_backend *backend,
+                        unsigned long num_pages, struct page **pages,
+                        struct page *dummy_read_page);
+       /**
+        * struct ttm_backend_func member clear
+        *
+        * @backend: Pointer to a struct ttm_backend.
+        *
+        * This is an "unpopulate" function. Release all resources
+        * allocated with populate.
+        */
+       void (*clear) (struct ttm_backend *backend);
+
+       /**
+        * struct ttm_backend_func member bind
+        *
+        * @backend: Pointer to a struct ttm_backend.
+        * @bo_mem: Pointer to a struct ttm_mem_reg describing the
+        * memory type and location for binding.
+        *
+        * Bind the backend pages into the aperture in the location
+        * indicated by @bo_mem. This function should be able to handle
+        * differences between aperture- and system page sizes.
+        */
+       int (*bind) (struct ttm_backend *backend, struct ttm_mem_reg *bo_mem);
+
+       /**
+        * struct ttm_backend_func member unbind
+        *
+        * @backend: Pointer to a struct ttm_backend.
+        *
+        * Unbind previously bound backend pages. This function should be
+        * able to handle differences between aperture- and system page sizes.
+        */
+       int (*unbind) (struct ttm_backend *backend);
+
+       /**
+        * struct ttm_backend_func member destroy
+        *
+        * @backend: Pointer to a struct ttm_backend.
+        *
+        * Destroy the backend.
+        */
+       void (*destroy) (struct ttm_backend *backend);
+};
+
+/**
+ * struct ttm_backend
+ *
+ * @bdev: Pointer to a struct ttm_bo_device.
+ * @flags: For driver use.
+ * @func: Pointer to a struct ttm_backend_func that describes
+ * the backend methods.
+ *
+ */
+
+struct ttm_backend {
+       struct ttm_bo_device *bdev;
+       uint32_t flags;
+       struct ttm_backend_func *func;
+};
+
+#define TTM_PAGE_FLAG_VMALLOC         (1 << 0)
+#define TTM_PAGE_FLAG_USER            (1 << 1)
+#define TTM_PAGE_FLAG_USER_DIRTY      (1 << 2)
+#define TTM_PAGE_FLAG_WRITE           (1 << 3)
+#define TTM_PAGE_FLAG_SWAPPED         (1 << 4)
+#define TTM_PAGE_FLAG_PERSISTANT_SWAP (1 << 5)
+#define TTM_PAGE_FLAG_ZERO_ALLOC      (1 << 6)
+
+enum ttm_caching_state {
+       tt_uncached,
+       tt_wc,
+       tt_cached
+};
+
+/**
+ * struct ttm_tt
+ *
+ * @dummy_read_page: Page to map where the ttm_tt page array contains a NULL
+ * pointer.
+ * @pages: Array of pages backing the data.
+ * @first_himem_page: Himem pages are put last in the page array, which
+ * enables us to run caching attribute changes on only the first part
+ * of the page array containing lomem pages. This is the index of the
+ * first himem page.
+ * @last_lomem_page: Index of the last lomem page in the page array.
+ * @num_pages: Number of pages in the page array.
+ * @bdev: Pointer to the current struct ttm_bo_device.
+ * @be: Pointer to the ttm backend.
+ * @tsk: The task for user ttm.
+ * @start: virtual address for user ttm.
+ * @swap_storage: Pointer to shmem struct file for swap storage.
+ * @caching_state: The current caching state of the pages.
+ * @state: The current binding state of the pages.
+ *
+ * This is a structure holding the pages, caching- and aperture binding
+ * status for a buffer object that isn't backed by fixed (VRAM / AGP)
+ * memory.
+ */
+
+struct ttm_tt {
+       struct page *dummy_read_page;
+       struct page **pages;
+       long first_himem_page;
+       long last_lomem_page;
+       uint32_t page_flags;
+       unsigned long num_pages;
+       struct ttm_bo_device *bdev;
+       struct ttm_backend *be;
+       struct task_struct *tsk;
+       unsigned long start;
+       struct file *swap_storage;
+       enum ttm_caching_state caching_state;
+       enum {
+               tt_bound,
+               tt_unbound,
+               tt_unpopulated,
+       } state;
+};
+
+#define TTM_MEMTYPE_FLAG_FIXED         (1 << 0)        /* Fixed (on-card) PCI memory */
+#define TTM_MEMTYPE_FLAG_MAPPABLE      (1 << 1)        /* Memory mappable */
+#define TTM_MEMTYPE_FLAG_NEEDS_IOREMAP (1 << 2)        /* Fixed memory needs ioremap
+                                                  before kernel access. */
+#define TTM_MEMTYPE_FLAG_CMA           (1 << 3)        /* Can't map aperture */
+
+/**
+ * struct ttm_mem_type_manager
+ *
+ * @has_type: The memory type has been initialized.
+ * @use_type: The memory type is enabled.
+ * @flags: TTM_MEMTYPE_XX flags identifying the traits of the memory
+ * managed by this memory type.
+ * @gpu_offset: If used, the GPU offset of the first managed page of
+ * fixed memory or the first managed location in an aperture.
+ * @io_offset: The io_offset of the first managed page of IO memory or
+ * the first managed location in an aperture. For TTM_MEMTYPE_FLAG_CMA
+ * memory, this should be set to NULL.
+ * @io_size: The size of a managed IO region (fixed memory or aperture).
+ * @io_addr: Virtual kernel address if the io region is pre-mapped. For
+ * TTM_MEMTYPE_FLAG_NEEDS_IOREMAP there is no pre-mapped io map and
+ * @io_addr should be set to NULL.
+ * @size: Size of the managed region.
+ * @available_caching: A mask of available caching types, TTM_PL_FLAG_XX,
+ * as defined in ttm_placement_common.h
+ * @default_caching: The default caching policy used for a buffer object
+ * placed in this memory type if the user doesn't provide one.
+ * @manager: The range manager used for this memory type. FIXME: If the aperture
+ * has a page size different from the underlying system, the granularity
+ * of this manager should take care of this. But the range allocating code
+ * in ttm_bo.c needs to be modified for this.
+ * @lru: The lru list for this memory type.
+ *
+ * This structure is used to identify and manage memory types for a device.
+ * It's set up by the ttm_bo_driver::init_mem_type method.
+ */
+
+struct ttm_mem_type_manager {
+
+       /*
+        * No protection. Constant from start.
+        */
+
+       bool has_type;
+       bool use_type;
+       uint32_t flags;
+       unsigned long gpu_offset;
+       unsigned long io_offset;
+       unsigned long io_size;
+       void *io_addr;
+       uint64_t size;
+       uint32_t available_caching;
+       uint32_t default_caching;
+
+       /*
+        * Protected by the bdev->lru_lock.
+        * TODO: Consider one lru_lock per ttm_mem_type_manager.
+        * Plays ill with list removal, though.
+        */
+
+       struct drm_mm manager;
+       struct list_head lru;
+};
+
+/**
+ * struct ttm_bo_driver
+ *
+ * @mem_type_prio: Priority array of memory types to place a buffer object in
+ * if it fits without evicting buffers from any of these memory types.
+ * @mem_busy_prio: Priority array of memory types to place a buffer object in
+ * if it needs to evict buffers to make room.
+ * @num_mem_type_prio: Number of elements in the @mem_type_prio array.
+ * @num_mem_busy_prio: Number of elements in the @num_mem_busy_prio array.
+ * @create_ttm_backend_entry: Callback to create a struct ttm_backend.
+ * @invalidate_caches: Callback to invalidate read caches when a buffer object
+ * has been evicted.
+ * @init_mem_type: Callback to initialize a struct ttm_mem_type_manager
+ * structure.
+ * @evict_flags: Callback to obtain placement flags when a buffer is evicted.
+ * @move: Callback for a driver to hook in accelerated functions to
+ * move a buffer.
+ * If set to NULL, a potentially slow memcpy() move is used.
+ * @sync_obj_signaled: See ttm_fence_api.h
+ * @sync_obj_wait: See ttm_fence_api.h
+ * @sync_obj_flush: See ttm_fence_api.h
+ * @sync_obj_unref: See ttm_fence_api.h
+ * @sync_obj_ref: See ttm_fence_api.h
+ */
+
+struct ttm_bo_driver {
+       const uint32_t *mem_type_prio;
+       const uint32_t *mem_busy_prio;
+       uint32_t num_mem_type_prio;
+       uint32_t num_mem_busy_prio;
+
+       /**
+        * struct ttm_bo_driver member create_ttm_backend_entry
+        *
+        * @bdev: The buffer object device.
+        *
+        * Create a driver specific struct ttm_backend.
+        */
+
+       struct ttm_backend *(*create_ttm_backend_entry)
+        (struct ttm_bo_device *bdev);
+
+       /**
+        * struct ttm_bo_driver member invalidate_caches
+        *
+        * @bdev: the buffer object device.
+        * @flags: new placement of the rebound buffer object.
+        *
+        * A previosly evicted buffer has been rebound in a
+        * potentially new location. Tell the driver that it might
+        * consider invalidating read (texture) caches on the next command
+        * submission as a consequence.
+        */
+
+       int (*invalidate_caches) (struct ttm_bo_device *bdev, uint32_t flags);
+       int (*init_mem_type) (struct ttm_bo_device *bdev, uint32_t type,
+                             struct ttm_mem_type_manager *man);
+       /**
+        * struct ttm_bo_driver member evict_flags:
+        *
+        * @bo: the buffer object to be evicted
+        *
+        * Return the bo flags for a buffer which is not mapped to the hardware.
+        * These will be placed in proposed_flags so that when the move is
+        * finished, they'll end up in bo->mem.flags
+        */
+
+        uint32_t(*evict_flags) (struct ttm_buffer_object *bo);
+       /**
+        * struct ttm_bo_driver member move:
+        *
+        * @bo: the buffer to move
+        * @evict: whether this motion is evicting the buffer from
+        * the graphics address space
+        * @interruptible: Use interruptible sleeps if possible when sleeping.
+        * @no_wait: whether this should give up and return -EBUSY
+        * if this move would require sleeping
+        * @new_mem: the new memory region receiving the buffer
+        *
+        * Move a buffer between two memory regions.
+        */
+       int (*move) (struct ttm_buffer_object *bo,
+                    bool evict, bool interruptible,
+                    bool no_wait, struct ttm_mem_reg *new_mem);
+
+       /**
+        * struct ttm_bo_driver_member verify_access
+        *
+        * @bo: Pointer to a buffer object.
+        * @filp: Pointer to a struct file trying to access the object.
+        *
+        * Called from the map / write / read methods to verify that the
+        * caller is permitted to access the buffer object.
+        * This member may be set to NULL, which will refuse this kind of
+        * access for all buffer objects.
+        * This function should return 0 if access is granted, -EPERM otherwise.
+        */
+       int (*verify_access) (struct ttm_buffer_object *bo,
+                             struct file *filp);
+
+       /**
+        * In case a driver writer dislikes the TTM fence objects,
+        * the driver writer can replace those with sync objects of
+        * his / her own. If it turns out that no driver writer is
+        * using these. I suggest we remove these hooks and plug in
+        * fences directly. The bo driver needs the following functionality:
+        * See the corresponding functions in the fence object API
+        * documentation.
+        */
+
+       bool (*sync_obj_signaled) (void *sync_obj, void *sync_arg);
+       int (*sync_obj_wait) (void *sync_obj, void *sync_arg,
+                             bool lazy, bool interruptible);
+       int (*sync_obj_flush) (void *sync_obj, void *sync_arg);
+       void (*sync_obj_unref) (void **sync_obj);
+       void *(*sync_obj_ref) (void *sync_obj);
+};
+
+#define TTM_NUM_MEM_TYPES 8
+
+#define TTM_BO_PRIV_FLAG_MOVING  0     /* Buffer object is moving and needs
+                                          idling before CPU mapping */
+#define TTM_BO_PRIV_FLAG_MAX 1
+/**
+ * struct ttm_bo_device - Buffer object driver device-specific data.
+ *
+ * @mem_glob: Pointer to a struct ttm_mem_global object for accounting.
+ * @driver: Pointer to a struct ttm_bo_driver struct setup by the driver.
+ * @count: Current number of buffer object.
+ * @pages: Current number of pinned pages.
+ * @dummy_read_page: Pointer to a dummy page used for mapping requests
+ * of unpopulated pages.
+ * @shrink: A shrink callback object used for buffre object swap.
+ * @ttm_bo_extra_size: Extra size (sizeof(struct ttm_buffer_object) excluded)
+ * used by a buffer object. This is excluding page arrays and backing pages.
+ * @ttm_bo_size: This is @ttm_bo_extra_size + sizeof(struct ttm_buffer_object).
+ * @man: An array of mem_type_managers.
+ * @addr_space_mm: Range manager for the device address space.
+ * lru_lock: Spinlock that protects the buffer+device lru lists and
+ * ddestroy lists.
+ * @nice_mode: Try nicely to wait for buffer idle when cleaning a manager.
+ * If a GPU lockup has been detected, this is forced to 0.
+ * @dev_mapping: A pointer to the struct address_space representing the
+ * device address space.
+ * @wq: Work queue structure for the delayed delete workqueue.
+ *
+ */
+
+struct ttm_bo_device {
+
+       /*
+        * Constant after bo device init / atomic.
+        */
+
+       struct ttm_mem_global *mem_glob;
+       struct ttm_bo_driver *driver;
+       struct page *dummy_read_page;
+       struct ttm_mem_shrink shrink;
+
+       size_t ttm_bo_extra_size;
+       size_t ttm_bo_size;
+
+       rwlock_t vm_lock;
+       /*
+        * Protected by the vm lock.
+        */
+       struct ttm_mem_type_manager man[TTM_NUM_MEM_TYPES];
+       struct rb_root addr_space_rb;
+       struct drm_mm addr_space_mm;
+
+       /*
+        * Might want to change this to one lock per manager.
+        */
+       spinlock_t lru_lock;
+       /*
+        * Protected by the lru lock.
+        */
+       struct list_head ddestroy;
+       struct list_head swap_lru;
+
+       /*
+        * Protected by load / firstopen / lastclose /unload sync.
+        */
+
+       bool nice_mode;
+       struct address_space *dev_mapping;
+
+       /*
+        * Internal protection.
+        */
+
+       struct delayed_work wq;
+};
+
+/**
+ * ttm_flag_masked
+ *
+ * @old: Pointer to the result and original value.
+ * @new: New value of bits.
+ * @mask: Mask of bits to change.
+ *
+ * Convenience function to change a number of bits identified by a mask.
+ */
+
+static inline uint32_t
+ttm_flag_masked(uint32_t *old, uint32_t new, uint32_t mask)
+{
+       *old ^= (*old ^ new) & mask;
+       return *old;
+}
+
+/**
+ * ttm_tt_create
+ *
+ * @bdev: pointer to a struct ttm_bo_device:
+ * @size: Size of the data needed backing.
+ * @page_flags: Page flags as identified by TTM_PAGE_FLAG_XX flags.
+ * @dummy_read_page: See struct ttm_bo_device.
+ *
+ * Create a struct ttm_tt to back data with system memory pages.
+ * No pages are actually allocated.
+ * Returns:
+ * NULL: Out of memory.
+ */
+extern struct ttm_tt *ttm_tt_create(struct ttm_bo_device *bdev,
+                                   unsigned long size,
+                                   uint32_t page_flags,
+                                   struct page *dummy_read_page);
+
+/**
+ * ttm_tt_set_user:
+ *
+ * @ttm: The struct ttm_tt to populate.
+ * @tsk: A struct task_struct for which @start is a valid user-space address.
+ * @start: A valid user-space address.
+ * @num_pages: Size in pages of the user memory area.
+ *
+ * Populate a struct ttm_tt with a user-space memory area after first pinning
+ * the pages backing it.
+ * Returns:
+ * !0: Error.
+ */
+
+extern int ttm_tt_set_user(struct ttm_tt *ttm,
+                          struct task_struct *tsk,
+                          unsigned long start, unsigned long num_pages);
+
+/**
+ * ttm_ttm_bind:
+ *
+ * @ttm: The struct ttm_tt containing backing pages.
+ * @bo_mem: The struct ttm_mem_reg identifying the binding location.
+ *
+ * Bind the pages of @ttm to an aperture location identified by @bo_mem
+ */
+extern int ttm_tt_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem);
+
+/**
+ * ttm_ttm_destroy:
+ *
+ * @ttm: The struct ttm_tt.
+ *
+ * Unbind, unpopulate and destroy a struct ttm_tt.
+ */
+extern void ttm_tt_destroy(struct ttm_tt *ttm);
+
+/**
+ * ttm_ttm_unbind:
+ *
+ * @ttm: The struct ttm_tt.
+ *
+ * Unbind a struct ttm_tt.
+ */
+extern void ttm_tt_unbind(struct ttm_tt *ttm);
+
+/**
+ * ttm_ttm_destroy:
+ *
+ * @ttm: The struct ttm_tt.
+ * @index: Index of the desired page.
+ *
+ * Return a pointer to the struct page backing @ttm at page
+ * index @index. If the page is unpopulated, one will be allocated to
+ * populate that index.
+ *
+ * Returns:
+ * NULL on OOM.
+ */
+extern struct page *ttm_tt_get_page(struct ttm_tt *ttm, int index);
+
+/**
+ * ttm_tt_cache_flush:
+ *
+ * @pages: An array of pointers to struct page:s to flush.
+ * @num_pages: Number of pages to flush.
+ *
+ * Flush the data of the indicated pages from the cpu caches.
+ * This is used when changing caching attributes of the pages from
+ * cache-coherent.
+ */
+extern void ttm_tt_cache_flush(struct page *pages[], unsigned long num_pages);
+
+/**
+ * ttm_tt_set_placement_caching:
+ *
+ * @ttm A struct ttm_tt the backing pages of which will change caching policy.
+ * @placement: Flag indicating the desired caching policy.
+ *
+ * This function will change caching policy of any default kernel mappings of
+ * the pages backing @ttm. If changing from cached to uncached or
+ * write-combined,
+ * all CPU caches will first be flushed to make sure the data of the pages
+ * hit RAM. This function may be very costly as it involves global TLB
+ * and cache flushes and potential page splitting / combining.
+ */
+extern int ttm_tt_set_placement_caching(struct ttm_tt *ttm, uint32_t placement);
+extern int ttm_tt_swapout(struct ttm_tt *ttm,
+                         struct file *persistant_swap_storage);
+
+/*
+ * ttm_bo.c
+ */
+
+/**
+ * ttm_mem_reg_is_pci
+ *
+ * @bdev: Pointer to a struct ttm_bo_device.
+ * @mem: A valid struct ttm_mem_reg.
+ *
+ * Returns true if the memory described by @mem is PCI memory,
+ * false otherwise.
+ */
+extern bool ttm_mem_reg_is_pci(struct ttm_bo_device *bdev,
+                                  struct ttm_mem_reg *mem);
+
+/**
+ * ttm_bo_mem_space
+ *
+ * @bo: Pointer to a struct ttm_buffer_object. the data of which
+ * we want to allocate space for.
+ * @proposed_placement: Proposed new placement for the buffer object.
+ * @mem: A struct ttm_mem_reg.
+ * @interruptible: Sleep interruptible when sliping.
+ * @no_wait: Don't sleep waiting for space to become available.
+ *
+ * Allocate memory space for the buffer object pointed to by @bo, using
+ * the placement flags in @mem, potentially evicting other idle buffer objects.
+ * This function may sleep while waiting for space to become available.
+ * Returns:
+ * -EBUSY: No space available (only if no_wait == 1).
+ * -ENOMEM: Could not allocate memory for the buffer object, either due to
+ * fragmentation or concurrent allocators.
+ * -ERESTART: An interruptible sleep was interrupted by a signal.
+ */
+extern int ttm_bo_mem_space(struct ttm_buffer_object *bo,
+                           uint32_t proposed_placement,
+                           struct ttm_mem_reg *mem,
+                           bool interruptible, bool no_wait);
+/**
+ * ttm_bo_wait_for_cpu
+ *
+ * @bo: Pointer to a struct ttm_buffer_object.
+ * @no_wait: Don't sleep while waiting.
+ *
+ * Wait until a buffer object is no longer sync'ed for CPU access.
+ * Returns:
+ * -EBUSY: Buffer object was sync'ed for CPU access. (only if no_wait == 1).
+ * -ERESTART: An interruptible sleep was interrupted by a signal.
+ */
+
+extern int ttm_bo_wait_cpu(struct ttm_buffer_object *bo, bool no_wait);
+
+/**
+ * ttm_bo_pci_offset - Get the PCI offset for the buffer object memory.
+ *
+ * @bo Pointer to a struct ttm_buffer_object.
+ * @bus_base On return the base of the PCI region
+ * @bus_offset On return the byte offset into the PCI region
+ * @bus_size On return the byte size of the buffer object or zero if
+ * the buffer object memory is not accessible through a PCI region.
+ *
+ * Returns:
+ * -EINVAL if the buffer object is currently not mappable.
+ * 0 otherwise.
+ */
+
+extern int ttm_bo_pci_offset(struct ttm_bo_device *bdev,
+                            struct ttm_mem_reg *mem,
+                            unsigned long *bus_base,
+                            unsigned long *bus_offset,
+                            unsigned long *bus_size);
+
+extern int ttm_bo_device_release(struct ttm_bo_device *bdev);
+
+/**
+ * ttm_bo_device_init
+ *
+ * @bdev: A pointer to a struct ttm_bo_device to initialize.
+ * @mem_global: A pointer to an initialized struct ttm_mem_global.
+ * @driver: A pointer to a struct ttm_bo_driver set up by the caller.
+ * @file_page_offset: Offset into the device address space that is available
+ * for buffer data. This ensures compatibility with other users of the
+ * address space.
+ *
+ * Initializes a struct ttm_bo_device:
+ * Returns:
+ * !0: Failure.
+ */
+extern int ttm_bo_device_init(struct ttm_bo_device *bdev,
+                             struct ttm_mem_global *mem_glob,
+                             struct ttm_bo_driver *driver,
+                             uint64_t file_page_offset);
+
+/**
+ * ttm_bo_reserve:
+ *
+ * @bo: A pointer to a struct ttm_buffer_object.
+ * @interruptible: Sleep interruptible if waiting.
+ * @no_wait: Don't sleep while trying to reserve, rather return -EBUSY.
+ * @use_sequence: If @bo is already reserved, Only sleep waiting for
+ * it to become unreserved if @sequence < (@bo)->sequence.
+ *
+ * Locks a buffer object for validation. (Or prevents other processes from
+ * locking it for validation) and removes it from lru lists, while taking
+ * a number of measures to prevent deadlocks.
+ *
+ * Deadlocks may occur when two processes try to reserve multiple buffers in
+ * different order, either by will or as a result of a buffer being evicted
+ * to make room for a buffer already reserved. (Buffers are reserved before
+ * they are evicted). The following algorithm prevents such deadlocks from
+ * occuring:
+ * 1) Buffers are reserved with the lru spinlock held. Upon successful
+ * reservation they are removed from the lru list. This stops a reserved buffer
+ * from being evicted. However the lru spinlock is released between the time
+ * a buffer is selected for eviction and the time it is reserved.
+ * Therefore a check is made when a buffer is reserved for eviction, that it
+ * is still the first buffer in the lru list, before it is removed from the
+ * list. @check_lru == 1 forces this check. If it fails, the function returns
+ * -EINVAL, and the caller should then choose a new buffer to evict and repeat
+ * the procedure.
+ * 2) Processes attempting to reserve multiple buffers other than for eviction,
+ * (typically execbuf), should first obtain a unique 32-bit
+ * validation sequence number,
+ * and call this function with @use_sequence == 1 and @sequence == the unique
+ * sequence number. If upon call of this function, the buffer object is already
+ * reserved, the validation sequence is checked against the validation
+ * sequence of the process currently reserving the buffer,
+ * and if the current validation sequence is greater than that of the process
+ * holding the reservation, the function returns -EAGAIN. Otherwise it sleeps
+ * waiting for the buffer to become unreserved, after which it retries
+ * reserving.
+ * The caller should, when receiving an -EAGAIN error
+ * release all its buffer reservations, wait for @bo to become unreserved, and
+ * then rerun the validation with the same validation sequence. This procedure
+ * will always guarantee that the process with the lowest validation sequence
+ * will eventually succeed, preventing both deadlocks and starvation.
+ *
+ * Returns:
+ * -EAGAIN: The reservation may cause a deadlock.
+ * Release all buffer reservations, wait for @bo to become unreserved and
+ * try again. (only if use_sequence == 1).
+ * -ERESTART: A wait for the buffer to become unreserved was interrupted by
+ * a signal. Release all buffer reservations and return to user-space.
+ */
+extern int ttm_bo_reserve(struct ttm_buffer_object *bo,
+                         bool interruptible,
+                         bool no_wait, bool use_sequence, uint32_t sequence);
+
+/**
+ * ttm_bo_unreserve
+ *
+ * @bo: A pointer to a struct ttm_buffer_object.
+ *
+ * Unreserve a previous reservation of @bo.
+ */
+extern void ttm_bo_unreserve(struct ttm_buffer_object *bo);
+
+/**
+ * ttm_bo_wait_unreserved
+ *
+ * @bo: A pointer to a struct ttm_buffer_object.
+ *
+ * Wait for a struct ttm_buffer_object to become unreserved.
+ * This is typically used in the execbuf code to relax cpu-usage when
+ * a potential deadlock condition backoff.
+ */
+extern int ttm_bo_wait_unreserved(struct ttm_buffer_object *bo,
+                                 bool interruptible);
+
+/**
+ * ttm_bo_block_reservation
+ *
+ * @bo: A pointer to a struct ttm_buffer_object.
+ * @interruptible: Use interruptible sleep when waiting.
+ * @no_wait: Don't sleep, but rather return -EBUSY.
+ *
+ * Block reservation for validation by simply reserving the buffer.
+ * This is intended for single buffer use only without eviction,
+ * and thus needs no deadlock protection.
+ *
+ * Returns:
+ * -EBUSY: If no_wait == 1 and the buffer is already reserved.
+ * -ERESTART: If interruptible == 1 and the process received a signal
+ * while sleeping.
+ */
+extern int ttm_bo_block_reservation(struct ttm_buffer_object *bo,
+                                   bool interruptible, bool no_wait);
+
+/**
+ * ttm_bo_unblock_reservation
+ *
+ * @bo: A pointer to a struct ttm_buffer_object.
+ *
+ * Unblocks reservation leaving lru lists untouched.
+ */
+extern void ttm_bo_unblock_reservation(struct ttm_buffer_object *bo);
+
+/*
+ * ttm_bo_util.c
+ */
+
+/**
+ * ttm_bo_move_ttm
+ *
+ * @bo: A pointer to a struct ttm_buffer_object.
+ * @evict: 1: This is an eviction. Don't try to pipeline.
+ * @no_wait: Never sleep, but rather return with -EBUSY.
+ * @new_mem: struct ttm_mem_reg indicating where to move.
+ *
+ * Optimized move function for a buffer object with both old and
+ * new placement backed by a TTM. The function will, if successful,
+ * free any old aperture space, and set (@new_mem)->mm_node to NULL,
+ * and update the (@bo)->mem placement flags. If unsuccessful, the old
+ * data remains untouched, and it's up to the caller to free the
+ * memory space indicated by @new_mem.
+ * Returns:
+ * !0: Failure.
+ */
+
+extern int ttm_bo_move_ttm(struct ttm_buffer_object *bo,
+                          bool evict, bool no_wait,
+                          struct ttm_mem_reg *new_mem);
+
+/**
+ * ttm_bo_move_memcpy
+ *
+ * @bo: A pointer to a struct ttm_buffer_object.
+ * @evict: 1: This is an eviction. Don't try to pipeline.
+ * @no_wait: Never sleep, but rather return with -EBUSY.
+ * @new_mem: struct ttm_mem_reg indicating where to move.
+ *
+ * Fallback move function for a mappable buffer object in mappable memory.
+ * The function will, if successful,
+ * free any old aperture space, and set (@new_mem)->mm_node to NULL,
+ * and update the (@bo)->mem placement flags. If unsuccessful, the old
+ * data remains untouched, and it's up to the caller to free the
+ * memory space indicated by @new_mem.
+ * Returns:
+ * !0: Failure.
+ */
+
+extern int ttm_bo_move_memcpy(struct ttm_buffer_object *bo,
+                             bool evict,
+                             bool no_wait, struct ttm_mem_reg *new_mem);
+
+/**
+ * ttm_bo_free_old_node
+ *
+ * @bo: A pointer to a struct ttm_buffer_object.
+ *
+ * Utility function to free an old placement after a successful move.
+ */
+extern void ttm_bo_free_old_node(struct ttm_buffer_object *bo);
+
+/**
+ * ttm_bo_move_accel_cleanup.
+ *
+ * @bo: A pointer to a struct ttm_buffer_object.
+ * @sync_obj: A sync object that signals when moving is complete.
+ * @sync_obj_arg: An argument to pass to the sync object idle / wait
+ * functions.
+ * @evict: This is an evict move. Don't return until the buffer is idle.
+ * @no_wait: Never sleep, but rather return with -EBUSY.
+ * @new_mem: struct ttm_mem_reg indicating where to move.
+ *
+ * Accelerated move function to be called when an accelerated move
+ * has been scheduled. The function will create a new temporary buffer object
+ * representing the old placement, and put the sync object on both buffer
+ * objects. After that the newly created buffer object is unref'd to be
+ * destroyed when the move is complete. This will help pipeline
+ * buffer moves.
+ */
+
+extern int ttm_bo_move_accel_cleanup(struct ttm_buffer_object *bo,
+                                    void *sync_obj,
+                                    void *sync_obj_arg,
+                                    bool evict, bool no_wait,
+                                    struct ttm_mem_reg *new_mem);
+/**
+ * ttm_io_prot
+ *
+ * @c_state: Caching state.
+ * @tmp: Page protection flag for a normal, cached mapping.
+ *
+ * Utility function that returns the pgprot_t that should be used for
+ * setting up a PTE with the caching model indicated by @c_state.
+ */
+extern pgprot_t ttm_io_prot(enum ttm_caching_state c_state, pgprot_t tmp);
+
+#if (defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE)))
+#define TTM_HAS_AGP
+#include <linux/agp_backend.h>
+
+/**
+ * ttm_agp_backend_init
+ *
+ * @bdev: Pointer to a struct ttm_bo_device.
+ * @bridge: The agp bridge this device is sitting on.
+ *
+ * Create a TTM backend that uses the indicated AGP bridge as an aperture
+ * for TT memory. This function uses the linux agpgart interface to
+ * bind and unbind memory backing a ttm_tt.
+ */
+extern struct ttm_backend *ttm_agp_backend_init(struct ttm_bo_device *bdev,
+                                               struct agp_bridge_data *bridge);
+#endif
+
+#endif
diff --git a/include/drm/ttm/ttm_memory.h b/include/drm/ttm/ttm_memory.h
new file mode 100644 (file)
index 0000000..d8b8f04
--- /dev/null
@@ -0,0 +1,153 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef TTM_MEMORY_H
+#define TTM_MEMORY_H
+
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+
+/**
+ * struct ttm_mem_shrink - callback to shrink TTM memory usage.
+ *
+ * @do_shrink: The callback function.
+ *
+ * Arguments to the do_shrink functions are intended to be passed using
+ * inheritance. That is, the argument class derives from struct ttm_mem_srink,
+ * and can be accessed using container_of().
+ */
+
+struct ttm_mem_shrink {
+       int (*do_shrink) (struct ttm_mem_shrink *);
+};
+
+/**
+ * struct ttm_mem_global - Global memory accounting structure.
+ *
+ * @shrink: A single callback to shrink TTM memory usage. Extend this
+ * to a linked list to be able to handle multiple callbacks when needed.
+ * @swap_queue: A workqueue to handle shrinking in low memory situations. We
+ * need a separate workqueue since it will spend a lot of time waiting
+ * for the GPU, and this will otherwise block other workqueue tasks(?)
+ * At this point we use only a single-threaded workqueue.
+ * @work: The workqueue callback for the shrink queue.
+ * @queue: Wait queue for processes suspended waiting for memory.
+ * @lock: Lock to protect the @shrink - and the memory accounting members,
+ * that is, essentially the whole structure with some exceptions.
+ * @emer_memory: Lowmem memory limit available for root.
+ * @max_memory: Lowmem memory limit available for non-root.
+ * @swap_limit: Lowmem memory limit where the shrink workqueue kicks in.
+ * @used_memory: Currently used lowmem memory.
+ * @used_total_memory: Currently used total (lowmem + highmem) memory.
+ * @total_memory_swap_limit: Total memory limit where the shrink workqueue
+ * kicks in.
+ * @max_total_memory: Total memory available to non-root processes.
+ * @emer_total_memory: Total memory available to root processes.
+ *
+ * Note that this structure is not per device. It should be global for all
+ * graphics devices.
+ */
+
+struct ttm_mem_global {
+       struct ttm_mem_shrink *shrink;
+       struct workqueue_struct *swap_queue;
+       struct work_struct work;
+       wait_queue_head_t queue;
+       spinlock_t lock;
+       uint64_t emer_memory;
+       uint64_t max_memory;
+       uint64_t swap_limit;
+       uint64_t used_memory;
+       uint64_t used_total_memory;
+       uint64_t total_memory_swap_limit;
+       uint64_t max_total_memory;
+       uint64_t emer_total_memory;
+};
+
+/**
+ * ttm_mem_init_shrink - initialize a struct ttm_mem_shrink object
+ *
+ * @shrink: The object to initialize.
+ * @func: The callback function.
+ */
+
+static inline void ttm_mem_init_shrink(struct ttm_mem_shrink *shrink,
+                                      int (*func) (struct ttm_mem_shrink *))
+{
+       shrink->do_shrink = func;
+}
+
+/**
+ * ttm_mem_register_shrink - register a struct ttm_mem_shrink object.
+ *
+ * @glob: The struct ttm_mem_global object to register with.
+ * @shrink: An initialized struct ttm_mem_shrink object to register.
+ *
+ * Returns:
+ * -EBUSY: There's already a callback registered. (May change).
+ */
+
+static inline int ttm_mem_register_shrink(struct ttm_mem_global *glob,
+                                         struct ttm_mem_shrink *shrink)
+{
+       spin_lock(&glob->lock);
+       if (glob->shrink != NULL) {
+               spin_unlock(&glob->lock);
+               return -EBUSY;
+       }
+       glob->shrink = shrink;
+       spin_unlock(&glob->lock);
+       return 0;
+}
+
+/**
+ * ttm_mem_unregister_shrink - unregister a struct ttm_mem_shrink object.
+ *
+ * @glob: The struct ttm_mem_global object to unregister from.
+ * @shrink: A previously registert struct ttm_mem_shrink object.
+ *
+ */
+
+static inline void ttm_mem_unregister_shrink(struct ttm_mem_global *glob,
+                                            struct ttm_mem_shrink *shrink)
+{
+       spin_lock(&glob->lock);
+       BUG_ON(glob->shrink != shrink);
+       glob->shrink = NULL;
+       spin_unlock(&glob->lock);
+}
+
+extern int ttm_mem_global_init(struct ttm_mem_global *glob);
+extern void ttm_mem_global_release(struct ttm_mem_global *glob);
+extern int ttm_mem_global_alloc(struct ttm_mem_global *glob, uint64_t memory,
+                               bool no_wait, bool interruptible, bool himem);
+extern void ttm_mem_global_free(struct ttm_mem_global *glob,
+                               uint64_t amount, bool himem);
+extern size_t ttm_round_pot(size_t size);
+#endif
diff --git a/include/drm/ttm/ttm_module.h b/include/drm/ttm/ttm_module.h
new file mode 100644 (file)
index 0000000..889a4c7
--- /dev/null
@@ -0,0 +1,58 @@
+/**************************************************************************
+ *
+ * Copyright 2008-2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+/*
+ * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
+ */
+
+#ifndef _TTM_MODULE_H_
+#define _TTM_MODULE_H_
+
+#include <linux/kernel.h>
+
+#define TTM_PFX "[TTM]"
+
+enum ttm_global_types {
+       TTM_GLOBAL_TTM_MEM = 0,
+       TTM_GLOBAL_TTM_BO,
+       TTM_GLOBAL_TTM_OBJECT,
+       TTM_GLOBAL_NUM
+};
+
+struct ttm_global_reference {
+       enum ttm_global_types global_type;
+       size_t size;
+       void *object;
+       int (*init) (struct ttm_global_reference *);
+       void (*release) (struct ttm_global_reference *);
+};
+
+extern void ttm_global_init(void);
+extern void ttm_global_release(void);
+extern int ttm_global_item_ref(struct ttm_global_reference *ref);
+extern void ttm_global_item_unref(struct ttm_global_reference *ref);
+
+#endif /* _TTM_MODULE_H_ */
diff --git a/include/drm/ttm/ttm_placement.h b/include/drm/ttm/ttm_placement.h
new file mode 100644 (file)
index 0000000..c84ff15
--- /dev/null
@@ -0,0 +1,92 @@
+/**************************************************************************
+ *
+ * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+/*
+ * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
+ */
+
+#ifndef _TTM_PLACEMENT_H_
+#define _TTM_PLACEMENT_H_
+/*
+ * Memory regions for data placement.
+ */
+
+#define TTM_PL_SYSTEM           0
+#define TTM_PL_TT               1
+#define TTM_PL_VRAM             2
+#define TTM_PL_PRIV0            3
+#define TTM_PL_PRIV1            4
+#define TTM_PL_PRIV2            5
+#define TTM_PL_PRIV3            6
+#define TTM_PL_PRIV4            7
+#define TTM_PL_PRIV5            8
+#define TTM_PL_SWAPPED          15
+
+#define TTM_PL_FLAG_SYSTEM      (1 << TTM_PL_SYSTEM)
+#define TTM_PL_FLAG_TT          (1 << TTM_PL_TT)
+#define TTM_PL_FLAG_VRAM        (1 << TTM_PL_VRAM)
+#define TTM_PL_FLAG_PRIV0       (1 << TTM_PL_PRIV0)
+#define TTM_PL_FLAG_PRIV1       (1 << TTM_PL_PRIV1)
+#define TTM_PL_FLAG_PRIV2       (1 << TTM_PL_PRIV2)
+#define TTM_PL_FLAG_PRIV3       (1 << TTM_PL_PRIV3)
+#define TTM_PL_FLAG_PRIV4       (1 << TTM_PL_PRIV4)
+#define TTM_PL_FLAG_PRIV5       (1 << TTM_PL_PRIV5)
+#define TTM_PL_FLAG_SWAPPED     (1 << TTM_PL_SWAPPED)
+#define TTM_PL_MASK_MEM         0x0000FFFF
+
+/*
+ * Other flags that affects data placement.
+ * TTM_PL_FLAG_CACHED indicates cache-coherent mappings
+ * if available.
+ * TTM_PL_FLAG_SHARED means that another application may
+ * reference the buffer.
+ * TTM_PL_FLAG_NO_EVICT means that the buffer may never
+ * be evicted to make room for other buffers.
+ */
+
+#define TTM_PL_FLAG_CACHED      (1 << 16)
+#define TTM_PL_FLAG_UNCACHED    (1 << 17)
+#define TTM_PL_FLAG_WC          (1 << 18)
+#define TTM_PL_FLAG_SHARED      (1 << 20)
+#define TTM_PL_FLAG_NO_EVICT    (1 << 21)
+
+#define TTM_PL_MASK_CACHING     (TTM_PL_FLAG_CACHED | \
+                                TTM_PL_FLAG_UNCACHED | \
+                                TTM_PL_FLAG_WC)
+
+#define TTM_PL_MASK_MEMTYPE     (TTM_PL_MASK_MEM | TTM_PL_MASK_CACHING)
+
+/*
+ * Access flags to be used for CPU- and GPU- mappings.
+ * The idea is that the TTM synchronization mechanism will
+ * allow concurrent READ access and exclusive write access.
+ * Currently GPU- and CPU accesses are exclusive.
+ */
+
+#define TTM_ACCESS_READ         (1 << 0)
+#define TTM_ACCESS_WRITE        (1 << 1)
+
+#endif
index 12737be58601108f81f486fcdfac99c4875d8fb5..2a04eb54c0dd05b8eda048c8463b9a8eddabde46 100644 (file)
@@ -590,6 +590,11 @@ static inline void bio_list_merge_head(struct bio_list *bl,
        bl->head = bl2->head;
 }
 
+static inline struct bio *bio_list_peek(struct bio_list *bl)
+{
+       return bl->head;
+}
+
 static inline struct bio *bio_list_pop(struct bio_list *bl)
 {
        struct bio *bio = bl->head;
index 0b1a6cae9de1ebbc5010c2464ddc43cf33ae462b..8963d9149b5fcf77e47d9b0c32379bd8f28e2476 100644 (file)
@@ -926,6 +926,7 @@ extern void blk_queue_alignment_offset(struct request_queue *q,
                                       unsigned int alignment);
 extern void blk_queue_io_min(struct request_queue *q, unsigned int min);
 extern void blk_queue_io_opt(struct request_queue *q, unsigned int opt);
+extern void blk_set_default_limits(struct queue_limits *lim);
 extern int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
                            sector_t offset);
 extern void disk_stack_limits(struct gendisk *disk, struct block_device *bdev,
index 54398d2c6d8df6cab9c898d91ee775acfabab108..d276b5510c83498bbd4815367ef05cf398beee3b 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef _LINUX_BUG_H
 #define _LINUX_BUG_H
 
-#include <linux/module.h>
 #include <asm/bug.h>
 
 enum bug_trap_type {
@@ -24,10 +23,6 @@ const struct bug_entry *find_bug(unsigned long bugaddr);
 
 enum bug_trap_type report_bug(unsigned long bug_addr, struct pt_regs *regs);
 
-int  module_bug_finalize(const Elf_Ehdr *, const Elf_Shdr *,
-                        struct module *);
-void module_bug_cleanup(struct module *);
-
 /* These are defined by the architecture */
 int is_valid_bugaddr(unsigned long addr);
 
@@ -38,13 +33,6 @@ static inline enum bug_trap_type report_bug(unsigned long bug_addr,
 {
        return BUG_TRAP_TYPE_BUG;
 }
-static inline int  module_bug_finalize(const Elf_Ehdr *hdr,
-                                       const Elf_Shdr *sechdrs,
-                                       struct module *mod)
-{
-       return 0;
-}
-static inline void module_bug_cleanup(struct module *mod) {}
 
 #endif /* CONFIG_GENERIC_BUG */
 #endif /* _LINUX_BUG_H */
index 7b5a2388ba67412dda1740cf869950648668fd31..2a5cd867c365c3fd4e7f776ceb7e6d42d4e255f9 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/device.h>
+#include <linux/kmemcheck.h>
 
 #define C2PORT_NAME_LEN                        32
 
 /* Main struct */
 struct c2port_ops;
 struct c2port_device {
+       kmemcheck_bitfield_begin(flags);
        unsigned int access:1;
        unsigned int flash_access:1;
+       kmemcheck_bitfield_end(flags);
 
        int id;
        char name[C2PORT_NAME_LEN];
index 05ea1dd7d681d072a5ae1c9c7c2da56d75bbc6e6..a5740fc4d04b9415478f4180dcbdad289f5eb281 100644 (file)
@@ -18,7 +18,6 @@
 
 extern int number_of_cpusets;  /* How many cpusets are defined in system? */
 
-extern int cpuset_init_early(void);
 extern int cpuset_init(void);
 extern void cpuset_init_smp(void);
 extern void cpuset_cpus_allowed(struct task_struct *p, struct cpumask *mask);
@@ -27,7 +26,6 @@ extern void cpuset_cpus_allowed_locked(struct task_struct *p,
 extern nodemask_t cpuset_mems_allowed(struct task_struct *p);
 #define cpuset_current_mems_allowed (current->mems_allowed)
 void cpuset_init_current_mems_allowed(void);
-void cpuset_update_task_memory_state(void);
 int cpuset_nodemask_valid_mems_allowed(nodemask_t *nodemask);
 
 extern int __cpuset_node_allowed_softwall(int node, gfp_t gfp_mask);
@@ -92,9 +90,13 @@ extern void rebuild_sched_domains(void);
 
 extern void cpuset_print_task_mems_allowed(struct task_struct *p);
 
+static inline void set_mems_allowed(nodemask_t nodemask)
+{
+       current->mems_allowed = nodemask;
+}
+
 #else /* !CONFIG_CPUSETS */
 
-static inline int cpuset_init_early(void) { return 0; }
 static inline int cpuset_init(void) { return 0; }
 static inline void cpuset_init_smp(void) {}
 
@@ -116,7 +118,6 @@ static inline nodemask_t cpuset_mems_allowed(struct task_struct *p)
 
 #define cpuset_current_mems_allowed (node_states[N_HIGH_MEMORY])
 static inline void cpuset_init_current_mems_allowed(void) {}
-static inline void cpuset_update_task_memory_state(void) {}
 
 static inline int cpuset_nodemask_valid_mems_allowed(nodemask_t *nodemask)
 {
@@ -188,6 +189,10 @@ static inline void cpuset_print_task_mems_allowed(struct task_struct *p)
 {
 }
 
+static inline void set_mems_allowed(nodemask_t nodemask)
+{
+}
+
 #endif /* !CONFIG_CPUSETS */
 
 #endif /* _LINUX_CPUSET_H */
index a4a7b10aaa48a8b086142876272466a888069ce4..ed4e39f2c4230da03f93651f5d323f805cdb6c94 100644 (file)
@@ -114,6 +114,8 @@ extern int bus_unregister_notifier(struct bus_type *bus,
 #define BUS_NOTIFY_BOUND_DRIVER                0x00000003 /* driver bound to device */
 #define BUS_NOTIFY_UNBIND_DRIVER       0x00000004 /* driver about to be
                                                      unbound */
+#define BUS_NOTIFY_UNBOUND_DRIVER      0x00000005 /* driver is unbound
+                                                     from the device */
 
 extern struct kset *bus_get_kset(struct bus_type *bus);
 extern struct klist *bus_get_device_klist(struct bus_type *bus);
@@ -192,6 +194,7 @@ struct class {
        struct kobject                  *dev_kobj;
 
        int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
+       char *(*nodename)(struct device *dev);
 
        void (*class_release)(struct class *class);
        void (*dev_release)(struct device *dev);
@@ -287,6 +290,7 @@ struct device_type {
        const char *name;
        struct attribute_group **groups;
        int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
+       char *(*nodename)(struct device *dev);
        void (*release)(struct device *dev);
 
        struct dev_pm_ops *pm;
@@ -486,6 +490,7 @@ extern struct device *device_find_child(struct device *dev, void *data,
 extern int device_rename(struct device *dev, char *new_name);
 extern int device_move(struct device *dev, struct device *new_parent,
                       enum dpm_order dpm_order);
+extern const char *device_get_nodename(struct device *dev, const char **tmp);
 
 /*
  * Root device objects for grouping under /sys/devices
index e61c0be2a45977fb61e48b0b0eb89f016b7c978d..6925249a5ac656a7cda3c104d04914816e303ff4 100644 (file)
@@ -78,12 +78,12 @@ static inline void eisa_driver_unregister (struct eisa_driver *edrv) { }
 /* Mimics pci.h... */
 static inline void *eisa_get_drvdata (struct eisa_device *edev)
 {
-        return edev->dev.driver_data;
+        return dev_get_drvdata(&edev->dev);
 }
 
 static inline void eisa_set_drvdata (struct eisa_device *edev, void *data)
 {
-        edev->dev.driver_data = data;
+        dev_set_drvdata(&edev->dev, data);
 }
 
 /* The EISA root device. There's rumours about machines with multiple
index 330c4b1bfcaa58b32907cd9f050c9cc67b097cb0..dd68358996b716da2b1be8e1ab9069b282ab9902 100644 (file)
@@ -677,6 +677,9 @@ struct fb_ops {
        /* get capability given var */
        void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,
                            struct fb_var_screeninfo *var);
+
+       /* teardown any resources to do with this framebuffer */
+       void (*fb_destroy)(struct fb_info *info);
 };
 
 #ifdef CONFIG_FB_TILEBLITTING
@@ -786,6 +789,8 @@ struct fb_tile_ops {
 #define FBINFO_MISC_USEREVENT          0x10000 /* event request
                                                  from userspace */
 #define FBINFO_MISC_TILEBLITTING       0x20000 /* use tile blitting */
+#define FBINFO_MISC_FIRMWARE           0x40000 /* a replaceable firmware
+                                                 inited framebuffer */
 
 /* A driver may set this flag to indicate that it does want a set_par to be
  * called every time when fbcon_switch is executed. The advantage is that with
@@ -854,7 +859,12 @@ struct fb_info {
        u32 state;                      /* Hardware state i.e suspend */
        void *fbcon_par;                /* fbcon use-only private area */
        /* From here on everything is device dependent */
-       void *par;      
+       void *par;
+       /* we need the PCI or similiar aperture base/size not
+          smem_start/size as smem_start may just be an object
+          allocated inside the aperture so may not actually overlap */
+       resource_size_t aperture_base;
+       resource_size_t aperture_size;
 };
 
 #ifdef MODULE
@@ -893,7 +903,7 @@ struct fb_info {
 #define fb_writeq sbus_writeq
 #define fb_memset sbus_memset_io
 
-#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || defined(__sh__) || defined(__powerpc__) || defined(__avr32__)
+#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || defined(__sh__) || defined(__powerpc__) || defined(__avr32__) || defined(__bfin__)
 
 #define fb_readb __raw_readb
 #define fb_readw __raw_readw
diff --git a/include/linux/firewire.h b/include/linux/firewire.h
new file mode 100644 (file)
index 0000000..e584b72
--- /dev/null
@@ -0,0 +1,358 @@
+#ifndef _LINUX_FIREWIRE_H
+#define _LINUX_FIREWIRE_H
+
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/sysfs.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+
+#include <asm/atomic.h>
+#include <asm/byteorder.h>
+
+#define fw_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, ## args)
+#define fw_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args)
+
+static inline void fw_memcpy_from_be32(void *_dst, void *_src, size_t size)
+{
+       u32    *dst = _dst;
+       __be32 *src = _src;
+       int i;
+
+       for (i = 0; i < size / 4; i++)
+               dst[i] = be32_to_cpu(src[i]);
+}
+
+static inline void fw_memcpy_to_be32(void *_dst, void *_src, size_t size)
+{
+       fw_memcpy_from_be32(_dst, _src, size);
+}
+#define CSR_REGISTER_BASE              0xfffff0000000ULL
+
+/* register offsets are relative to CSR_REGISTER_BASE */
+#define CSR_STATE_CLEAR                        0x0
+#define CSR_STATE_SET                  0x4
+#define CSR_NODE_IDS                   0x8
+#define CSR_RESET_START                        0xc
+#define CSR_SPLIT_TIMEOUT_HI           0x18
+#define CSR_SPLIT_TIMEOUT_LO           0x1c
+#define CSR_CYCLE_TIME                 0x200
+#define CSR_BUS_TIME                   0x204
+#define CSR_BUSY_TIMEOUT               0x210
+#define CSR_BUS_MANAGER_ID             0x21c
+#define CSR_BANDWIDTH_AVAILABLE                0x220
+#define CSR_CHANNELS_AVAILABLE         0x224
+#define CSR_CHANNELS_AVAILABLE_HI      0x224
+#define CSR_CHANNELS_AVAILABLE_LO      0x228
+#define CSR_BROADCAST_CHANNEL          0x234
+#define CSR_CONFIG_ROM                 0x400
+#define CSR_CONFIG_ROM_END             0x800
+#define CSR_FCP_COMMAND                        0xB00
+#define CSR_FCP_RESPONSE               0xD00
+#define CSR_FCP_END                    0xF00
+#define CSR_TOPOLOGY_MAP               0x1000
+#define CSR_TOPOLOGY_MAP_END           0x1400
+#define CSR_SPEED_MAP                  0x2000
+#define CSR_SPEED_MAP_END              0x3000
+
+#define CSR_OFFSET             0x40
+#define CSR_LEAF               0x80
+#define CSR_DIRECTORY          0xc0
+
+#define CSR_DESCRIPTOR         0x01
+#define CSR_VENDOR             0x03
+#define CSR_HARDWARE_VERSION   0x04
+#define CSR_NODE_CAPABILITIES  0x0c
+#define CSR_UNIT               0x11
+#define CSR_SPECIFIER_ID       0x12
+#define CSR_VERSION            0x13
+#define CSR_DEPENDENT_INFO     0x14
+#define CSR_MODEL              0x17
+#define CSR_INSTANCE           0x18
+#define CSR_DIRECTORY_ID       0x20
+
+struct fw_csr_iterator {
+       u32 *p;
+       u32 *end;
+};
+
+void fw_csr_iterator_init(struct fw_csr_iterator *ci, u32 *p);
+int fw_csr_iterator_next(struct fw_csr_iterator *ci, int *key, int *value);
+
+extern struct bus_type fw_bus_type;
+
+struct fw_card_driver;
+struct fw_node;
+
+struct fw_card {
+       const struct fw_card_driver *driver;
+       struct device *device;
+       struct kref kref;
+       struct completion done;
+
+       int node_id;
+       int generation;
+       int current_tlabel;
+       u64 tlabel_mask;
+       struct list_head transaction_list;
+       struct timer_list flush_timer;
+       unsigned long reset_jiffies;
+
+       unsigned long long guid;
+       unsigned max_receive;
+       int link_speed;
+       int config_rom_generation;
+
+       spinlock_t lock; /* Take this lock when handling the lists in
+                         * this struct. */
+       struct fw_node *local_node;
+       struct fw_node *root_node;
+       struct fw_node *irm_node;
+       u8 color; /* must be u8 to match the definition in struct fw_node */
+       int gap_count;
+       bool beta_repeaters_present;
+
+       int index;
+
+       struct list_head link;
+
+       /* Work struct for BM duties. */
+       struct delayed_work work;
+       int bm_retries;
+       int bm_generation;
+
+       bool broadcast_channel_allocated;
+       u32 broadcast_channel;
+       u32 topology_map[(CSR_TOPOLOGY_MAP_END - CSR_TOPOLOGY_MAP) / 4];
+};
+
+static inline struct fw_card *fw_card_get(struct fw_card *card)
+{
+       kref_get(&card->kref);
+
+       return card;
+}
+
+void fw_card_release(struct kref *kref);
+
+static inline void fw_card_put(struct fw_card *card)
+{
+       kref_put(&card->kref, fw_card_release);
+}
+
+struct fw_attribute_group {
+       struct attribute_group *groups[2];
+       struct attribute_group group;
+       struct attribute *attrs[12];
+};
+
+enum fw_device_state {
+       FW_DEVICE_INITIALIZING,
+       FW_DEVICE_RUNNING,
+       FW_DEVICE_GONE,
+       FW_DEVICE_SHUTDOWN,
+};
+
+/*
+ * Note, fw_device.generation always has to be read before fw_device.node_id.
+ * Use SMP memory barriers to ensure this.  Otherwise requests will be sent
+ * to an outdated node_id if the generation was updated in the meantime due
+ * to a bus reset.
+ *
+ * Likewise, fw-core will take care to update .node_id before .generation so
+ * that whenever fw_device.generation is current WRT the actual bus generation,
+ * fw_device.node_id is guaranteed to be current too.
+ *
+ * The same applies to fw_device.card->node_id vs. fw_device.generation.
+ *
+ * fw_device.config_rom and fw_device.config_rom_length may be accessed during
+ * the lifetime of any fw_unit belonging to the fw_device, before device_del()
+ * was called on the last fw_unit.  Alternatively, they may be accessed while
+ * holding fw_device_rwsem.
+ */
+struct fw_device {
+       atomic_t state;
+       struct fw_node *node;
+       int node_id;
+       int generation;
+       unsigned max_speed;
+       struct fw_card *card;
+       struct device device;
+
+       struct mutex client_list_mutex;
+       struct list_head client_list;
+
+       u32 *config_rom;
+       size_t config_rom_length;
+       int config_rom_retries;
+       unsigned is_local:1;
+       unsigned max_rec:4;
+       unsigned cmc:1;
+       unsigned irmc:1;
+       unsigned bc_implemented:2;
+
+       struct delayed_work work;
+       struct fw_attribute_group attribute_group;
+};
+
+static inline struct fw_device *fw_device(struct device *dev)
+{
+       return container_of(dev, struct fw_device, device);
+}
+
+static inline int fw_device_is_shutdown(struct fw_device *device)
+{
+       return atomic_read(&device->state) == FW_DEVICE_SHUTDOWN;
+}
+
+static inline struct fw_device *fw_device_get(struct fw_device *device)
+{
+       get_device(&device->device);
+
+       return device;
+}
+
+static inline void fw_device_put(struct fw_device *device)
+{
+       put_device(&device->device);
+}
+
+int fw_device_enable_phys_dma(struct fw_device *device);
+
+/*
+ * fw_unit.directory must not be accessed after device_del(&fw_unit.device).
+ */
+struct fw_unit {
+       struct device device;
+       u32 *directory;
+       struct fw_attribute_group attribute_group;
+};
+
+static inline struct fw_unit *fw_unit(struct device *dev)
+{
+       return container_of(dev, struct fw_unit, device);
+}
+
+static inline struct fw_unit *fw_unit_get(struct fw_unit *unit)
+{
+       get_device(&unit->device);
+
+       return unit;
+}
+
+static inline void fw_unit_put(struct fw_unit *unit)
+{
+       put_device(&unit->device);
+}
+
+static inline struct fw_device *fw_parent_device(struct fw_unit *unit)
+{
+       return fw_device(unit->device.parent);
+}
+
+struct ieee1394_device_id;
+
+struct fw_driver {
+       struct device_driver driver;
+       /* Called when the parent device sits through a bus reset. */
+       void (*update)(struct fw_unit *unit);
+       const struct ieee1394_device_id *id_table;
+};
+
+struct fw_packet;
+struct fw_request;
+
+typedef void (*fw_packet_callback_t)(struct fw_packet *packet,
+                                    struct fw_card *card, int status);
+typedef void (*fw_transaction_callback_t)(struct fw_card *card, int rcode,
+                                         void *data, size_t length,
+                                         void *callback_data);
+/*
+ * Important note:  The callback must guarantee that either fw_send_response()
+ * or kfree() is called on the @request.
+ */
+typedef void (*fw_address_callback_t)(struct fw_card *card,
+                                     struct fw_request *request,
+                                     int tcode, int destination, int source,
+                                     int generation, int speed,
+                                     unsigned long long offset,
+                                     void *data, size_t length,
+                                     void *callback_data);
+
+struct fw_packet {
+       int speed;
+       int generation;
+       u32 header[4];
+       size_t header_length;
+       void *payload;
+       size_t payload_length;
+       dma_addr_t payload_bus;
+       u32 timestamp;
+
+       /*
+        * This callback is called when the packet transmission has
+        * completed; for successful transmission, the status code is
+        * the ack received from the destination, otherwise it's a
+        * negative errno: ENOMEM, ESTALE, ETIMEDOUT, ENODEV, EIO.
+        * The callback can be called from tasklet context and thus
+        * must never block.
+        */
+       fw_packet_callback_t callback;
+       int ack;
+       struct list_head link;
+       void *driver_data;
+};
+
+struct fw_transaction {
+       int node_id; /* The generation is implied; it is always the current. */
+       int tlabel;
+       int timestamp;
+       struct list_head link;
+
+       struct fw_packet packet;
+
+       /*
+        * The data passed to the callback is valid only during the
+        * callback.
+        */
+       fw_transaction_callback_t callback;
+       void *callback_data;
+};
+
+struct fw_address_handler {
+       u64 offset;
+       size_t length;
+       fw_address_callback_t address_callback;
+       void *callback_data;
+       struct list_head link;
+};
+
+struct fw_address_region {
+       u64 start;
+       u64 end;
+};
+
+extern const struct fw_address_region fw_high_memory_region;
+
+int fw_core_add_address_handler(struct fw_address_handler *handler,
+                               const struct fw_address_region *region);
+void fw_core_remove_address_handler(struct fw_address_handler *handler);
+void fw_send_response(struct fw_card *card,
+                     struct fw_request *request, int rcode);
+void fw_send_request(struct fw_card *card, struct fw_transaction *t,
+                    int tcode, int destination_id, int generation, int speed,
+                    unsigned long long offset, void *payload, size_t length,
+                    fw_transaction_callback_t callback, void *callback_data);
+int fw_cancel_transaction(struct fw_card *card,
+                         struct fw_transaction *transaction);
+int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
+                      int generation, int speed, unsigned long long offset,
+                      void *payload, size_t length);
+
+#endif /* _LINUX_FIREWIRE_H */
index cca686b39123dca178f26512e5fcbf0db114a41b..875451f1373a3ce38bfbfd81699eddd4c26ccecf 100644 (file)
  */
 #ifdef CONFIG_FIRMWARE_MEMMAP
 
-int firmware_map_add(resource_size_t start, resource_size_t end,
-                    const char *type);
-int firmware_map_add_early(resource_size_t start, resource_size_t end,
-                          const char *type);
+int firmware_map_add(u64 start, u64 end, const char *type);
+int firmware_map_add_early(u64 start, u64 end, const char *type);
 
 #else /* CONFIG_FIRMWARE_MEMMAP */
 
-static inline int firmware_map_add(resource_size_t start, resource_size_t end,
-                                  const char *type)
+static inline int firmware_map_add(u64 start, u64 end, const char *type)
 {
        return 0;
 }
 
-static inline int firmware_map_add_early(resource_size_t start,
-                                        resource_size_t end, const char *type)
+static inline int firmware_map_add_early(u64 start, u64 end, const char *type)
 {
        return 0;
 }
index c8ecf5b2a207371d5662234ec4eb9be9d3420c14..d31544628436cb717b88079f7f99bf6e9b775b68 100644 (file)
@@ -5,7 +5,6 @@
 #include <linux/types.h>
 #include <linux/compiler.h>
 
-#define FIRMWARE_NAME_MAX 30 
 #define FW_ACTION_NOHOTPLUG 0
 #define FW_ACTION_HOTPLUG 1
 
index ede84fa7da5d07dacaeafdaf104107a06a4aa7fa..74a57938c8801dafadeea3e0519f4849f01afd91 100644 (file)
@@ -879,7 +879,7 @@ struct file_ra_state {
                                           there are only # of pages ahead */
 
        unsigned int ra_pages;          /* Maximum readahead window */
-       int mmap_miss;                  /* Cache miss stat for mmap accesses */
+       unsigned int mmap_miss;         /* Cache miss stat for mmap accesses */
        loff_t prev_pos;                /* Cache last read() position */
 };
 
@@ -1919,8 +1919,9 @@ extern void __init vfs_caches_init(unsigned long);
 
 extern struct kmem_cache *names_cachep;
 
-#define __getname()    kmem_cache_alloc(names_cachep, GFP_KERNEL)
-#define __putname(name) kmem_cache_free(names_cachep, (void *)(name))
+#define __getname_gfp(gfp)     kmem_cache_alloc(names_cachep, (gfp))
+#define __getname()            __getname_gfp(GFP_KERNEL)
+#define __putname(name)                kmem_cache_free(names_cachep, (void *)(name))
 #ifndef CONFIG_AUDITSYSCALL
 #define putname(name)   __putname(name)
 #else
@@ -2036,9 +2037,6 @@ extern int __invalidate_device(struct block_device *);
 extern int invalidate_partition(struct gendisk *, int);
 #endif
 extern int invalidate_inodes(struct super_block *);
-unsigned long __invalidate_mapping_pages(struct address_space *mapping,
-                                       pgoff_t start, pgoff_t end,
-                                       bool be_atomic);
 unsigned long invalidate_mapping_pages(struct address_space *mapping,
                                        pgoff_t start, pgoff_t end);
 
index 7cbd38d363a2f051af1abbd30d7bbf90c066151e..45fc320a53c6f002fbb466d2b38315254b19ff94 100644 (file)
@@ -142,7 +142,7 @@ struct gendisk {
                                          * disks that can't be partitioned. */
 
        char disk_name[DISK_NAME_LEN];  /* name of major driver */
-
+       char *(*nodename)(struct gendisk *gd);
        /* Array of pointers to partitions indexed by partno.
         * Protected with matching bdev lock but stat and other
         * non-critical accesses use RCU.  Always access through
index 3760e7c5de0264aaec173486daca51035e80b252..cfdb35d71bcab52831d4de557312122d72a11810 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/stddef.h>
 #include <linux/linkage.h>
 #include <linux/topology.h>
+#include <linux/mmdebug.h>
 
 struct vm_area_struct;
 
@@ -20,7 +21,8 @@ struct vm_area_struct;
 #define __GFP_DMA      ((__force gfp_t)0x01u)
 #define __GFP_HIGHMEM  ((__force gfp_t)0x02u)
 #define __GFP_DMA32    ((__force gfp_t)0x04u)
-
+#define __GFP_MOVABLE  ((__force gfp_t)0x08u)  /* Page is movable */
+#define GFP_ZONEMASK   (__GFP_DMA|__GFP_HIGHMEM|__GFP_DMA32|__GFP_MOVABLE)
 /*
  * Action modifiers - doesn't change the zoning
  *
@@ -50,9 +52,20 @@ struct vm_area_struct;
 #define __GFP_HARDWALL   ((__force gfp_t)0x20000u) /* Enforce hardwall cpuset memory allocs */
 #define __GFP_THISNODE ((__force gfp_t)0x40000u)/* No fallback, no policies */
 #define __GFP_RECLAIMABLE ((__force gfp_t)0x80000u) /* Page is reclaimable */
-#define __GFP_MOVABLE  ((__force gfp_t)0x100000u)  /* Page is movable */
 
-#define __GFP_BITS_SHIFT 21    /* Room for 21 __GFP_FOO bits */
+#ifdef CONFIG_KMEMCHECK
+#define __GFP_NOTRACK  ((__force gfp_t)0x200000u)  /* Don't track with kmemcheck */
+#else
+#define __GFP_NOTRACK  ((__force gfp_t)0)
+#endif
+
+/*
+ * This may seem redundant, but it's a way of annotating false positives vs.
+ * allocations that simply cannot be supported (e.g. page tables).
+ */
+#define __GFP_NOTRACK_FALSE_POSITIVE (__GFP_NOTRACK)
+
+#define __GFP_BITS_SHIFT 22    /* Room for 22 __GFP_FOO bits */
 #define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1))
 
 /* This equals 0, but use constants in case they ever change */
@@ -115,24 +128,105 @@ static inline int allocflags_to_migratetype(gfp_t gfp_flags)
                ((gfp_flags & __GFP_RECLAIMABLE) != 0);
 }
 
-static inline enum zone_type gfp_zone(gfp_t flags)
-{
+#ifdef CONFIG_HIGHMEM
+#define OPT_ZONE_HIGHMEM ZONE_HIGHMEM
+#else
+#define OPT_ZONE_HIGHMEM ZONE_NORMAL
+#endif
+
 #ifdef CONFIG_ZONE_DMA
-       if (flags & __GFP_DMA)
-               return ZONE_DMA;
+#define OPT_ZONE_DMA ZONE_DMA
+#else
+#define OPT_ZONE_DMA ZONE_NORMAL
 #endif
+
 #ifdef CONFIG_ZONE_DMA32
-       if (flags & __GFP_DMA32)
-               return ZONE_DMA32;
+#define OPT_ZONE_DMA32 ZONE_DMA32
+#else
+#define OPT_ZONE_DMA32 ZONE_NORMAL
 #endif
-       if ((flags & (__GFP_HIGHMEM | __GFP_MOVABLE)) ==
-                       (__GFP_HIGHMEM | __GFP_MOVABLE))
-               return ZONE_MOVABLE;
-#ifdef CONFIG_HIGHMEM
-       if (flags & __GFP_HIGHMEM)
-               return ZONE_HIGHMEM;
+
+/*
+ * GFP_ZONE_TABLE is a word size bitstring that is used for looking up the
+ * zone to use given the lowest 4 bits of gfp_t. Entries are ZONE_SHIFT long
+ * and there are 16 of them to cover all possible combinations of
+ * __GFP_DMA, __GFP_DMA32, __GFP_MOVABLE and __GFP_HIGHMEM
+ *
+ * The zone fallback order is MOVABLE=>HIGHMEM=>NORMAL=>DMA32=>DMA.
+ * But GFP_MOVABLE is not only a zone specifier but also an allocation
+ * policy. Therefore __GFP_MOVABLE plus another zone selector is valid.
+ * Only 1bit of the lowest 3 bit (DMA,DMA32,HIGHMEM) can be set to "1".
+ *
+ *       bit       result
+ *       =================
+ *       0x0    => NORMAL
+ *       0x1    => DMA or NORMAL
+ *       0x2    => HIGHMEM or NORMAL
+ *       0x3    => BAD (DMA+HIGHMEM)
+ *       0x4    => DMA32 or DMA or NORMAL
+ *       0x5    => BAD (DMA+DMA32)
+ *       0x6    => BAD (HIGHMEM+DMA32)
+ *       0x7    => BAD (HIGHMEM+DMA32+DMA)
+ *       0x8    => NORMAL (MOVABLE+0)
+ *       0x9    => DMA or NORMAL (MOVABLE+DMA)
+ *       0xa    => MOVABLE (Movable is valid only if HIGHMEM is set too)
+ *       0xb    => BAD (MOVABLE+HIGHMEM+DMA)
+ *       0xc    => DMA32 (MOVABLE+HIGHMEM+DMA32)
+ *       0xd    => BAD (MOVABLE+DMA32+DMA)
+ *       0xe    => BAD (MOVABLE+DMA32+HIGHMEM)
+ *       0xf    => BAD (MOVABLE+DMA32+HIGHMEM+DMA)
+ *
+ * ZONES_SHIFT must be <= 2 on 32 bit platforms.
+ */
+
+#if 16 * ZONES_SHIFT > BITS_PER_LONG
+#error ZONES_SHIFT too large to create GFP_ZONE_TABLE integer
+#endif
+
+#define GFP_ZONE_TABLE ( \
+       (ZONE_NORMAL << 0 * ZONES_SHIFT)                                \
+       | (OPT_ZONE_DMA << __GFP_DMA * ZONES_SHIFT)                     \
+       | (OPT_ZONE_HIGHMEM << __GFP_HIGHMEM * ZONES_SHIFT)             \
+       | (OPT_ZONE_DMA32 << __GFP_DMA32 * ZONES_SHIFT)                 \
+       | (ZONE_NORMAL << __GFP_MOVABLE * ZONES_SHIFT)                  \
+       | (OPT_ZONE_DMA << (__GFP_MOVABLE | __GFP_DMA) * ZONES_SHIFT)   \
+       | (ZONE_MOVABLE << (__GFP_MOVABLE | __GFP_HIGHMEM) * ZONES_SHIFT)\
+       | (OPT_ZONE_DMA32 << (__GFP_MOVABLE | __GFP_DMA32) * ZONES_SHIFT)\
+)
+
+/*
+ * GFP_ZONE_BAD is a bitmap for all combination of __GFP_DMA, __GFP_DMA32
+ * __GFP_HIGHMEM and __GFP_MOVABLE that are not permitted. One flag per
+ * entry starting with bit 0. Bit is set if the combination is not
+ * allowed.
+ */
+#define GFP_ZONE_BAD ( \
+       1 << (__GFP_DMA | __GFP_HIGHMEM)                                \
+       | 1 << (__GFP_DMA | __GFP_DMA32)                                \
+       | 1 << (__GFP_DMA32 | __GFP_HIGHMEM)                            \
+       | 1 << (__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM)                \
+       | 1 << (__GFP_MOVABLE | __GFP_HIGHMEM | __GFP_DMA)              \
+       | 1 << (__GFP_MOVABLE | __GFP_DMA32 | __GFP_DMA)                \
+       | 1 << (__GFP_MOVABLE | __GFP_DMA32 | __GFP_HIGHMEM)            \
+       | 1 << (__GFP_MOVABLE | __GFP_DMA32 | __GFP_DMA | __GFP_HIGHMEM)\
+)
+
+static inline enum zone_type gfp_zone(gfp_t flags)
+{
+       enum zone_type z;
+       int bit = flags & GFP_ZONEMASK;
+
+       z = (GFP_ZONE_TABLE >> (bit * ZONES_SHIFT)) &
+                                        ((1 << ZONES_SHIFT) - 1);
+
+       if (__builtin_constant_p(bit))
+               BUILD_BUG_ON((GFP_ZONE_BAD >> bit) & 1);
+       else {
+#ifdef CONFIG_DEBUG_VM
+               BUG_ON((GFP_ZONE_BAD >> bit) & 1);
 #endif
-       return ZONE_NORMAL;
+       }
+       return z;
 }
 
 /*
@@ -172,30 +266,19 @@ static inline void arch_alloc_page(struct page *page, int order) { }
 #endif
 
 struct page *
-__alloc_pages_internal(gfp_t gfp_mask, unsigned int order,
+__alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
                       struct zonelist *zonelist, nodemask_t *nodemask);
 
 static inline struct page *
 __alloc_pages(gfp_t gfp_mask, unsigned int order,
                struct zonelist *zonelist)
 {
-       return __alloc_pages_internal(gfp_mask, order, zonelist, NULL);
+       return __alloc_pages_nodemask(gfp_mask, order, zonelist, NULL);
 }
 
-static inline struct page *
-__alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
-               struct zonelist *zonelist, nodemask_t *nodemask)
-{
-       return __alloc_pages_internal(gfp_mask, order, zonelist, nodemask);
-}
-
-
 static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask,
                                                unsigned int order)
 {
-       if (unlikely(order >= MAX_ORDER))
-               return NULL;
-
        /* Unknown node is current node */
        if (nid < 0)
                nid = numa_node_id();
@@ -203,15 +286,20 @@ static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask,
        return __alloc_pages(gfp_mask, order, node_zonelist(nid, gfp_mask));
 }
 
+static inline struct page *alloc_pages_exact_node(int nid, gfp_t gfp_mask,
+                                               unsigned int order)
+{
+       VM_BUG_ON(nid < 0 || nid >= MAX_NUMNODES);
+
+       return __alloc_pages(gfp_mask, order, node_zonelist(nid, gfp_mask));
+}
+
 #ifdef CONFIG_NUMA
 extern struct page *alloc_pages_current(gfp_t gfp_mask, unsigned order);
 
 static inline struct page *
 alloc_pages(gfp_t gfp_mask, unsigned int order)
 {
-       if (unlikely(order >= MAX_ORDER))
-               return NULL;
-
        return alloc_pages_current(gfp_mask, order);
 }
 extern struct page *alloc_page_vma(gfp_t gfp_mask,
@@ -248,4 +336,16 @@ void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp);
 void drain_all_pages(void);
 void drain_local_pages(void *dummy);
 
+extern bool oom_killer_disabled;
+
+static inline void oom_killer_disable(void)
+{
+       oom_killer_disabled = true;
+}
+
+static inline void oom_killer_enable(void)
+{
+       oom_killer_disabled = false;
+}
+
 #endif /* __LINUX_GFP_H */
index 1fcb7126a01f1aa3e7a4c63abd46c4311946c843..211ff4497269e8228951524c8bf2b01a7d1dbeb3 100644 (file)
@@ -55,7 +55,9 @@ static inline void *kmap(struct page *page)
        return page_address(page);
 }
 
-#define kunmap(page) do { (void) (page); } while (0)
+static inline void kunmap(struct page *page)
+{
+}
 
 static inline void *kmap_atomic(struct page *page, enum km_type idx)
 {
index 03be7f29ca0153e8c1da31650b14ce3d95f59d80..a05a5ef33391d0e2ef816666f2bb08ca10fba491 100644 (file)
@@ -11,6 +11,8 @@
 
 struct ctl_table;
 
+int PageHuge(struct page *page);
+
 static inline int is_vm_hugetlb_page(struct vm_area_struct *vma)
 {
        return vma->vm_flags & VM_HUGETLB;
@@ -61,6 +63,11 @@ void hugetlb_change_protection(struct vm_area_struct *vma,
 
 #else /* !CONFIG_HUGETLB_PAGE */
 
+static inline int PageHuge(struct page *page)
+{
+       return 0;
+}
+
 static inline int is_vm_hugetlb_page(struct vm_area_struct *vma)
 {
        return 0;
index b2189803f19afb4ff111fed17bd56b0c514e3f43..8c2c9989626db737941654fcf8a57c60607f5053 100644 (file)
@@ -29,7 +29,7 @@
  * sign followed by value, e.g.:
  *
  * static int init_variable __initdata = 0;
- * static char linux_logo[] __initdata = { 0x32, 0x36, ... };
+ * static const char linux_logo[] __initconst = { 0x32, 0x36, ... };
  *
  * Don't forget to initialize data not at file scope, i.e. within a function,
  * as gcc otherwise puts the data into the bss section and not into the init
index 28b1f30601b555d6f12532a9223428244dad7e87..5368fbdc78018c573c9f20a1dab76adbc8cb0f24 100644 (file)
 extern struct files_struct init_files;
 extern struct fs_struct init_fs;
 
-#define INIT_MM(name) \
-{                                                              \
-       .mm_rb          = RB_ROOT,                              \
-       .pgd            = swapper_pg_dir,                       \
-       .mm_users       = ATOMIC_INIT(2),                       \
-       .mm_count       = ATOMIC_INIT(1),                       \
-       .mmap_sem       = __RWSEM_INITIALIZER(name.mmap_sem),   \
-       .page_table_lock =  __SPIN_LOCK_UNLOCKED(name.page_table_lock), \
-       .mmlist         = LIST_HEAD_INIT(name.mmlist),          \
-       .cpu_vm_mask    = CPU_MASK_ALL,                         \
-}
-
 #define INIT_SIGNALS(sig) {                                            \
        .count          = ATOMIC_INIT(1),                               \
        .wait_chldexit  = __WAIT_QUEUE_HEAD_INITIALIZER(sig.wait_chldexit),\
index c41e812e9d5ef17fcc894c0e316f5c9da95e486f..2721f07e93548150a195123bb13e02e1bfa4664b 100644 (file)
@@ -472,6 +472,20 @@ static inline void tasklet_hi_schedule(struct tasklet_struct *t)
                __tasklet_hi_schedule(t);
 }
 
+extern void __tasklet_hi_schedule_first(struct tasklet_struct *t);
+
+/*
+ * This version avoids touching any other tasklets. Needed for kmemcheck
+ * in order not to take any page faults while enqueueing this tasklet;
+ * consider VERY carefully whether you really need this or
+ * tasklet_hi_schedule()...
+ */
+static inline void tasklet_hi_schedule_first(struct tasklet_struct *t)
+{
+       if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
+               __tasklet_hi_schedule_first(t);
+}
+
 
 static inline void tasklet_disable_nosync(struct tasklet_struct *t)
 {
index 883cd44ff765d9d90fdac42c11f51062bb8b8ef3..c5a71c38a95f5521b17aef7ca178e43e2ca11b0e 100644 (file)
@@ -97,12 +97,14 @@ extern const char linux_proc_banner[];
 #define        KERN_INFO       "<6>"   /* informational                        */
 #define        KERN_DEBUG      "<7>"   /* debug-level messages                 */
 
+/* Use the default kernel loglevel */
+#define KERN_DEFAULT   "<d>"
 /*
  * Annotation for a "continued" line of log printout (only done after a
  * line that had no enclosing \n). Only to be used by core/arch code
  * during early bootup (a continued line is not SMP-safe otherwise).
  */
-#define        KERN_CONT       ""
+#define        KERN_CONT       "<c>"
 
 extern int console_printk[];
 
@@ -406,7 +408,7 @@ static inline char *pack_hex_byte(char *buf, u8 byte)
  *
  * Use tracing_on/tracing_off when you want to quickly turn on or off
  * tracing. It simply enables or disables the recording of the trace events.
- * This also corresponds to the user space debugfs/tracing/tracing_on
+ * This also corresponds to the user space /sys/kernel/debug/tracing/tracing_on
  * file, which gives a means for the kernel and userspace to interact.
  * Place a tracing_off() in the kernel where you want tracing to end.
  * From user space, examine the trace, and then echo 1 > tracing_on
diff --git a/include/linux/kmemcheck.h b/include/linux/kmemcheck.h
new file mode 100644 (file)
index 0000000..47b39b7
--- /dev/null
@@ -0,0 +1,153 @@
+#ifndef LINUX_KMEMCHECK_H
+#define LINUX_KMEMCHECK_H
+
+#include <linux/mm_types.h>
+#include <linux/types.h>
+
+#ifdef CONFIG_KMEMCHECK
+extern int kmemcheck_enabled;
+
+/* The slab-related functions. */
+void kmemcheck_alloc_shadow(struct page *page, int order, gfp_t flags, int node);
+void kmemcheck_free_shadow(struct page *page, int order);
+void kmemcheck_slab_alloc(struct kmem_cache *s, gfp_t gfpflags, void *object,
+                         size_t size);
+void kmemcheck_slab_free(struct kmem_cache *s, void *object, size_t size);
+
+void kmemcheck_pagealloc_alloc(struct page *p, unsigned int order,
+                              gfp_t gfpflags);
+
+void kmemcheck_show_pages(struct page *p, unsigned int n);
+void kmemcheck_hide_pages(struct page *p, unsigned int n);
+
+bool kmemcheck_page_is_tracked(struct page *p);
+
+void kmemcheck_mark_unallocated(void *address, unsigned int n);
+void kmemcheck_mark_uninitialized(void *address, unsigned int n);
+void kmemcheck_mark_initialized(void *address, unsigned int n);
+void kmemcheck_mark_freed(void *address, unsigned int n);
+
+void kmemcheck_mark_unallocated_pages(struct page *p, unsigned int n);
+void kmemcheck_mark_uninitialized_pages(struct page *p, unsigned int n);
+void kmemcheck_mark_initialized_pages(struct page *p, unsigned int n);
+
+int kmemcheck_show_addr(unsigned long address);
+int kmemcheck_hide_addr(unsigned long address);
+
+#else
+#define kmemcheck_enabled 0
+
+static inline void
+kmemcheck_alloc_shadow(struct page *page, int order, gfp_t flags, int node)
+{
+}
+
+static inline void
+kmemcheck_free_shadow(struct page *page, int order)
+{
+}
+
+static inline void
+kmemcheck_slab_alloc(struct kmem_cache *s, gfp_t gfpflags, void *object,
+                    size_t size)
+{
+}
+
+static inline void kmemcheck_slab_free(struct kmem_cache *s, void *object,
+                                      size_t size)
+{
+}
+
+static inline void kmemcheck_pagealloc_alloc(struct page *p,
+       unsigned int order, gfp_t gfpflags)
+{
+}
+
+static inline bool kmemcheck_page_is_tracked(struct page *p)
+{
+       return false;
+}
+
+static inline void kmemcheck_mark_unallocated(void *address, unsigned int n)
+{
+}
+
+static inline void kmemcheck_mark_uninitialized(void *address, unsigned int n)
+{
+}
+
+static inline void kmemcheck_mark_initialized(void *address, unsigned int n)
+{
+}
+
+static inline void kmemcheck_mark_freed(void *address, unsigned int n)
+{
+}
+
+static inline void kmemcheck_mark_unallocated_pages(struct page *p,
+                                                   unsigned int n)
+{
+}
+
+static inline void kmemcheck_mark_uninitialized_pages(struct page *p,
+                                                     unsigned int n)
+{
+}
+
+static inline void kmemcheck_mark_initialized_pages(struct page *p,
+                                                   unsigned int n)
+{
+}
+
+#endif /* CONFIG_KMEMCHECK */
+
+/*
+ * Bitfield annotations
+ *
+ * How to use: If you have a struct using bitfields, for example
+ *
+ *     struct a {
+ *             int x:8, y:8;
+ *     };
+ *
+ * then this should be rewritten as
+ *
+ *     struct a {
+ *             kmemcheck_bitfield_begin(flags);
+ *             int x:8, y:8;
+ *             kmemcheck_bitfield_end(flags);
+ *     };
+ *
+ * Now the "flags_begin" and "flags_end" members may be used to refer to the
+ * beginning and end, respectively, of the bitfield (and things like
+ * &x.flags_begin is allowed). As soon as the struct is allocated, the bit-
+ * fields should be annotated:
+ *
+ *     struct a *a = kmalloc(sizeof(struct a), GFP_KERNEL);
+ *     kmemcheck_annotate_bitfield(a, flags);
+ *
+ * Note: We provide the same definitions for both kmemcheck and non-
+ * kmemcheck kernels. This makes it harder to introduce accidental errors. It
+ * is also allowed to pass NULL pointers to kmemcheck_annotate_bitfield().
+ */
+#define kmemcheck_bitfield_begin(name) \
+       int name##_begin[0];
+
+#define kmemcheck_bitfield_end(name)   \
+       int name##_end[0];
+
+#define kmemcheck_annotate_bitfield(ptr, name)                         \
+       do if (ptr) {                                                   \
+               int _n = (long) &((ptr)->name##_end)                    \
+                       - (long) &((ptr)->name##_begin);                \
+               BUILD_BUG_ON(_n < 0);                                   \
+                                                                       \
+               kmemcheck_mark_initialized(&((ptr)->name##_begin), _n); \
+       } while (0)
+
+#define kmemcheck_annotate_variable(var)                               \
+       do {                                                            \
+               kmemcheck_mark_initialized(&(var), sizeof(var));        \
+       } while (0)                                                     \
+
+#endif /* LINUX_KMEMCHECK_H */
index 08a92969c76e09f99ad546ec4f8a84aa8b6ed917..ca5bd91d12e169cd80eb6a546fe73c35df8ead91 100644 (file)
@@ -32,6 +32,22 @@ struct linux_logo {
        const unsigned char *data;
 };
 
+extern const struct linux_logo logo_linux_mono;
+extern const struct linux_logo logo_linux_vga16;
+extern const struct linux_logo logo_linux_clut224;
+extern const struct linux_logo logo_blackfin_vga16;
+extern const struct linux_logo logo_blackfin_clut224;
+extern const struct linux_logo logo_dec_clut224;
+extern const struct linux_logo logo_mac_clut224;
+extern const struct linux_logo logo_parisc_clut224;
+extern const struct linux_logo logo_sgi_clut224;
+extern const struct linux_logo logo_sun_clut224;
+extern const struct linux_logo logo_superh_mono;
+extern const struct linux_logo logo_superh_vga16;
+extern const struct linux_logo logo_superh_clut224;
+extern const struct linux_logo logo_m32r_clut224;
+extern const struct linux_logo logo_spe_clut224;
+
 extern const struct linux_logo *fb_find_logo(int depth);
 #ifdef CONFIG_FB_LOGO_EXTRA
 extern void fb_append_extra_logo(const struct linux_logo *logo,
diff --git a/include/linux/lis3lv02d.h b/include/linux/lis3lv02d.h
new file mode 100644 (file)
index 0000000..ad651f4
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef __LIS3LV02D_H_
+#define __LIS3LV02D_H_
+
+struct lis3lv02d_platform_data {
+       /* please note: the 'click' feature is only supported for
+        * LIS[32]02DL variants of the chip and will be ignored for
+        * others */
+#define LIS3_CLICK_SINGLE_X    (1 << 0)
+#define LIS3_CLICK_DOUBLE_X    (1 << 1)
+#define LIS3_CLICK_SINGLE_Y    (1 << 2)
+#define LIS3_CLICK_DOUBLE_Y    (1 << 3)
+#define LIS3_CLICK_SINGLE_Z    (1 << 4)
+#define LIS3_CLICK_DOUBLE_Z    (1 << 5)
+       unsigned char click_flags;
+       unsigned char click_thresh_x;
+       unsigned char click_thresh_y;
+       unsigned char click_thresh_z;
+       unsigned char click_time_limit;
+       unsigned char click_latency;
+       unsigned char click_window;
+
+#define LIS3_IRQ1_DISABLE      (0 << 0)
+#define LIS3_IRQ1_FF_WU_1      (1 << 0)
+#define LIS3_IRQ1_FF_WU_2      (2 << 0)
+#define LIS3_IRQ1_FF_WU_12     (3 << 0)
+#define LIS3_IRQ1_DATA_READY   (4 << 0)
+#define LIS3_IRQ1_CLICK                (7 << 0)
+#define LIS3_IRQ2_DISABLE      (0 << 3)
+#define LIS3_IRQ2_FF_WU_1      (1 << 3)
+#define LIS3_IRQ2_FF_WU_2      (2 << 3)
+#define LIS3_IRQ2_FF_WU_12     (3 << 3)
+#define LIS3_IRQ2_DATA_READY   (4 << 3)
+#define LIS3_IRQ2_CLICK                (7 << 3)
+#define LIS3_IRQ_OPEN_DRAIN    (1 << 6)
+#define LIS3_IRQ_ACTIVE_HIGH   (1 << 7)
+       unsigned char irq_cfg;
+};
+
+#endif /* __LIS3LV02D_H_ */
index 058ec15dd060341391277f6f82f479b151a494eb..6a8ca98c9a962ee67fbcf3da94fe0222f6885c2c 100644 (file)
 #define UNIX98_PTY_MAJOR_COUNT 8
 #define UNIX98_PTY_SLAVE_MAJOR (UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT)
 
+#define DRBD_MAJOR             147
 #define RTF_MAJOR              150
 #define RAW_MAJOR              162
 
index 25b9ca93d2327e942da46f8d9545a7a514c6ed13..45add35dda1b5da25a1ad7d9ff88c94687cb3cad 100644 (file)
@@ -94,6 +94,7 @@ extern void mem_cgroup_note_reclaim_priority(struct mem_cgroup *mem,
 extern void mem_cgroup_record_reclaim_priority(struct mem_cgroup *mem,
                                                        int priority);
 int mem_cgroup_inactive_anon_is_low(struct mem_cgroup *memcg);
+int mem_cgroup_inactive_file_is_low(struct mem_cgroup *memcg);
 unsigned long mem_cgroup_zone_nr_pages(struct mem_cgroup *memcg,
                                       struct zone *zone,
                                       enum lru_list lru);
@@ -239,6 +240,12 @@ mem_cgroup_inactive_anon_is_low(struct mem_cgroup *memcg)
        return 1;
 }
 
+static inline int
+mem_cgroup_inactive_file_is_low(struct mem_cgroup *memcg)
+{
+       return 1;
+}
+
 static inline unsigned long
 mem_cgroup_zone_nr_pages(struct mem_cgroup *memcg, struct zone *zone,
                         enum lru_list lru)
diff --git a/include/linux/mg_disk.h b/include/linux/mg_disk.h
new file mode 100644 (file)
index 0000000..e11f4d9
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ *  include/linux/mg_disk.c
+ *
+ *  Private data for mflash platform driver
+ *
+ * (c) 2008 mGine Co.,LTD
+ * (c) 2008 unsik Kim <donari75@gmail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#ifndef __MG_DISK_H__
+#define __MG_DISK_H__
+
+/* name for platform device */
+#define MG_DEV_NAME "mg_disk"
+
+/* names of GPIO resource */
+#define MG_RST_PIN     "mg_rst"
+/* except MG_BOOT_DEV, reset-out pin should be assigned */
+#define MG_RSTOUT_PIN  "mg_rstout"
+
+/* device attribution */
+/* use mflash as boot device */
+#define MG_BOOT_DEV            (1 << 0)
+/* use mflash as storage device */
+#define MG_STORAGE_DEV         (1 << 1)
+/* same as MG_STORAGE_DEV, but bootloader already done reset sequence */
+#define MG_STORAGE_DEV_SKIP_RST        (1 << 2)
+
+/* private driver data */
+struct mg_drv_data {
+       /* disk resource */
+       u32 use_polling;
+
+       /* device attribution */
+       u32 dev_attr;
+
+       /* internally used */
+       void *host;
+};
+
+#endif
index beb6ec99cfefb768b4ff43488c1a6137715eda15..052117744629bfd05e300528f99e5675574dda3e 100644 (file)
@@ -41,6 +41,7 @@ struct miscdevice  {
        struct list_head list;
        struct device *parent;
        struct device *this_device;
+       const char *devnode;
 };
 
 extern int misc_register(struct miscdevice * misc);
index ad613ed66ab07b60e0f859eba21be6c6c4a1202e..d88d6fc530ade07b88272c033804404c064c2440 100644 (file)
@@ -7,7 +7,6 @@
 
 #include <linux/gfp.h>
 #include <linux/list.h>
-#include <linux/mmdebug.h>
 #include <linux/mmzone.h>
 #include <linux/rbtree.h>
 #include <linux/prio_tree.h>
@@ -725,7 +724,7 @@ static inline int shmem_lock(struct file *file, int lock,
        return 0;
 }
 #endif
-struct file *shmem_file_setup(char *name, loff_t size, unsigned long flags);
+struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags);
 
 int shmem_zero_setup(struct vm_area_struct *);
 
@@ -793,6 +792,8 @@ int copy_page_range(struct mm_struct *dst, struct mm_struct *src,
                        struct vm_area_struct *vma);
 void unmap_mapping_range(struct address_space *mapping,
                loff_t const holebegin, loff_t const holelen, int even_cows);
+int follow_pfn(struct vm_area_struct *vma, unsigned long address,
+       unsigned long *pfn);
 int follow_phys(struct vm_area_struct *vma, unsigned long address,
                unsigned int flags, unsigned long *prot, resource_size_t *phys);
 int generic_access_phys(struct vm_area_struct *vma, unsigned long addr,
@@ -824,8 +825,11 @@ static inline int handle_mm_fault(struct mm_struct *mm,
 extern int make_pages_present(unsigned long addr, unsigned long end);
 extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
 
-int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
-               int len, int write, int force, struct page **pages, struct vm_area_struct **vmas);
+int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
+                       unsigned long start, int len, int write, int force,
+                       struct page **pages, struct vm_area_struct **vmas);
+int get_user_pages_fast(unsigned long start, int nr_pages, int write,
+                       struct page **pages);
 
 extern int try_to_release_page(struct page * page, gfp_t gfp_mask);
 extern void do_invalidatepage(struct page *page, unsigned long offset);
@@ -849,19 +853,6 @@ extern int mprotect_fixup(struct vm_area_struct *vma,
                          struct vm_area_struct **pprev, unsigned long start,
                          unsigned long end, unsigned long newflags);
 
-/*
- * get_user_pages_fast provides equivalent functionality to get_user_pages,
- * operating on current and current->mm (force=0 and doesn't return any vmas).
- *
- * get_user_pages_fast may take mmap_sem and page tables, so no assumptions
- * can be made about locking. get_user_pages_fast is to be implemented in a
- * way that is advantageous (vs get_user_pages()) when the user memory area is
- * already faulted in and present in ptes. However if the pages have to be
- * faulted in, it may turn out to be slightly slower).
- */
-int get_user_pages_fast(unsigned long start, int nr_pages, int write,
-                       struct page **pages);
-
 /*
  * A callback you can register to apply pressure to ageable caches.
  *
@@ -1061,7 +1052,8 @@ extern int __meminit __early_pfn_to_nid(unsigned long pfn);
 extern void set_dma_reserve(unsigned long new_dma_reserve);
 extern void memmap_init_zone(unsigned long, int, unsigned long,
                                unsigned long, enum memmap_context);
-extern void setup_per_zone_pages_min(void);
+extern void setup_per_zone_wmarks(void);
+extern void calculate_zone_inactive_ratio(struct zone *zone);
 extern void mem_init(void);
 extern void __init mmap_init(void);
 extern void show_mem(void);
@@ -1178,8 +1170,6 @@ void task_dirty_inc(struct task_struct *tsk);
 #define VM_MAX_READAHEAD       128     /* kbytes */
 #define VM_MIN_READAHEAD       16      /* kbytes (includes current page) */
 
-int do_page_cache_readahead(struct address_space *mapping, struct file *filp,
-                       pgoff_t offset, unsigned long nr_to_read);
 int force_page_cache_readahead(struct address_space *mapping, struct file *filp,
                        pgoff_t offset, unsigned long nr_to_read);
 
@@ -1197,6 +1187,9 @@ void page_cache_async_readahead(struct address_space *mapping,
                                unsigned long size);
 
 unsigned long max_sane_readahead(unsigned long nr);
+unsigned long ra_submit(struct file_ra_state *ra,
+                       struct address_space *mapping,
+                       struct file *filp);
 
 /* Do stack extension */
 extern int expand_stack(struct vm_area_struct *vma, unsigned long address);
index 0e80e26ecf21220104d8d2abbeb9cca6a1215e6e..7acc8439d9b305caad3d8354ee7ad43e0a3de465 100644 (file)
@@ -98,6 +98,14 @@ struct page {
 #ifdef CONFIG_WANT_PAGE_DEBUG_FLAGS
        unsigned long debug_flags;      /* Use atomic bitops on this */
 #endif
+
+#ifdef CONFIG_KMEMCHECK
+       /*
+        * kmemcheck wants to track the status of each byte in a page; this
+        * is a pointer to such a status block. NULL if not tracked.
+        */
+       void *shadow;
+#endif
 };
 
 /*
@@ -232,6 +240,8 @@ struct mm_struct {
 
        unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */
 
+       s8 oom_adj;     /* OOM kill score adjustment (bit shift) */
+
        cpumask_t cpu_vm_mask;
 
        /* Architecture-specific MM context */
index c7211ab6dd4be15f61ba7cc899703f0f29b08474..39751c8cde9cb010773a43c23a926bc9001b2de7 100644 (file)
 #define SDIO_DEVICE_ID_MARVELL_8688WLAN                0x9104
 #define SDIO_DEVICE_ID_MARVELL_8688BT          0x9105
 
+#define SDIO_VENDOR_ID_SIANO                   0x039a
+#define SDIO_DEVICE_ID_SIANO_NOVA_B0           0x0201
+#define SDIO_DEVICE_ID_SIANO_NICE              0x0202
+#define SDIO_DEVICE_ID_SIANO_VEGA_A0           0x0300
+#define SDIO_DEVICE_ID_SIANO_VENICE            0x0301
+#define SDIO_DEVICE_ID_SIANO_NOVA_A0           0x1100
+#define SDIO_DEVICE_ID_SIANO_STELLAR           0x5347
+
 #endif
index a47c879e1304cc19397543403aa068bd02433f29..889598537370b6f1de72e672efd55b6f3db1b377 100644 (file)
@@ -50,9 +50,6 @@ extern int page_group_by_mobility_disabled;
 
 static inline int get_pageblock_migratetype(struct page *page)
 {
-       if (unlikely(page_group_by_mobility_disabled))
-               return MIGRATE_UNMOVABLE;
-
        return get_pageblock_flags_group(page, PB_migrate, PB_migrate_end);
 }
 
@@ -86,13 +83,8 @@ enum zone_stat_item {
        NR_ACTIVE_ANON,         /*  "     "     "   "       "         */
        NR_INACTIVE_FILE,       /*  "     "     "   "       "         */
        NR_ACTIVE_FILE,         /*  "     "     "   "       "         */
-#ifdef CONFIG_UNEVICTABLE_LRU
        NR_UNEVICTABLE,         /*  "     "     "   "       "         */
        NR_MLOCK,               /* mlock()ed pages found and moved off LRU */
-#else
-       NR_UNEVICTABLE = NR_ACTIVE_FILE, /* avoid compiler errors in dead code */
-       NR_MLOCK = NR_ACTIVE_FILE,
-#endif
        NR_ANON_PAGES,  /* Mapped anonymous pages */
        NR_FILE_MAPPED, /* pagecache pages mapped into pagetables.
                           only modified from process context */
@@ -135,11 +127,7 @@ enum lru_list {
        LRU_ACTIVE_ANON = LRU_BASE + LRU_ACTIVE,
        LRU_INACTIVE_FILE = LRU_BASE + LRU_FILE,
        LRU_ACTIVE_FILE = LRU_BASE + LRU_FILE + LRU_ACTIVE,
-#ifdef CONFIG_UNEVICTABLE_LRU
        LRU_UNEVICTABLE,
-#else
-       LRU_UNEVICTABLE = LRU_ACTIVE_FILE, /* avoid compiler errors in dead code */
-#endif
        NR_LRU_LISTS
 };
 
@@ -159,13 +147,20 @@ static inline int is_active_lru(enum lru_list l)
 
 static inline int is_unevictable_lru(enum lru_list l)
 {
-#ifdef CONFIG_UNEVICTABLE_LRU
        return (l == LRU_UNEVICTABLE);
-#else
-       return 0;
-#endif
 }
 
+enum zone_watermarks {
+       WMARK_MIN,
+       WMARK_LOW,
+       WMARK_HIGH,
+       NR_WMARK
+};
+
+#define min_wmark_pages(z) (z->watermark[WMARK_MIN])
+#define low_wmark_pages(z) (z->watermark[WMARK_LOW])
+#define high_wmark_pages(z) (z->watermark[WMARK_HIGH])
+
 struct per_cpu_pages {
        int count;              /* number of pages in the list */
        int high;               /* high watermark, emptying needed */
@@ -278,7 +273,10 @@ struct zone_reclaim_stat {
 
 struct zone {
        /* Fields commonly accessed by the page allocator */
-       unsigned long           pages_min, pages_low, pages_high;
+
+       /* zone watermarks, access with *_wmark_pages(zone) macros */
+       unsigned long watermark[NR_WMARK];
+
        /*
         * We don't know if the memory that we're going to allocate will be freeable
         * or/and it will be released eventually, so to avoid totally wasting several
@@ -323,9 +321,9 @@ struct zone {
 
        /* Fields commonly accessed by the page reclaim scanner */
        spinlock_t              lru_lock;       
-       struct {
+       struct zone_lru {
                struct list_head list;
-               unsigned long nr_scan;
+               unsigned long nr_saved_scan;    /* accumulated for batching */
        } lru[NR_LRU_LISTS];
 
        struct zone_reclaim_stat reclaim_stat;
index a7bc6e7b43a7c429b9e4993933a900057034cf77..505f20dcc1c7bcc4c19aab80e7d1353c5970b4c4 100644 (file)
@@ -697,4 +697,21 @@ static inline void module_remove_modinfo_attrs(struct module *mod)
 
 #define __MODULE_STRING(x) __stringify(x)
 
+
+#ifdef CONFIG_GENERIC_BUG
+int  module_bug_finalize(const Elf_Ehdr *, const Elf_Shdr *,
+                        struct module *);
+void module_bug_cleanup(struct module *);
+
+#else  /* !CONFIG_GENERIC_BUG */
+
+static inline int  module_bug_finalize(const Elf_Ehdr *hdr,
+                                       const Elf_Shdr *sechdrs,
+                                       struct module *mod)
+{
+       return 0;
+}
+static inline void module_bug_cleanup(struct module *mod) {}
+#endif /* CONFIG_GENERIC_BUG */
+
 #endif /* _LINUX_MODULE_H */
index 52b1a76c1b431520773888b0861d5a61163d408f..d47beef08dfdd59374c9d4b41309d99ba9682fd0 100644 (file)
@@ -3,8 +3,23 @@
 
 #include <linux/init.h>
 
-/* unicode character */
-typedef __u16 wchar_t;
+/* Unicode has changed over the years.  Unicode code points no longer
+ * fit into 16 bits; as of Unicode 5 valid code points range from 0
+ * to 0x10ffff (17 planes, where each plane holds 65536 code points).
+ *
+ * The original decision to represent Unicode characters as 16-bit
+ * wchar_t values is now outdated.  But plane 0 still includes the
+ * most commonly used characters, so we will retain it.  The newer
+ * 32-bit unicode_t type can be used when it is necessary to
+ * represent the full Unicode character set.
+ */
+
+/* Plane-0 Unicode character */
+typedef u16 wchar_t;
+#define MAX_WCHAR_T    0xffff
+
+/* Arbitrary Unicode character */
+typedef u32 unicode_t;
 
 struct nls_table {
        const char *charset;
@@ -21,6 +36,13 @@ struct nls_table {
 /* this value hold the maximum octet of charset */
 #define NLS_MAX_CHARSET_SIZE 6 /* for UTF-8 */
 
+/* Byte order for UTF-16 strings */
+enum utf16_endian {
+       UTF16_HOST_ENDIAN,
+       UTF16_LITTLE_ENDIAN,
+       UTF16_BIG_ENDIAN
+};
+
 /* nls.c */
 extern int register_nls(struct nls_table *);
 extern int unregister_nls(struct nls_table *);
@@ -28,10 +50,11 @@ extern struct nls_table *load_nls(char *);
 extern void unload_nls(struct nls_table *);
 extern struct nls_table *load_nls_default(void);
 
-extern int utf8_mbtowc(wchar_t *, const __u8 *, int);
-extern int utf8_mbstowcs(wchar_t *, const __u8 *, int);
-extern int utf8_wctomb(__u8 *, wchar_t, int);
-extern int utf8_wcstombs(__u8 *, const wchar_t *, int);
+extern int utf8_to_utf32(const u8 *s, int len, unicode_t *pu);
+extern int utf32_to_utf8(unicode_t u, u8 *s, int maxlen);
+extern int utf8s_to_utf16s(const u8 *s, int len, wchar_t *pwcs);
+extern int utf16s_to_utf8s(const wchar_t *pwcs, int len,
+               enum utf16_endian endian, u8 *s, int maxlen);
 
 static inline unsigned char nls_tolower(struct nls_table *t, unsigned char c)
 {
index 848025cd708783795c96a35c08a6176d0fe84a9f..829b94b156f28ec0ed7c0d8dbc2dfeab4ea6825b 100644 (file)
@@ -408,6 +408,19 @@ static inline int num_node_state(enum node_states state)
 #define next_online_node(nid)  next_node((nid), node_states[N_ONLINE])
 
 extern int nr_node_ids;
+extern int nr_online_nodes;
+
+static inline void node_set_online(int nid)
+{
+       node_set_state(nid, N_ONLINE);
+       nr_online_nodes = num_node_state(N_ONLINE);
+}
+
+static inline void node_set_offline(int nid)
+{
+       node_clear_state(nid, N_ONLINE);
+       nr_online_nodes = num_node_state(N_ONLINE);
+}
 #else
 
 static inline int node_state(int node, enum node_states state)
@@ -434,7 +447,10 @@ static inline int num_node_state(enum node_states state)
 #define first_online_node      0
 #define next_online_node(nid)  (MAX_NUMNODES)
 #define nr_node_ids            1
+#define nr_online_nodes                1
 
+#define node_set_online(node)     node_set_state((node), N_ONLINE)
+#define node_set_offline(node)    node_clear_state((node), N_ONLINE)
 #endif
 
 #define node_online_map        node_states[N_ONLINE]
@@ -454,9 +470,6 @@ static inline int num_node_state(enum node_states state)
 #define node_online(node)      node_state((node), N_ONLINE)
 #define node_possible(node)    node_state((node), N_POSSIBLE)
 
-#define node_set_online(node)     node_set_state((node), N_ONLINE)
-#define node_set_offline(node)    node_clear_state((node), N_ONLINE)
-
 #define for_each_node(node)       for_each_node_state(node, N_POSSIBLE)
 #define for_each_online_node(node) for_each_node_state(node, N_ONLINE)
 
index 62214c7d2d939e734352bf888e058001e44ccc30..d6792f88a1769c0ece3dbf7084fb6c8072a150b4 100644 (file)
@@ -95,9 +95,7 @@ enum pageflags {
        PG_reclaim,             /* To be reclaimed asap */
        PG_buddy,               /* Page is free, on buddy lists */
        PG_swapbacked,          /* Page is backed by RAM/swap */
-#ifdef CONFIG_UNEVICTABLE_LRU
        PG_unevictable,         /* Page is "unevictable"  */
-#endif
 #ifdef CONFIG_HAVE_MLOCKED_PAGE_BIT
        PG_mlocked,             /* Page is vma mlocked */
 #endif
@@ -248,14 +246,8 @@ PAGEFLAG_FALSE(SwapCache)
        SETPAGEFLAG_NOOP(SwapCache) CLEARPAGEFLAG_NOOP(SwapCache)
 #endif
 
-#ifdef CONFIG_UNEVICTABLE_LRU
 PAGEFLAG(Unevictable, unevictable) __CLEARPAGEFLAG(Unevictable, unevictable)
        TESTCLEARFLAG(Unevictable, unevictable)
-#else
-PAGEFLAG_FALSE(Unevictable) TESTCLEARFLAG_FALSE(Unevictable)
-       SETPAGEFLAG_NOOP(Unevictable) CLEARPAGEFLAG_NOOP(Unevictable)
-       __CLEARPAGEFLAG_NOOP(Unevictable)
-#endif
 
 #ifdef CONFIG_HAVE_MLOCKED_PAGE_BIT
 #define MLOCK_PAGES 1
@@ -382,12 +374,6 @@ static inline void __ClearPageTail(struct page *page)
 
 #endif /* !PAGEFLAGS_EXTENDED */
 
-#ifdef CONFIG_UNEVICTABLE_LRU
-#define __PG_UNEVICTABLE       (1 << PG_unevictable)
-#else
-#define __PG_UNEVICTABLE       0
-#endif
-
 #ifdef CONFIG_HAVE_MLOCKED_PAGE_BIT
 #define __PG_MLOCKED           (1 << PG_mlocked)
 #else
@@ -403,7 +389,7 @@ static inline void __ClearPageTail(struct page *page)
         1 << PG_private | 1 << PG_private_2 | \
         1 << PG_buddy   | 1 << PG_writeback | 1 << PG_reserved | \
         1 << PG_slab    | 1 << PG_swapcache | 1 << PG_active | \
-        __PG_UNEVICTABLE | __PG_MLOCKED)
+        1 << PG_unevictable | __PG_MLOCKED)
 
 /*
  * Flags checked when a page is prepped for return by the page allocator.
index 34da5230faab4617cfe9bba4c43ac83cc083ab12..aec3252afcf5f4f48df2bedc9f3747f62a241bc5 100644 (file)
@@ -22,9 +22,7 @@ enum mapping_flags {
        AS_EIO          = __GFP_BITS_SHIFT + 0, /* IO error on async write */
        AS_ENOSPC       = __GFP_BITS_SHIFT + 1, /* ENOSPC on async write */
        AS_MM_ALL_LOCKS = __GFP_BITS_SHIFT + 2, /* under mm_take_all_locks() */
-#ifdef CONFIG_UNEVICTABLE_LRU
        AS_UNEVICTABLE  = __GFP_BITS_SHIFT + 3, /* e.g., ramdisk, SHM_LOCK */
-#endif
 };
 
 static inline void mapping_set_error(struct address_space *mapping, int error)
@@ -37,8 +35,6 @@ static inline void mapping_set_error(struct address_space *mapping, int error)
        }
 }
 
-#ifdef CONFIG_UNEVICTABLE_LRU
-
 static inline void mapping_set_unevictable(struct address_space *mapping)
 {
        set_bit(AS_UNEVICTABLE, &mapping->flags);
@@ -55,14 +51,6 @@ static inline int mapping_unevictable(struct address_space *mapping)
                return test_bit(AS_UNEVICTABLE, &mapping->flags);
        return !!mapping;
 }
-#else
-static inline void mapping_set_unevictable(struct address_space *mapping) { }
-static inline void mapping_clear_unevictable(struct address_space *mapping) { }
-static inline int mapping_unevictable(struct address_space *mapping)
-{
-       return 0;
-}
-#endif
 
 static inline gfp_t mapping_gfp_mask(struct address_space * mapping)
 {
index 72698d89e767c76909fb0b4cdb65f292c93e0b76..8e366bb0705fc5e4c386d5dea5b2a71f0bbeb58e 100644 (file)
@@ -124,6 +124,14 @@ typedef int __bitwise pci_power_t;
 #define PCI_UNKNOWN    ((pci_power_t __force) 5)
 #define PCI_POWER_ERROR        ((pci_power_t __force) -1)
 
+/* Remember to update this when the list above changes! */
+extern const char *pci_power_names[];
+
+static inline const char *pci_power_name(pci_power_t state)
+{
+       return pci_power_names[1 + (int) state];
+}
+
 #define PCI_PM_D2_DELAY        200
 #define PCI_PM_D3_WAIT 10
 #define PCI_PM_BUS_WAIT        50
index aa01d38c9971a745feec8bb70b0fa93392dcc08e..a3b0003657955da3651542059572387fda381308 100644 (file)
 #define PCI_CLASS_SERIAL_USB_UHCI      0x0c0300
 #define PCI_CLASS_SERIAL_USB_OHCI      0x0c0310
 #define PCI_CLASS_SERIAL_USB_EHCI      0x0c0320
+#define PCI_CLASS_SERIAL_USB_XHCI      0x0c0330
 #define PCI_CLASS_SERIAL_FIBER         0x0c04
 #define PCI_CLASS_SERIAL_SMBUS         0x0c05
 
index b67bb5d7b2211208da085524a1e2cdf2fdb41c00..8dc5123b63057f3e16ca400847477282a993e892 100644 (file)
@@ -36,8 +36,8 @@ extern struct device platform_bus;
 
 extern struct resource *platform_get_resource(struct platform_device *, unsigned int, unsigned int);
 extern int platform_get_irq(struct platform_device *, unsigned int);
-extern struct resource *platform_get_resource_byname(struct platform_device *, unsigned int, char *);
-extern int platform_get_irq_byname(struct platform_device *, char *);
+extern struct resource *platform_get_resource_byname(struct platform_device *, unsigned int, const char *);
+extern int platform_get_irq_byname(struct platform_device *, const char *);
 extern int platform_add_devices(struct platform_device **, int);
 
 extern struct platform_device *platform_device_register_simple(const char *, int id,
index 8c24ef8d99769520e737f2735bbf9dc8f1931db7..fa287f25138dc2a243e27825f92d670b210a4b6b 100644 (file)
@@ -32,6 +32,7 @@ typedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, struct poll_
 
 typedef struct poll_table_struct {
        poll_queue_proc qproc;
+       unsigned long key;
 } poll_table;
 
 static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
@@ -43,10 +44,12 @@ static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_addres
 static inline void init_poll_funcptr(poll_table *pt, poll_queue_proc qproc)
 {
        pt->qproc = qproc;
+       pt->key   = ~0UL; /* all events enabled */
 }
 
 struct poll_table_entry {
        struct file *filp;
+       unsigned long key;
        wait_queue_t wait;
        wait_queue_head_t *wait_address;
 };
index 355f6e80db0d3e8afd4de9d4bcf447ec4e637ea3..c5da7491809655fde7650c0ba65753988b41c4ab 100644 (file)
@@ -167,6 +167,8 @@ radix_tree_gang_lookup_slot(struct radix_tree_root *root, void ***results,
                        unsigned long first_index, unsigned int max_items);
 unsigned long radix_tree_next_hole(struct radix_tree_root *root,
                                unsigned long index, unsigned long max_scan);
+unsigned long radix_tree_prev_hole(struct radix_tree_root *root,
+                               unsigned long index, unsigned long max_scan);
 int radix_tree_preload(gfp_t gfp_mask);
 void radix_tree_init(void);
 void *radix_tree_tag_set(struct radix_tree_root *root,
index 8670f1575fe19abe7793b700aa70d525080c83bf..29f8599e6bea0db5ef5e963511925138a06b2ad1 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _LINUX_RING_BUFFER_H
 #define _LINUX_RING_BUFFER_H
 
+#include <linux/kmemcheck.h>
 #include <linux/mm.h>
 #include <linux/seq_file.h>
 
@@ -11,7 +12,10 @@ struct ring_buffer_iter;
  * Don't refer to this struct directly, use functions below.
  */
 struct ring_buffer_event {
+       kmemcheck_bitfield_begin(bitfield);
        u32             type_len:5, time_delta:27;
+       kmemcheck_bitfield_end(bitfield);
+
        u32             array[];
 };
 
index b35bc0e19cd9a69ee1bedc7e2e98253b40a486be..216d024f830d2f272d4b38a768819c00bc7239d1 100644 (file)
@@ -83,7 +83,8 @@ static inline void page_dup_rmap(struct page *page, struct vm_area_struct *vma,
 /*
  * Called from mm/vmscan.c to handle paging out
  */
-int page_referenced(struct page *, int is_locked, struct mem_cgroup *cnt);
+int page_referenced(struct page *, int is_locked,
+                       struct mem_cgroup *cnt, unsigned long *vm_flags);
 int try_to_unmap(struct page *, int ignore_refs);
 
 /*
@@ -105,18 +106,11 @@ unsigned long page_address_in_vma(struct page *, struct vm_area_struct *);
  */
 int page_mkclean(struct page *);
 
-#ifdef CONFIG_UNEVICTABLE_LRU
 /*
  * called in munlock()/munmap() path to check for other vmas holding
  * the page mlocked.
  */
 int try_to_munlock(struct page *);
-#else
-static inline int try_to_munlock(struct page *page)
-{
-       return 0;       /* a.k.a. SWAP_SUCCESS */
-}
-#endif
 
 #else  /* !CONFIG_MMU */
 
@@ -124,7 +118,7 @@ static inline int try_to_munlock(struct page *page)
 #define anon_vma_prepare(vma)  (0)
 #define anon_vma_link(vma)     do {} while (0)
 
-#define page_referenced(page,l,cnt) TestClearPageReferenced(page)
+#define page_referenced(page, locked, cnt, flags) TestClearPageReferenced(page)
 #define try_to_unmap(page, refs) SWAP_FAIL
 
 static inline int page_mkclean(struct page *page)
index c900aa530070d7c08ad4a0851e684ac6931c98b9..02042e7f21965c3e7b4bbf43f8b5e996076f6f4f 100644 (file)
@@ -674,7 +674,7 @@ struct user_struct {
        struct task_group *tg;
 #ifdef CONFIG_SYSFS
        struct kobject kobj;
-       struct work_struct work;
+       struct delayed_work work;
 #endif
 #endif
 
@@ -1178,7 +1178,6 @@ struct task_struct {
         * a short time
         */
        unsigned char fpu_counter;
-       s8 oomkilladj; /* OOM kill score adjustment (bit shift). */
 #ifdef CONFIG_BLK_DEV_IO_TRACE
        unsigned int btrace_seq;
 #endif
@@ -1318,7 +1317,8 @@ struct task_struct {
 /* Thread group tracking */
        u32 parent_exec_id;
        u32 self_exec_id;
-/* Protection of (de-)allocation: mm, files, fs, tty, keyrings */
+/* Protection of (de-)allocation: mm, files, fs, tty, keyrings, mems_allowed,
+ * mempolicy */
        spinlock_t alloc_lock;
 
 #ifdef CONFIG_GENERIC_HARDIRQS
@@ -1386,8 +1386,7 @@ struct task_struct {
        cputime_t acct_timexpd; /* stime + utime since last update */
 #endif
 #ifdef CONFIG_CPUSETS
-       nodemask_t mems_allowed;
-       int cpuset_mems_generation;
+       nodemask_t mems_allowed;        /* Protected by alloc_lock */
        int cpuset_mem_spread_rotor;
 #endif
 #ifdef CONFIG_CGROUPS
@@ -1410,7 +1409,7 @@ struct task_struct {
        struct list_head perf_counter_list;
 #endif
 #ifdef CONFIG_NUMA
-       struct mempolicy *mempolicy;
+       struct mempolicy *mempolicy;    /* Protected by alloc_lock */
        short il_next;
 #endif
        atomic_t fs_excl;       /* holding fs exclusive resources */
index fa51293f270811832b97e8f660f979ae14e0bc44..63ef24bc01d0eb728ab2ff3d7544b6c8380c8fcf 100644 (file)
@@ -15,6 +15,7 @@
 #define _LINUX_SKBUFF_H
 
 #include <linux/kernel.h>
+#include <linux/kmemcheck.h>
 #include <linux/compiler.h>
 #include <linux/time.h>
 #include <linux/cache.h>
@@ -343,6 +344,7 @@ struct sk_buff {
                };
        };
        __u32                   priority;
+       kmemcheck_bitfield_begin(flags1);
        __u8                    local_df:1,
                                cloned:1,
                                ip_summed:2,
@@ -353,6 +355,7 @@ struct sk_buff {
                                ipvs_property:1,
                                peeked:1,
                                nf_trace:1;
+       kmemcheck_bitfield_end(flags1);
        __be16                  protocol;
 
        void                    (*destructor)(struct sk_buff *skb);
@@ -372,12 +375,16 @@ struct sk_buff {
        __u16                   tc_verd;        /* traffic control verdict */
 #endif
 #endif
+
+       kmemcheck_bitfield_begin(flags2);
 #ifdef CONFIG_IPV6_NDISC_NODETYPE
        __u8                    ndisc_nodetype:2;
 #endif
 #if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE)
        __u8                    do_not_encrypt:1;
 #endif
+       kmemcheck_bitfield_end(flags2);
+
        /* 0/13/14 bit hole */
 
 #ifdef CONFIG_NET_DMA
index 219b8fb4651dd1b15d4c2fe9296c01fef9e2b1e2..2da8372519f5e96a32027a9be8b0efc66f35b907 100644 (file)
 
 #define SLAB_NOLEAKTRACE       0x00800000UL    /* Avoid kmemleak tracing */
 
+/* Don't track use of uninitialized memory */
+#ifdef CONFIG_KMEMCHECK
+# define SLAB_NOTRACK          0x01000000UL
+#else
+# define SLAB_NOTRACK          0x00000000UL
+#endif
+
 /* The following flags affect the page allocator grouping pages by mobility */
 #define SLAB_RECLAIM_ACCOUNT   0x00020000UL            /* Objects are reclaimable */
 #define SLAB_TEMPORARY         SLAB_RECLAIM_ACCOUNT    /* Objects are short-lived */
index 713f841ecaa914e74aead8e4d8ff5d74cb5040d3..850d057500dece3f52497b2bed3aab51dd677852 100644 (file)
 #include <linux/compiler.h>
 #include <linux/kmemtrace.h>
 
+/*
+ * struct kmem_cache
+ *
+ * manages a cache.
+ */
+
+struct kmem_cache {
+/* 1) per-cpu data, touched during every alloc/free */
+       struct array_cache *array[NR_CPUS];
+/* 2) Cache tunables. Protected by cache_chain_mutex */
+       unsigned int batchcount;
+       unsigned int limit;
+       unsigned int shared;
+
+       unsigned int buffer_size;
+       u32 reciprocal_buffer_size;
+/* 3) touched by every alloc & free from the backend */
+
+       unsigned int flags;             /* constant flags */
+       unsigned int num;               /* # of objs per slab */
+
+/* 4) cache_grow/shrink */
+       /* order of pgs per slab (2^n) */
+       unsigned int gfporder;
+
+       /* force GFP flags, e.g. GFP_DMA */
+       gfp_t gfpflags;
+
+       size_t colour;                  /* cache colouring range */
+       unsigned int colour_off;        /* colour offset */
+       struct kmem_cache *slabp_cache;
+       unsigned int slab_size;
+       unsigned int dflags;            /* dynamic flags */
+
+       /* constructor func */
+       void (*ctor)(void *obj);
+
+/* 5) cache creation/removal */
+       const char *name;
+       struct list_head next;
+
+/* 6) statistics */
+#ifdef CONFIG_DEBUG_SLAB
+       unsigned long num_active;
+       unsigned long num_allocations;
+       unsigned long high_mark;
+       unsigned long grown;
+       unsigned long reaped;
+       unsigned long errors;
+       unsigned long max_freeable;
+       unsigned long node_allocs;
+       unsigned long node_frees;
+       unsigned long node_overflow;
+       atomic_t allochit;
+       atomic_t allocmiss;
+       atomic_t freehit;
+       atomic_t freemiss;
+
+       /*
+        * If debugging is enabled, then the allocator can add additional
+        * fields and/or padding to every object. buffer_size contains the total
+        * object size including these internal fields, the following two
+        * variables contain the offset to the user object and its size.
+        */
+       int obj_offset;
+       int obj_size;
+#endif /* CONFIG_DEBUG_SLAB */
+
+       /*
+        * We put nodelists[] at the end of kmem_cache, because we want to size
+        * this array to nr_node_ids slots instead of MAX_NUMNODES
+        * (see kmem_cache_init())
+        * We still use [MAX_NUMNODES] and not [1] or [0] because cache_cache
+        * is statically defined, so we reserve the max number of nodes.
+        */
+       struct kmem_list3 *nodelists[MAX_NUMNODES];
+       /*
+        * Do not add fields after nodelists[]
+        */
+};
+
 /* Size description struct for general caches. */
 struct cache_sizes {
        size_t                  cs_size;
index a69db820eed6b33bfe71e6f946536209dd935372..9e3d8af09207c9ec5ecf58dbb6c0034200947158 100644 (file)
@@ -177,7 +177,6 @@ static inline void init_call_single_data(void)
 
 #define get_cpu()              ({ preempt_disable(); smp_processor_id(); })
 #define put_cpu()              preempt_enable()
-#define put_cpu_no_resched()   preempt_enable_no_resched()
 
 /*
  * Callback to arch code if there's nosmp or maxcpus=0 on the
index 1a8cecc4f38cd2b91a90f267a54fd39bb4de196b..51efbef38fb0e204cfddb61b56619d52cefab623 100644 (file)
@@ -4,6 +4,8 @@
 struct task_struct;
 
 #ifdef CONFIG_STACKTRACE
+struct task_struct;
+
 struct stack_trace {
        unsigned int nr_entries, max_entries;
        unsigned long *entries;
@@ -11,6 +13,7 @@ struct stack_trace {
 };
 
 extern void save_stack_trace(struct stack_trace *trace);
+extern void save_stack_trace_bp(struct stack_trace *trace, unsigned long bp);
 extern void save_stack_trace_tsk(struct task_struct *tsk,
                                struct stack_trace *trace);
 
index d476aad3ff577faf4fe7883dc7b33a3aea99b38a..0cedf31af0b0ed4cd230c2eb9cc2cf1a8c5e95af 100644 (file)
@@ -129,9 +129,10 @@ enum {
 
 #define SWAP_CLUSTER_MAX 32
 
-#define SWAP_MAP_MAX   0x7fff
-#define SWAP_MAP_BAD   0x8000
-
+#define SWAP_MAP_MAX   0x7ffe
+#define SWAP_MAP_BAD   0x7fff
+#define SWAP_HAS_CACHE  0x8000         /* There is a swap cache of entry. */
+#define SWAP_COUNT_MASK (~SWAP_HAS_CACHE)
 /*
  * The in-memory structure used to track swap areas.
  */
@@ -235,7 +236,6 @@ static inline int zone_reclaim(struct zone *z, gfp_t mask, unsigned int order)
 }
 #endif
 
-#ifdef CONFIG_UNEVICTABLE_LRU
 extern int page_evictable(struct page *page, struct vm_area_struct *vma);
 extern void scan_mapping_unevictable_pages(struct address_space *);
 
@@ -244,24 +244,6 @@ extern int scan_unevictable_handler(struct ctl_table *, int, struct file *,
                                        void __user *, size_t *, loff_t *);
 extern int scan_unevictable_register_node(struct node *node);
 extern void scan_unevictable_unregister_node(struct node *node);
-#else
-static inline int page_evictable(struct page *page,
-                                               struct vm_area_struct *vma)
-{
-       return 1;
-}
-
-static inline void scan_mapping_unevictable_pages(struct address_space *mapping)
-{
-}
-
-static inline int scan_unevictable_register_node(struct node *node)
-{
-       return 0;
-}
-
-static inline void scan_unevictable_unregister_node(struct node *node) { }
-#endif
 
 extern int kswapd_run(int nid);
 
@@ -274,7 +256,7 @@ extern void swap_unplug_io_fn(struct backing_dev_info *, struct page *);
 
 #ifdef CONFIG_SWAP
 /* linux/mm/page_io.c */
-extern int swap_readpage(struct file *, struct page *);
+extern int swap_readpage(struct page *);
 extern int swap_writepage(struct page *page, struct writeback_control *wbc);
 extern void end_swap_bio_read(struct bio *bio, int err);
 
@@ -300,9 +282,11 @@ extern long total_swap_pages;
 extern void si_swapinfo(struct sysinfo *);
 extern swp_entry_t get_swap_page(void);
 extern swp_entry_t get_swap_page_of_type(int);
-extern int swap_duplicate(swp_entry_t);
+extern void swap_duplicate(swp_entry_t);
+extern int swapcache_prepare(swp_entry_t);
 extern int valid_swaphandles(swp_entry_t, unsigned long *);
 extern void swap_free(swp_entry_t);
+extern void swapcache_free(swp_entry_t, struct page *page);
 extern int free_swap_and_cache(swp_entry_t);
 extern int swap_type_of(dev_t, sector_t, struct block_device **);
 extern unsigned int count_swap_pages(int, int);
@@ -370,12 +354,20 @@ static inline void show_swap_cache_info(void)
 }
 
 #define free_swap_and_cache(swp)       is_migration_entry(swp)
-#define swap_duplicate(swp)            is_migration_entry(swp)
+#define swapcache_prepare(swp)         is_migration_entry(swp)
+
+static inline void swap_duplicate(swp_entry_t swp)
+{
+}
 
 static inline void swap_free(swp_entry_t swp)
 {
 }
 
+static inline void swapcache_free(swp_entry_t swp, struct page *page)
+{
+}
+
 static inline struct page *swapin_readahead(swp_entry_t swp, gfp_t gfp_mask,
                        struct vm_area_struct *vma, unsigned long addr)
 {
index 418d90f5effe72ff9921a6ea066bb526a7337127..fa4242cdade86f9b956c949b5253e965e7aa74c9 100644 (file)
@@ -434,6 +434,7 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg);
 asmlinkage long sys_fcntl64(unsigned int fd,
                                unsigned int cmd, unsigned long arg);
 #endif
+asmlinkage long sys_pipe(int __user *fildes);
 asmlinkage long sys_pipe2(int __user *fildes, int flags);
 asmlinkage long sys_dup(unsigned int fildes);
 asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd);
@@ -751,8 +752,6 @@ asmlinkage long sys_pselect6(int, fd_set __user *, fd_set __user *,
 asmlinkage long sys_ppoll(struct pollfd __user *, unsigned int,
                          struct timespec __user *, const sigset_t __user *,
                          size_t);
-asmlinkage long sys_pipe2(int __user *, int);
-asmlinkage long sys_pipe(int __user *);
 
 int kernel_execve(const char *filename, char *const argv[], char *const envp[]);
 
index 9910e3bd5b316918466359ca20ae3a88914892bd..e6967d10d9e5ea39f77efecca64c59beb9d009d5 100644 (file)
@@ -280,6 +280,9 @@ extern int do_adjtimex(struct timex *);
 
 int read_current_timer(unsigned long *timer_val);
 
+/* The clock frequency of the i8253/i8254 PIT */
+#define PIT_TICK_RATE 1193182ul
+
 #endif /* KERNEL */
 
 #endif /* LINUX_TIMEX_H */
index 14df7e635d439e07d438e9890f0c8f718fa2aa15..b9dc4ca0246f1b802983e7a672d0093601f6d587 100644 (file)
@@ -198,7 +198,7 @@ static inline void tracepoint_synchronize_unregister(void)
  *     * This is how the trace record is structured and will
  *     * be saved into the ring buffer. These are the fields
  *     * that will be exposed to user-space in
- *     * /debug/tracing/events/<*>/format.
+ *     * /sys/kernel/debug/tracing/events/<*>/format.
  *     *
  *     * The declared 'local variable' is called '__entry'
  *     *
@@ -258,7 +258,7 @@ static inline void tracepoint_synchronize_unregister(void)
  * tracepoint callback (this is used by programmatic plugins and
  * can also by used by generic instrumentation like SystemTap), and
  * it is also used to expose a structured trace record in
- * /debug/tracing/events/.
+ * /sys/kernel/debug/tracing/events/.
  */
 
 #define TRACE_EVENT(name, proto, args, struct, assign, print)  \
index 3aa2cd1f8d082fd699a5fcfb672e2dd555ea7dcc..84929e9140341583cbc8fd7050c4e5e5a12b8d29 100644 (file)
@@ -36,6 +36,7 @@ struct wusb_dev;
  *  - configs have one (often) or more interfaces;
  *  - interfaces have one (usually) or more settings;
  *  - each interface setting has zero or (usually) more endpoints.
+ *  - a SuperSpeed endpoint has a companion descriptor
  *
  * And there might be other descriptors mixed in with those.
  *
@@ -44,6 +45,19 @@ struct wusb_dev;
 
 struct ep_device;
 
+/* For SS devices */
+/**
+ * struct usb_host_ss_ep_comp - Valid for SuperSpeed devices only
+ * @desc: endpoint companion descriptor, wMaxPacketSize in native byteorder
+ * @extra: descriptors following this endpoint companion descriptor
+ * @extralen: how many bytes of "extra" are valid
+ */
+struct usb_host_ss_ep_comp {
+       struct usb_ss_ep_comp_descriptor        desc;
+       unsigned char                           *extra;   /* Extra descriptors */
+       int                                     extralen;
+};
+
 /**
  * struct usb_host_endpoint - host-side endpoint descriptor and queue
  * @desc: descriptor for this endpoint, wMaxPacketSize in native byteorder
@@ -51,6 +65,7 @@ struct ep_device;
  * @hcpriv: for use by HCD; typically holds hardware dma queue head (QH)
  *     with one or more transfer descriptors (TDs) per urb
  * @ep_dev: ep_device for sysfs info
+ * @ss_ep_comp: companion descriptor information for this endpoint
  * @extra: descriptors following this endpoint in the configuration
  * @extralen: how many bytes of "extra" are valid
  * @enabled: URBs may be submitted to this endpoint
@@ -63,6 +78,7 @@ struct usb_host_endpoint {
        struct list_head                urb_list;
        void                            *hcpriv;
        struct ep_device                *ep_dev;        /* For sysfs info */
+       struct usb_host_ss_ep_comp      *ss_ep_comp;    /* For SS devices */
 
        unsigned char *extra;   /* Extra descriptors */
        int extralen;
@@ -336,7 +352,6 @@ struct usb_bus {
 #ifdef CONFIG_USB_DEVICEFS
        struct dentry *usbfs_dentry;    /* usbfs dentry entry for the bus */
 #endif
-       struct device *dev;             /* device for this bus */
 
 #if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
        struct mon_bus *mon_bus;        /* non-null when associated */
@@ -363,6 +378,7 @@ struct usb_tt;
  * struct usb_device - kernel's representation of a USB device
  * @devnum: device number; address on a USB bus
  * @devpath: device ID string for use in messages (e.g., /port/...)
+ * @route: tree topology hex string for use with xHCI
  * @state: device state: configured, not attached, etc.
  * @speed: device speed: high/full/low (or error)
  * @tt: Transaction Translator info; used with low/full speed dev, highspeed hub
@@ -420,6 +436,7 @@ struct usb_tt;
  * @skip_sys_resume: skip the next system resume
  * @wusb_dev: if this is a Wireless USB device, link to the WUSB
  *     specific data for the device.
+ * @slot_id: Slot ID assigned by xHCI
  *
  * Notes:
  * Usbcore drivers should not set usbdev->state directly.  Instead use
@@ -428,6 +445,7 @@ struct usb_tt;
 struct usb_device {
        int             devnum;
        char            devpath [16];
+       u32             route;
        enum usb_device_state   state;
        enum usb_device_speed   speed;
 
@@ -503,6 +521,7 @@ struct usb_device {
        unsigned skip_sys_resume:1;
 #endif
        struct wusb_dev *wusb_dev;
+       int slot_id;
 };
 #define        to_usb_device(d) container_of(d, struct usb_device, dev)
 
@@ -869,6 +888,8 @@ struct usb_driver {
  * struct usb_device_driver - identifies USB device driver to usbcore
  * @name: The driver name should be unique among USB drivers,
  *     and should normally be the same as the module name.
+ * @nodename: Callback to provide a naming hint for a possible
+ *     device node to create.
  * @probe: Called to see if the driver is willing to manage a particular
  *     device.  If it is, probe returns zero and uses dev_set_drvdata()
  *     to associate driver-specific data with the device.  If unwilling
@@ -912,6 +933,7 @@ extern struct bus_type usb_bus_type;
  */
 struct usb_class_driver {
        char *name;
+       char *(*nodename)(struct device *dev);
        const struct file_operations *fops;
        int minor_base;
 };
@@ -1041,7 +1063,9 @@ typedef void (*usb_complete_t)(struct urb *);
  * @setup_dma: For control transfers with URB_NO_SETUP_DMA_MAP set, the
  *     device driver has provided this DMA address for the setup packet.
  *     The host controller driver should use this in preference to
- *     setup_packet.
+ *     setup_packet, but the HCD may chose to ignore the address if it must
+ *     copy the setup packet into internal structures.  Therefore, setup_packet
+ *     must always point to a valid buffer.
  * @start_frame: Returns the initial frame for isochronous transfers.
  * @number_of_packets: Lists the number of ISO transfer buffers.
  * @interval: Specifies the polling interval for interrupt or isochronous
@@ -1177,6 +1201,8 @@ struct urb {
        unsigned int transfer_flags;    /* (in) URB_SHORT_NOT_OK | ...*/
        void *transfer_buffer;          /* (in) associated data buffer */
        dma_addr_t transfer_dma;        /* (in) dma addr for transfer_buffer */
+       struct usb_sg_request *sg;      /* (in) scatter gather buffer list */
+       int num_sgs;                    /* (in) number of entries in the sg list */
        u32 transfer_buffer_length;     /* (in) data buffer length */
        u32 actual_length;              /* (return) actual transfer length */
        unsigned char *setup_packet;    /* (in) setup packet (control only) */
@@ -1422,8 +1448,8 @@ struct usb_sg_request {
        int                     status;
        size_t                  bytes;
 
-       /*
-        * members below are private: to usbcore,
+       /* private:
+        * members below are private to usbcore,
         * and are not provided for driver access!
         */
        spinlock_t              lock;
@@ -1558,6 +1584,9 @@ extern void usb_unregister_notify(struct notifier_block *nb);
 #define err(format, arg...) printk(KERN_ERR KBUILD_MODNAME ": " \
        format "\n" , ## arg)
 
+/* debugfs stuff */
+extern struct dentry *usb_debug_root;
+
 #endif  /* __KERNEL__ */
 
 #endif
index 8cb025fef6346a63270cd55a8de69b3b93a49006..b5744bc218ab576b7671602a643decc6bf508542 100644 (file)
 #define USB_SUBCLASS_AUDIOCONTROL      0x01
 #define USB_SUBCLASS_AUDIOSTREAMING    0x02
 #define USB_SUBCLASS_MIDISTREAMING     0x03
+#define USB_SUBCLASS_VENDOR_SPEC       0xff
 
+/* A.5 Audio Class-Specific AC interface Descriptor Subtypes*/
+#define HEADER                         0x01
+#define INPUT_TERMINAL                 0x02
+#define OUTPUT_TERMINAL                        0x03
+#define MIXER_UNIT                     0x04
+#define SELECTOR_UNIT                  0x05
+#define FEATURE_UNIT                   0x06
+#define PROCESSING_UNIT                        0x07
+#define EXTENSION_UNIT                 0x08
+
+#define AS_GENERAL                     0x01
+#define FORMAT_TYPE                    0x02
+#define FORMAT_SPECIFIC                        0x03
+
+#define EP_GENERAL                     0x01
+
+#define MS_GENERAL                     0x01
+#define MIDI_IN_JACK                   0x02
+#define MIDI_OUT_JACK                  0x03
+
+/* endpoint attributes */
+#define EP_ATTR_MASK                   0x0c
+#define EP_ATTR_ASYNC                  0x04
+#define EP_ATTR_ADAPTIVE               0x08
+#define EP_ATTR_SYNC                   0x0c
+
+/* cs endpoint attributes */
+#define EP_CS_ATTR_SAMPLE_RATE         0x01
+#define EP_CS_ATTR_PITCH_CONTROL       0x02
+#define EP_CS_ATTR_FILL_MAX            0x80
+
+/* Audio Class specific Request Codes */
+#define USB_AUDIO_SET_INTF             0x21
+#define USB_AUDIO_SET_ENDPOINT         0x22
+#define USB_AUDIO_GET_INTF             0xa1
+#define USB_AUDIO_GET_ENDPOINT         0xa2
+
+#define SET_   0x00
+#define GET_   0x80
+
+#define _CUR   0x1
+#define _MIN   0x2
+#define _MAX   0x3
+#define _RES   0x4
+#define _MEM   0x5
+
+#define SET_CUR                (SET_ | _CUR)
+#define GET_CUR                (GET_ | _CUR)
+#define SET_MIN                (SET_ | _MIN)
+#define GET_MIN                (GET_ | _MIN)
+#define SET_MAX                (SET_ | _MAX)
+#define GET_MAX                (GET_ | _MAX)
+#define SET_RES                (SET_ | _RES)
+#define GET_RES                (GET_ | _RES)
+#define SET_MEM                (SET_ | _MEM)
+#define GET_MEM                (GET_ | _MEM)
+
+#define GET_STAT       0xff
+
+#define USB_AC_TERMINAL_UNDEFINED      0x100
+#define USB_AC_TERMINAL_STREAMING      0x101
+#define USB_AC_TERMINAL_VENDOR_SPEC    0x1FF
+
+/* Terminal Control Selectors */
 /* 4.3.2  Class-Specific AC Interface Descriptor */
 struct usb_ac_header_descriptor {
-       __u8  bLength;                  /* 8+n */
+       __u8  bLength;                  /* 8 + n */
        __u8  bDescriptorType;          /* USB_DT_CS_INTERFACE */
        __u8  bDescriptorSubtype;       /* USB_MS_HEADER */
        __le16 bcdADC;                  /* 0x0100 */
@@ -36,7 +101,7 @@ struct usb_ac_header_descriptor {
        __u8  baInterfaceNr[];          /* [n] */
 } __attribute__ ((packed));
 
-#define USB_DT_AC_HEADER_SIZE(n)       (8+(n))
+#define USB_DT_AC_HEADER_SIZE(n)       (8 + (n))
 
 /* As above, but more useful for defining your own descriptors: */
 #define DECLARE_USB_AC_HEADER_DESCRIPTOR(n)                    \
@@ -50,4 +115,200 @@ struct usb_ac_header_descriptor_##n {                              \
        __u8  baInterfaceNr[n];                                 \
 } __attribute__ ((packed))
 
+/* 4.3.2.1 Input Terminal Descriptor */
+struct usb_input_terminal_descriptor {
+       __u8  bLength;                  /* in bytes: 12 */
+       __u8  bDescriptorType;          /* CS_INTERFACE descriptor type */
+       __u8  bDescriptorSubtype;       /* INPUT_TERMINAL descriptor subtype */
+       __u8  bTerminalID;              /* Constant uniquely terminal ID */
+       __le16 wTerminalType;           /* USB Audio Terminal Types */
+       __u8  bAssocTerminal;           /* ID of the Output Terminal associated */
+       __u8  bNrChannels;              /* Number of logical output channels */
+       __le16 wChannelConfig;
+       __u8  iChannelNames;
+       __u8  iTerminal;
+} __attribute__ ((packed));
+
+#define USB_DT_AC_INPUT_TERMINAL_SIZE                  12
+
+#define USB_AC_INPUT_TERMINAL_UNDEFINED                        0x200
+#define USB_AC_INPUT_TERMINAL_MICROPHONE               0x201
+#define USB_AC_INPUT_TERMINAL_DESKTOP_MICROPHONE       0x202
+#define USB_AC_INPUT_TERMINAL_PERSONAL_MICROPHONE      0x203
+#define USB_AC_INPUT_TERMINAL_OMNI_DIR_MICROPHONE      0x204
+#define USB_AC_INPUT_TERMINAL_MICROPHONE_ARRAY         0x205
+#define USB_AC_INPUT_TERMINAL_PROC_MICROPHONE_ARRAY    0x206
+
+/* 4.3.2.2 Output Terminal Descriptor */
+struct usb_output_terminal_descriptor {
+       __u8  bLength;                  /* in bytes: 9 */
+       __u8  bDescriptorType;          /* CS_INTERFACE descriptor type */
+       __u8  bDescriptorSubtype;       /* OUTPUT_TERMINAL descriptor subtype */
+       __u8  bTerminalID;              /* Constant uniquely terminal ID */
+       __le16 wTerminalType;           /* USB Audio Terminal Types */
+       __u8  bAssocTerminal;           /* ID of the Input Terminal associated */
+       __u8  bSourceID;                /* ID of the connected Unit or Terminal*/
+       __u8  iTerminal;
+} __attribute__ ((packed));
+
+#define USB_DT_AC_OUTPUT_TERMINAL_SIZE                         9
+
+#define USB_AC_OUTPUT_TERMINAL_UNDEFINED                       0x300
+#define USB_AC_OUTPUT_TERMINAL_SPEAKER                         0x301
+#define USB_AC_OUTPUT_TERMINAL_HEADPHONES                      0x302
+#define USB_AC_OUTPUT_TERMINAL_HEAD_MOUNTED_DISPLAY_AUDIO      0x303
+#define USB_AC_OUTPUT_TERMINAL_DESKTOP_SPEAKER                 0x304
+#define USB_AC_OUTPUT_TERMINAL_ROOM_SPEAKER                    0x305
+#define USB_AC_OUTPUT_TERMINAL_COMMUNICATION_SPEAKER           0x306
+#define USB_AC_OUTPUT_TERMINAL_LOW_FREQ_EFFECTS_SPEAKER                0x307
+
+/* Set bControlSize = 2 as default setting */
+#define USB_DT_AC_FEATURE_UNIT_SIZE(ch)                (7 + ((ch) + 1) * 2)
+
+/* As above, but more useful for defining your own descriptors: */
+#define DECLARE_USB_AC_FEATURE_UNIT_DESCRIPTOR(ch)             \
+struct usb_ac_feature_unit_descriptor_##ch {                   \
+       __u8  bLength;                                          \
+       __u8  bDescriptorType;                                  \
+       __u8  bDescriptorSubtype;                               \
+       __u8  bUnitID;                                          \
+       __u8  bSourceID;                                        \
+       __u8  bControlSize;                                     \
+       __le16 bmaControls[ch + 1];                             \
+       __u8  iFeature;                                         \
+} __attribute__ ((packed))
+
+/* 4.5.2 Class-Specific AS Interface Descriptor */
+struct usb_as_header_descriptor {
+       __u8  bLength;                  /* in bytes: 7 */
+       __u8  bDescriptorType;          /* USB_DT_CS_INTERFACE */
+       __u8  bDescriptorSubtype;       /* AS_GENERAL */
+       __u8  bTerminalLink;            /* Terminal ID of connected Terminal */
+       __u8  bDelay;                   /* Delay introduced by the data path */
+       __le16 wFormatTag;              /* The Audio Data Format */
+} __attribute__ ((packed));
+
+#define USB_DT_AS_HEADER_SIZE          7
+
+#define USB_AS_AUDIO_FORMAT_TYPE_I_UNDEFINED   0x0
+#define USB_AS_AUDIO_FORMAT_TYPE_I_PCM         0x1
+#define USB_AS_AUDIO_FORMAT_TYPE_I_PCM8                0x2
+#define USB_AS_AUDIO_FORMAT_TYPE_I_IEEE_FLOAT  0x3
+#define USB_AS_AUDIO_FORMAT_TYPE_I_ALAW                0x4
+#define USB_AS_AUDIO_FORMAT_TYPE_I_MULAW       0x5
+
+struct usb_as_format_type_i_continuous_descriptor {
+       __u8  bLength;                  /* in bytes: 8 + (ns * 3) */
+       __u8  bDescriptorType;          /* USB_DT_CS_INTERFACE */
+       __u8  bDescriptorSubtype;       /* FORMAT_TYPE */
+       __u8  bFormatType;              /* FORMAT_TYPE_1 */
+       __u8  bNrChannels;              /* physical channels in the stream */
+       __u8  bSubframeSize;            /* */
+       __u8  bBitResolution;
+       __u8  bSamFreqType;
+       __u8  tLowerSamFreq[3];
+       __u8  tUpperSamFreq[3];
+} __attribute__ ((packed));
+
+#define USB_AS_FORMAT_TYPE_I_CONTINUOUS_DESC_SIZE      14
+
+struct usb_as_formate_type_i_discrete_descriptor {
+       __u8  bLength;                  /* in bytes: 8 + (ns * 3) */
+       __u8  bDescriptorType;          /* USB_DT_CS_INTERFACE */
+       __u8  bDescriptorSubtype;       /* FORMAT_TYPE */
+       __u8  bFormatType;              /* FORMAT_TYPE_1 */
+       __u8  bNrChannels;              /* physical channels in the stream */
+       __u8  bSubframeSize;            /* */
+       __u8  bBitResolution;
+       __u8  bSamFreqType;
+       __u8  tSamFreq[][3];
+} __attribute__ ((packed));
+
+#define DECLARE_USB_AS_FORMAT_TYPE_I_DISCRETE_DESC(n)          \
+struct usb_as_formate_type_i_discrete_descriptor_##n {         \
+       __u8  bLength;                                          \
+       __u8  bDescriptorType;                                  \
+       __u8  bDescriptorSubtype;                               \
+       __u8  bFormatType;                                      \
+       __u8  bNrChannels;                                      \
+       __u8  bSubframeSize;                                    \
+       __u8  bBitResolution;                                   \
+       __u8  bSamFreqType;                                     \
+       __u8  tSamFreq[n][3];                                   \
+} __attribute__ ((packed))
+
+#define USB_AS_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(n)     (8 + (n * 3))
+
+#define USB_AS_FORMAT_TYPE_UNDEFINED   0x0
+#define USB_AS_FORMAT_TYPE_I           0x1
+#define USB_AS_FORMAT_TYPE_II          0x2
+#define USB_AS_FORMAT_TYPE_III         0x3
+
+#define USB_AS_ENDPOINT_ASYNC          (1 << 2)
+#define USB_AS_ENDPOINT_ADAPTIVE       (2 << 2)
+#define USB_AS_ENDPOINT_SYNC           (3 << 2)
+
+struct usb_as_iso_endpoint_descriptor {
+       __u8  bLength;                  /* in bytes: 7 */
+       __u8  bDescriptorType;          /* USB_DT_CS_ENDPOINT */
+       __u8  bDescriptorSubtype;       /* EP_GENERAL */
+       __u8  bmAttributes;
+       __u8  bLockDelayUnits;
+       __le16 wLockDelay;
+};
+#define USB_AS_ISO_ENDPOINT_DESC_SIZE  7
+
+#define FU_CONTROL_UNDEFINED           0x00
+#define MUTE_CONTROL                   0x01
+#define VOLUME_CONTROL                 0x02
+#define BASS_CONTROL                   0x03
+#define MID_CONTROL                    0x04
+#define TREBLE_CONTROL                 0x05
+#define GRAPHIC_EQUALIZER_CONTROL      0x06
+#define AUTOMATIC_GAIN_CONTROL         0x07
+#define DELAY_CONTROL                  0x08
+#define BASS_BOOST_CONTROL             0x09
+#define LOUDNESS_CONTROL               0x0a
+
+#define FU_MUTE                (1 << (MUTE_CONTROL - 1))
+#define FU_VOLUME      (1 << (VOLUME_CONTROL - 1))
+#define FU_BASS                (1 << (BASS_CONTROL - 1))
+#define FU_MID         (1 << (MID_CONTROL - 1))
+#define FU_TREBLE      (1 << (TREBLE_CONTROL - 1))
+#define FU_GRAPHIC_EQ  (1 << (GRAPHIC_EQUALIZER_CONTROL - 1))
+#define FU_AUTO_GAIN   (1 << (AUTOMATIC_GAIN_CONTROL - 1))
+#define FU_DELAY       (1 << (DELAY_CONTROL - 1))
+#define FU_BASS_BOOST  (1 << (BASS_BOOST_CONTROL - 1))
+#define FU_LOUDNESS    (1 << (LOUDNESS_CONTROL - 1))
+
+struct usb_audio_control {
+       struct list_head list;
+       const char *name;
+       u8 type;
+       int data[5];
+       int (*set)(struct usb_audio_control *con, u8 cmd, int value);
+       int (*get)(struct usb_audio_control *con, u8 cmd);
+};
+
+static inline int generic_set_cmd(struct usb_audio_control *con, u8 cmd, int value)
+{
+       con->data[cmd] = value;
+
+       return 0;
+}
+
+static inline int generic_get_cmd(struct usb_audio_control *con, u8 cmd)
+{
+       return con->data[cmd];
+}
+
+struct usb_audio_control_selector {
+       struct list_head list;
+       struct list_head control;
+       u8 id;
+       const char *name;
+       u8 type;
+       struct usb_descriptor_header *desc;
+};
+
 #endif /* __LINUX_USB_AUDIO_H */
index b145119a90da509b493c3b8d62dfd4e9bb53231e..93223638f702c90513f4ea308c4ed3f2c873c18c 100644 (file)
@@ -191,6 +191,8 @@ struct usb_ctrlrequest {
 #define USB_DT_WIRE_ADAPTER            0x21
 #define USB_DT_RPIPE                   0x22
 #define USB_DT_CS_RADIO_CONTROL                0x23
+/* From the USB 3.0 spec */
+#define        USB_DT_SS_ENDPOINT_COMP         0x30
 
 /* Conventional codes for class-specific descriptors.  The convention is
  * defined in the USB "Common Class" Spec (3.11).  Individual class specs
@@ -535,6 +537,20 @@ static inline int usb_endpoint_is_isoc_out(
 
 /*-------------------------------------------------------------------------*/
 
+/* USB_DT_SS_ENDPOINT_COMP: SuperSpeed Endpoint Companion descriptor */
+struct usb_ss_ep_comp_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __u8  bMaxBurst;
+       __u8  bmAttributes;
+       __u16 wBytesPerInterval;
+} __attribute__ ((packed));
+
+#define USB_DT_SS_EP_COMP_SIZE         6
+
+/*-------------------------------------------------------------------------*/
+
 /* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */
 struct usb_qualifier_descriptor {
        __u8  bLength;
@@ -752,6 +768,7 @@ enum usb_device_speed {
        USB_SPEED_LOW, USB_SPEED_FULL,          /* usb 1.1 */
        USB_SPEED_HIGH,                         /* usb 2.0 */
        USB_SPEED_VARIABLE,                     /* wireless (usb 2.5) */
+       USB_SPEED_SUPER,                        /* usb 3.0 */
 };
 
 enum usb_device_state {
index acd7b0f06c8aa3941ddd5746ac9dbc1ebc701782..4f6bb3d2160e9f8d84516aae44363a662418431a 100644 (file)
@@ -124,6 +124,7 @@ struct usb_function {
        void                    (*suspend)(struct usb_function *);
        void                    (*resume)(struct usb_function *);
 
+       /* private: */
        /* internals */
        struct list_head                list;
 };
@@ -219,6 +220,7 @@ struct usb_configuration {
 
        struct usb_composite_dev        *cdev;
 
+       /* private: */
        /* internals */
        struct list_head        list;
        struct list_head        functions;
@@ -321,6 +323,7 @@ struct usb_composite_dev {
 
        struct usb_configuration        *config;
 
+       /* private: */
        /* internals */
        struct usb_device_descriptor    desc;
        struct list_head                configs;
diff --git a/include/linux/usb/langwell_otg.h b/include/linux/usb/langwell_otg.h
new file mode 100644 (file)
index 0000000..e115ae6
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Intel Langwell USB OTG transceiver driver
+ * Copyright (C) 2008, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef __LANGWELL_OTG_H__
+#define __LANGWELL_OTG_H__
+
+/* notify transceiver driver about OTG events */
+extern void langwell_update_transceiver(void);
+/* HCD register bus driver */
+extern int langwell_register_host(struct pci_driver *host_driver);
+/* HCD unregister bus driver */
+extern void langwell_unregister_host(struct pci_driver *host_driver);
+/* DCD register bus driver */
+extern int langwell_register_peripheral(struct pci_driver *client_driver);
+/* DCD unregister bus driver */
+extern void langwell_unregister_peripheral(struct pci_driver *client_driver);
+/* No silent failure, output warning message */
+extern void langwell_otg_nsf_msg(unsigned long message);
+
+#define CI_USBCMD              0x30
+#      define USBCMD_RST               BIT(1)
+#      define USBCMD_RS                BIT(0)
+#define CI_USBSTS              0x34
+#      define USBSTS_SLI               BIT(8)
+#      define USBSTS_URI               BIT(6)
+#      define USBSTS_PCI               BIT(2)
+#define CI_PORTSC1             0x74
+#      define PORTSC_PP                BIT(12)
+#      define PORTSC_LS                (BIT(11) | BIT(10))
+#      define PORTSC_SUSP              BIT(7)
+#      define PORTSC_CCS               BIT(0)
+#define CI_HOSTPC1             0xb4
+#      define HOSTPC1_PHCD             BIT(22)
+#define CI_OTGSC               0xf4
+#      define OTGSC_DPIE               BIT(30)
+#      define OTGSC_1MSE               BIT(29)
+#      define OTGSC_BSEIE              BIT(28)
+#      define OTGSC_BSVIE              BIT(27)
+#      define OTGSC_ASVIE              BIT(26)
+#      define OTGSC_AVVIE              BIT(25)
+#      define OTGSC_IDIE               BIT(24)
+#      define OTGSC_DPIS               BIT(22)
+#      define OTGSC_1MSS               BIT(21)
+#      define OTGSC_BSEIS              BIT(20)
+#      define OTGSC_BSVIS              BIT(19)
+#      define OTGSC_ASVIS              BIT(18)
+#      define OTGSC_AVVIS              BIT(17)
+#      define OTGSC_IDIS               BIT(16)
+#      define OTGSC_DPS                BIT(14)
+#      define OTGSC_1MST               BIT(13)
+#      define OTGSC_BSE                BIT(12)
+#      define OTGSC_BSV                BIT(11)
+#      define OTGSC_ASV                BIT(10)
+#      define OTGSC_AVV                BIT(9)
+#      define OTGSC_ID                 BIT(8)
+#      define OTGSC_HABA               BIT(7)
+#      define OTGSC_HADP               BIT(6)
+#      define OTGSC_IDPU               BIT(5)
+#      define OTGSC_DP                 BIT(4)
+#      define OTGSC_OT                 BIT(3)
+#      define OTGSC_HAAR               BIT(2)
+#      define OTGSC_VC                 BIT(1)
+#      define OTGSC_VD                 BIT(0)
+#      define OTGSC_INTEN_MASK         (0x7f << 24)
+#      define OTGSC_INTSTS_MASK        (0x7f << 16)
+#define CI_USBMODE             0xf8
+#      define USBMODE_CM               (BIT(1) | BIT(0))
+#      define USBMODE_IDLE             0
+#      define USBMODE_DEVICE           0x2
+#      define USBMODE_HOST             0x3
+
+#define INTR_DUMMY_MASK (USBSTS_SLI | USBSTS_URI | USBSTS_PCI)
+
+struct otg_hsm {
+       /* Input */
+       int a_bus_resume;
+       int a_bus_suspend;
+       int a_conn;
+       int a_sess_vld;
+       int a_srp_det;
+       int a_vbus_vld;
+       int b_bus_resume;
+       int b_bus_suspend;
+       int b_conn;
+       int b_se0_srp;
+       int b_sess_end;
+       int b_sess_vld;
+       int id;
+
+       /* Internal variables */
+       int a_set_b_hnp_en;
+       int b_srp_done;
+       int b_hnp_enable;
+
+       /* Timeout indicator for timers */
+       int a_wait_vrise_tmout;
+       int a_wait_bcon_tmout;
+       int a_aidl_bdis_tmout;
+       int b_ase0_brst_tmout;
+       int b_bus_suspend_tmout;
+       int b_srp_res_tmout;
+
+       /* Informative variables */
+       int a_bus_drop;
+       int a_bus_req;
+       int a_clr_err;
+       int a_suspend_req;
+       int b_bus_req;
+
+       /* Output */
+       int drv_vbus;
+       int loc_conn;
+       int loc_sof;
+
+       /* Others */
+       int b_bus_suspend_vld;
+};
+
+#define TA_WAIT_VRISE  100
+#define TA_WAIT_BCON   30000
+#define TA_AIDL_BDIS   15000
+#define TB_ASE0_BRST   5000
+#define TB_SE0_SRP     2
+#define TB_SRP_RES     100
+#define TB_BUS_SUSPEND 500
+
+struct langwell_otg_timer {
+       unsigned long expires;  /* Number of count increase to timeout */
+       unsigned long count;    /* Tick counter */
+       void (*function)(unsigned long);        /* Timeout function */
+       unsigned long data;     /* Data passed to function */
+       struct list_head list;
+};
+
+struct langwell_otg {
+       struct otg_transceiver  otg;
+       struct otg_hsm          hsm;
+       void __iomem            *regs;
+       unsigned                region;
+       struct pci_driver       *host_ops;
+       struct pci_driver       *client_ops;
+       struct pci_dev          *pdev;
+       struct work_struct      work;
+       struct workqueue_struct *qwork;
+       spinlock_t              lock;
+       spinlock_t              wq_lock;
+};
+
+static inline struct langwell_otg *otg_to_langwell(struct otg_transceiver *otg)
+{
+       return container_of(otg, struct langwell_otg, otg);
+}
+
+#ifdef DEBUG
+#define otg_dbg(fmt, args...) \
+       printk(KERN_DEBUG fmt , ## args)
+#else
+#define otg_dbg(fmt, args...) \
+       do { } while (0)
+#endif /* DEBUG */
+#endif /* __LANGWELL_OTG_H__ */
diff --git a/include/linux/usb/langwell_udc.h b/include/linux/usb/langwell_udc.h
new file mode 100644 (file)
index 0000000..c949178
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * Intel Langwell USB Device Controller driver
+ * Copyright (C) 2008-2009, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#ifndef __LANGWELL_UDC_H
+#define __LANGWELL_UDC_H
+
+
+/* MACRO defines */
+#define        CAP_REG_OFFSET          0x0
+#define        OP_REG_OFFSET           0x28
+
+#define        DMA_ADDR_INVALID        (~(dma_addr_t)0)
+
+#define        DQH_ALIGNMENT           2048
+#define        DTD_ALIGNMENT           64
+#define        DMA_BOUNDARY            4096
+
+#define        EP0_MAX_PKT_SIZE        64
+#define EP_DIR_IN              1
+#define EP_DIR_OUT             0
+
+#define FLUSH_TIMEOUT          1000
+#define RESET_TIMEOUT          1000
+#define SETUPSTAT_TIMEOUT      100
+#define PRIME_TIMEOUT          100
+
+
+/* device memory space registers */
+
+/* Capability Registers, BAR0 + CAP_REG_OFFSET */
+struct langwell_cap_regs {
+       /* offset: 0x0 */
+       u8      caplength;      /* offset of Operational Register */
+       u8      _reserved3;
+       u16     hciversion;     /* H: BCD encoding of host version */
+       u32     hcsparams;      /* H: host port steering logic capability */
+       u32     hccparams;      /* H: host multiple mode control capability */
+#define        HCC_LEN BIT(17)         /* Link power management (LPM) capability */
+       u8      _reserved4[0x20-0xc];
+       /* offset: 0x20 */
+       u16     dciversion;     /* BCD encoding of device version */
+       u8      _reserved5[0x24-0x22];
+       u32     dccparams;      /* overall device controller capability */
+#define        HOSTCAP BIT(8)          /* host capable */
+#define        DEVCAP  BIT(7)          /* device capable */
+#define DEN(d) \
+       (((d)>>0)&0x1f)         /* bits 4:0, device endpoint number */
+} __attribute__ ((packed));
+
+
+/* Operational Registers, BAR0 + OP_REG_OFFSET */
+struct langwell_op_regs {
+       /* offset: 0x28 */
+       u32     extsts;
+#define        EXTS_TI1        BIT(4)  /* general purpose timer interrupt 1 */
+#define        EXTS_TI1TI0     BIT(3)  /* general purpose timer interrupt 0 */
+#define        EXTS_TI1UPI     BIT(2)  /* USB host periodic interrupt */
+#define        EXTS_TI1UAI     BIT(1)  /* USB host asynchronous interrupt */
+#define        EXTS_TI1NAKI    BIT(0)  /* NAK interrupt */
+       u32     extintr;
+#define        EXTI_TIE1       BIT(4)  /* general purpose timer interrupt enable 1 */
+#define        EXTI_TIE0       BIT(3)  /* general purpose timer interrupt enable 0 */
+#define        EXTI_UPIE       BIT(2)  /* USB host periodic interrupt enable */
+#define        EXTI_UAIE       BIT(1)  /* USB host asynchronous interrupt enable */
+#define        EXTI_NAKE       BIT(0)  /* NAK interrupt enable */
+       /* offset: 0x30 */
+       u32     usbcmd;
+#define        CMD_HIRD(u)     \
+       (((u)>>24)&0xf)         /* bits 27:24, host init resume duration */
+#define        CMD_ITC(u)      \
+       (((u)>>16)&0xff)        /* bits 23:16, interrupt threshold control */
+#define        CMD_PPE         BIT(15) /* per-port change events enable */
+#define        CMD_ATDTW       BIT(14) /* add dTD tripwire */
+#define        CMD_SUTW        BIT(13) /* setup tripwire */
+#define        CMD_ASPE        BIT(11) /* asynchronous schedule park mode enable */
+#define        CMD_FS2         BIT(10) /* frame list size */
+#define        CMD_ASP1        BIT(9)  /* asynchronous schedule park mode count */
+#define        CMD_ASP0        BIT(8)
+#define        CMD_LR          BIT(7)  /* light host/device controller reset */
+#define        CMD_IAA         BIT(6)  /* interrupt on async advance doorbell */
+#define        CMD_ASE         BIT(5)  /* asynchronous schedule enable */
+#define        CMD_PSE         BIT(4)  /* periodic schedule enable */
+#define        CMD_FS1         BIT(3)
+#define        CMD_FS0         BIT(2)
+#define        CMD_RST         BIT(1)  /* controller reset */
+#define        CMD_RUNSTOP     BIT(0)  /* run/stop */
+       u32     usbsts;
+#define        STS_PPCI(u)     \
+       (((u)>>16)&0xffff)      /* bits 31:16, port-n change detect */
+#define        STS_AS          BIT(15) /* asynchronous schedule status */
+#define        STS_PS          BIT(14) /* periodic schedule status */
+#define        STS_RCL         BIT(13) /* reclamation */
+#define        STS_HCH         BIT(12) /* HC halted */
+#define        STS_ULPII       BIT(10) /* ULPI interrupt */
+#define        STS_SLI         BIT(8)  /* DC suspend */
+#define        STS_SRI         BIT(7)  /* SOF received */
+#define        STS_URI         BIT(6)  /* USB reset received */
+#define        STS_AAI         BIT(5)  /* interrupt on async advance */
+#define        STS_SEI         BIT(4)  /* system error */
+#define        STS_FRI         BIT(3)  /* frame list rollover */
+#define        STS_PCI         BIT(2)  /* port change detect */
+#define        STS_UEI         BIT(1)  /* USB error interrupt */
+#define        STS_UI          BIT(0)  /* USB interrupt */
+       u32     usbintr;
+/* bits 31:16, per-port interrupt enable */
+#define        INTR_PPCE(u)    (((u)>>16)&0xffff)
+#define        INTR_ULPIE      BIT(10) /* ULPI enable */
+#define        INTR_SLE        BIT(8)  /* DC sleep/suspend enable */
+#define        INTR_SRE        BIT(7)  /* SOF received enable */
+#define        INTR_URE        BIT(6)  /* USB reset enable */
+#define        INTR_AAE        BIT(5)  /* interrupt on async advance enable */
+#define        INTR_SEE        BIT(4)  /* system error enable */
+#define        INTR_FRE        BIT(3)  /* frame list rollover enable */
+#define        INTR_PCE        BIT(2)  /* port change detect enable */
+#define        INTR_UEE        BIT(1)  /* USB error interrupt enable */
+#define        INTR_UE         BIT(0)  /* USB interrupt enable */
+       u32     frindex;        /* frame index */
+#define        FRINDEX_MASK    (0x3fff << 0)
+       u32     ctrldssegment;  /* not used */
+       u32     deviceaddr;
+#define USBADR_SHIFT   25
+#define        USBADR(d)       \
+       (((d)>>25)&0x7f)        /* bits 31:25, device address */
+#define USBADR_MASK    (0x7f << 25)
+#define        USBADRA         BIT(24) /* device address advance */
+       u32     endpointlistaddr;/* endpoint list top memory address */
+/* bits 31:11, endpoint list pointer */
+#define        EPBASE(d)       (((d)>>11)&0x1fffff)
+#define        ENDPOINTLISTADDR_MASK   (0x1fffff << 11)
+       u32     ttctrl;         /* H: TT operatin, not used */
+       /* offset: 0x50 */
+       u32     burstsize;      /* burst size of data movement */
+#define        TXPBURST(b)     \
+       (((b)>>8)&0xff)         /* bits 15:8, TX burst length */
+#define        RXPBURST(b)     \
+       (((b)>>0)&0xff)         /* bits 7:0, RX burst length */
+       u32     txfilltuning;   /* TX tuning */
+       u32     txttfilltuning; /* H: TX TT tuning */
+       u32     ic_usb;         /* control the IC_USB FS/LS transceiver */
+       /* offset: 0x60 */
+       u32     ulpi_viewport;  /* indirect access to ULPI PHY */
+#define        ULPIWU          BIT(31) /* ULPI wakeup */
+#define        ULPIRUN         BIT(30) /* ULPI read/write run */
+#define        ULPIRW          BIT(29) /* ULPI read/write control */
+#define        ULPISS          BIT(27) /* ULPI sync state */
+#define        ULPIPORT(u)     \
+       (((u)>>24)&7)           /* bits 26:24, ULPI port number */
+#define        ULPIADDR(u)     \
+       (((u)>>16)&0xff)        /* bits 23:16, ULPI data address */
+#define        ULPIDATRD(u)    \
+       (((u)>>8)&0xff)         /* bits 15:8, ULPI data read */
+#define        ULPIDATWR(u)    \
+       (((u)>>0)&0xff)         /* bits 7:0, ULPI date write */
+       u8      _reserved6[0x70-0x64];
+       /* offset: 0x70 */
+       u32     configflag;     /* H: not used */
+       u32     portsc1;        /* port status */
+#define        DA(p)   \
+       (((p)>>25)&0x7f)        /* bits 31:25, device address */
+#define        PORTS_SSTS      (BIT(24) | BIT(23))     /* suspend status */
+#define        PORTS_WKOC      BIT(22) /* wake on over-current enable */
+#define        PORTS_WKDS      BIT(21) /* wake on disconnect enable */
+#define        PORTS_WKCN      BIT(20) /* wake on connect enable */
+#define        PORTS_PTC(p)    (((p)>>16)&0xf) /* bits 19:16, port test control */
+#define        PORTS_PIC       (BIT(15) | BIT(14))     /* port indicator control */
+#define        PORTS_PO        BIT(13) /* port owner */
+#define        PORTS_PP        BIT(12) /* port power */
+#define        PORTS_LS        (BIT(11) | BIT(10))     /* line status */
+#define        PORTS_SLP       BIT(9)  /* suspend using L1 */
+#define        PORTS_PR        BIT(8)  /* port reset */
+#define        PORTS_SUSP      BIT(7)  /* suspend */
+#define        PORTS_FPR       BIT(6)  /* force port resume */
+#define        PORTS_OCC       BIT(5)  /* over-current change */
+#define        PORTS_OCA       BIT(4)  /* over-current active */
+#define        PORTS_PEC       BIT(3)  /* port enable/disable change */
+#define        PORTS_PE        BIT(2)  /* port enable/disable */
+#define        PORTS_CSC       BIT(1)  /* connect status change */
+#define        PORTS_CCS       BIT(0)  /* current connect status */
+       u8      _reserved7[0xb4-0x78];
+       /* offset: 0xb4 */
+       u32     devlc;          /* control LPM and each USB port behavior */
+/* bits 31:29, parallel transceiver select */
+#define        LPM_PTS(d)      (((d)>>29)&7)
+#define        LPM_STS         BIT(28) /* serial transceiver select */
+#define        LPM_PTW         BIT(27) /* parallel transceiver width */
+#define        LPM_PSPD(d)     (((d)>>25)&3)   /* bits 26:25, port speed */
+#define LPM_PSPD_MASK  (BIT(26) | BIT(25))
+#define LPM_SPEED_FULL 0
+#define LPM_SPEED_LOW  1
+#define LPM_SPEED_HIGH 2
+#define        LPM_SRT         BIT(24) /* shorten reset time */
+#define        LPM_PFSC        BIT(23) /* port force full speed connect */
+#define        LPM_PHCD        BIT(22) /* PHY low power suspend clock disable */
+#define        LPM_STL         BIT(16) /* STALL reply to LPM token */
+#define        LPM_BA(d)       \
+       (((d)>>1)&0x7ff)        /* bits 11:1, BmAttributes */
+#define        LPM_NYT_ACK     BIT(0)  /* NYET/ACK reply to LPM token */
+       u8      _reserved8[0xf4-0xb8];
+       /* offset: 0xf4 */
+       u32     otgsc;          /* On-The-Go status and control */
+#define        OTGSC_DPIE      BIT(30) /* data pulse interrupt enable */
+#define        OTGSC_MSE       BIT(29) /* 1 ms timer interrupt enable */
+#define        OTGSC_BSEIE     BIT(28) /* B session end interrupt enable */
+#define        OTGSC_BSVIE     BIT(27) /* B session valid interrupt enable */
+#define        OTGSC_ASVIE     BIT(26) /* A session valid interrupt enable */
+#define        OTGSC_AVVIE     BIT(25) /* A VBUS valid interrupt enable */
+#define        OTGSC_IDIE      BIT(24) /* USB ID interrupt enable */
+#define        OTGSC_DPIS      BIT(22) /* data pulse interrupt status */
+#define        OTGSC_MSS       BIT(21) /* 1 ms timer interrupt status */
+#define        OTGSC_BSEIS     BIT(20) /* B session end interrupt status */
+#define        OTGSC_BSVIS     BIT(19) /* B session valid interrupt status */
+#define        OTGSC_ASVIS     BIT(18) /* A session valid interrupt status */
+#define        OTGSC_AVVIS     BIT(17) /* A VBUS valid interrupt status */
+#define        OTGSC_IDIS      BIT(16) /* USB ID interrupt status */
+#define        OTGSC_DPS       BIT(14) /* data bus pulsing status */
+#define        OTGSC_MST       BIT(13) /* 1 ms timer toggle */
+#define        OTGSC_BSE       BIT(12) /* B session end */
+#define        OTGSC_BSV       BIT(11) /* B session valid */
+#define        OTGSC_ASV       BIT(10) /* A session valid */
+#define        OTGSC_AVV       BIT(9)  /* A VBUS valid */
+#define        OTGSC_USBID     BIT(8)  /* USB ID */
+#define        OTGSC_HABA      BIT(7)  /* hw assist B-disconnect to A-connect */
+#define        OTGSC_HADP      BIT(6)  /* hw assist data pulse */
+#define        OTGSC_IDPU      BIT(5)  /* ID pullup */
+#define        OTGSC_DP        BIT(4)  /* data pulsing */
+#define        OTGSC_OT        BIT(3)  /* OTG termination */
+#define        OTGSC_HAAR      BIT(2)  /* hw assist auto reset */
+#define        OTGSC_VC        BIT(1)  /* VBUS charge */
+#define        OTGSC_VD        BIT(0)  /* VBUS discharge */
+       u32     usbmode;
+#define        MODE_VBPS       BIT(5)  /* R/W VBUS power select */
+#define        MODE_SDIS       BIT(4)  /* R/W stream disable mode */
+#define        MODE_SLOM       BIT(3)  /* R/W setup lockout mode */
+#define        MODE_ENSE       BIT(2)  /* endian select */
+#define        MODE_CM(u)      (((u)>>0)&3)    /* bits 1:0, controller mode */
+#define        MODE_IDLE       0
+#define        MODE_DEVICE     2
+#define        MODE_HOST       3
+       u8      _reserved9[0x100-0xfc];
+       /* offset: 0x100 */
+       u32     endptnak;
+#define        EPTN(e)         \
+       (((e)>>16)&0xffff)      /* bits 31:16, TX endpoint NAK */
+#define        EPRN(e)         \
+       (((e)>>0)&0xffff)       /* bits 15:0, RX endpoint NAK */
+       u32     endptnaken;
+#define        EPTNE(e)        \
+       (((e)>>16)&0xffff)      /* bits 31:16, TX endpoint NAK enable */
+#define        EPRNE(e)        \
+       (((e)>>0)&0xffff)       /* bits 15:0, RX endpoint NAK enable */
+       u32     endptsetupstat;
+#define        SETUPSTAT_MASK          (0xffff << 0)   /* bits 15:0 */
+#define EP0SETUPSTAT_MASK      1
+       u32     endptprime;
+/* bits 31:16, prime endpoint transmit buffer */
+#define        PETB(e)         (((e)>>16)&0xffff)
+/* bits 15:0, prime endpoint receive buffer */
+#define        PERB(e)         (((e)>>0)&0xffff)
+       /* offset: 0x110 */
+       u32     endptflush;
+/* bits 31:16, flush endpoint transmit buffer */
+#define        FETB(e)         (((e)>>16)&0xffff)
+/* bits 15:0, flush endpoint receive buffer */
+#define        FERB(e)         (((e)>>0)&0xffff)
+       u32     endptstat;
+/* bits 31:16, endpoint transmit buffer ready */
+#define        ETBR(e)         (((e)>>16)&0xffff)
+/* bits 15:0, endpoint receive buffer ready */
+#define        ERBR(e)         (((e)>>0)&0xffff)
+       u32     endptcomplete;
+/* bits 31:16, endpoint transmit complete event */
+#define        ETCE(e)         (((e)>>16)&0xffff)
+/* bits 15:0, endpoint receive complete event */
+#define        ERCE(e)         (((e)>>0)&0xffff)
+       /* offset: 0x11c */
+       u32     endptctrl[16];
+#define        EPCTRL_TXE      BIT(23) /* TX endpoint enable */
+#define        EPCTRL_TXR      BIT(22) /* TX data toggle reset */
+#define        EPCTRL_TXI      BIT(21) /* TX data toggle inhibit */
+#define        EPCTRL_TXT(e)   (((e)>>18)&3)   /* bits 19:18, TX endpoint type */
+#define        EPCTRL_TXT_SHIFT        18
+#define        EPCTRL_TXD      BIT(17) /* TX endpoint data source */
+#define        EPCTRL_TXS      BIT(16) /* TX endpoint STALL */
+#define        EPCTRL_RXE      BIT(7)  /* RX endpoint enable */
+#define        EPCTRL_RXR      BIT(6)  /* RX data toggle reset */
+#define        EPCTRL_RXI      BIT(5)  /* RX data toggle inhibit */
+#define        EPCTRL_RXT(e)   (((e)>>2)&3)    /* bits 3:2, RX endpoint type */
+#define        EPCTRL_RXT_SHIFT        2       /* bits 19:18, TX endpoint type */
+#define        EPCTRL_RXD      BIT(1)  /* RX endpoint data sink */
+#define        EPCTRL_RXS      BIT(0)  /* RX endpoint STALL */
+} __attribute__ ((packed));
+
+#endif /* __LANGWELL_UDC_H */
+
index 1aaa826396a1462555925b871f22f95ff8870299..2443c0e7a80cd5e25ca77d217a0f5abbd2c1151e 100644 (file)
@@ -80,10 +80,10 @@ struct otg_transceiver {
 
 /* for board-specific init logic */
 extern int otg_set_transceiver(struct otg_transceiver *);
-#ifdef CONFIG_NOP_USB_XCEIV
+
+/* sometimes transceivers are accessed only through e.g. ULPI */
 extern void usb_nop_xceiv_register(void);
 extern void usb_nop_xceiv_unregister(void);
-#endif
 
 
 /* for usb host and peripheral controller drivers */
diff --git a/include/linux/usb/r8a66597.h b/include/linux/usb/r8a66597.h
new file mode 100644 (file)
index 0000000..e9f0384
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * R8A66597 driver platform data
+ *
+ * Copyright (C) 2009  Renesas Solutions Corp.
+ *
+ * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __LINUX_USB_R8A66597_H
+#define __LINUX_USB_R8A66597_H
+
+#define R8A66597_PLATDATA_XTAL_12MHZ   0x01
+#define R8A66597_PLATDATA_XTAL_24MHZ   0x02
+#define R8A66597_PLATDATA_XTAL_48MHZ   0x03
+
+struct r8a66597_platdata {
+       /* This ops can controll port power instead of DVSTCTR register. */
+       void (*port_power)(int port, int power);
+
+       /* (external controller only) set R8A66597_PLATDATA_XTAL_nnMHZ */
+       unsigned        xtal:2;
+
+       /* set one = 3.3V, set zero = 1.5V */
+       unsigned        vif:1;
+
+       /* set one = big endian, set zero = little endian */
+       unsigned        endian:1;
+};
+#endif
+
index 8cdfed738fe4b8b28d0f7208c8553f0cf2eaee03..44801d26a37a7888d7ebd88dbb5cf0e4a1836de0 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <linux/kref.h>
 #include <linux/mutex.h>
+#include <linux/sysrq.h>
 
 #define SERIAL_TTY_MAJOR       188     /* Nice legal number now */
 #define SERIAL_TTY_MINORS      254     /* loads of devices :) */
 /* parity check flag */
 #define RELEVANT_IFLAG(iflag)  (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
 
+enum port_dev_state {
+       PORT_UNREGISTERED,
+       PORT_REGISTERING,
+       PORT_REGISTERED,
+       PORT_UNREGISTERING,
+};
+
 /**
  * usb_serial_port: structure for the specific ports of a device.
  * @serial: pointer back to the struct usb_serial owner of this port.
@@ -91,12 +99,17 @@ struct usb_serial_port {
        int                     write_urb_busy;
        __u8                    bulk_out_endpointAddress;
 
+       int                     tx_bytes_flight;
+       int                     urbs_in_flight;
+
        wait_queue_head_t       write_wait;
        struct work_struct      work;
        char                    throttled;
        char                    throttle_req;
        char                    console;
+       unsigned long           sysrq; /* sysrq timeout */
        struct device           dev;
+       enum port_dev_state     dev_state;
 };
 #define to_usb_serial_port(d) container_of(d, struct usb_serial_port, dev)
 
@@ -181,8 +194,10 @@ static inline void usb_set_serial_data(struct usb_serial *serial, void *data)
  *     This will be called when the struct usb_serial structure is fully set
  *     set up.  Do any local initialization of the device, or any private
  *     memory structure allocation at this point in time.
- * @shutdown: pointer to the driver's shutdown function.  This will be
- *     called when the device is removed from the system.
+ * @disconnect: pointer to the driver's disconnect function.  This will be
+ *     called when the device is unplugged or unbound from the driver.
+ * @release: pointer to the driver's release function.  This will be called
+ *     when the usb_serial data structure is about to be destroyed.
  * @usb_driver: pointer to the struct usb_driver that controls this
  *     device.  This is necessary to allow dynamic ids to be added to
  *     the driver from sysfs.
@@ -207,12 +222,14 @@ struct usb_serial_driver {
        struct device_driver    driver;
        struct usb_driver       *usb_driver;
        struct usb_dynids       dynids;
+       int                     max_in_flight_urbs;
 
        int (*probe)(struct usb_serial *serial, const struct usb_device_id *id);
        int (*attach)(struct usb_serial *serial);
        int (*calc_num_ports) (struct usb_serial *serial);
 
-       void (*shutdown)(struct usb_serial *serial);
+       void (*disconnect)(struct usb_serial *serial);
+       void (*release)(struct usb_serial *serial);
 
        int (*port_probe)(struct usb_serial_port *port);
        int (*port_remove)(struct usb_serial_port *port);
@@ -294,9 +311,16 @@ extern void usb_serial_generic_read_bulk_callback(struct urb *urb);
 extern void usb_serial_generic_write_bulk_callback(struct urb *urb);
 extern void usb_serial_generic_throttle(struct tty_struct *tty);
 extern void usb_serial_generic_unthrottle(struct tty_struct *tty);
-extern void usb_serial_generic_shutdown(struct usb_serial *serial);
+extern void usb_serial_generic_disconnect(struct usb_serial *serial);
+extern void usb_serial_generic_release(struct usb_serial *serial);
 extern int usb_serial_generic_register(int debug);
 extern void usb_serial_generic_deregister(void);
+extern void usb_serial_generic_resubmit_read_urb(struct usb_serial_port *port,
+                                                gfp_t mem_flags);
+extern int usb_serial_handle_sysrq_char(struct usb_serial_port *port,
+                                       unsigned int ch);
+extern int usb_serial_handle_break(struct usb_serial_port *port);
+
 
 extern int usb_serial_bus_register(struct usb_serial_driver *device);
 extern void usb_serial_bus_deregister(struct usb_serial_driver *device);
index 11232676bfff59af017b4b3343c67dc430004c4b..3656b300de3a740e39620172e4eb0e0997b06aea 100644 (file)
@@ -22,12 +22,12 @@ struct old_utsname {
 };
 
 struct new_utsname {
-       char sysname[65];
-       char nodename[65];
-       char release[65];
-       char version[65];
-       char machine[65];
-       char domainname[65];
+       char sysname[__NEW_UTS_LEN + 1];
+       char nodename[__NEW_UTS_LEN + 1];
+       char release[__NEW_UTS_LEN + 1];
+       char version[__NEW_UTS_LEN + 1];
+       char machine[__NEW_UTS_LEN + 1];
+       char domainname[__NEW_UTS_LEN + 1];
 };
 
 #ifdef __KERNEL__
index ebb2ea6b499598d20c066f2d670381dedc8758c9..f24eceecc5a602562e5b3d6d1dbae338df319633 100644 (file)
@@ -347,7 +347,8 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_MR97310A v4l2_fourcc('M', '3', '1', '0') /* compressed BGGR bayer */
 #define V4L2_PIX_FMT_SQ905C   v4l2_fourcc('9', '0', '5', 'C') /* compressed RGGB bayer */
 #define V4L2_PIX_FMT_PJPG     v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */
-#define V4L2_PIX_FMT_YVYU    v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16  YVU 4:2:2     */
+#define V4L2_PIX_FMT_YVYU     v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16 YVU 4:2:2 */
+#define V4L2_PIX_FMT_OV518    v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */
 
 /*
  *     F O R M A T   E N U M E R A T I O N
diff --git a/include/linux/vlynq.h b/include/linux/vlynq.h
new file mode 100644 (file)
index 0000000..8f6a958
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2006, 2007 Eugene Konev <ejka@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __VLYNQ_H__
+#define __VLYNQ_H__
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+#define VLYNQ_NUM_IRQS 32
+
+struct vlynq_mapping {
+       u32 size;
+       u32 offset;
+};
+
+enum vlynq_divisor {
+       vlynq_div_auto = 0,
+       vlynq_ldiv1,
+       vlynq_ldiv2,
+       vlynq_ldiv3,
+       vlynq_ldiv4,
+       vlynq_ldiv5,
+       vlynq_ldiv6,
+       vlynq_ldiv7,
+       vlynq_ldiv8,
+       vlynq_rdiv1,
+       vlynq_rdiv2,
+       vlynq_rdiv3,
+       vlynq_rdiv4,
+       vlynq_rdiv5,
+       vlynq_rdiv6,
+       vlynq_rdiv7,
+       vlynq_rdiv8,
+       vlynq_div_external
+};
+
+struct vlynq_device_id {
+       u32 id;
+       enum vlynq_divisor divisor;
+       unsigned long driver_data;
+};
+
+struct vlynq_regs;
+struct vlynq_device {
+       u32 id, dev_id;
+       int local_irq;
+       int remote_irq;
+       enum vlynq_divisor divisor;
+       u32 regs_start, regs_end;
+       u32 mem_start, mem_end;
+       u32 irq_start, irq_end;
+       int irq;
+       int enabled;
+       struct vlynq_regs *local;
+       struct vlynq_regs *remote;
+       struct device dev;
+};
+
+struct vlynq_driver {
+       char *name;
+       struct vlynq_device_id *id_table;
+       int (*probe)(struct vlynq_device *dev, struct vlynq_device_id *id);
+       void (*remove)(struct vlynq_device *dev);
+       struct device_driver driver;
+};
+
+struct plat_vlynq_ops {
+       int (*on)(struct vlynq_device *dev);
+       void (*off)(struct vlynq_device *dev);
+};
+
+static inline struct vlynq_driver *to_vlynq_driver(struct device_driver *drv)
+{
+       return container_of(drv, struct vlynq_driver, driver);
+}
+
+static inline struct vlynq_device *to_vlynq_device(struct device *device)
+{
+       return container_of(device, struct vlynq_device, dev);
+}
+
+extern struct bus_type vlynq_bus_type;
+
+extern int __vlynq_register_driver(struct vlynq_driver *driver,
+                                  struct module *owner);
+
+static inline int vlynq_register_driver(struct vlynq_driver *driver)
+{
+       return __vlynq_register_driver(driver, THIS_MODULE);
+}
+
+static inline void *vlynq_get_drvdata(struct vlynq_device *dev)
+{
+       return dev_get_drvdata(&dev->dev);
+}
+
+static inline void vlynq_set_drvdata(struct vlynq_device *dev, void *data)
+{
+       dev_set_drvdata(&dev->dev, data);
+}
+
+static inline u32 vlynq_mem_start(struct vlynq_device *dev)
+{
+       return dev->mem_start;
+}
+
+static inline u32 vlynq_mem_end(struct vlynq_device *dev)
+{
+       return dev->mem_end;
+}
+
+static inline u32 vlynq_mem_len(struct vlynq_device *dev)
+{
+       return dev->mem_end - dev->mem_start + 1;
+}
+
+static inline int vlynq_virq_to_irq(struct vlynq_device *dev, int virq)
+{
+       int irq = dev->irq_start + virq;
+       if ((irq < dev->irq_start) || (irq > dev->irq_end))
+               return -EINVAL;
+
+       return irq;
+}
+
+static inline int vlynq_irq_to_virq(struct vlynq_device *dev, int irq)
+{
+       if ((irq < dev->irq_start) || (irq > dev->irq_end))
+               return -EINVAL;
+
+       return irq - dev->irq_start;
+}
+
+extern void vlynq_unregister_driver(struct vlynq_driver *driver);
+extern int vlynq_enable_device(struct vlynq_device *dev);
+extern void vlynq_disable_device(struct vlynq_device *dev);
+extern int vlynq_set_local_mapping(struct vlynq_device *dev, u32 tx_offset,
+                                  struct vlynq_mapping *mapping);
+extern int vlynq_set_remote_mapping(struct vlynq_device *dev, u32 tx_offset,
+                                   struct vlynq_mapping *mapping);
+extern int vlynq_set_local_irq(struct vlynq_device *dev, int virq);
+extern int vlynq_set_remote_irq(struct vlynq_device *dev, int virq);
+
+#endif /* __VLYNQ_H__ */
index 524cd1b28ecb0ff62a9d3620f9d21d48f8c1e32e..81a97cf8f0a0845a102a1200dc316aa32a47920f 100644 (file)
@@ -36,12 +36,14 @@ enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT,
                FOR_ALL_ZONES(PGSTEAL),
                FOR_ALL_ZONES(PGSCAN_KSWAPD),
                FOR_ALL_ZONES(PGSCAN_DIRECT),
+#ifdef CONFIG_NUMA
+               PGSCAN_ZONE_RECLAIM_FAILED,
+#endif
                PGINODESTEAL, SLABS_SCANNED, KSWAPD_STEAL, KSWAPD_INODESTEAL,
                PAGEOUTRUN, ALLOCSTALL, PGROTATED,
 #ifdef CONFIG_HUGETLB_PAGE
                HTLB_BUDDY_PGALLOC, HTLB_BUDDY_PGALLOC_FAIL,
 #endif
-#ifdef CONFIG_UNEVICTABLE_LRU
                UNEVICTABLE_PGCULLED,   /* culled to noreclaim list */
                UNEVICTABLE_PGSCANNED,  /* scanned for reclaimability */
                UNEVICTABLE_PGRESCUED,  /* rescued from noreclaim list */
@@ -50,7 +52,6 @@ enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT,
                UNEVICTABLE_PGCLEARED,  /* on COW, page truncate */
                UNEVICTABLE_PGSTRANDED, /* unable to isolate on unlock */
                UNEVICTABLE_MLOCKFREED,
-#endif
                NR_VM_EVENT_ITEMS
 };
 
diff --git a/include/media/adv7343.h b/include/media/adv7343.h
new file mode 100644 (file)
index 0000000..d6f8a4e
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * ADV7343 header file
+ *
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed .as is. WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef ADV7343_H
+#define ADV7343_H
+
+#define ADV7343_COMPOSITE_ID   (0)
+#define ADV7343_COMPONENT_ID   (1)
+#define ADV7343_SVIDEO_ID      (2)
+
+#endif                         /* End of #ifndef ADV7343_H */
index 07963d7054008be6490f79ee91a4f9740900e5d6..3ad4ed5402fb8b6782ad6b1600f8dfdfd4394ea1 100644 (file)
@@ -7,7 +7,7 @@ struct IR_i2c;
 
 struct IR_i2c {
        IR_KEYTAB_TYPE         *ir_codes;
-       struct i2c_client      c;
+       struct i2c_client      *c;
        struct input_dev       *input;
        struct ir_input_state  ir;
 
@@ -15,7 +15,15 @@ struct IR_i2c {
        unsigned char          old;
 
        struct delayed_work    work;
+       char                   name[32];
        char                   phys[32];
        int                    (*get_key)(struct IR_i2c*, u32*, u32*);
 };
+
+/* Can be passed when instantiating an ir_video i2c device */
+struct IR_i2c_init_data {
+       IR_KEYTAB_TYPE         *ir_codes;
+       const char             *name;
+       int                    (*get_key)(struct IR_i2c*, u32*, u32*);
+};
 #endif
index 37013688af44b64c8107e94fa7e416411e69dcfa..23ecead35e7a70c4f4d03fd6634ec88e8a3ae319 100644 (file)
@@ -60,7 +60,7 @@ struct soc_camera_file {
 
 struct soc_camera_host {
        struct list_head list;
-       struct device dev;
+       struct device *dev;
        unsigned char nr;                               /* Host number */
        void *priv;
        const char *drv_name;
@@ -92,11 +92,16 @@ struct soc_camera_host_ops {
 #define SOCAM_SENSOR_INVERT_VSYNC      (1 << 3)
 #define SOCAM_SENSOR_INVERT_DATA       (1 << 4)
 
+struct i2c_board_info;
+
 struct soc_camera_link {
        /* Camera bus id, used to match a camera and a bus */
        int bus_id;
        /* Per camera SOCAM_SENSOR_* bus flags */
        unsigned long flags;
+       int i2c_adapter_id;
+       struct i2c_board_info *board_info;
+       const char *module_name;
        /* Optional callbacks to power on or off and reset the sensor */
        int (*power)(struct device *, int);
        int (*reset)(struct device *);
@@ -107,6 +112,7 @@ struct soc_camera_link {
         */
        int (*set_bus_param)(struct soc_camera_link *, unsigned long flags);
        unsigned long (*query_bus_param)(struct soc_camera_link *);
+       void (*free_bus)(struct soc_camera_link *);
 };
 
 static inline struct soc_camera_device *to_soc_camera_dev(struct device *dev)
@@ -116,7 +122,7 @@ static inline struct soc_camera_device *to_soc_camera_dev(struct device *dev)
 
 static inline struct soc_camera_host *to_soc_camera_host(struct device *dev)
 {
-       return container_of(dev, struct soc_camera_host, dev);
+       return dev_get_drvdata(dev);
 }
 
 extern int soc_camera_host_register(struct soc_camera_host *ici);
index 7d4e2db780767709579367fe6e50cb15ee825c85..cbf97f45fbec3abd6dde9da35c074de6bc20e36f 100644 (file)
 #define TUNER_XC5000                   76      /* Xceive Silicon Tuner */
 #define TUNER_TCL_MF02GIP_5N           77      /* TCL MF02GIP_5N */
 #define TUNER_PHILIPS_FMD1216MEX_MK3   78
+#define TUNER_PHILIPS_FM1216MK5                79
+#define TUNER_PHILIPS_FQ1216LME_MK3    80      /* Active loopthrough, no FM */
 
 /* tv card specific */
 #define TDA9887_PRESENT                (1<<0)
index 1be461a2907768d29dbe060030c85dedfc4766b7..4d7e2272c42f0c37e0aabb5dbc912c6c24361a34 100644 (file)
@@ -137,6 +137,12 @@ enum {
        /* module saa7191: just ident 7191 */
        V4L2_IDENT_SAA7191 = 7191,
 
+       /* module ths7303: just ident 7303 */
+       V4L2_IDENT_THS7303 = 7303,
+
+       /* module adv7343: just ident 7343 */
+       V4L2_IDENT_ADV7343 = 7343,
+
        /* module wm8739: just ident 8739 */
        V4L2_IDENT_WM8739 = 8739,
 
index 0dd3e8e8653e136d28b97154d35c9cdb7f074b09..5d5d550e63ad0e2c7a0c1811a42e1f031743068a 100644 (file)
@@ -30,7 +30,7 @@
    basic V4L2 device-level support.
  */
 
-#define V4L2_DEVICE_NAME_SIZE (BUS_ID_SIZE + 16)
+#define V4L2_DEVICE_NAME_SIZE (20 + 16)
 
 struct v4l2_device {
        /* dev->driver_data points to this struct.
@@ -53,10 +53,31 @@ struct v4l2_device {
    dev may be NULL in rare cases (ISA devices). In that case you
    must fill in the v4l2_dev->name field before calling this function. */
 int __must_check v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);
+
+/* Optional function to initialize the name field of struct v4l2_device using
+   the driver name and a driver-global atomic_t instance.
+   This function will increment the instance counter and returns the instance
+   value used in the name.
+
+   Example:
+
+   static atomic_t drv_instance = ATOMIC_INIT(0);
+
+   ...
+
+   instance = v4l2_device_set_name(&v4l2_dev, "foo", &drv_instance);
+
+   The first time this is called the name field will be set to foo0 and
+   this function returns 0. If the name ends with a digit (e.g. cx18),
+   then the name will be set to cx18-0 since cx180 looks really odd. */
+int v4l2_device_set_name(struct v4l2_device *v4l2_dev, const char *basename,
+                                               atomic_t *instance);
+
 /* Set v4l2_dev->dev to NULL. Call when the USB parent disconnects.
    Since the parent disappears this ensures that v4l2_dev doesn't have an
    invalid parent pointer. */
 void v4l2_device_disconnect(struct v4l2_device *v4l2_dev);
+
 /* Unregister all sub-devices and any other resources related to v4l2_dev. */
 void v4l2_device_unregister(struct v4l2_device *v4l2_dev);
 
index 17856081c80942d6ec9f4e0e7a0d362d2c4277df..a503e1cee78bd7e2554faf22310ff78db54c5a57 100644 (file)
@@ -230,12 +230,16 @@ struct v4l2_subdev_ops {
 
 #define V4L2_SUBDEV_NAME_SIZE 32
 
+/* Set this flag if this subdev is a i2c device. */
+#define V4L2_SUBDEV_FL_IS_I2C (1U << 0)
+
 /* Each instance of a subdev driver should create this struct, either
    stand-alone or embedded in a larger struct.
  */
 struct v4l2_subdev {
        struct list_head list;
        struct module *owner;
+       u32 flags;
        struct v4l2_device *v4l2_dev;
        const struct v4l2_subdev_ops *ops;
        /* name must be unique */
@@ -264,6 +268,7 @@ static inline void v4l2_subdev_init(struct v4l2_subdev *sd,
        BUG_ON(!ops || !ops->core);
        sd->ops = ops;
        sd->v4l2_dev = NULL;
+       sd->flags = 0;
        sd->name[0] = '\0';
        sd->grp_id = 0;
        sd->priv = NULL;
index 20a6957af870a0b12973a4b3cb937d5e0aeac011..47004f35cc7eaf6f2b3cac2779ea7b7ccd5d9c1f 100644 (file)
@@ -17,6 +17,7 @@
 #define _INET_SOCK_H
 
 
+#include <linux/kmemcheck.h>
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/jhash.h>
@@ -66,14 +67,16 @@ struct inet_request_sock {
        __be32                  loc_addr;
        __be32                  rmt_addr;
        __be16                  rmt_port;
-       u16                     snd_wscale : 4, 
-                               rcv_wscale : 4, 
+       kmemcheck_bitfield_begin(flags);
+       u16                     snd_wscale : 4,
+                               rcv_wscale : 4,
                                tstamp_ok  : 1,
                                sack_ok    : 1,
                                wscale_ok  : 1,
                                ecn_ok     : 1,
                                acked      : 1,
                                no_srccheck: 1;
+       kmemcheck_bitfield_end(flags);
        struct ip_options       *opt;
 };
 
@@ -199,9 +202,12 @@ static inline int inet_sk_ehashfn(const struct sock *sk)
 static inline struct request_sock *inet_reqsk_alloc(struct request_sock_ops *ops)
 {
        struct request_sock *req = reqsk_alloc(ops);
+       struct inet_request_sock *ireq = inet_rsk(req);
 
-       if (req != NULL)
-               inet_rsk(req)->opt = NULL;
+       if (req != NULL) {
+               kmemcheck_annotate_bitfield(ireq, flags);
+               ireq->opt = NULL;
+       }
 
        return req;
 }
index 4b8ece22b8e94417879a6504e87afe5bd0ecc371..b63b80fac567a2e103c996d8c021b10ef6e150e8 100644 (file)
@@ -16,6 +16,7 @@
 #define _INET_TIMEWAIT_SOCK_
 
 
+#include <linux/kmemcheck.h>
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/timer.h>
@@ -127,10 +128,12 @@ struct inet_timewait_sock {
        __be32                  tw_rcv_saddr;
        __be16                  tw_dport;
        __u16                   tw_num;
+       kmemcheck_bitfield_begin(flags);
        /* And these are ours. */
        __u8                    tw_ipv6only:1,
                                tw_transparent:1;
-       /* 15 bits hole, try to pack */
+       /* 14 bits hole, try to pack */
+       kmemcheck_bitfield_end(flags);
        __u16                   tw_ipv6_offset;
        unsigned long           tw_ttd;
        struct inet_bind_bucket *tw_tb;
index 010e14a93c9256a0d92e35232e2292e746e8f86c..95bd3fd75f942d42351cd42450420334fef6f2a0 100644 (file)
@@ -218,9 +218,11 @@ struct sock {
 #define sk_hash                        __sk_common.skc_hash
 #define sk_prot                        __sk_common.skc_prot
 #define sk_net                 __sk_common.skc_net
+       kmemcheck_bitfield_begin(flags);
        unsigned char           sk_shutdown : 2,
                                sk_no_check : 2,
                                sk_userlocks : 4;
+       kmemcheck_bitfield_end(flags);
        unsigned char           sk_protocol;
        unsigned short          sk_type;
        int                     sk_rcvbuf;
index c3b2a2aa7140afed4251baabb45a1671fe16ccc7..f0736cff2ca3f15f2762634726f55a6f27af22e7 100644 (file)
 #define S1DREG_DELAYOFF                        0xFFFE
 #define S1DREG_DELAYON                 0xFFFF
 
+#define BBLT_FIFO_EMPTY                        0x00
+#define BBLT_FIFO_NOT_EMPTY            0x40
+#define BBLT_FIFO_NOT_FULL             0x30
+#define BBLT_FIFO_HALF_FULL            0x20
+#define BBLT_FIFO_FULL                 0x10
+
+#define BBLT_SOLID_FILL                        0x0c
+
+
 /* Note: all above defines should go in separate header files
    when implementing other S1D13xxx chip support. */
 
index fed6dc31b0dae854c26ac29216fc5a08824eaa53..c4b3c6d51a72bae4e3f127b68c67ebdde8684bd8 100644 (file)
@@ -616,13 +616,13 @@ config SYSFS_DEPRECATED
        bool
 
 config SYSFS_DEPRECATED_V2
-       bool "Create deprecated sysfs layout for older userspace tools"
+       bool "remove sysfs features which may confuse old userspace tools"
        depends on SYSFS
-       default y
+       default n
        select SYSFS_DEPRECATED
        help
          This option switches the layout of sysfs to the deprecated
-         version.
+         version. Do not use it on recent distributions.
 
          The current sysfs layout features a unified device tree at
          /sys/devices/, which is able to express a hierarchy between
index dd7ee5f203f3f9c476a92d9ef39257a2791b132f..093f65915501bad5db5a8f9c348b5d62ad8a484c 100644 (file)
@@ -231,7 +231,8 @@ static int __init do_mount_root(char *name, char *fs, int flags, void *data)
 
 void __init mount_block_root(char *name, int flags)
 {
-       char *fs_names = __getname();
+       char *fs_names = __getname_gfp(GFP_KERNEL
+               | __GFP_NOTRACK_FALSE_POSITIVE);
        char *p;
 #ifdef CONFIG_BLOCK
        char b[BDEVNAME_SIZE];
index f6204f712e7c639652d06cbefb70bba4df2ae7a1..0e7aedeaa05f4f56a6737c078331f675201505a1 100644 (file)
@@ -65,6 +65,7 @@
 #include <linux/idr.h>
 #include <linux/ftrace.h>
 #include <linux/async.h>
+#include <linux/kmemcheck.h>
 #include <linux/kmemtrace.h>
 #include <trace/boot.h>
 
@@ -546,6 +547,7 @@ static void __init mm_init(void)
        page_cgroup_init_flatmem();
        mem_init();
        kmem_cache_init();
+       pgtable_cache_init();
        vmalloc_init();
 }
 
@@ -670,7 +672,6 @@ asmlinkage void __init start_kernel(void)
                initrd_start = 0;
        }
 #endif
-       cpuset_init_early();
        page_cgroup_init();
        enable_debug_pagealloc();
        cpu_hotplug_init();
@@ -684,7 +685,6 @@ asmlinkage void __init start_kernel(void)
                late_time_init();
        calibrate_delay();
        pidmap_init();
-       pgtable_cache_init();
        anon_vma_init();
 #ifdef CONFIG_X86
        if (efi_enabled)
@@ -867,6 +867,11 @@ static noinline int init_post(void)
 static int __init kernel_init(void * unused)
 {
        lock_kernel();
+
+       /*
+        * init can allocate pages on any node
+        */
+       set_mems_allowed(node_possible_map);
        /*
         * init can run on any cpu.
         */
index 90b53f6dc226c674d9b05eee60bcc671bab0edc9..9df4501cb92158d64ac3db254f7ae9e4ca93d22c 100644 (file)
@@ -11,6 +11,7 @@ obj-y     = sched.o fork.o exec_domain.o panic.o printk.o \
            hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \
            notifier.o ksysfs.o pm_qos_params.o sched_clock.o cred.o \
            async.o
+obj-y += groups.o
 
 ifdef CONFIG_FUNCTION_TRACER
 # Do not trace debug files and internal ftrace files
index d5a7e17474ee354259e71878156b6ea82ac8a6a2..7e75a41bd50855caf3a33109bed11a52fa967f80 100644 (file)
@@ -97,12 +97,6 @@ struct cpuset {
 
        struct cpuset *parent;          /* my parent */
 
-       /*
-        * Copy of global cpuset_mems_generation as of the most
-        * recent time this cpuset changed its mems_allowed.
-        */
-       int mems_generation;
-
        struct fmeter fmeter;           /* memory_pressure filter */
 
        /* partition number for rebuild_sched_domains() */
@@ -176,27 +170,6 @@ static inline int is_spread_slab(const struct cpuset *cs)
        return test_bit(CS_SPREAD_SLAB, &cs->flags);
 }
 
-/*
- * Increment this integer everytime any cpuset changes its
- * mems_allowed value.  Users of cpusets can track this generation
- * number, and avoid having to lock and reload mems_allowed unless
- * the cpuset they're using changes generation.
- *
- * A single, global generation is needed because cpuset_attach_task() could
- * reattach a task to a different cpuset, which must not have its
- * generation numbers aliased with those of that tasks previous cpuset.
- *
- * Generations are needed for mems_allowed because one task cannot
- * modify another's memory placement.  So we must enable every task,
- * on every visit to __alloc_pages(), to efficiently check whether
- * its current->cpuset->mems_allowed has changed, requiring an update
- * of its current->mems_allowed.
- *
- * Since writes to cpuset_mems_generation are guarded by the cgroup lock
- * there is no need to mark it atomic.
- */
-static int cpuset_mems_generation;
-
 static struct cpuset top_cpuset = {
        .flags = ((1 << CS_CPU_EXCLUSIVE) | (1 << CS_MEM_EXCLUSIVE)),
 };
@@ -228,8 +201,9 @@ static struct cpuset top_cpuset = {
  * If a task is only holding callback_mutex, then it has read-only
  * access to cpusets.
  *
- * The task_struct fields mems_allowed and mems_generation may only
- * be accessed in the context of that task, so require no locks.
+ * Now, the task_struct fields mems_allowed and mempolicy may be changed
+ * by other task, we use alloc_lock in the task_struct fields to protect
+ * them.
  *
  * The cpuset_common_file_read() handlers only hold callback_mutex across
  * small pieces of code, such as when reading out possibly multi-word
@@ -331,75 +305,22 @@ static void guarantee_online_mems(const struct cpuset *cs, nodemask_t *pmask)
        BUG_ON(!nodes_intersects(*pmask, node_states[N_HIGH_MEMORY]));
 }
 
-/**
- * cpuset_update_task_memory_state - update task memory placement
- *
- * If the current tasks cpusets mems_allowed changed behind our
- * backs, update current->mems_allowed, mems_generation and task NUMA
- * mempolicy to the new value.
- *
- * Task mempolicy is updated by rebinding it relative to the
- * current->cpuset if a task has its memory placement changed.
- * Do not call this routine if in_interrupt().
- *
- * Call without callback_mutex or task_lock() held.  May be
- * called with or without cgroup_mutex held.  Thanks in part to
- * 'the_top_cpuset_hack', the task's cpuset pointer will never
- * be NULL.  This routine also might acquire callback_mutex during
- * call.
- *
- * Reading current->cpuset->mems_generation doesn't need task_lock
- * to guard the current->cpuset derefence, because it is guarded
- * from concurrent freeing of current->cpuset using RCU.
- *
- * The rcu_dereference() is technically probably not needed,
- * as I don't actually mind if I see a new cpuset pointer but
- * an old value of mems_generation.  However this really only
- * matters on alpha systems using cpusets heavily.  If I dropped
- * that rcu_dereference(), it would save them a memory barrier.
- * For all other arch's, rcu_dereference is a no-op anyway, and for
- * alpha systems not using cpusets, another planned optimization,
- * avoiding the rcu critical section for tasks in the root cpuset
- * which is statically allocated, so can't vanish, will make this
- * irrelevant.  Better to use RCU as intended, than to engage in
- * some cute trick to save a memory barrier that is impossible to
- * test, for alpha systems using cpusets heavily, which might not
- * even exist.
- *
- * This routine is needed to update the per-task mems_allowed data,
- * within the tasks context, when it is trying to allocate memory
- * (in various mm/mempolicy.c routines) and notices that some other
- * task has been modifying its cpuset.
+/*
+ * update task's spread flag if cpuset's page/slab spread flag is set
+ *
+ * Called with callback_mutex/cgroup_mutex held
  */
-
-void cpuset_update_task_memory_state(void)
+static void cpuset_update_task_spread_flag(struct cpuset *cs,
+                                       struct task_struct *tsk)
 {
-       int my_cpusets_mem_gen;
-       struct task_struct *tsk = current;
-       struct cpuset *cs;
-
-       rcu_read_lock();
-       my_cpusets_mem_gen = task_cs(tsk)->mems_generation;
-       rcu_read_unlock();
-
-       if (my_cpusets_mem_gen != tsk->cpuset_mems_generation) {
-               mutex_lock(&callback_mutex);
-               task_lock(tsk);
-               cs = task_cs(tsk); /* Maybe changed when task not locked */
-               guarantee_online_mems(cs, &tsk->mems_allowed);
-               tsk->cpuset_mems_generation = cs->mems_generation;
-               if (is_spread_page(cs))
-                       tsk->flags |= PF_SPREAD_PAGE;
-               else
-                       tsk->flags &= ~PF_SPREAD_PAGE;
-               if (is_spread_slab(cs))
-                       tsk->flags |= PF_SPREAD_SLAB;
-               else
-                       tsk->flags &= ~PF_SPREAD_SLAB;
-               task_unlock(tsk);
-               mutex_unlock(&callback_mutex);
-               mpol_rebind_task(tsk, &tsk->mems_allowed);
-       }
+       if (is_spread_page(cs))
+               tsk->flags |= PF_SPREAD_PAGE;
+       else
+               tsk->flags &= ~PF_SPREAD_PAGE;
+       if (is_spread_slab(cs))
+               tsk->flags |= PF_SPREAD_SLAB;
+       else
+               tsk->flags &= ~PF_SPREAD_SLAB;
 }
 
 /*
@@ -1007,14 +928,6 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
  *    other task, the task_struct mems_allowed that we are hacking
  *    is for our current task, which must allocate new pages for that
  *    migrating memory region.
- *
- *    We call cpuset_update_task_memory_state() before hacking
- *    our tasks mems_allowed, so that we are assured of being in
- *    sync with our tasks cpuset, and in particular, callbacks to
- *    cpuset_update_task_memory_state() from nested page allocations
- *    won't see any mismatch of our cpuset and task mems_generation
- *    values, so won't overwrite our hacked tasks mems_allowed
- *    nodemask.
  */
 
 static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from,
@@ -1022,22 +935,37 @@ static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from,
 {
        struct task_struct *tsk = current;
 
-       cpuset_update_task_memory_state();
-
-       mutex_lock(&callback_mutex);
        tsk->mems_allowed = *to;
-       mutex_unlock(&callback_mutex);
 
        do_migrate_pages(mm, from, to, MPOL_MF_MOVE_ALL);
 
-       mutex_lock(&callback_mutex);
        guarantee_online_mems(task_cs(tsk),&tsk->mems_allowed);
-       mutex_unlock(&callback_mutex);
 }
 
 /*
- * Rebind task's vmas to cpuset's new mems_allowed, and migrate pages to new
- * nodes if memory_migrate flag is set. Called with cgroup_mutex held.
+ * cpuset_change_task_nodemask - change task's mems_allowed and mempolicy
+ * @tsk: the task to change
+ * @newmems: new nodes that the task will be set
+ *
+ * In order to avoid seeing no nodes if the old and new nodes are disjoint,
+ * we structure updates as setting all new allowed nodes, then clearing newly
+ * disallowed ones.
+ *
+ * Called with task's alloc_lock held
+ */
+static void cpuset_change_task_nodemask(struct task_struct *tsk,
+                                       nodemask_t *newmems)
+{
+       nodes_or(tsk->mems_allowed, tsk->mems_allowed, *newmems);
+       mpol_rebind_task(tsk, &tsk->mems_allowed);
+       mpol_rebind_task(tsk, newmems);
+       tsk->mems_allowed = *newmems;
+}
+
+/*
+ * Update task's mems_allowed and rebind its mempolicy and vmas' mempolicy
+ * of it to cpuset's new mems_allowed, and migrate pages to new nodes if
+ * memory_migrate flag is set. Called with cgroup_mutex held.
  */
 static void cpuset_change_nodemask(struct task_struct *p,
                                   struct cgroup_scanner *scan)
@@ -1046,12 +974,19 @@ static void cpuset_change_nodemask(struct task_struct *p,
        struct cpuset *cs;
        int migrate;
        const nodemask_t *oldmem = scan->data;
+       nodemask_t newmems;
+
+       cs = cgroup_cs(scan->cg);
+       guarantee_online_mems(cs, &newmems);
+
+       task_lock(p);
+       cpuset_change_task_nodemask(p, &newmems);
+       task_unlock(p);
 
        mm = get_task_mm(p);
        if (!mm)
                return;
 
-       cs = cgroup_cs(scan->cg);
        migrate = is_memory_migrate(cs);
 
        mpol_rebind_mm(mm, &cs->mems_allowed);
@@ -1104,10 +1039,10 @@ static void update_tasks_nodemask(struct cpuset *cs, const nodemask_t *oldmem,
 /*
  * Handle user request to change the 'mems' memory placement
  * of a cpuset.  Needs to validate the request, update the
- * cpusets mems_allowed and mems_generation, and for each
- * task in the cpuset, rebind any vma mempolicies and if
- * the cpuset is marked 'memory_migrate', migrate the tasks
- * pages to the new memory.
+ * cpusets mems_allowed, and for each task in the cpuset,
+ * update mems_allowed and rebind task's mempolicy and any vma
+ * mempolicies and if the cpuset is marked 'memory_migrate',
+ * migrate the tasks pages to the new memory.
  *
  * Call with cgroup_mutex held.  May take callback_mutex during call.
  * Will take tasklist_lock, scan tasklist for tasks in cpuset cs,
@@ -1160,7 +1095,6 @@ static int update_nodemask(struct cpuset *cs, struct cpuset *trialcs,
 
        mutex_lock(&callback_mutex);
        cs->mems_allowed = trialcs->mems_allowed;
-       cs->mems_generation = cpuset_mems_generation++;
        mutex_unlock(&callback_mutex);
 
        update_tasks_nodemask(cs, &oldmem, &heap);
@@ -1192,6 +1126,46 @@ static int update_relax_domain_level(struct cpuset *cs, s64 val)
        return 0;
 }
 
+/*
+ * cpuset_change_flag - make a task's spread flags the same as its cpuset's
+ * @tsk: task to be updated
+ * @scan: struct cgroup_scanner containing the cgroup of the task
+ *
+ * Called by cgroup_scan_tasks() for each task in a cgroup.
+ *
+ * We don't need to re-check for the cgroup/cpuset membership, since we're
+ * holding cgroup_lock() at this point.
+ */
+static void cpuset_change_flag(struct task_struct *tsk,
+                               struct cgroup_scanner *scan)
+{
+       cpuset_update_task_spread_flag(cgroup_cs(scan->cg), tsk);
+}
+
+/*
+ * update_tasks_flags - update the spread flags of tasks in the cpuset.
+ * @cs: the cpuset in which each task's spread flags needs to be changed
+ * @heap: if NULL, defer allocating heap memory to cgroup_scan_tasks()
+ *
+ * Called with cgroup_mutex held
+ *
+ * The cgroup_scan_tasks() function will scan all the tasks in a cgroup,
+ * calling callback functions for each.
+ *
+ * No return value. It's guaranteed that cgroup_scan_tasks() always returns 0
+ * if @heap != NULL.
+ */
+static void update_tasks_flags(struct cpuset *cs, struct ptr_heap *heap)
+{
+       struct cgroup_scanner scan;
+
+       scan.cg = cs->css.cgroup;
+       scan.test_task = NULL;
+       scan.process_task = cpuset_change_flag;
+       scan.heap = heap;
+       cgroup_scan_tasks(&scan);
+}
+
 /*
  * update_flag - read a 0 or a 1 in a file and update associated flag
  * bit:                the bit to update (see cpuset_flagbits_t)
@@ -1205,8 +1179,10 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs,
                       int turning_on)
 {
        struct cpuset *trialcs;
-       int err;
        int balance_flag_changed;
+       int spread_flag_changed;
+       struct ptr_heap heap;
+       int err;
 
        trialcs = alloc_trial_cpuset(cs);
        if (!trialcs)
@@ -1221,9 +1197,16 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs,
        if (err < 0)
                goto out;
 
+       err = heap_init(&heap, PAGE_SIZE, GFP_KERNEL, NULL);
+       if (err < 0)
+               goto out;
+
        balance_flag_changed = (is_sched_load_balance(cs) !=
                                is_sched_load_balance(trialcs));
 
+       spread_flag_changed = ((is_spread_slab(cs) != is_spread_slab(trialcs))
+                       || (is_spread_page(cs) != is_spread_page(trialcs)));
+
        mutex_lock(&callback_mutex);
        cs->flags = trialcs->flags;
        mutex_unlock(&callback_mutex);
@@ -1231,6 +1214,9 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs,
        if (!cpumask_empty(trialcs->cpus_allowed) && balance_flag_changed)
                async_rebuild_sched_domains();
 
+       if (spread_flag_changed)
+               update_tasks_flags(cs, &heap);
+       heap_free(&heap);
 out:
        free_trial_cpuset(trialcs);
        return err;
@@ -1372,15 +1358,20 @@ static void cpuset_attach(struct cgroup_subsys *ss,
 
        if (cs == &top_cpuset) {
                cpumask_copy(cpus_attach, cpu_possible_mask);
+               to = node_possible_map;
        } else {
-               mutex_lock(&callback_mutex);
                guarantee_online_cpus(cs, cpus_attach);
-               mutex_unlock(&callback_mutex);
+               guarantee_online_mems(cs, &to);
        }
        err = set_cpus_allowed_ptr(tsk, cpus_attach);
        if (err)
                return;
 
+       task_lock(tsk);
+       cpuset_change_task_nodemask(tsk, &to);
+       task_unlock(tsk);
+       cpuset_update_task_spread_flag(cs, tsk);
+
        from = oldcs->mems_allowed;
        to = cs->mems_allowed;
        mm = get_task_mm(tsk);
@@ -1442,11 +1433,9 @@ static int cpuset_write_u64(struct cgroup *cgrp, struct cftype *cft, u64 val)
                break;
        case FILE_SPREAD_PAGE:
                retval = update_flag(CS_SPREAD_PAGE, cs, val);
-               cs->mems_generation = cpuset_mems_generation++;
                break;
        case FILE_SPREAD_SLAB:
                retval = update_flag(CS_SPREAD_SLAB, cs, val);
-               cs->mems_generation = cpuset_mems_generation++;
                break;
        default:
                retval = -EINVAL;
@@ -1786,8 +1775,6 @@ static struct cgroup_subsys_state *cpuset_create(
        struct cpuset *parent;
 
        if (!cont->parent) {
-               /* This is early initialization for the top cgroup */
-               top_cpuset.mems_generation = cpuset_mems_generation++;
                return &top_cpuset.css;
        }
        parent = cgroup_cs(cont->parent);
@@ -1799,7 +1786,6 @@ static struct cgroup_subsys_state *cpuset_create(
                return ERR_PTR(-ENOMEM);
        }
 
-       cpuset_update_task_memory_state();
        cs->flags = 0;
        if (is_spread_page(parent))
                set_bit(CS_SPREAD_PAGE, &cs->flags);
@@ -1808,7 +1794,6 @@ static struct cgroup_subsys_state *cpuset_create(
        set_bit(CS_SCHED_LOAD_BALANCE, &cs->flags);
        cpumask_clear(cs->cpus_allowed);
        nodes_clear(cs->mems_allowed);
-       cs->mems_generation = cpuset_mems_generation++;
        fmeter_init(&cs->fmeter);
        cs->relax_domain_level = -1;
 
@@ -1827,8 +1812,6 @@ static void cpuset_destroy(struct cgroup_subsys *ss, struct cgroup *cont)
 {
        struct cpuset *cs = cgroup_cs(cont);
 
-       cpuset_update_task_memory_state();
-
        if (is_sched_load_balance(cs))
                update_flag(CS_SCHED_LOAD_BALANCE, cs, 0);
 
@@ -1849,21 +1832,6 @@ struct cgroup_subsys cpuset_subsys = {
        .early_init = 1,
 };
 
-/*
- * cpuset_init_early - just enough so that the calls to
- * cpuset_update_task_memory_state() in early init code
- * are harmless.
- */
-
-int __init cpuset_init_early(void)
-{
-       alloc_cpumask_var(&top_cpuset.cpus_allowed, GFP_NOWAIT);
-
-       top_cpuset.mems_generation = cpuset_mems_generation++;
-       return 0;
-}
-
-
 /**
  * cpuset_init - initialize cpusets at system boot
  *
@@ -1874,11 +1842,13 @@ int __init cpuset_init(void)
 {
        int err = 0;
 
+       if (!alloc_cpumask_var(&top_cpuset.cpus_allowed, GFP_KERNEL))
+               BUG();
+
        cpumask_setall(top_cpuset.cpus_allowed);
        nodes_setall(top_cpuset.mems_allowed);
 
        fmeter_init(&top_cpuset.fmeter);
-       top_cpuset.mems_generation = cpuset_mems_generation++;
        set_bit(CS_SCHED_LOAD_BALANCE, &top_cpuset.flags);
        top_cpuset.relax_domain_level = -1;
 
index 4430eb1376f257bd008dab17d3c6ea19cc9c2d3b..be022c200da67fdf1206761ba3adbb38a3208cdd 100644 (file)
@@ -178,7 +178,7 @@ void __init fork_init(unsigned long mempages)
        /* create a slab on which task_structs can be allocated */
        task_struct_cachep =
                kmem_cache_create("task_struct", sizeof(struct task_struct),
-                       ARCH_MIN_TASKALIGN, SLAB_PANIC, NULL);
+                       ARCH_MIN_TASKALIGN, SLAB_PANIC | SLAB_NOTRACK, NULL);
 #endif
 
        /* do the arch specific task caches init */
@@ -1470,20 +1470,20 @@ void __init proc_caches_init(void)
 {
        sighand_cachep = kmem_cache_create("sighand_cache",
                        sizeof(struct sighand_struct), 0,
-                       SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_DESTROY_BY_RCU,
-                       sighand_ctor);
+                       SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_DESTROY_BY_RCU|
+                       SLAB_NOTRACK, sighand_ctor);
        signal_cachep = kmem_cache_create("signal_cache",
                        sizeof(struct signal_struct), 0,
-                       SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
+                       SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_NOTRACK, NULL);
        files_cachep = kmem_cache_create("files_cache",
                        sizeof(struct files_struct), 0,
-                       SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
+                       SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_NOTRACK, NULL);
        fs_cachep = kmem_cache_create("fs_cache",
                        sizeof(struct fs_struct), 0,
-                       SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
+                       SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_NOTRACK, NULL);
        mm_cachep = kmem_cache_create("mm_struct",
                        sizeof(struct mm_struct), ARCH_MIN_MMSTRUCT_ALIGN,
-                       SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
+                       SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_NOTRACK, NULL);
        vm_area_cachep = KMEM_CACHE(vm_area_struct, SLAB_PANIC);
        mmap_init();
 }
diff --git a/kernel/groups.c b/kernel/groups.c
new file mode 100644 (file)
index 0000000..2b45b2e
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ * Supplementary group IDs
+ */
+#include <linux/cred.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/security.h>
+#include <linux/syscalls.h>
+#include <asm/uaccess.h>
+
+/* init to 2 - one for init_task, one to ensure it is never freed */
+struct group_info init_groups = { .usage = ATOMIC_INIT(2) };
+
+struct group_info *groups_alloc(int gidsetsize)
+{
+       struct group_info *group_info;
+       int nblocks;
+       int i;
+
+       nblocks = (gidsetsize + NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK;
+       /* Make sure we always allocate at least one indirect block pointer */
+       nblocks = nblocks ? : 1;
+       group_info = kmalloc(sizeof(*group_info) + nblocks*sizeof(gid_t *), GFP_USER);
+       if (!group_info)
+               return NULL;
+       group_info->ngroups = gidsetsize;
+       group_info->nblocks = nblocks;
+       atomic_set(&group_info->usage, 1);
+
+       if (gidsetsize <= NGROUPS_SMALL)
+               group_info->blocks[0] = group_info->small_block;
+       else {
+               for (i = 0; i < nblocks; i++) {
+                       gid_t *b;
+                       b = (void *)__get_free_page(GFP_USER);
+                       if (!b)
+                               goto out_undo_partial_alloc;
+                       group_info->blocks[i] = b;
+               }
+       }
+       return group_info;
+
+out_undo_partial_alloc:
+       while (--i >= 0) {
+               free_page((unsigned long)group_info->blocks[i]);
+       }
+       kfree(group_info);
+       return NULL;
+}
+
+EXPORT_SYMBOL(groups_alloc);
+
+void groups_free(struct group_info *group_info)
+{
+       if (group_info->blocks[0] != group_info->small_block) {
+               int i;
+               for (i = 0; i < group_info->nblocks; i++)
+                       free_page((unsigned long)group_info->blocks[i]);
+       }
+       kfree(group_info);
+}
+
+EXPORT_SYMBOL(groups_free);
+
+/* export the group_info to a user-space array */
+static int groups_to_user(gid_t __user *grouplist,
+                         const struct group_info *group_info)
+{
+       int i;
+       unsigned int count = group_info->ngroups;
+
+       for (i = 0; i < group_info->nblocks; i++) {
+               unsigned int cp_count = min(NGROUPS_PER_BLOCK, count);
+               unsigned int len = cp_count * sizeof(*grouplist);
+
+               if (copy_to_user(grouplist, group_info->blocks[i], len))
+                       return -EFAULT;
+
+               grouplist += NGROUPS_PER_BLOCK;
+               count -= cp_count;
+       }
+       return 0;
+}
+
+/* fill a group_info from a user-space array - it must be allocated already */
+static int groups_from_user(struct group_info *group_info,
+    gid_t __user *grouplist)
+{
+       int i;
+       unsigned int count = group_info->ngroups;
+
+       for (i = 0; i < group_info->nblocks; i++) {
+               unsigned int cp_count = min(NGROUPS_PER_BLOCK, count);
+               unsigned int len = cp_count * sizeof(*grouplist);
+
+               if (copy_from_user(group_info->blocks[i], grouplist, len))
+                       return -EFAULT;
+
+               grouplist += NGROUPS_PER_BLOCK;
+               count -= cp_count;
+       }
+       return 0;
+}
+
+/* a simple Shell sort */
+static void groups_sort(struct group_info *group_info)
+{
+       int base, max, stride;
+       int gidsetsize = group_info->ngroups;
+
+       for (stride = 1; stride < gidsetsize; stride = 3 * stride + 1)
+               ; /* nothing */
+       stride /= 3;
+
+       while (stride) {
+               max = gidsetsize - stride;
+               for (base = 0; base < max; base++) {
+                       int left = base;
+                       int right = left + stride;
+                       gid_t tmp = GROUP_AT(group_info, right);
+
+                       while (left >= 0 && GROUP_AT(group_info, left) > tmp) {
+                               GROUP_AT(group_info, right) =
+                                   GROUP_AT(group_info, left);
+                               right = left;
+                               left -= stride;
+                       }
+                       GROUP_AT(group_info, right) = tmp;
+               }
+               stride /= 3;
+       }
+}
+
+/* a simple bsearch */
+int groups_search(const struct group_info *group_info, gid_t grp)
+{
+       unsigned int left, right;
+
+       if (!group_info)
+               return 0;
+
+       left = 0;
+       right = group_info->ngroups;
+       while (left < right) {
+               unsigned int mid = (left+right)/2;
+               int cmp = grp - GROUP_AT(group_info, mid);
+               if (cmp > 0)
+                       left = mid + 1;
+               else if (cmp < 0)
+                       right = mid;
+               else
+                       return 1;
+       }
+       return 0;
+}
+
+/**
+ * set_groups - Change a group subscription in a set of credentials
+ * @new: The newly prepared set of credentials to alter
+ * @group_info: The group list to install
+ *
+ * Validate a group subscription and, if valid, insert it into a set
+ * of credentials.
+ */
+int set_groups(struct cred *new, struct group_info *group_info)
+{
+       int retval;
+
+       retval = security_task_setgroups(group_info);
+       if (retval)
+               return retval;
+
+       put_group_info(new->group_info);
+       groups_sort(group_info);
+       get_group_info(group_info);
+       new->group_info = group_info;
+       return 0;
+}
+
+EXPORT_SYMBOL(set_groups);
+
+/**
+ * set_current_groups - Change current's group subscription
+ * @group_info: The group list to impose
+ *
+ * Validate a group subscription and, if valid, impose it upon current's task
+ * security record.
+ */
+int set_current_groups(struct group_info *group_info)
+{
+       struct cred *new;
+       int ret;
+
+       new = prepare_creds();
+       if (!new)
+               return -ENOMEM;
+
+       ret = set_groups(new, group_info);
+       if (ret < 0) {
+               abort_creds(new);
+               return ret;
+       }
+
+       return commit_creds(new);
+}
+
+EXPORT_SYMBOL(set_current_groups);
+
+SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t __user *, grouplist)
+{
+       const struct cred *cred = current_cred();
+       int i;
+
+       if (gidsetsize < 0)
+               return -EINVAL;
+
+       /* no need to grab task_lock here; it cannot change */
+       i = cred->group_info->ngroups;
+       if (gidsetsize) {
+               if (i > gidsetsize) {
+                       i = -EINVAL;
+                       goto out;
+               }
+               if (groups_to_user(grouplist, cred->group_info)) {
+                       i = -EFAULT;
+                       goto out;
+               }
+       }
+out:
+       return i;
+}
+
+/*
+ *     SMP: Our groups are copy-on-write. We can set them safely
+ *     without another task interfering.
+ */
+
+SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist)
+{
+       struct group_info *group_info;
+       int retval;
+
+       if (!capable(CAP_SETGID))
+               return -EPERM;
+       if ((unsigned)gidsetsize > NGROUPS_MAX)
+               return -EINVAL;
+
+       group_info = groups_alloc(gidsetsize);
+       if (!group_info)
+               return -ENOMEM;
+       retval = groups_from_user(group_info, grouplist);
+       if (retval) {
+               put_group_info(group_info);
+               return retval;
+       }
+
+       retval = set_current_groups(group_info);
+       put_group_info(group_info);
+
+       return retval;
+}
+
+/*
+ * Check whether we're fsgid/egid or in the supplemental group..
+ */
+int in_group_p(gid_t grp)
+{
+       const struct cred *cred = current_cred();
+       int retval = 1;
+
+       if (grp != cred->fsgid)
+               retval = groups_search(cred->group_info, grp);
+       return retval;
+}
+
+EXPORT_SYMBOL(in_group_p);
+
+int in_egroup_p(gid_t grp)
+{
+       const struct cred *cred = current_cred();
+       int retval = 1;
+
+       if (grp != cred->egid)
+               retval = groups_search(cred->group_info, grp);
+       return retval;
+}
+
+EXPORT_SYMBOL(in_egroup_p);
index bc41ad0f24f881845d96d77a00a3d3535968566b..26539e3228e50f81ca892122a23b6bd1fcf98fe6 100644 (file)
@@ -72,9 +72,9 @@ struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock)
 
        /*
         * round up to the next power of 2, since our 'let the indices
-        * wrap' tachnique works only in this case.
+        * wrap' technique works only in this case.
         */
-       if (size & (size - 1)) {
+       if (!is_power_of_2(size)) {
                BUG_ON(size > 0x80000000);
                size = roundup_pow_of_two(size);
        }
index 41c88fe40500399c76f0382d51a3fb05aef03211..7fa441333529588586cd5a538e7b1fbdd118fbfd 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/kthread.h>
 #include <linux/completion.h>
 #include <linux/err.h>
+#include <linux/cpuset.h>
 #include <linux/unistd.h>
 #include <linux/file.h>
 #include <linux/module.h>
@@ -236,6 +237,7 @@ int kthreadd(void *unused)
        ignore_signals(tsk);
        set_user_nice(tsk, KTHREAD_NICE_LEVEL);
        set_cpus_allowed_ptr(tsk, cpu_all_mask);
+       set_mems_allowed(node_possible_map);
 
        current->flags |= PF_NOFREEZE | PF_FREEZER_NOSIG;
 
index e4ab36ce767222becc860650e0892399ab58b96d..215aaab09e91e1e76839f403dc2e4474a512ef40 100644 (file)
@@ -2899,7 +2899,7 @@ void print_modules(void)
        struct module *mod;
        char buf[8];
 
-       printk("Modules linked in:");
+       printk(KERN_DEFAULT "Modules linked in:");
        /* Most callers should already have preempt disabled, but make sure */
        preempt_disable();
        list_for_each_entry_rcu(mod, &modules, list)
index ca634019497a5cf8b035872bdaf8edcfaefd8b88..da2072d7381160493d540a51976f45a966b265fb 100644 (file)
@@ -117,9 +117,12 @@ int freeze_processes(void)
        if (error)
                goto Exit;
        printk("done.");
+
+       oom_killer_disable();
  Exit:
        BUG_ON(in_atomic());
        printk("\n");
+
        return error;
 }
 
@@ -145,6 +148,8 @@ static void thaw_tasks(bool nosig_only)
 
 void thaw_processes(void)
 {
+       oom_killer_enable();
+
        printk("Restarting tasks ... ");
        thaw_tasks(true);
        thaw_tasks(false);
index 5052b5497c67995f57c6b548b0b52c1989f4027b..b4d97b54c1ecfa729eaa4b07dc2f721c25bca3ca 100644 (file)
@@ -687,20 +687,35 @@ asmlinkage int vprintk(const char *fmt, va_list args)
                                  sizeof(printk_buf) - printed_len, fmt, args);
 
 
+       p = printk_buf;
+
+       /* Do we have a loglevel in the string? */
+       if (p[0] == '<') {
+               unsigned char c = p[1];
+               if (c && p[2] == '>') {
+                       switch (c) {
+                       case '0' ... '7': /* loglevel */
+                               current_log_level = c - '0';
+                       /* Fallthrough - make sure we're on a new line */
+                       case 'd': /* KERN_DEFAULT */
+                               if (!new_text_line) {
+                                       emit_log_char('\n');
+                                       new_text_line = 1;
+                               }
+                       /* Fallthrough - skip the loglevel */
+                       case 'c': /* KERN_CONT */
+                               p += 3;
+                               break;
+                       }
+               }
+       }
+
        /*
         * Copy the output into log_buf.  If the caller didn't provide
         * appropriate log level tags, we insert them here
         */
-       for (p = printk_buf; *p; p++) {
+       for ( ; *p; p++) {
                if (new_text_line) {
-                       /* If a token, set current_log_level and skip over */
-                       if (p[0] == '<' && p[1] >= '0' && p[1] <= '7' &&
-                           p[2] == '>') {
-                               current_log_level = p[1] - '0';
-                               p += 3;
-                               printed_len -= 3;
-                       }
-
                        /* Always output the token */
                        emit_log_char('<');
                        emit_log_char(current_log_level + '0');
index 28cf26ad2d247e497411f4603496209b1f8493f0..69911b5745eb1a9fd406e7bf3ef4a653033898a2 100644 (file)
@@ -365,7 +365,7 @@ static int __cpuinit profile_cpu_callback(struct notifier_block *info,
                node = cpu_to_node(cpu);
                per_cpu(cpu_profile_flip, cpu) = 0;
                if (!per_cpu(cpu_profile_hits, cpu)[1]) {
-                       page = alloc_pages_node(node,
+                       page = alloc_pages_exact_node(node,
                                        GFP_KERNEL | __GFP_ZERO,
                                        0);
                        if (!page)
@@ -373,7 +373,7 @@ static int __cpuinit profile_cpu_callback(struct notifier_block *info,
                        per_cpu(cpu_profile_hits, cpu)[1] = page_address(page);
                }
                if (!per_cpu(cpu_profile_hits, cpu)[0]) {
-                       page = alloc_pages_node(node,
+                       page = alloc_pages_exact_node(node,
                                        GFP_KERNEL | __GFP_ZERO,
                                        0);
                        if (!page)
@@ -564,14 +564,14 @@ static int create_hash_tables(void)
                int node = cpu_to_node(cpu);
                struct page *page;
 
-               page = alloc_pages_node(node,
+               page = alloc_pages_exact_node(node,
                                GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
                                0);
                if (!page)
                        goto out_cleanup;
                per_cpu(cpu_profile_hits, cpu)[1]
                                = (struct profile_hit *)page_address(page);
-               page = alloc_pages_node(node,
+               page = alloc_pages_exact_node(node,
                                GFP_KERNEL | __GFP_ZERO | GFP_THISNODE,
                                0);
                if (!page)
index 809a228019adeb06c8979d86f52473a0d4a168ac..d81f4952eebbcfa484c338256e3ff2e84c9d3b1e 100644 (file)
@@ -832,6 +832,7 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
 {
        struct sigpending *pending;
        struct sigqueue *q;
+       int override_rlimit;
 
        trace_sched_signal_send(sig, t);
 
@@ -863,9 +864,13 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
           make sure at least one signal gets delivered and don't
           pass on the info struct.  */
 
-       q = __sigqueue_alloc(t, GFP_ATOMIC, (sig < SIGRTMIN &&
-                                            (is_si_special(info) ||
-                                             info->si_code >= 0)));
+       if (sig < SIGRTMIN)
+               override_rlimit = (is_si_special(info) || info->si_code >= 0);
+       else
+               override_rlimit = 0;
+
+       q = __sigqueue_alloc(t, GFP_ATOMIC | __GFP_NOTRACK_FALSE_POSITIVE,
+               override_rlimit);
        if (q) {
                list_add_tail(&q->list, &pending->list);
                switch ((unsigned long) info) {
index 521ed2004d63fc7cf2bfbd8eff33d7d1bf58f1d3..09d7519557d35181fab35591a17516efe5aba723 100644 (file)
@@ -318,6 +318,15 @@ cant_get_ref:
 }
 EXPORT_SYMBOL(slow_work_enqueue);
 
+/*
+ * Schedule a cull of the thread pool at some time in the near future
+ */
+static void slow_work_schedule_cull(void)
+{
+       mod_timer(&slow_work_cull_timer,
+                 round_jiffies(jiffies + SLOW_WORK_CULL_TIMEOUT));
+}
+
 /*
  * Worker thread culling algorithm
  */
@@ -335,8 +344,7 @@ static bool slow_work_cull_thread(void)
                    list_empty(&vslow_work_queue) &&
                    atomic_read(&slow_work_thread_count) >
                    slow_work_min_threads) {
-                       mod_timer(&slow_work_cull_timer,
-                                 jiffies + SLOW_WORK_CULL_TIMEOUT);
+                       slow_work_schedule_cull();
                        do_cull = true;
                }
        }
@@ -393,8 +401,7 @@ static int slow_work_thread(void *_data)
                            list_empty(&vslow_work_queue) &&
                            atomic_read(&slow_work_thread_count) >
                            slow_work_min_threads)
-                               mod_timer(&slow_work_cull_timer,
-                                         jiffies + SLOW_WORK_CULL_TIMEOUT);
+                               slow_work_schedule_cull();
                        continue;
                }
 
@@ -458,7 +465,7 @@ static void slow_work_new_thread_execute(struct slow_work *work)
                if (atomic_dec_and_test(&slow_work_thread_count))
                        BUG(); /* we're running on a slow work thread... */
                mod_timer(&slow_work_oom_timer,
-                         jiffies + SLOW_WORK_OOM_TIMEOUT);
+                         round_jiffies(jiffies + SLOW_WORK_OOM_TIMEOUT));
        } else {
                /* ratelimit the starting of new threads */
                mod_timer(&slow_work_oom_timer, jiffies + 1);
@@ -502,8 +509,7 @@ static int slow_work_min_threads_sysctl(struct ctl_table *table, int write,
                        if (n < 0 && !slow_work_may_not_start_new_thread)
                                slow_work_enqueue(&slow_work_new_thread);
                        else if (n > 0)
-                               mod_timer(&slow_work_cull_timer,
-                                         jiffies + SLOW_WORK_CULL_TIMEOUT);
+                               slow_work_schedule_cull();
                }
                mutex_unlock(&slow_work_user_lock);
        }
@@ -529,8 +535,7 @@ static int slow_work_max_threads_sysctl(struct ctl_table *table, int write,
                                atomic_read(&slow_work_thread_count);
 
                        if (n < 0)
-                               mod_timer(&slow_work_cull_timer,
-                                         jiffies + SLOW_WORK_CULL_TIMEOUT);
+                               slow_work_schedule_cull();
                }
                mutex_unlock(&slow_work_user_lock);
        }
index 258885a543db60692a695aa682abb6c95f3ffcdf..b41fb710e114f5d233c18c37b0e0aee9344fa7d8 100644 (file)
@@ -382,6 +382,17 @@ void __tasklet_hi_schedule(struct tasklet_struct *t)
 
 EXPORT_SYMBOL(__tasklet_hi_schedule);
 
+void __tasklet_hi_schedule_first(struct tasklet_struct *t)
+{
+       BUG_ON(!irqs_disabled());
+
+       t->next = __get_cpu_var(tasklet_hi_vec).head;
+       __get_cpu_var(tasklet_hi_vec).head = t;
+       __raise_softirq_irqoff(HI_SOFTIRQ);
+}
+
+EXPORT_SYMBOL(__tasklet_hi_schedule_first);
+
 static void tasklet_action(struct softirq_action *a)
 {
        struct tasklet_struct *list;
index 438d99a38c87f343dd318c3966799ec73bb6072a..b3f1097c76fa481df3597e035d7b0c36fe2db6c2 100644 (file)
@@ -1113,289 +1113,6 @@ out:
        return err;
 }
 
-/*
- * Supplementary group IDs
- */
-
-/* init to 2 - one for init_task, one to ensure it is never freed */
-struct group_info init_groups = { .usage = ATOMIC_INIT(2) };
-
-struct group_info *groups_alloc(int gidsetsize)
-{
-       struct group_info *group_info;
-       int nblocks;
-       int i;
-
-       nblocks = (gidsetsize + NGROUPS_PER_BLOCK - 1) / NGROUPS_PER_BLOCK;
-       /* Make sure we always allocate at least one indirect block pointer */
-       nblocks = nblocks ? : 1;
-       group_info = kmalloc(sizeof(*group_info) + nblocks*sizeof(gid_t *), GFP_USER);
-       if (!group_info)
-               return NULL;
-       group_info->ngroups = gidsetsize;
-       group_info->nblocks = nblocks;
-       atomic_set(&group_info->usage, 1);
-
-       if (gidsetsize <= NGROUPS_SMALL)
-               group_info->blocks[0] = group_info->small_block;
-       else {
-               for (i = 0; i < nblocks; i++) {
-                       gid_t *b;
-                       b = (void *)__get_free_page(GFP_USER);
-                       if (!b)
-                               goto out_undo_partial_alloc;
-                       group_info->blocks[i] = b;
-               }
-       }
-       return group_info;
-
-out_undo_partial_alloc:
-       while (--i >= 0) {
-               free_page((unsigned long)group_info->blocks[i]);
-       }
-       kfree(group_info);
-       return NULL;
-}
-
-EXPORT_SYMBOL(groups_alloc);
-
-void groups_free(struct group_info *group_info)
-{
-       if (group_info->blocks[0] != group_info->small_block) {
-               int i;
-               for (i = 0; i < group_info->nblocks; i++)
-                       free_page((unsigned long)group_info->blocks[i]);
-       }
-       kfree(group_info);
-}
-
-EXPORT_SYMBOL(groups_free);
-
-/* export the group_info to a user-space array */
-static int groups_to_user(gid_t __user *grouplist,
-                         const struct group_info *group_info)
-{
-       int i;
-       unsigned int count = group_info->ngroups;
-
-       for (i = 0; i < group_info->nblocks; i++) {
-               unsigned int cp_count = min(NGROUPS_PER_BLOCK, count);
-               unsigned int len = cp_count * sizeof(*grouplist);
-
-               if (copy_to_user(grouplist, group_info->blocks[i], len))
-                       return -EFAULT;
-
-               grouplist += NGROUPS_PER_BLOCK;
-               count -= cp_count;
-       }
-       return 0;
-}
-
-/* fill a group_info from a user-space array - it must be allocated already */
-static int groups_from_user(struct group_info *group_info,
-    gid_t __user *grouplist)
-{
-       int i;
-       unsigned int count = group_info->ngroups;
-
-       for (i = 0; i < group_info->nblocks; i++) {
-               unsigned int cp_count = min(NGROUPS_PER_BLOCK, count);
-               unsigned int len = cp_count * sizeof(*grouplist);
-
-               if (copy_from_user(group_info->blocks[i], grouplist, len))
-                       return -EFAULT;
-
-               grouplist += NGROUPS_PER_BLOCK;
-               count -= cp_count;
-       }
-       return 0;
-}
-
-/* a simple Shell sort */
-static void groups_sort(struct group_info *group_info)
-{
-       int base, max, stride;
-       int gidsetsize = group_info->ngroups;
-
-       for (stride = 1; stride < gidsetsize; stride = 3 * stride + 1)
-               ; /* nothing */
-       stride /= 3;
-
-       while (stride) {
-               max = gidsetsize - stride;
-               for (base = 0; base < max; base++) {
-                       int left = base;
-                       int right = left + stride;
-                       gid_t tmp = GROUP_AT(group_info, right);
-
-                       while (left >= 0 && GROUP_AT(group_info, left) > tmp) {
-                               GROUP_AT(group_info, right) =
-                                   GROUP_AT(group_info, left);
-                               right = left;
-                               left -= stride;
-                       }
-                       GROUP_AT(group_info, right) = tmp;
-               }
-               stride /= 3;
-       }
-}
-
-/* a simple bsearch */
-int groups_search(const struct group_info *group_info, gid_t grp)
-{
-       unsigned int left, right;
-
-       if (!group_info)
-               return 0;
-
-       left = 0;
-       right = group_info->ngroups;
-       while (left < right) {
-               unsigned int mid = (left+right)/2;
-               int cmp = grp - GROUP_AT(group_info, mid);
-               if (cmp > 0)
-                       left = mid + 1;
-               else if (cmp < 0)
-                       right = mid;
-               else
-                       return 1;
-       }
-       return 0;
-}
-
-/**
- * set_groups - Change a group subscription in a set of credentials
- * @new: The newly prepared set of credentials to alter
- * @group_info: The group list to install
- *
- * Validate a group subscription and, if valid, insert it into a set
- * of credentials.
- */
-int set_groups(struct cred *new, struct group_info *group_info)
-{
-       int retval;
-
-       retval = security_task_setgroups(group_info);
-       if (retval)
-               return retval;
-
-       put_group_info(new->group_info);
-       groups_sort(group_info);
-       get_group_info(group_info);
-       new->group_info = group_info;
-       return 0;
-}
-
-EXPORT_SYMBOL(set_groups);
-
-/**
- * set_current_groups - Change current's group subscription
- * @group_info: The group list to impose
- *
- * Validate a group subscription and, if valid, impose it upon current's task
- * security record.
- */
-int set_current_groups(struct group_info *group_info)
-{
-       struct cred *new;
-       int ret;
-
-       new = prepare_creds();
-       if (!new)
-               return -ENOMEM;
-
-       ret = set_groups(new, group_info);
-       if (ret < 0) {
-               abort_creds(new);
-               return ret;
-       }
-
-       return commit_creds(new);
-}
-
-EXPORT_SYMBOL(set_current_groups);
-
-SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t __user *, grouplist)
-{
-       const struct cred *cred = current_cred();
-       int i;
-
-       if (gidsetsize < 0)
-               return -EINVAL;
-
-       /* no need to grab task_lock here; it cannot change */
-       i = cred->group_info->ngroups;
-       if (gidsetsize) {
-               if (i > gidsetsize) {
-                       i = -EINVAL;
-                       goto out;
-               }
-               if (groups_to_user(grouplist, cred->group_info)) {
-                       i = -EFAULT;
-                       goto out;
-               }
-       }
-out:
-       return i;
-}
-
-/*
- *     SMP: Our groups are copy-on-write. We can set them safely
- *     without another task interfering.
- */
-SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist)
-{
-       struct group_info *group_info;
-       int retval;
-
-       if (!capable(CAP_SETGID))
-               return -EPERM;
-       if ((unsigned)gidsetsize > NGROUPS_MAX)
-               return -EINVAL;
-
-       group_info = groups_alloc(gidsetsize);
-       if (!group_info)
-               return -ENOMEM;
-       retval = groups_from_user(group_info, grouplist);
-       if (retval) {
-               put_group_info(group_info);
-               return retval;
-       }
-
-       retval = set_current_groups(group_info);
-       put_group_info(group_info);
-
-       return retval;
-}
-
-/*
- * Check whether we're fsgid/egid or in the supplemental group..
- */
-int in_group_p(gid_t grp)
-{
-       const struct cred *cred = current_cred();
-       int retval = 1;
-
-       if (grp != cred->fsgid)
-               retval = groups_search(cred->group_info, grp);
-       return retval;
-}
-
-EXPORT_SYMBOL(in_group_p);
-
-int in_egroup_p(gid_t grp)
-{
-       const struct cred *cred = current_cred();
-       int retval = 1;
-
-       if (grp != cred->egid)
-               retval = groups_search(cred->group_info, grp);
-       return retval;
-}
-
-EXPORT_SYMBOL(in_egroup_p);
-
 DECLARE_RWSEM(uts_sem);
 
 SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
index 0e51a35a44869425aa3f4e7cf9fca498787fd0fb..ab462b9968d579072de5e3421dcfa5ead354d590 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/security.h>
 #include <linux/ctype.h>
 #include <linux/utsname.h>
+#include <linux/kmemcheck.h>
 #include <linux/smp_lock.h>
 #include <linux/fs.h>
 #include <linux/init.h>
@@ -967,6 +968,17 @@ static struct ctl_table kern_table[] = {
                .proc_handler   = &proc_dointvec,
        },
 #endif
+#ifdef CONFIG_KMEMCHECK
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "kmemcheck",
+               .data           = &kmemcheck_enabled,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
+#endif
+
 /*
  * NOTE: do not add new entries to this table unless you have read
  * Documentation/sysctl/ctl_unnumbered.txt
@@ -1325,7 +1337,6 @@ static struct ctl_table vm_table[] = {
                .extra2         = &one,
        },
 #endif
-#ifdef CONFIG_UNEVICTABLE_LRU
        {
                .ctl_name       = CTL_UNNUMBERED,
                .procname       = "scan_unevictable_pages",
@@ -1334,7 +1345,6 @@ static struct ctl_table vm_table[] = {
                .mode           = 0644,
                .proc_handler   = &scan_unevictable_handler,
        },
-#endif
 /*
  * NOTE: do not add new entries to this table unless you have read
  * Documentation/sysctl/ctl_unnumbered.txt
index 4a13e5a01ce318c62c75c991a8694096e4821f40..61071fecc82e5a6f2ed1dad5605efe35a40e3f6e 100644 (file)
@@ -147,7 +147,7 @@ config IRQSOFF_TRACER
          disabled by default and can be runtime (re-)started
          via:
 
-             echo 0 > /debugfs/tracing/tracing_max_latency
+             echo 0 > /sys/kernel/debug/tracing/tracing_max_latency
 
          (Note that kernel size and overhead increases with this option
          enabled. This option and the preempt-off timing option can be
@@ -168,7 +168,7 @@ config PREEMPT_TRACER
          disabled by default and can be runtime (re-)started
          via:
 
-             echo 0 > /debugfs/tracing/tracing_max_latency
+             echo 0 > /sys/kernel/debug/tracing/tracing_max_latency
 
          (Note that kernel size and overhead increases with this option
          enabled. This option and the irqs-off timing option can be
@@ -261,7 +261,7 @@ config PROFILE_ANNOTATED_BRANCHES
          This tracer profiles all the the likely and unlikely macros
          in the kernel. It will display the results in:
 
-         /debugfs/tracing/profile_annotated_branch
+         /sys/kernel/debug/tracing/profile_annotated_branch
 
          Note: this will add a significant overhead, only turn this
          on if you need to profile the system's use of these macros.
@@ -274,7 +274,7 @@ config PROFILE_ALL_BRANCHES
          taken in the kernel is recorded whether it hit or miss.
          The results will be displayed in:
 
-         /debugfs/tracing/profile_branch
+         /sys/kernel/debug/tracing/profile_branch
 
          This option also enables the likely/unlikely profiler.
 
@@ -323,7 +323,7 @@ config STACK_TRACER
        select KALLSYMS
        help
          This special tracer records the maximum stack footprint of the
-         kernel and displays it in debugfs/tracing/stack_trace.
+         kernel and displays it in /sys/kernel/debug/tracing/stack_trace.
 
          This tracer works by hooking into every function call that the
          kernel executes, and keeping a maximum stack depth value and
index 2e642b2b7253d11ddce40c657a471f007561be65..dc4dc70171ce2236236a396430f228f15b1a732d 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
 #include <linux/hardirq.h>
+#include <linux/kmemcheck.h>
 #include <linux/module.h>
 #include <linux/percpu.h>
 #include <linux/mutex.h>
@@ -1270,6 +1271,7 @@ rb_move_tail(struct ring_buffer_per_cpu *cpu_buffer,
        if (tail < BUF_PAGE_SIZE) {
                /* Mark the rest of the page with padding */
                event = __rb_page_index(tail_page, tail);
+               kmemcheck_annotate_bitfield(event, bitfield);
                rb_event_set_padding(event);
        }
 
@@ -1327,6 +1329,7 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
                return NULL;
 
        event = __rb_page_index(tail_page, tail);
+       kmemcheck_annotate_bitfield(event, bitfield);
        rb_update_event(event, type, length);
 
        /* The passed in type is zero for DATA */
index 8acd9b81a5d76046ee52c9d1dc9224cc43edb1c2..c1878bfb2e1ec4fe8efbf56764a341023b1307c3 100644 (file)
@@ -344,7 +344,7 @@ static raw_spinlock_t ftrace_max_lock =
 /*
  * Copy the new maximum trace into the separate maximum-trace
  * structure. (this way the maximum trace is permanently saved,
- * for later retrieval via /debugfs/tracing/latency_trace)
+ * for later retrieval via /sys/kernel/debug/tracing/latency_trace)
  */
 static void
 __update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)
@@ -2414,21 +2414,20 @@ static const struct file_operations tracing_iter_fops = {
 
 static const char readme_msg[] =
        "tracing mini-HOWTO:\n\n"
-       "# mkdir /debug\n"
-       "# mount -t debugfs nodev /debug\n\n"
-       "# cat /debug/tracing/available_tracers\n"
+       "# mount -t debugfs nodev /sys/kernel/debug\n\n"
+       "# cat /sys/kernel/debug/tracing/available_tracers\n"
        "wakeup preemptirqsoff preemptoff irqsoff function sched_switch nop\n\n"
-       "# cat /debug/tracing/current_tracer\n"
+       "# cat /sys/kernel/debug/tracing/current_tracer\n"
        "nop\n"
-       "# echo sched_switch > /debug/tracing/current_tracer\n"
-       "# cat /debug/tracing/current_tracer\n"
+       "# echo sched_switch > /sys/kernel/debug/tracing/current_tracer\n"
+       "# cat /sys/kernel/debug/tracing/current_tracer\n"
        "sched_switch\n"
-       "# cat /debug/tracing/trace_options\n"
+       "# cat /sys/kernel/debug/tracing/trace_options\n"
        "noprint-parent nosym-offset nosym-addr noverbose\n"
-       "# echo print-parent > /debug/tracing/trace_options\n"
-       "# echo 1 > /debug/tracing/tracing_enabled\n"
-       "# cat /debug/tracing/trace > /tmp/trace.txt\n"
-       "# echo 0 > /debug/tracing/tracing_enabled\n"
+       "# echo print-parent > /sys/kernel/debug/tracing/trace_options\n"
+       "# echo 1 > /sys/kernel/debug/tracing/tracing_enabled\n"
+       "# cat /sys/kernel/debug/tracing/trace > /tmp/trace.txt\n"
+       "# echo 0 > /sys/kernel/debug/tracing/tracing_enabled\n"
 ;
 
 static ssize_t
index 850e0ba41c1e60f7983f2c3e7890bee4b2bec53c..2c000e7132acec2201a872e992ca0fc791894528 100644 (file)
@@ -75,21 +75,6 @@ static void uid_hash_remove(struct user_struct *up)
        put_user_ns(up->user_ns);
 }
 
-static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent)
-{
-       struct user_struct *user;
-       struct hlist_node *h;
-
-       hlist_for_each_entry(user, h, hashent, uidhash_node) {
-               if (user->uid == uid) {
-                       atomic_inc(&user->__count);
-                       return user;
-               }
-       }
-
-       return NULL;
-}
-
 #ifdef CONFIG_USER_SCHED
 
 static void sched_destroy_user(struct user_struct *up)
@@ -119,6 +104,23 @@ static int sched_create_user(struct user_struct *up) { return 0; }
 
 #if defined(CONFIG_USER_SCHED) && defined(CONFIG_SYSFS)
 
+static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent)
+{
+       struct user_struct *user;
+       struct hlist_node *h;
+
+       hlist_for_each_entry(user, h, hashent, uidhash_node) {
+               if (user->uid == uid) {
+                       /* possibly resurrect an "almost deleted" object */
+                       if (atomic_inc_return(&user->__count) == 1)
+                               cancel_delayed_work(&user->work);
+                       return user;
+               }
+       }
+
+       return NULL;
+}
+
 static struct kset *uids_kset; /* represents the /sys/kernel/uids/ directory */
 static DEFINE_MUTEX(uids_mutex);
 
@@ -283,12 +285,12 @@ int __init uids_sysfs_init(void)
        return uids_user_create(&root_user);
 }
 
-/* work function to remove sysfs directory for a user and free up
+/* delayed work function to remove sysfs directory for a user and free up
  * corresponding structures.
  */
 static void cleanup_user_struct(struct work_struct *w)
 {
-       struct user_struct *up = container_of(w, struct user_struct, work);
+       struct user_struct *up = container_of(w, struct user_struct, work.work);
        unsigned long flags;
        int remove_user = 0;
 
@@ -297,15 +299,12 @@ static void cleanup_user_struct(struct work_struct *w)
         */
        uids_mutex_lock();
 
-       local_irq_save(flags);
-
-       if (atomic_dec_and_lock(&up->__count, &uidhash_lock)) {
+       spin_lock_irqsave(&uidhash_lock, flags);
+       if (atomic_read(&up->__count) == 0) {
                uid_hash_remove(up);
                remove_user = 1;
-               spin_unlock_irqrestore(&uidhash_lock, flags);
-       } else {
-               local_irq_restore(flags);
        }
+       spin_unlock_irqrestore(&uidhash_lock, flags);
 
        if (!remove_user)
                goto done;
@@ -331,16 +330,28 @@ done:
  */
 static void free_user(struct user_struct *up, unsigned long flags)
 {
-       /* restore back the count */
-       atomic_inc(&up->__count);
        spin_unlock_irqrestore(&uidhash_lock, flags);
-
-       INIT_WORK(&up->work, cleanup_user_struct);
-       schedule_work(&up->work);
+       INIT_DELAYED_WORK(&up->work, cleanup_user_struct);
+       schedule_delayed_work(&up->work, msecs_to_jiffies(1000));
 }
 
 #else  /* CONFIG_USER_SCHED && CONFIG_SYSFS */
 
+static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent)
+{
+       struct user_struct *user;
+       struct hlist_node *h;
+
+       hlist_for_each_entry(user, h, hashent, uidhash_node) {
+               if (user->uid == uid) {
+                       atomic_inc(&user->__count);
+                       return user;
+               }
+       }
+
+       return NULL;
+}
+
 int uids_sysfs_init(void) { return 0; }
 static inline int uids_user_create(struct user_struct *up) { return 0; }
 static inline void uids_mutex_lock(void) { }
index 9960be04cbbe608cad81733096dd49d73928dbba..bb1326d3839c9aaa468e6ad501a1087389b1934f 100644 (file)
@@ -194,4 +194,10 @@ config DISABLE_OBSOLETE_CPUMASK_FUNCTIONS
 config NLATTR
        bool
 
+#
+# Generic 64-bit atomic support is selected if needed
+#
+config GENERIC_ATOMIC64
+       bool
+
 endmenu
index 116a35051be6fef457075c18b78e5c4cb17ec58e..6b0c2d8a21294e9de3a1ca3738134746c035f2d5 100644 (file)
@@ -300,7 +300,7 @@ config DEBUG_OBJECTS_ENABLE_DEFAULT
 
 config DEBUG_SLAB
        bool "Debug slab memory allocations"
-       depends on DEBUG_KERNEL && SLAB
+       depends on DEBUG_KERNEL && SLAB && !KMEMCHECK
        help
          Say Y here to have the kernel do limited verification on memory
          allocation as well as poisoning memory on free to catch use of freed
@@ -312,7 +312,7 @@ config DEBUG_SLAB_LEAK
 
 config SLUB_DEBUG_ON
        bool "SLUB debugging on by default"
-       depends on SLUB && SLUB_DEBUG
+       depends on SLUB && SLUB_DEBUG && !KMEMCHECK
        default n
        help
          Boot with debugging on by default. SLUB boots by default with
@@ -996,3 +996,5 @@ config DMA_API_DEBUG
 source "samples/Kconfig"
 
 source "lib/Kconfig.kgdb"
+
+source "lib/Kconfig.kmemcheck"
diff --git a/lib/Kconfig.kmemcheck b/lib/Kconfig.kmemcheck
new file mode 100644 (file)
index 0000000..603c81b
--- /dev/null
@@ -0,0 +1,91 @@
+config HAVE_ARCH_KMEMCHECK
+       bool
+
+menuconfig KMEMCHECK
+       bool "kmemcheck: trap use of uninitialized memory"
+       depends on DEBUG_KERNEL
+       depends on !X86_USE_3DNOW
+       depends on SLUB || SLAB
+       depends on !CC_OPTIMIZE_FOR_SIZE
+       depends on !FUNCTION_TRACER
+       select FRAME_POINTER
+       select STACKTRACE
+       default n
+       help
+         This option enables tracing of dynamically allocated kernel memory
+         to see if memory is used before it has been given an initial value.
+         Be aware that this requires half of your memory for bookkeeping and
+         will insert extra code at *every* read and write to tracked memory
+         thus slow down the kernel code (but user code is unaffected).
+
+         The kernel may be started with kmemcheck=0 or kmemcheck=1 to disable
+         or enable kmemcheck at boot-time. If the kernel is started with
+         kmemcheck=0, the large memory and CPU overhead is not incurred.
+
+choice
+       prompt "kmemcheck: default mode at boot"
+       depends on KMEMCHECK
+       default KMEMCHECK_ONESHOT_BY_DEFAULT
+       help
+         This option controls the default behaviour of kmemcheck when the
+         kernel boots and no kmemcheck= parameter is given.
+
+config KMEMCHECK_DISABLED_BY_DEFAULT
+       bool "disabled"
+       depends on KMEMCHECK
+
+config KMEMCHECK_ENABLED_BY_DEFAULT
+       bool "enabled"
+       depends on KMEMCHECK
+
+config KMEMCHECK_ONESHOT_BY_DEFAULT
+       bool "one-shot"
+       depends on KMEMCHECK
+       help
+         In one-shot mode, only the first error detected is reported before
+         kmemcheck is disabled.
+
+endchoice
+
+config KMEMCHECK_QUEUE_SIZE
+       int "kmemcheck: error queue size"
+       depends on KMEMCHECK
+       default 64
+       help
+         Select the maximum number of errors to store in the queue. Since
+         errors can occur virtually anywhere and in any context, we need a
+         temporary storage area which is guarantueed not to generate any
+         other faults. The queue will be emptied as soon as a tasklet may
+         be scheduled. If the queue is full, new error reports will be
+         lost.
+
+config KMEMCHECK_SHADOW_COPY_SHIFT
+       int "kmemcheck: shadow copy size (5 => 32 bytes, 6 => 64 bytes)"
+       depends on KMEMCHECK
+       range 2 8
+       default 5
+       help
+         Select the number of shadow bytes to save along with each entry of
+         the queue. These bytes indicate what parts of an allocation are
+         initialized, uninitialized, etc. and will be displayed when an
+         error is detected to help the debugging of a particular problem.
+
+config KMEMCHECK_PARTIAL_OK
+       bool "kmemcheck: allow partially uninitialized memory"
+       depends on KMEMCHECK
+       default y
+       help
+         This option works around certain GCC optimizations that produce
+         32-bit reads from 16-bit variables where the upper 16 bits are
+         thrown away afterwards. This may of course also hide some real
+         bugs.
+
+config KMEMCHECK_BITOPS_OK
+       bool "kmemcheck: allow bit-field manipulation"
+       depends on KMEMCHECK
+       default n
+       help
+         This option silences warnings that would be generated for bit-field
+         accesses where not all the bits are initialized at the same time.
+         This may also hide some real bugs.
+
index 34c5c0e6222ecf289112358c44751badd60569ab..8e9bcf9d3261cb09b91cb6f42e2e5750c8b16812 100644 (file)
@@ -95,6 +95,8 @@ obj-$(CONFIG_DMA_API_DEBUG) += dma-debug.o
 
 obj-$(CONFIG_GENERIC_CSUM) += checksum.o
 
+obj-$(CONFIG_GENERIC_ATOMIC64) += atomic64.o
+
 hostprogs-y    := gen_crc32table
 clean-files    := crc32table.h
 
diff --git a/lib/atomic64.c b/lib/atomic64.c
new file mode 100644 (file)
index 0000000..c5e7255
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Generic implementation of 64-bit atomics using spinlocks,
+ * useful on processors that don't have 64-bit atomic instructions.
+ *
+ * Copyright Â© 2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/types.h>
+#include <linux/cache.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <asm/atomic.h>
+
+/*
+ * We use a hashed array of spinlocks to provide exclusive access
+ * to each atomic64_t variable.  Since this is expected to used on
+ * systems with small numbers of CPUs (<= 4 or so), we use a
+ * relatively small array of 16 spinlocks to avoid wasting too much
+ * memory on the spinlock array.
+ */
+#define NR_LOCKS       16
+
+/*
+ * Ensure each lock is in a separate cacheline.
+ */
+static union {
+       spinlock_t lock;
+       char pad[L1_CACHE_BYTES];
+} atomic64_lock[NR_LOCKS] __cacheline_aligned_in_smp;
+
+static inline spinlock_t *lock_addr(const atomic64_t *v)
+{
+       unsigned long addr = (unsigned long) v;
+
+       addr >>= L1_CACHE_SHIFT;
+       addr ^= (addr >> 8) ^ (addr >> 16);
+       return &atomic64_lock[addr & (NR_LOCKS - 1)].lock;
+}
+
+long long atomic64_read(const atomic64_t *v)
+{
+       unsigned long flags;
+       spinlock_t *lock = lock_addr(v);
+       long long val;
+
+       spin_lock_irqsave(lock, flags);
+       val = v->counter;
+       spin_unlock_irqrestore(lock, flags);
+       return val;
+}
+
+void atomic64_set(atomic64_t *v, long long i)
+{
+       unsigned long flags;
+       spinlock_t *lock = lock_addr(v);
+
+       spin_lock_irqsave(lock, flags);
+       v->counter = i;
+       spin_unlock_irqrestore(lock, flags);
+}
+
+void atomic64_add(long long a, atomic64_t *v)
+{
+       unsigned long flags;
+       spinlock_t *lock = lock_addr(v);
+
+       spin_lock_irqsave(lock, flags);
+       v->counter += a;
+       spin_unlock_irqrestore(lock, flags);
+}
+
+long long atomic64_add_return(long long a, atomic64_t *v)
+{
+       unsigned long flags;
+       spinlock_t *lock = lock_addr(v);
+       long long val;
+
+       spin_lock_irqsave(lock, flags);
+       val = v->counter += a;
+       spin_unlock_irqrestore(lock, flags);
+       return val;
+}
+
+void atomic64_sub(long long a, atomic64_t *v)
+{
+       unsigned long flags;
+       spinlock_t *lock = lock_addr(v);
+
+       spin_lock_irqsave(lock, flags);
+       v->counter -= a;
+       spin_unlock_irqrestore(lock, flags);
+}
+
+long long atomic64_sub_return(long long a, atomic64_t *v)
+{
+       unsigned long flags;
+       spinlock_t *lock = lock_addr(v);
+       long long val;
+
+       spin_lock_irqsave(lock, flags);
+       val = v->counter -= a;
+       spin_unlock_irqrestore(lock, flags);
+       return val;
+}
+
+long long atomic64_dec_if_positive(atomic64_t *v)
+{
+       unsigned long flags;
+       spinlock_t *lock = lock_addr(v);
+       long long val;
+
+       spin_lock_irqsave(lock, flags);
+       val = v->counter - 1;
+       if (val >= 0)
+               v->counter = val;
+       spin_unlock_irqrestore(lock, flags);
+       return val;
+}
+
+long long atomic64_cmpxchg(atomic64_t *v, long long o, long long n)
+{
+       unsigned long flags;
+       spinlock_t *lock = lock_addr(v);
+       long long val;
+
+       spin_lock_irqsave(lock, flags);
+       val = v->counter;
+       if (val == o)
+               v->counter = n;
+       spin_unlock_irqrestore(lock, flags);
+       return val;
+}
+
+long long atomic64_xchg(atomic64_t *v, long long new)
+{
+       unsigned long flags;
+       spinlock_t *lock = lock_addr(v);
+       long long val;
+
+       spin_lock_irqsave(lock, flags);
+       val = v->counter;
+       v->counter = new;
+       spin_unlock_irqrestore(lock, flags);
+       return val;
+}
+
+int atomic64_add_unless(atomic64_t *v, long long a, long long u)
+{
+       unsigned long flags;
+       spinlock_t *lock = lock_addr(v);
+       int ret = 1;
+
+       spin_lock_irqsave(lock, flags);
+       if (v->counter != u) {
+               v->counter += a;
+               ret = 0;
+       }
+       spin_unlock_irqrestore(lock, flags);
+       return ret;
+}
+
+static int init_atomic64_lock(void)
+{
+       int i;
+
+       for (i = 0; i < NR_LOCKS; ++i)
+               spin_lock_init(&atomic64_lock[i].lock);
+       return 0;
+}
+
+pure_initcall(init_atomic64_lock);
index a65c314555416d9f1ea262455d1da313e1959902..e73822aa6e9a68131df955c0a6025c7aa5556fc6 100644 (file)
  */
 int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
 {
-#ifdef CONFIG_SMP
        /* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */
        if (atomic_add_unless(atomic, -1, 1))
                return 0;
-#endif
+
        /* Otherwise do it the slow way */
        spin_lock(lock);
        if (atomic_dec_and_test(atomic))
index f6d276db2d58f97c80db2b0aececde84120893a9..eed2bdb865e76673bfe24834301de8406d9cfc88 100644 (file)
@@ -85,7 +85,6 @@ void gen_pool_destroy(struct gen_pool *pool)
        int bit, end_bit;
 
 
-       write_lock(&pool->lock);
        list_for_each_safe(_chunk, _next_chunk, &pool->chunks) {
                chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);
                list_del(&chunk->next_chunk);
index f07c0db81d262eb8ff185391bf6577adae064e1f..39af2560f765f9815ccb724fecbe38173c986aab 100644 (file)
@@ -65,7 +65,8 @@ void hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
 
                for (j = 0; j < ngroups; j++)
                        lx += scnprintf(linebuf + lx, linebuflen - lx,
-                               "%16.16llx ", (unsigned long long)*(ptr8 + j));
+                               "%s%16.16llx", j ? " " : "",
+                               (unsigned long long)*(ptr8 + j));
                ascii_column = 17 * ngroups + 2;
                break;
        }
@@ -76,7 +77,7 @@ void hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
 
                for (j = 0; j < ngroups; j++)
                        lx += scnprintf(linebuf + lx, linebuflen - lx,
-                               "%8.8x ", *(ptr4 + j));
+                               "%s%8.8x", j ? " " : "", *(ptr4 + j));
                ascii_column = 9 * ngroups + 2;
                break;
        }
@@ -87,19 +88,21 @@ void hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
 
                for (j = 0; j < ngroups; j++)
                        lx += scnprintf(linebuf + lx, linebuflen - lx,
-                               "%4.4x ", *(ptr2 + j));
+                               "%s%4.4x", j ? " " : "", *(ptr2 + j));
                ascii_column = 5 * ngroups + 2;
                break;
        }
 
        default:
-               for (j = 0; (j < rowsize) && (j < len) && (lx + 4) < linebuflen;
-                    j++) {
+               for (j = 0; (j < len) && (lx + 3) <= linebuflen; j++) {
                        ch = ptr[j];
                        linebuf[lx++] = hex_asc_hi(ch);
                        linebuf[lx++] = hex_asc_lo(ch);
                        linebuf[lx++] = ' ';
                }
+               if (j)
+                       lx--;
+
                ascii_column = 3 * rowsize + 2;
                break;
        }
@@ -108,7 +111,7 @@ void hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
 
        while (lx < (linebuflen - 1) && lx < (ascii_column - 1))
                linebuf[lx++] = ' ';
-       for (j = 0; (j < rowsize) && (j < len) && (lx + 2) < linebuflen; j++)
+       for (j = 0; (j < len) && (lx + 2) < linebuflen; j++)
                linebuf[lx++] = (isascii(ptr[j]) && isprint(ptr[j])) ? ptr[j]
                                : '.';
 nil:
index bacf6fe4f7a0347bb958ebc85a059ab582eb93b4..b512b746d2aff464e1c18a01c53300ef7b6e68f4 100644 (file)
@@ -793,11 +793,16 @@ static struct kset *kset_create(const char *name,
                                struct kobject *parent_kobj)
 {
        struct kset *kset;
+       int retval;
 
        kset = kzalloc(sizeof(*kset), GFP_KERNEL);
        if (!kset)
                return NULL;
-       kobject_set_name(&kset->kobj, name);
+       retval = kobject_set_name(&kset->kobj, name);
+       if (retval) {
+               kfree(kset);
+               return NULL;
+       }
        kset->uevent_ops = uevent_ops;
        kset->kobj.parent = parent_kobj;
 
index 4bb42a0344ec49f5224d74c932786f0842446bef..23abbd93cae1fd50b87b2ed5f8ffd95d940230b1 100644 (file)
@@ -351,20 +351,12 @@ int radix_tree_insert(struct radix_tree_root *root,
 }
 EXPORT_SYMBOL(radix_tree_insert);
 
-/**
- *     radix_tree_lookup_slot    -    lookup a slot in a radix tree
- *     @root:          radix tree root
- *     @index:         index key
- *
- *     Returns:  the slot corresponding to the position @index in the
- *     radix tree @root. This is useful for update-if-exists operations.
- *
- *     This function can be called under rcu_read_lock iff the slot is not
- *     modified by radix_tree_replace_slot, otherwise it must be called
- *     exclusive from other writers. Any dereference of the slot must be done
- *     using radix_tree_deref_slot.
+/*
+ * is_slot == 1 : search for the slot.
+ * is_slot == 0 : search for the node.
  */
-void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index)
+static void *radix_tree_lookup_element(struct radix_tree_root *root,
+                               unsigned long index, int is_slot)
 {
        unsigned int height, shift;
        struct radix_tree_node *node, **slot;
@@ -376,7 +368,7 @@ void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index)
        if (!radix_tree_is_indirect_ptr(node)) {
                if (index > 0)
                        return NULL;
-               return (void **)&root->rnode;
+               return is_slot ? (void *)&root->rnode : node;
        }
        node = radix_tree_indirect_to_ptr(node);
 
@@ -397,7 +389,25 @@ void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index)
                height--;
        } while (height > 0);
 
-       return (void **)slot;
+       return is_slot ? (void *)slot:node;
+}
+
+/**
+ *     radix_tree_lookup_slot    -    lookup a slot in a radix tree
+ *     @root:          radix tree root
+ *     @index:         index key
+ *
+ *     Returns:  the slot corresponding to the position @index in the
+ *     radix tree @root. This is useful for update-if-exists operations.
+ *
+ *     This function can be called under rcu_read_lock iff the slot is not
+ *     modified by radix_tree_replace_slot, otherwise it must be called
+ *     exclusive from other writers. Any dereference of the slot must be done
+ *     using radix_tree_deref_slot.
+ */
+void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index)
+{
+       return (void **)radix_tree_lookup_element(root, index, 1);
 }
 EXPORT_SYMBOL(radix_tree_lookup_slot);
 
@@ -415,38 +425,7 @@ EXPORT_SYMBOL(radix_tree_lookup_slot);
  */
 void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index)
 {
-       unsigned int height, shift;
-       struct radix_tree_node *node, **slot;
-
-       node = rcu_dereference(root->rnode);
-       if (node == NULL)
-               return NULL;
-
-       if (!radix_tree_is_indirect_ptr(node)) {
-               if (index > 0)
-                       return NULL;
-               return node;
-       }
-       node = radix_tree_indirect_to_ptr(node);
-
-       height = node->height;
-       if (index > radix_tree_maxindex(height))
-               return NULL;
-
-       shift = (height-1) * RADIX_TREE_MAP_SHIFT;
-
-       do {
-               slot = (struct radix_tree_node **)
-                       (node->slots + ((index>>shift) & RADIX_TREE_MAP_MASK));
-               node = rcu_dereference(*slot);
-               if (node == NULL)
-                       return NULL;
-
-               shift -= RADIX_TREE_MAP_SHIFT;
-               height--;
-       } while (height > 0);
-
-       return node;
+       return radix_tree_lookup_element(root, index, 0);
 }
 EXPORT_SYMBOL(radix_tree_lookup);
 
@@ -666,6 +645,43 @@ unsigned long radix_tree_next_hole(struct radix_tree_root *root,
 }
 EXPORT_SYMBOL(radix_tree_next_hole);
 
+/**
+ *     radix_tree_prev_hole    -    find the prev hole (not-present entry)
+ *     @root:          tree root
+ *     @index:         index key
+ *     @max_scan:      maximum range to search
+ *
+ *     Search backwards in the range [max(index-max_scan+1, 0), index]
+ *     for the first hole.
+ *
+ *     Returns: the index of the hole if found, otherwise returns an index
+ *     outside of the set specified (in which case 'index - return >= max_scan'
+ *     will be true). In rare cases of wrap-around, LONG_MAX will be returned.
+ *
+ *     radix_tree_next_hole may be called under rcu_read_lock. However, like
+ *     radix_tree_gang_lookup, this will not atomically search a snapshot of
+ *     the tree at a single point in time. For example, if a hole is created
+ *     at index 10, then subsequently a hole is created at index 5,
+ *     radix_tree_prev_hole covering both indexes may return 5 if called under
+ *     rcu_read_lock.
+ */
+unsigned long radix_tree_prev_hole(struct radix_tree_root *root,
+                                  unsigned long index, unsigned long max_scan)
+{
+       unsigned long i;
+
+       for (i = 0; i < max_scan; i++) {
+               if (!radix_tree_lookup(root, index))
+                       break;
+               index--;
+               if (index == LONG_MAX)
+                       break;
+       }
+
+       return index;
+}
+EXPORT_SYMBOL(radix_tree_prev_hole);
+
 static unsigned int
 __lookup(struct radix_tree_node *slot, void ***results, unsigned long index,
        unsigned int max_items, unsigned long *next_index)
index f653659e0bc1fb161525332d775c973e2fb0ba98..e2aa3be29858cdcdd69bf4a43a67813db84079ee 100644 (file)
@@ -231,34 +231,34 @@ void rb_erase(struct rb_node *node, struct rb_root *root)
                node = node->rb_right;
                while ((left = node->rb_left) != NULL)
                        node = left;
+
+               if (rb_parent(old)) {
+                       if (rb_parent(old)->rb_left == old)
+                               rb_parent(old)->rb_left = node;
+                       else
+                               rb_parent(old)->rb_right = node;
+               } else
+                       root->rb_node = node;
+
                child = node->rb_right;
                parent = rb_parent(node);
                color = rb_color(node);
 
-               if (child)
-                       rb_set_parent(child, parent);
                if (parent == old) {
-                       parent->rb_right = child;
                        parent = node;
-               } else
+               } else {
+                       if (child)
+                               rb_set_parent(child, parent);
                        parent->rb_left = child;
 
+                       node->rb_right = old->rb_right;
+                       rb_set_parent(old->rb_right, node);
+               }
+
                node->rb_parent_color = old->rb_parent_color;
-               node->rb_right = old->rb_right;
                node->rb_left = old->rb_left;
-
-               if (rb_parent(old))
-               {
-                       if (rb_parent(old)->rb_left == old)
-                               rb_parent(old)->rb_left = node;
-                       else
-                               rb_parent(old)->rb_right = node;
-               } else
-                       root->rb_node = node;
-
                rb_set_parent(old->rb_left, node);
-               if (old->rb_right)
-                       rb_set_parent(old->rb_right, node);
+
                goto color;
        }
 
index 71830ba7b986a8e4da4b448793791bf2bc65c245..c948d4ca8bde0dc0d73ba1c40b984d395a73b4d8 100644 (file)
@@ -128,11 +128,11 @@ config SPARSEMEM_VMEMMAP
 config MEMORY_HOTPLUG
        bool "Allow for memory hot-add"
        depends on SPARSEMEM || X86_64_ACPI_NUMA
-       depends on HOTPLUG && !HIBERNATION && ARCH_ENABLE_MEMORY_HOTPLUG
+       depends on HOTPLUG && !(HIBERNATION && !S390) && ARCH_ENABLE_MEMORY_HOTPLUG
        depends on (IA64 || X86 || PPC64 || SUPERH || S390)
 
 comment "Memory hotplug is currently incompatible with Software Suspend"
-       depends on SPARSEMEM && HOTPLUG && HIBERNATION
+       depends on SPARSEMEM && HOTPLUG && HIBERNATION && !S390
 
 config MEMORY_HOTPLUG_SPARSE
        def_bool y
@@ -203,25 +203,13 @@ config VIRT_TO_BUS
        def_bool y
        depends on !ARCH_NO_VIRT_TO_BUS
 
-config UNEVICTABLE_LRU
-       bool "Add LRU list to track non-evictable pages"
-       default y
-       help
-         Keeps unevictable pages off of the active and inactive pageout
-         lists, so kswapd will not waste CPU time or have its balancing
-         algorithms thrown off by scanning these pages.  Selecting this
-         will use one page flag and increase the code size a little,
-         say Y unless you know what you are doing.
-
-         See Documentation/vm/unevictable-lru.txt for more information.
-
 config HAVE_MLOCK
        bool
        default y if MMU=y
 
 config HAVE_MLOCKED_PAGE_BIT
        bool
-       default y if HAVE_MLOCK=y && UNEVICTABLE_LRU=y
+       default y if HAVE_MLOCK=y
 
 config MMU_NOTIFIER
        bool
index bb01e298f260b84c82b03acdfb11582e42ecbbe6..aa99fd1f7109f03ef24085dd2ab37e5eb7c72534 100644 (file)
@@ -2,6 +2,7 @@ config DEBUG_PAGEALLOC
        bool "Debug page memory allocations"
        depends on DEBUG_KERNEL && ARCH_SUPPORTS_DEBUG_PAGEALLOC
        depends on !HIBERNATION || !PPC && !SPARC
+       depends on !KMEMCHECK
        ---help---
          Unmap pages from the kernel linear mapping after free_pages().
          This results in a large slowdown, but helps to find certain types
index e89acb090b4dfe7c24aefc846ad492bb157fcbc6..5e0bd64266932e54184879dff3104c372c12c152 100644 (file)
@@ -12,6 +12,7 @@ obj-y                 := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \
                           readahead.o swap.o truncate.o vmscan.o shmem.o \
                           prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \
                           page_isolation.o mm_init.o $(mmu-y)
+obj-y += init-mm.o
 
 obj-$(CONFIG_PROC_PAGE_MONITOR) += pagewalk.o
 obj-$(CONFIG_BOUNCE)   += bounce.o
@@ -27,6 +28,7 @@ obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o
 obj-$(CONFIG_PAGE_POISONING) += debug-pagealloc.o
 obj-$(CONFIG_SLAB) += slab.o
 obj-$(CONFIG_SLUB) += slub.o
+obj-$(CONFIG_KMEMCHECK) += kmemcheck.o
 obj-$(CONFIG_FAILSLAB) += failslab.o
 obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
 obj-$(CONFIG_FS_XIP) += filemap_xip.o
index 4ebe3ea837952a3f784159a9009212c3506e4a0f..a2b76a588e348e0d46f2bfed4131af6ac3eea86b 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/init.h>
 #include <linux/hash.h>
 #include <linux/highmem.h>
-#include <linux/blktrace_api.h>
 #include <asm/tlbflush.h>
 
 #include <trace/events/block.h>
index 54a0f8040afa339a7e2f0cb459fd5b23c3d16acf..e43359214f6ff15020b6f05cc07aa5e6ddcb4162 100644 (file)
@@ -101,7 +101,7 @@ SYSCALL_DEFINE(fadvise64_64)(int fd, loff_t offset, loff_t len, int advice)
                
                ret = force_page_cache_readahead(mapping, file,
                                start_index,
-                               max_sane_readahead(nrpages));
+                               nrpages);
                if (ret > 0)
                        ret = 0;
                break;
index 1b60f30cebfa88aa135c17173ec9ce831612fa90..22396713feb9684647aa5c90a3b18e6661b2f798 100644 (file)
@@ -521,7 +521,7 @@ struct page *__page_cache_alloc(gfp_t gfp)
 {
        if (cpuset_do_page_mem_spread()) {
                int n = cpuset_mem_spread_node();
-               return alloc_pages_node(n, gfp, 0);
+               return alloc_pages_exact_node(n, gfp, 0);
        }
        return alloc_pages(gfp, 0);
 }
@@ -1004,9 +1004,6 @@ EXPORT_SYMBOL(grab_cache_page_nowait);
 static void shrink_readahead_size_eio(struct file *filp,
                                        struct file_ra_state *ra)
 {
-       if (!ra->ra_pages)
-               return;
-
        ra->ra_pages /= 4;
 }
 
@@ -1390,8 +1387,7 @@ do_readahead(struct address_space *mapping, struct file *filp,
        if (!mapping || !mapping->a_ops || !mapping->a_ops->readpage)
                return -EINVAL;
 
-       force_page_cache_readahead(mapping, filp, index,
-                                       max_sane_readahead(nr));
+       force_page_cache_readahead(mapping, filp, index, nr);
        return 0;
 }
 
@@ -1457,6 +1453,73 @@ static int page_cache_read(struct file *file, pgoff_t offset)
 
 #define MMAP_LOTSAMISS  (100)
 
+/*
+ * Synchronous readahead happens when we don't even find
+ * a page in the page cache at all.
+ */
+static void do_sync_mmap_readahead(struct vm_area_struct *vma,
+                                  struct file_ra_state *ra,
+                                  struct file *file,
+                                  pgoff_t offset)
+{
+       unsigned long ra_pages;
+       struct address_space *mapping = file->f_mapping;
+
+       /* If we don't want any read-ahead, don't bother */
+       if (VM_RandomReadHint(vma))
+               return;
+
+       if (VM_SequentialReadHint(vma) ||
+                       offset - 1 == (ra->prev_pos >> PAGE_CACHE_SHIFT)) {
+               page_cache_sync_readahead(mapping, ra, file, offset,
+                                         ra->ra_pages);
+               return;
+       }
+
+       if (ra->mmap_miss < INT_MAX)
+               ra->mmap_miss++;
+
+       /*
+        * Do we miss much more than hit in this file? If so,
+        * stop bothering with read-ahead. It will only hurt.
+        */
+       if (ra->mmap_miss > MMAP_LOTSAMISS)
+               return;
+
+       /*
+        * mmap read-around
+        */
+       ra_pages = max_sane_readahead(ra->ra_pages);
+       if (ra_pages) {
+               ra->start = max_t(long, 0, offset - ra_pages/2);
+               ra->size = ra_pages;
+               ra->async_size = 0;
+               ra_submit(ra, mapping, file);
+       }
+}
+
+/*
+ * Asynchronous readahead happens when we find the page and PG_readahead,
+ * so we want to possibly extend the readahead further..
+ */
+static void do_async_mmap_readahead(struct vm_area_struct *vma,
+                                   struct file_ra_state *ra,
+                                   struct file *file,
+                                   struct page *page,
+                                   pgoff_t offset)
+{
+       struct address_space *mapping = file->f_mapping;
+
+       /* If we don't want any read-ahead, don't bother */
+       if (VM_RandomReadHint(vma))
+               return;
+       if (ra->mmap_miss > 0)
+               ra->mmap_miss--;
+       if (PageReadahead(page))
+               page_cache_async_readahead(mapping, ra, file,
+                                          page, offset, ra->ra_pages);
+}
+
 /**
  * filemap_fault - read in file data for page fault handling
  * @vma:       vma in which the fault was taken
@@ -1476,78 +1539,44 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
        struct address_space *mapping = file->f_mapping;
        struct file_ra_state *ra = &file->f_ra;
        struct inode *inode = mapping->host;
+       pgoff_t offset = vmf->pgoff;
        struct page *page;
        pgoff_t size;
-       int did_readaround = 0;
        int ret = 0;
 
        size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-       if (vmf->pgoff >= size)
+       if (offset >= size)
                return VM_FAULT_SIGBUS;
 
-       /* If we don't want any read-ahead, don't bother */
-       if (VM_RandomReadHint(vma))
-               goto no_cached_page;
-
        /*
         * Do we have something in the page cache already?
         */
-retry_find:
-       page = find_lock_page(mapping, vmf->pgoff);
-       /*
-        * For sequential accesses, we use the generic readahead logic.
-        */
-       if (VM_SequentialReadHint(vma)) {
-               if (!page) {
-                       page_cache_sync_readahead(mapping, ra, file,
-                                                          vmf->pgoff, 1);
-                       page = find_lock_page(mapping, vmf->pgoff);
-                       if (!page)
-                               goto no_cached_page;
-               }
-               if (PageReadahead(page)) {
-                       page_cache_async_readahead(mapping, ra, file, page,
-                                                          vmf->pgoff, 1);
-               }
-       }
-
-       if (!page) {
-               unsigned long ra_pages;
-
-               ra->mmap_miss++;
-
+       page = find_get_page(mapping, offset);
+       if (likely(page)) {
                /*
-                * Do we miss much more than hit in this file? If so,
-                * stop bothering with read-ahead. It will only hurt.
+                * We found the page, so try async readahead before
+                * waiting for the lock.
                 */
-               if (ra->mmap_miss > MMAP_LOTSAMISS)
-                       goto no_cached_page;
+               do_async_mmap_readahead(vma, ra, file, page, offset);
+               lock_page(page);
 
-               /*
-                * To keep the pgmajfault counter straight, we need to
-                * check did_readaround, as this is an inner loop.
-                */
-               if (!did_readaround) {
-                       ret = VM_FAULT_MAJOR;
-                       count_vm_event(PGMAJFAULT);
-               }
-               did_readaround = 1;
-               ra_pages = max_sane_readahead(file->f_ra.ra_pages);
-               if (ra_pages) {
-                       pgoff_t start = 0;
-
-                       if (vmf->pgoff > ra_pages / 2)
-                               start = vmf->pgoff - ra_pages / 2;
-                       do_page_cache_readahead(mapping, file, start, ra_pages);
+               /* Did it get truncated? */
+               if (unlikely(page->mapping != mapping)) {
+                       unlock_page(page);
+                       put_page(page);
+                       goto no_cached_page;
                }
-               page = find_lock_page(mapping, vmf->pgoff);
+       } else {
+               /* No page in the page cache at all */
+               do_sync_mmap_readahead(vma, ra, file, offset);
+               count_vm_event(PGMAJFAULT);
+               ret = VM_FAULT_MAJOR;
+retry_find:
+               page = find_lock_page(mapping, offset);
                if (!page)
                        goto no_cached_page;
        }
 
-       if (!did_readaround)
-               ra->mmap_miss--;
-
        /*
         * We have a locked page in the page cache, now we need to check
         * that it's up-to-date. If not, it is going to be due to an error.
@@ -1555,18 +1584,18 @@ retry_find:
        if (unlikely(!PageUptodate(page)))
                goto page_not_uptodate;
 
-       /* Must recheck i_size under page lock */
+       /*
+        * Found the page and have a reference on it.
+        * We must recheck i_size under page lock.
+        */
        size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-       if (unlikely(vmf->pgoff >= size)) {
+       if (unlikely(offset >= size)) {
                unlock_page(page);
                page_cache_release(page);
                return VM_FAULT_SIGBUS;
        }
 
-       /*
-        * Found the page and have a reference on it.
-        */
-       ra->prev_pos = (loff_t)page->index << PAGE_CACHE_SHIFT;
+       ra->prev_pos = (loff_t)offset << PAGE_CACHE_SHIFT;
        vmf->page = page;
        return ret | VM_FAULT_LOCKED;
 
@@ -1575,7 +1604,7 @@ no_cached_page:
         * We're only likely to ever get here if MADV_RANDOM is in
         * effect.
         */
-       error = page_cache_read(file, vmf->pgoff);
+       error = page_cache_read(file, offset);
 
        /*
         * The page we want has now been added to the page cache.
@@ -1595,12 +1624,6 @@ no_cached_page:
        return VM_FAULT_SIGBUS;
 
 page_not_uptodate:
-       /* IO error path */
-       if (!did_readaround) {
-               ret = VM_FAULT_MAJOR;
-               count_vm_event(PGMAJFAULT);
-       }
-
        /*
         * Umm, take care of errors if the page isn't up-to-date.
         * Try to re-read it _once_. We do this synchronously,
index 68eb1d9b63fa5daba881a8b6551fa38f8e0eabfc..25878cc49daa268806f46dfa4e05af8d6f8f3998 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/init.h>
 #include <linux/hash.h>
 #include <linux/highmem.h>
-#include <linux/blktrace_api.h>
 #include <asm/tlbflush.h>
 
 /*
index e83ad2c9228c1242a582920c3a03b691f5dd56f9..a56e6f3ce97937bc3d28713f67555cf890dc9069 100644 (file)
@@ -578,41 +578,6 @@ static void free_huge_page(struct page *page)
                hugetlb_put_quota(mapping, 1);
 }
 
-/*
- * Increment or decrement surplus_huge_pages.  Keep node-specific counters
- * balanced by operating on them in a round-robin fashion.
- * Returns 1 if an adjustment was made.
- */
-static int adjust_pool_surplus(struct hstate *h, int delta)
-{
-       static int prev_nid;
-       int nid = prev_nid;
-       int ret = 0;
-
-       VM_BUG_ON(delta != -1 && delta != 1);
-       do {
-               nid = next_node(nid, node_online_map);
-               if (nid == MAX_NUMNODES)
-                       nid = first_node(node_online_map);
-
-               /* To shrink on this node, there must be a surplus page */
-               if (delta < 0 && !h->surplus_huge_pages_node[nid])
-                       continue;
-               /* Surplus cannot exceed the total number of pages */
-               if (delta > 0 && h->surplus_huge_pages_node[nid] >=
-                                               h->nr_huge_pages_node[nid])
-                       continue;
-
-               h->surplus_huge_pages += delta;
-               h->surplus_huge_pages_node[nid] += delta;
-               ret = 1;
-               break;
-       } while (nid != prev_nid);
-
-       prev_nid = nid;
-       return ret;
-}
-
 static void prep_new_huge_page(struct hstate *h, struct page *page, int nid)
 {
        set_compound_page_dtor(page, free_huge_page);
@@ -623,6 +588,34 @@ static void prep_new_huge_page(struct hstate *h, struct page *page, int nid)
        put_page(page); /* free it into the hugepage allocator */
 }
 
+static void prep_compound_gigantic_page(struct page *page, unsigned long order)
+{
+       int i;
+       int nr_pages = 1 << order;
+       struct page *p = page + 1;
+
+       /* we rely on prep_new_huge_page to set the destructor */
+       set_compound_order(page, order);
+       __SetPageHead(page);
+       for (i = 1; i < nr_pages; i++, p = mem_map_next(p, page, i)) {
+               __SetPageTail(p);
+               p->first_page = page;
+       }
+}
+
+int PageHuge(struct page *page)
+{
+       compound_page_dtor *dtor;
+
+       if (!PageCompound(page))
+               return 0;
+
+       page = compound_head(page);
+       dtor = get_compound_page_dtor(page);
+
+       return dtor == free_huge_page;
+}
+
 static struct page *alloc_fresh_huge_page_node(struct hstate *h, int nid)
 {
        struct page *page;
@@ -630,7 +623,7 @@ static struct page *alloc_fresh_huge_page_node(struct hstate *h, int nid)
        if (h->order >= MAX_ORDER)
                return NULL;
 
-       page = alloc_pages_node(nid,
+       page = alloc_pages_exact_node(nid,
                htlb_alloc_mask|__GFP_COMP|__GFP_THISNODE|
                                                __GFP_REPEAT|__GFP_NOWARN,
                huge_page_order(h));
@@ -649,7 +642,7 @@ static struct page *alloc_fresh_huge_page_node(struct hstate *h, int nid)
  * Use a helper variable to find the next node and then
  * copy it back to hugetlb_next_nid afterwards:
  * otherwise there's a window in which a racer might
- * pass invalid nid MAX_NUMNODES to alloc_pages_node.
+ * pass invalid nid MAX_NUMNODES to alloc_pages_exact_node.
  * But we don't need to use a spin_lock here: it really
  * doesn't matter if occasionally a racer chooses the
  * same nid as we do.  Move nid forward in the mask even
@@ -875,7 +868,7 @@ static void return_unused_surplus_pages(struct hstate *h,
         * can no longer free unreserved surplus pages. This occurs when
         * the nodes with surplus pages have no free pages.
         */
-       unsigned long remaining_iterations = num_online_nodes();
+       unsigned long remaining_iterations = nr_online_nodes;
 
        /* Uncommit the reservation */
        h->resv_huge_pages -= unused_resv_pages;
@@ -904,7 +897,7 @@ static void return_unused_surplus_pages(struct hstate *h,
                        h->surplus_huge_pages--;
                        h->surplus_huge_pages_node[nid]--;
                        nr_pages--;
-                       remaining_iterations = num_online_nodes();
+                       remaining_iterations = nr_online_nodes;
                }
        }
 }
@@ -1140,6 +1133,41 @@ static inline void try_to_free_low(struct hstate *h, unsigned long count)
 }
 #endif
 
+/*
+ * Increment or decrement surplus_huge_pages.  Keep node-specific counters
+ * balanced by operating on them in a round-robin fashion.
+ * Returns 1 if an adjustment was made.
+ */
+static int adjust_pool_surplus(struct hstate *h, int delta)
+{
+       static int prev_nid;
+       int nid = prev_nid;
+       int ret = 0;
+
+       VM_BUG_ON(delta != -1 && delta != 1);
+       do {
+               nid = next_node(nid, node_online_map);
+               if (nid == MAX_NUMNODES)
+                       nid = first_node(node_online_map);
+
+               /* To shrink on this node, there must be a surplus page */
+               if (delta < 0 && !h->surplus_huge_pages_node[nid])
+                       continue;
+               /* Surplus cannot exceed the total number of pages */
+               if (delta > 0 && h->surplus_huge_pages_node[nid] >=
+                                               h->nr_huge_pages_node[nid])
+                       continue;
+
+               h->surplus_huge_pages += delta;
+               h->surplus_huge_pages_node[nid] += delta;
+               ret = 1;
+               break;
+       } while (nid != prev_nid);
+
+       prev_nid = nid;
+       return ret;
+}
+
 #define persistent_huge_pages(h) (h->nr_huge_pages - h->surplus_huge_pages)
 static unsigned long set_max_huge_pages(struct hstate *h, unsigned long count)
 {
diff --git a/mm/init-mm.c b/mm/init-mm.c
new file mode 100644 (file)
index 0000000..57aba0d
--- /dev/null
@@ -0,0 +1,20 @@
+#include <linux/mm_types.h>
+#include <linux/rbtree.h>
+#include <linux/rwsem.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/cpumask.h>
+
+#include <asm/atomic.h>
+#include <asm/pgtable.h>
+
+struct mm_struct init_mm = {
+       .mm_rb          = RB_ROOT,
+       .pgd            = swapper_pg_dir,
+       .mm_users       = ATOMIC_INIT(2),
+       .mm_count       = ATOMIC_INIT(1),
+       .mmap_sem       = __RWSEM_INITIALIZER(init_mm.mmap_sem),
+       .page_table_lock =  __SPIN_LOCK_UNLOCKED(init_mm.page_table_lock),
+       .mmlist         = LIST_HEAD_INIT(init_mm.mmlist),
+       .cpu_vm_mask    = CPU_MASK_ALL,
+};
index 987bb03fbdd88f33f36986b6ecbb33f02a62c6e2..f290c4db528b0e38afb243e498e8891007788545 100644 (file)
@@ -16,9 +16,6 @@
 void free_pgtables(struct mmu_gather *tlb, struct vm_area_struct *start_vma,
                unsigned long floor, unsigned long ceiling);
 
-extern void prep_compound_page(struct page *page, unsigned long order);
-extern void prep_compound_gigantic_page(struct page *page, unsigned long order);
-
 static inline void set_page_count(struct page *page, int v)
 {
        atomic_set(&page->_count, v);
@@ -51,6 +48,8 @@ extern void putback_lru_page(struct page *page);
  */
 extern unsigned long highest_memmap_pfn;
 extern void __free_pages_bootmem(struct page *page, unsigned int order);
+extern void prep_compound_page(struct page *page, unsigned long order);
+
 
 /*
  * function for dealing with page's order in buddy system.
@@ -74,7 +73,6 @@ static inline void munlock_vma_pages_all(struct vm_area_struct *vma)
 }
 #endif
 
-#ifdef CONFIG_UNEVICTABLE_LRU
 /*
  * unevictable_migrate_page() called only from migrate_page_copy() to
  * migrate unevictable flag to new page.
@@ -86,11 +84,6 @@ static inline void unevictable_migrate_page(struct page *new, struct page *old)
        if (TestClearPageUnevictable(old))
                SetPageUnevictable(new);
 }
-#else
-static inline void unevictable_migrate_page(struct page *new, struct page *old)
-{
-}
-#endif
 
 #ifdef CONFIG_HAVE_MLOCKED_PAGE_BIT
 /*
@@ -150,23 +143,6 @@ static inline void mlock_migrate_page(struct page *newpage, struct page *page)
        }
 }
 
-/*
- * free_page_mlock() -- clean up attempts to free and mlocked() page.
- * Page should not be on lru, so no need to fix that up.
- * free_pages_check() will verify...
- */
-static inline void free_page_mlock(struct page *page)
-{
-       if (unlikely(TestClearPageMlocked(page))) {
-               unsigned long flags;
-
-               local_irq_save(flags);
-               __dec_zone_page_state(page, NR_MLOCK);
-               __count_vm_event(UNEVICTABLE_MLOCKFREED);
-               local_irq_restore(flags);
-       }
-}
-
 #else /* CONFIG_HAVE_MLOCKED_PAGE_BIT */
 static inline int is_mlocked_vma(struct vm_area_struct *v, struct page *p)
 {
@@ -175,7 +151,6 @@ static inline int is_mlocked_vma(struct vm_area_struct *v, struct page *p)
 static inline void clear_page_mlock(struct page *page) { }
 static inline void mlock_vma_page(struct page *page) { }
 static inline void mlock_migrate_page(struct page *new, struct page *old) { }
-static inline void free_page_mlock(struct page *page) { }
 
 #endif /* CONFIG_HAVE_MLOCKED_PAGE_BIT */
 
@@ -284,4 +259,8 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                     unsigned long start, int len, int flags,
                     struct page **pages, struct vm_area_struct **vmas);
 
+#define ZONE_RECLAIM_NOSCAN    -2
+#define ZONE_RECLAIM_FULL      -1
+#define ZONE_RECLAIM_SOME      0
+#define ZONE_RECLAIM_SUCCESS   1
 #endif
diff --git a/mm/kmemcheck.c b/mm/kmemcheck.c
new file mode 100644 (file)
index 0000000..fd814fd
--- /dev/null
@@ -0,0 +1,122 @@
+#include <linux/gfp.h>
+#include <linux/mm_types.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/kmemcheck.h>
+
+void kmemcheck_alloc_shadow(struct page *page, int order, gfp_t flags, int node)
+{
+       struct page *shadow;
+       int pages;
+       int i;
+
+       pages = 1 << order;
+
+       /*
+        * With kmemcheck enabled, we need to allocate a memory area for the
+        * shadow bits as well.
+        */
+       shadow = alloc_pages_node(node, flags | __GFP_NOTRACK, order);
+       if (!shadow) {
+               if (printk_ratelimit())
+                       printk(KERN_ERR "kmemcheck: failed to allocate "
+                               "shadow bitmap\n");
+               return;
+       }
+
+       for(i = 0; i < pages; ++i)
+               page[i].shadow = page_address(&shadow[i]);
+
+       /*
+        * Mark it as non-present for the MMU so that our accesses to
+        * this memory will trigger a page fault and let us analyze
+        * the memory accesses.
+        */
+       kmemcheck_hide_pages(page, pages);
+}
+
+void kmemcheck_free_shadow(struct page *page, int order)
+{
+       struct page *shadow;
+       int pages;
+       int i;
+
+       if (!kmemcheck_page_is_tracked(page))
+               return;
+
+       pages = 1 << order;
+
+       kmemcheck_show_pages(page, pages);
+
+       shadow = virt_to_page(page[0].shadow);
+
+       for(i = 0; i < pages; ++i)
+               page[i].shadow = NULL;
+
+       __free_pages(shadow, order);
+}
+
+void kmemcheck_slab_alloc(struct kmem_cache *s, gfp_t gfpflags, void *object,
+                         size_t size)
+{
+       /*
+        * Has already been memset(), which initializes the shadow for us
+        * as well.
+        */
+       if (gfpflags & __GFP_ZERO)
+               return;
+
+       /* No need to initialize the shadow of a non-tracked slab. */
+       if (s->flags & SLAB_NOTRACK)
+               return;
+
+       if (!kmemcheck_enabled || gfpflags & __GFP_NOTRACK) {
+               /*
+                * Allow notracked objects to be allocated from
+                * tracked caches. Note however that these objects
+                * will still get page faults on access, they just
+                * won't ever be flagged as uninitialized. If page
+                * faults are not acceptable, the slab cache itself
+                * should be marked NOTRACK.
+                */
+               kmemcheck_mark_initialized(object, size);
+       } else if (!s->ctor) {
+               /*
+                * New objects should be marked uninitialized before
+                * they're returned to the called.
+                */
+               kmemcheck_mark_uninitialized(object, size);
+       }
+}
+
+void kmemcheck_slab_free(struct kmem_cache *s, void *object, size_t size)
+{
+       /* TODO: RCU freeing is unsupported for now; hide false positives. */
+       if (!s->ctor && !(s->flags & SLAB_DESTROY_BY_RCU))
+               kmemcheck_mark_freed(object, size);
+}
+
+void kmemcheck_pagealloc_alloc(struct page *page, unsigned int order,
+                              gfp_t gfpflags)
+{
+       int pages;
+
+       if (gfpflags & (__GFP_HIGHMEM | __GFP_NOTRACK))
+               return;
+
+       pages = 1 << order;
+
+       /*
+        * NOTE: We choose to track GFP_ZERO pages too; in fact, they
+        * can become uninitialized by copying uninitialized memory
+        * into them.
+        */
+
+       /* XXX: Can use zone->node for node? */
+       kmemcheck_alloc_shadow(page, order, gfpflags, -1);
+
+       if (gfpflags & __GFP_ZERO)
+               kmemcheck_mark_initialized_pages(page, pages);
+       else
+               kmemcheck_mark_uninitialized_pages(page, pages);
+}
index b9ce574827c8a2a48b972f0261decc234edf9e27..76eb4193acddb2e739b1e42a0a8371b59464f39f 100644 (file)
@@ -123,8 +123,7 @@ static long madvise_willneed(struct vm_area_struct * vma,
                end = vma->vm_end;
        end = ((end - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
 
-       force_page_cache_readahead(file->f_mapping,
-                       file, start, max_sane_readahead(end - start));
+       force_page_cache_readahead(file->f_mapping, file, start, end - start);
        return 0;
 }
 
@@ -239,12 +238,30 @@ madvise_vma(struct vm_area_struct *vma, struct vm_area_struct **prev,
                break;
 
        default:
-               error = -EINVAL;
+               BUG();
                break;
        }
        return error;
 }
 
+static int
+madvise_behavior_valid(int behavior)
+{
+       switch (behavior) {
+       case MADV_DOFORK:
+       case MADV_DONTFORK:
+       case MADV_NORMAL:
+       case MADV_SEQUENTIAL:
+       case MADV_RANDOM:
+       case MADV_REMOVE:
+       case MADV_WILLNEED:
+       case MADV_DONTNEED:
+               return 1;
+
+       default:
+               return 0;
+       }
+}
 /*
  * The madvise(2) system call.
  *
@@ -290,6 +307,9 @@ SYSCALL_DEFINE3(madvise, unsigned long, start, size_t, len_in, int, behavior)
        int write;
        size_t len;
 
+       if (!madvise_behavior_valid(behavior))
+               return error;
+
        write = madvise_need_mmap_write(behavior);
        if (write)
                down_write(&current->mm->mmap_sem);
index 78eb8552818b6b94d4add7ec06ecdc881add1f67..70db6e0a5eece0a3a6d40f2089d91271968c3361 100644 (file)
@@ -570,6 +570,17 @@ int mem_cgroup_inactive_anon_is_low(struct mem_cgroup *memcg)
        return 0;
 }
 
+int mem_cgroup_inactive_file_is_low(struct mem_cgroup *memcg)
+{
+       unsigned long active;
+       unsigned long inactive;
+
+       inactive = mem_cgroup_get_local_zonestat(memcg, LRU_INACTIVE_FILE);
+       active = mem_cgroup_get_local_zonestat(memcg, LRU_ACTIVE_FILE);
+
+       return (active > inactive);
+}
+
 unsigned long mem_cgroup_zone_nr_pages(struct mem_cgroup *memcg,
                                       struct zone *zone,
                                       enum lru_list lru)
index 4126dd16778c36595af938988c9d8ec144d0f8aa..d5d1653d60a6be51a4ba74de53fd997d8b0bc94c 100644 (file)
@@ -1360,6 +1360,56 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
        return i;
 }
 
+/**
+ * get_user_pages() - pin user pages in memory
+ * @tsk:       task_struct of target task
+ * @mm:                mm_struct of target mm
+ * @start:     starting user address
+ * @len:       number of pages from start to pin
+ * @write:     whether pages will be written to by the caller
+ * @force:     whether to force write access even if user mapping is
+ *             readonly. This will result in the page being COWed even
+ *             in MAP_SHARED mappings. You do not want this.
+ * @pages:     array that receives pointers to the pages pinned.
+ *             Should be at least nr_pages long. Or NULL, if caller
+ *             only intends to ensure the pages are faulted in.
+ * @vmas:      array of pointers to vmas corresponding to each page.
+ *             Or NULL if the caller does not require them.
+ *
+ * Returns number of pages pinned. This may be fewer than the number
+ * requested. If len is 0 or negative, returns 0. If no pages
+ * were pinned, returns -errno. Each page returned must be released
+ * with a put_page() call when it is finished with. vmas will only
+ * remain valid while mmap_sem is held.
+ *
+ * Must be called with mmap_sem held for read or write.
+ *
+ * get_user_pages walks a process's page tables and takes a reference to
+ * each struct page that each user address corresponds to at a given
+ * instant. That is, it takes the page that would be accessed if a user
+ * thread accesses the given user virtual address at that instant.
+ *
+ * This does not guarantee that the page exists in the user mappings when
+ * get_user_pages returns, and there may even be a completely different
+ * page there in some cases (eg. if mmapped pagecache has been invalidated
+ * and subsequently re faulted). However it does guarantee that the page
+ * won't be freed completely. And mostly callers simply care that the page
+ * contains data that was valid *at some point in time*. Typically, an IO
+ * or similar operation cannot guarantee anything stronger anyway because
+ * locks can't be held over the syscall boundary.
+ *
+ * If write=0, the page must not be written to. If the page is written to,
+ * set_page_dirty (or set_page_dirty_lock, as appropriate) must be called
+ * after the page is finished with, and before put_page is called.
+ *
+ * get_user_pages is typically used for fewer-copy IO operations, to get a
+ * handle on the memory by some means other than accesses via the user virtual
+ * addresses. The pages may be submitted for DMA to devices or accessed via
+ * their kernel linear mapping (via the kmap APIs). Care should be taken to
+ * use the correct cache flushing APIs.
+ *
+ * See also get_user_pages_fast, for performance critical applications.
+ */
 int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
                unsigned long start, int len, int write, int force,
                struct page **pages, struct vm_area_struct **vmas)
@@ -3053,22 +3103,13 @@ int in_gate_area_no_task(unsigned long addr)
 
 #endif /* __HAVE_ARCH_GATE_AREA */
 
-#ifdef CONFIG_HAVE_IOREMAP_PROT
-int follow_phys(struct vm_area_struct *vma,
-               unsigned long address, unsigned int flags,
-               unsigned long *prot, resource_size_t *phys)
+static int follow_pte(struct mm_struct *mm, unsigned long address,
+               pte_t **ptepp, spinlock_t **ptlp)
 {
        pgd_t *pgd;
        pud_t *pud;
        pmd_t *pmd;
-       pte_t *ptep, pte;
-       spinlock_t *ptl;
-       resource_size_t phys_addr = 0;
-       struct mm_struct *mm = vma->vm_mm;
-       int ret = -EINVAL;
-
-       if (!(vma->vm_flags & (VM_IO | VM_PFNMAP)))
-               goto out;
+       pte_t *ptep;
 
        pgd = pgd_offset(mm, address);
        if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
@@ -3086,22 +3127,71 @@ int follow_phys(struct vm_area_struct *vma,
        if (pmd_huge(*pmd))
                goto out;
 
-       ptep = pte_offset_map_lock(mm, pmd, address, &ptl);
+       ptep = pte_offset_map_lock(mm, pmd, address, ptlp);
        if (!ptep)
                goto out;
+       if (!pte_present(*ptep))
+               goto unlock;
+       *ptepp = ptep;
+       return 0;
+unlock:
+       pte_unmap_unlock(ptep, *ptlp);
+out:
+       return -EINVAL;
+}
 
+/**
+ * follow_pfn - look up PFN at a user virtual address
+ * @vma: memory mapping
+ * @address: user virtual address
+ * @pfn: location to store found PFN
+ *
+ * Only IO mappings and raw PFN mappings are allowed.
+ *
+ * Returns zero and the pfn at @pfn on success, -ve otherwise.
+ */
+int follow_pfn(struct vm_area_struct *vma, unsigned long address,
+       unsigned long *pfn)
+{
+       int ret = -EINVAL;
+       spinlock_t *ptl;
+       pte_t *ptep;
+
+       if (!(vma->vm_flags & (VM_IO | VM_PFNMAP)))
+               return ret;
+
+       ret = follow_pte(vma->vm_mm, address, &ptep, &ptl);
+       if (ret)
+               return ret;
+       *pfn = pte_pfn(*ptep);
+       pte_unmap_unlock(ptep, ptl);
+       return 0;
+}
+EXPORT_SYMBOL(follow_pfn);
+
+#ifdef CONFIG_HAVE_IOREMAP_PROT
+int follow_phys(struct vm_area_struct *vma,
+               unsigned long address, unsigned int flags,
+               unsigned long *prot, resource_size_t *phys)
+{
+       int ret = -EINVAL;
+       pte_t *ptep, pte;
+       spinlock_t *ptl;
+
+       if (!(vma->vm_flags & (VM_IO | VM_PFNMAP)))
+               goto out;
+
+       if (follow_pte(vma->vm_mm, address, &ptep, &ptl))
+               goto out;
        pte = *ptep;
-       if (!pte_present(pte))
-               goto unlock;
+
        if ((flags & FOLL_WRITE) && !pte_write(pte))
                goto unlock;
-       phys_addr = pte_pfn(pte);
-       phys_addr <<= PAGE_SHIFT; /* Shift here to avoid overflow on PAE */
 
        *prot = pgprot_val(pte_pgprot(pte));
-       *phys = phys_addr;
-       ret = 0;
+       *phys = (resource_size_t)pte_pfn(pte) << PAGE_SHIFT;
 
+       ret = 0;
 unlock:
        pte_unmap_unlock(ptep, ptl);
 out:
index c083cf5fd6df920b8f984351f11942cfa2f9b317..e4412a676c88494ec313ebb3e974d2d71ee5c525 100644 (file)
@@ -422,7 +422,8 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
        zone->present_pages += onlined_pages;
        zone->zone_pgdat->node_present_pages += onlined_pages;
 
-       setup_per_zone_pages_min();
+       setup_per_zone_wmarks();
+       calculate_zone_inactive_ratio(zone);
        if (onlined_pages) {
                kswapd_run(zone_to_nid(zone));
                node_set_state(zone_to_nid(zone), N_HIGH_MEMORY);
@@ -832,6 +833,9 @@ repeat:
        totalram_pages -= offlined_pages;
        num_physpages -= offlined_pages;
 
+       setup_per_zone_wmarks();
+       calculate_zone_inactive_ratio(zone);
+
        vm_total_pages = nr_free_pagecache_pages();
        writeback_set_ratelimit();
 
index 3eb4a6fdc04377130f628daaadfc2f970503addc..e08e2c4da63a5dc45bfcfb9f56cd440d557d0772 100644 (file)
@@ -182,13 +182,54 @@ static int mpol_new_bind(struct mempolicy *pol, const nodemask_t *nodes)
        return 0;
 }
 
-/* Create a new policy */
+/*
+ * mpol_set_nodemask is called after mpol_new() to set up the nodemask, if
+ * any, for the new policy.  mpol_new() has already validated the nodes
+ * parameter with respect to the policy mode and flags.  But, we need to
+ * handle an empty nodemask with MPOL_PREFERRED here.
+ *
+ * Must be called holding task's alloc_lock to protect task's mems_allowed
+ * and mempolicy.  May also be called holding the mmap_semaphore for write.
+ */
+static int mpol_set_nodemask(struct mempolicy *pol, const nodemask_t *nodes)
+{
+       nodemask_t cpuset_context_nmask;
+       int ret;
+
+       /* if mode is MPOL_DEFAULT, pol is NULL. This is right. */
+       if (pol == NULL)
+               return 0;
+
+       VM_BUG_ON(!nodes);
+       if (pol->mode == MPOL_PREFERRED && nodes_empty(*nodes))
+               nodes = NULL;   /* explicit local allocation */
+       else {
+               if (pol->flags & MPOL_F_RELATIVE_NODES)
+                       mpol_relative_nodemask(&cpuset_context_nmask, nodes,
+                                              &cpuset_current_mems_allowed);
+               else
+                       nodes_and(cpuset_context_nmask, *nodes,
+                                 cpuset_current_mems_allowed);
+               if (mpol_store_user_nodemask(pol))
+                       pol->w.user_nodemask = *nodes;
+               else
+                       pol->w.cpuset_mems_allowed =
+                                               cpuset_current_mems_allowed;
+       }
+
+       ret = mpol_ops[pol->mode].create(pol,
+                               nodes ? &cpuset_context_nmask : NULL);
+       return ret;
+}
+
+/*
+ * This function just creates a new policy, does some check and simple
+ * initialization. You must invoke mpol_set_nodemask() to set nodes.
+ */
 static struct mempolicy *mpol_new(unsigned short mode, unsigned short flags,
                                  nodemask_t *nodes)
 {
        struct mempolicy *policy;
-       nodemask_t cpuset_context_nmask;
-       int ret;
 
        pr_debug("setting mode %d flags %d nodes[0] %lx\n",
                 mode, flags, nodes ? nodes_addr(*nodes)[0] : -1);
@@ -210,7 +251,6 @@ static struct mempolicy *mpol_new(unsigned short mode, unsigned short flags,
                        if (((flags & MPOL_F_STATIC_NODES) ||
                             (flags & MPOL_F_RELATIVE_NODES)))
                                return ERR_PTR(-EINVAL);
-                       nodes = NULL;   /* flag local alloc */
                }
        } else if (nodes_empty(*nodes))
                return ERR_PTR(-EINVAL);
@@ -221,30 +261,6 @@ static struct mempolicy *mpol_new(unsigned short mode, unsigned short flags,
        policy->mode = mode;
        policy->flags = flags;
 
-       if (nodes) {
-               /*
-                * cpuset related setup doesn't apply to local allocation
-                */
-               cpuset_update_task_memory_state();
-               if (flags & MPOL_F_RELATIVE_NODES)
-                       mpol_relative_nodemask(&cpuset_context_nmask, nodes,
-                                              &cpuset_current_mems_allowed);
-               else
-                       nodes_and(cpuset_context_nmask, *nodes,
-                                 cpuset_current_mems_allowed);
-               if (mpol_store_user_nodemask(policy))
-                       policy->w.user_nodemask = *nodes;
-               else
-                       policy->w.cpuset_mems_allowed =
-                                               cpuset_mems_allowed(current);
-       }
-
-       ret = mpol_ops[mode].create(policy,
-                               nodes ? &cpuset_context_nmask : NULL);
-       if (ret < 0) {
-               kmem_cache_free(policy_cache, policy);
-               return ERR_PTR(ret);
-       }
        return policy;
 }
 
@@ -324,6 +340,8 @@ static void mpol_rebind_policy(struct mempolicy *pol,
 /*
  * Wrapper for mpol_rebind_policy() that just requires task
  * pointer, and updates task mempolicy.
+ *
+ * Called with task's alloc_lock held.
  */
 
 void mpol_rebind_task(struct task_struct *tsk, const nodemask_t *new)
@@ -600,8 +618,9 @@ static void mpol_set_task_struct_flag(void)
 static long do_set_mempolicy(unsigned short mode, unsigned short flags,
                             nodemask_t *nodes)
 {
-       struct mempolicy *new;
+       struct mempolicy *new, *old;
        struct mm_struct *mm = current->mm;
+       int ret;
 
        new = mpol_new(mode, flags, nodes);
        if (IS_ERR(new))
@@ -615,20 +634,33 @@ static long do_set_mempolicy(unsigned short mode, unsigned short flags,
         */
        if (mm)
                down_write(&mm->mmap_sem);
-       mpol_put(current->mempolicy);
+       task_lock(current);
+       ret = mpol_set_nodemask(new, nodes);
+       if (ret) {
+               task_unlock(current);
+               if (mm)
+                       up_write(&mm->mmap_sem);
+               mpol_put(new);
+               return ret;
+       }
+       old = current->mempolicy;
        current->mempolicy = new;
        mpol_set_task_struct_flag();
        if (new && new->mode == MPOL_INTERLEAVE &&
            nodes_weight(new->v.nodes))
                current->il_next = first_node(new->v.nodes);
+       task_unlock(current);
        if (mm)
                up_write(&mm->mmap_sem);
 
+       mpol_put(old);
        return 0;
 }
 
 /*
  * Return nodemask for policy for get_mempolicy() query
+ *
+ * Called with task's alloc_lock held
  */
 static void get_policy_nodemask(struct mempolicy *p, nodemask_t *nodes)
 {
@@ -674,7 +706,6 @@ static long do_get_mempolicy(int *policy, nodemask_t *nmask,
        struct vm_area_struct *vma = NULL;
        struct mempolicy *pol = current->mempolicy;
 
-       cpuset_update_task_memory_state();
        if (flags &
                ~(unsigned long)(MPOL_F_NODE|MPOL_F_ADDR|MPOL_F_MEMS_ALLOWED))
                return -EINVAL;
@@ -683,7 +714,9 @@ static long do_get_mempolicy(int *policy, nodemask_t *nmask,
                if (flags & (MPOL_F_NODE|MPOL_F_ADDR))
                        return -EINVAL;
                *policy = 0;    /* just so it's initialized */
+               task_lock(current);
                *nmask  = cpuset_current_mems_allowed;
+               task_unlock(current);
                return 0;
        }
 
@@ -738,8 +771,11 @@ static long do_get_mempolicy(int *policy, nodemask_t *nmask,
        }
 
        err = 0;
-       if (nmask)
+       if (nmask) {
+               task_lock(current);
                get_policy_nodemask(pol, nmask);
+               task_unlock(current);
+       }
 
  out:
        mpol_cond_put(pol);
@@ -767,7 +803,7 @@ static void migrate_page_add(struct page *page, struct list_head *pagelist,
 
 static struct page *new_node_page(struct page *page, unsigned long node, int **x)
 {
-       return alloc_pages_node(node, GFP_HIGHUSER_MOVABLE, 0);
+       return alloc_pages_exact_node(node, GFP_HIGHUSER_MOVABLE, 0);
 }
 
 /*
@@ -979,6 +1015,14 @@ static long do_mbind(unsigned long start, unsigned long len,
                        return err;
        }
        down_write(&mm->mmap_sem);
+       task_lock(current);
+       err = mpol_set_nodemask(new, nmask);
+       task_unlock(current);
+       if (err) {
+               up_write(&mm->mmap_sem);
+               mpol_put(new);
+               return err;
+       }
        vma = check_range(mm, start, end, nmask,
                          flags | MPOL_MF_INVERT, &pagelist);
 
@@ -1545,8 +1589,6 @@ alloc_page_vma(gfp_t gfp, struct vm_area_struct *vma, unsigned long addr)
        struct mempolicy *pol = get_vma_policy(current, vma, addr);
        struct zonelist *zl;
 
-       cpuset_update_task_memory_state();
-
        if (unlikely(pol->mode == MPOL_INTERLEAVE)) {
                unsigned nid;
 
@@ -1593,8 +1635,6 @@ struct page *alloc_pages_current(gfp_t gfp, unsigned order)
 {
        struct mempolicy *pol = current->mempolicy;
 
-       if ((gfp & __GFP_WAIT) && !in_interrupt())
-               cpuset_update_task_memory_state();
        if (!pol || in_interrupt() || (gfp & __GFP_THISNODE))
                pol = &default_policy;
 
@@ -1854,6 +1894,8 @@ restart:
  */
 void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol)
 {
+       int ret;
+
        sp->root = RB_ROOT;             /* empty tree == default mempolicy */
        spin_lock_init(&sp->lock);
 
@@ -1863,9 +1905,19 @@ void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol)
 
                /* contextualize the tmpfs mount point mempolicy */
                new = mpol_new(mpol->mode, mpol->flags, &mpol->w.user_nodemask);
-               mpol_put(mpol); /* drop our ref on sb mpol */
-               if (IS_ERR(new))
+               if (IS_ERR(new)) {
+                       mpol_put(mpol); /* drop our ref on sb mpol */
                        return;         /* no valid nodemask intersection */
+               }
+
+               task_lock(current);
+               ret = mpol_set_nodemask(new, &mpol->w.user_nodemask);
+               task_unlock(current);
+               mpol_put(mpol); /* drop our ref on sb mpol */
+               if (ret) {
+                       mpol_put(new);
+                       return;
+               }
 
                /* Create pseudo-vma that contains just the policy */
                memset(&pvma, 0, sizeof(struct vm_area_struct));
@@ -2086,8 +2138,19 @@ int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context)
        new = mpol_new(mode, mode_flags, &nodes);
        if (IS_ERR(new))
                err = 1;
-       else if (no_context)
-               new->w.user_nodemask = nodes;   /* save for contextualization */
+       else {
+               int ret;
+
+               task_lock(current);
+               ret = mpol_set_nodemask(new, &nodes);
+               task_unlock(current);
+               if (ret)
+                       err = 1;
+               else if (no_context) {
+                       /* save for contextualization */
+                       new->w.user_nodemask = nodes;
+               }
+       }
 
 out:
        /* Restore string for error message */
index 068655d8f883a8d2a79ae3f3247ced23f0b5db76..939888f9ddab21ecabdc2f732a8ee604cb56da13 100644 (file)
@@ -802,7 +802,7 @@ static struct page *new_page_node(struct page *p, unsigned long private,
 
        *result = &pm->status;
 
-       return alloc_pages_node(pm->node,
+       return alloc_pages_exact_node(pm->node,
                                GFP_HIGHUSER_MOVABLE | GFP_THISNODE, 0);
 }
 
@@ -820,7 +820,6 @@ static int do_move_page_to_node_array(struct mm_struct *mm,
        struct page_to_node *pp;
        LIST_HEAD(pagelist);
 
-       migrate_prep();
        down_read(&mm->mmap_sem);
 
        /*
@@ -907,6 +906,9 @@ static int do_pages_move(struct mm_struct *mm, struct task_struct *task,
        pm = (struct page_to_node *)__get_free_page(GFP_KERNEL);
        if (!pm)
                goto out;
+
+       migrate_prep();
+
        /*
         * Store a chunk of page_to_node array in a page,
         * but keep the last one as a marker
index ac130433c7d35da275b1ad081bfddd9fbf017173..45eb650b9654ed09bebe3b4de3c203442538792d 100644 (file)
@@ -31,7 +31,6 @@ int can_do_mlock(void)
 }
 EXPORT_SYMBOL(can_do_mlock);
 
-#ifdef CONFIG_UNEVICTABLE_LRU
 /*
  * Mlocked pages are marked with PageMlocked() flag for efficient testing
  * in vmscan and, possibly, the fault path; and to support semi-accurate
@@ -261,27 +260,6 @@ static int __mlock_posix_error_return(long retval)
        return retval;
 }
 
-#else /* CONFIG_UNEVICTABLE_LRU */
-
-/*
- * Just make pages present if VM_LOCKED.  No-op if unlocking.
- */
-static long __mlock_vma_pages_range(struct vm_area_struct *vma,
-                                  unsigned long start, unsigned long end,
-                                  int mlock)
-{
-       if (mlock && (vma->vm_flags & VM_LOCKED))
-               return make_pages_present(start, end);
-       return 0;
-}
-
-static inline int __mlock_posix_error_return(long retval)
-{
-       return 0;
-}
-
-#endif /* CONFIG_UNEVICTABLE_LRU */
-
 /**
  * mlock_vma_pages_range() - mlock pages in specified vma range.
  * @vma - the vma containing the specfied address range
index a7b2460e922b779252ebcc225cecaf6060b0e964..175a67a78a99e7b0368dfba11edf9888bc049674 100644 (file)
@@ -58,6 +58,7 @@ unsigned long badness(struct task_struct *p, unsigned long uptime)
        unsigned long points, cpu_time, run_time;
        struct mm_struct *mm;
        struct task_struct *child;
+       int oom_adj;
 
        task_lock(p);
        mm = p->mm;
@@ -65,6 +66,11 @@ unsigned long badness(struct task_struct *p, unsigned long uptime)
                task_unlock(p);
                return 0;
        }
+       oom_adj = mm->oom_adj;
+       if (oom_adj == OOM_DISABLE) {
+               task_unlock(p);
+               return 0;
+       }
 
        /*
         * The memory size of the process is the basis for the badness.
@@ -148,15 +154,15 @@ unsigned long badness(struct task_struct *p, unsigned long uptime)
                points /= 8;
 
        /*
-        * Adjust the score by oomkilladj.
+        * Adjust the score by oom_adj.
         */
-       if (p->oomkilladj) {
-               if (p->oomkilladj > 0) {
+       if (oom_adj) {
+               if (oom_adj > 0) {
                        if (!points)
                                points = 1;
-                       points <<= p->oomkilladj;
+                       points <<= oom_adj;
                } else
-                       points >>= -(p->oomkilladj);
+                       points >>= -(oom_adj);
        }
 
 #ifdef DEBUG
@@ -251,11 +257,8 @@ static struct task_struct *select_bad_process(unsigned long *ppoints,
                        *ppoints = ULONG_MAX;
                }
 
-               if (p->oomkilladj == OOM_DISABLE)
-                       continue;
-
                points = badness(p, uptime.tv_sec);
-               if (points > *ppoints || !chosen) {
+               if (points > *ppoints) {
                        chosen = p;
                        *ppoints = points;
                }
@@ -304,8 +307,7 @@ static void dump_tasks(const struct mem_cgroup *mem)
                }
                printk(KERN_INFO "[%5d] %5d %5d %8lu %8lu %3d     %3d %s\n",
                       p->pid, __task_cred(p)->uid, p->tgid, mm->total_vm,
-                      get_mm_rss(mm), (int)task_cpu(p), p->oomkilladj,
-                      p->comm);
+                      get_mm_rss(mm), (int)task_cpu(p), mm->oom_adj, p->comm);
                task_unlock(p);
        } while_each_thread(g, p);
 }
@@ -323,11 +325,8 @@ static void __oom_kill_task(struct task_struct *p, int verbose)
                return;
        }
 
-       if (!p->mm) {
-               WARN_ON(1);
-               printk(KERN_WARNING "tried to kill an mm-less task!\n");
+       if (!p->mm)
                return;
-       }
 
        if (verbose)
                printk(KERN_ERR "Killed process %d (%s)\n",
@@ -349,28 +348,13 @@ static int oom_kill_task(struct task_struct *p)
        struct mm_struct *mm;
        struct task_struct *g, *q;
 
+       task_lock(p);
        mm = p->mm;
-
-       /* WARNING: mm may not be dereferenced since we did not obtain its
-        * value from get_task_mm(p).  This is OK since all we need to do is
-        * compare mm to q->mm below.
-        *
-        * Furthermore, even if mm contains a non-NULL value, p->mm may
-        * change to NULL at any time since we do not hold task_lock(p).
-        * However, this is of no concern to us.
-        */
-
-       if (mm == NULL)
+       if (!mm || mm->oom_adj == OOM_DISABLE) {
+               task_unlock(p);
                return 1;
-
-       /*
-        * Don't kill the process if any threads are set to OOM_DISABLE
-        */
-       do_each_thread(g, q) {
-               if (q->mm == mm && q->oomkilladj == OOM_DISABLE)
-                       return 1;
-       } while_each_thread(g, q);
-
+       }
+       task_unlock(p);
        __oom_kill_task(p, 1);
 
        /*
@@ -393,10 +377,11 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,
        struct task_struct *c;
 
        if (printk_ratelimit()) {
-               printk(KERN_WARNING "%s invoked oom-killer: "
-                       "gfp_mask=0x%x, order=%d, oomkilladj=%d\n",
-                       current->comm, gfp_mask, order, current->oomkilladj);
                task_lock(current);
+               printk(KERN_WARNING "%s invoked oom-killer: "
+                       "gfp_mask=0x%x, order=%d, oom_adj=%d\n",
+                       current->comm, gfp_mask, order,
+                       current->mm ? current->mm->oom_adj : OOM_DISABLE);
                cpuset_print_task_mems_allowed(current);
                task_unlock(current);
                dump_stack();
@@ -409,8 +394,9 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,
        /*
         * If the task is already exiting, don't alarm the sysadmin or kill
         * its children or threads, just set TIF_MEMDIE so it can die quickly
+        * if its mm is still attached.
         */
-       if (p->flags & PF_EXITING) {
+       if (p->mm && (p->flags & PF_EXITING)) {
                __oom_kill_task(p, 0);
                return 0;
        }
index bb553c3e955da10631ca7f8229be2b1bdb791f25..7b0dcea4935bea292730ce7d1926fc0ea00df062 100644 (file)
@@ -265,18 +265,19 @@ static void bdi_writeout_fraction(struct backing_dev_info *bdi,
  * This avoids exceeding the total dirty_limit when the floating averages
  * fluctuate too quickly.
  */
-static void
-clip_bdi_dirty_limit(struct backing_dev_info *bdi, long dirty, long *pbdi_dirty)
+static void clip_bdi_dirty_limit(struct backing_dev_info *bdi,
+               unsigned long dirty, unsigned long *pbdi_dirty)
 {
-       long avail_dirty;
+       unsigned long avail_dirty;
 
-       avail_dirty = dirty -
-               (global_page_state(NR_FILE_DIRTY) +
+       avail_dirty = global_page_state(NR_FILE_DIRTY) +
                 global_page_state(NR_WRITEBACK) +
                 global_page_state(NR_UNSTABLE_NFS) +
-                global_page_state(NR_WRITEBACK_TEMP));
+                global_page_state(NR_WRITEBACK_TEMP);
 
-       if (avail_dirty < 0)
+       if (avail_dirty < dirty)
+               avail_dirty = dirty - avail_dirty;
+       else
                avail_dirty = 0;
 
        avail_dirty += bdi_stat(bdi, BDI_RECLAIMABLE) +
@@ -299,10 +300,10 @@ static inline void task_dirties_fraction(struct task_struct *tsk,
  *
  *   dirty -= (dirty/8) * p_{t}
  */
-static void task_dirty_limit(struct task_struct *tsk, long *pdirty)
+static void task_dirty_limit(struct task_struct *tsk, unsigned long *pdirty)
 {
        long numerator, denominator;
-       long dirty = *pdirty;
+       unsigned long dirty = *pdirty;
        u64 inv = dirty >> 3;
 
        task_dirties_fraction(tsk, &numerator, &denominator);
index 17d5f539a9aa58a18accc8f97904faf02d93d04e..a5f3c278c5732f4f3c8c9258f5b95b2c86b3e490 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/bootmem.h>
 #include <linux/compiler.h>
 #include <linux/kernel.h>
+#include <linux/kmemcheck.h>
 #include <linux/module.h>
 #include <linux/suspend.h>
 #include <linux/pagevec.h>
@@ -161,17 +162,25 @@ static unsigned long __meminitdata dma_reserve;
 
 #if MAX_NUMNODES > 1
 int nr_node_ids __read_mostly = MAX_NUMNODES;
+int nr_online_nodes __read_mostly = 1;
 EXPORT_SYMBOL(nr_node_ids);
+EXPORT_SYMBOL(nr_online_nodes);
 #endif
 
 int page_group_by_mobility_disabled __read_mostly;
 
 static void set_pageblock_migratetype(struct page *page, int migratetype)
 {
+
+       if (unlikely(page_group_by_mobility_disabled))
+               migratetype = MIGRATE_UNMOVABLE;
+
        set_pageblock_flags_group(page, (unsigned long)migratetype,
                                        PB_migrate, PB_migrate_end);
 }
 
+bool oom_killer_disabled __read_mostly;
+
 #ifdef CONFIG_DEBUG_VM
 static int page_outside_zone_boundaries(struct zone *zone, struct page *page)
 {
@@ -294,23 +303,6 @@ void prep_compound_page(struct page *page, unsigned long order)
        }
 }
 
-#ifdef CONFIG_HUGETLBFS
-void prep_compound_gigantic_page(struct page *page, unsigned long order)
-{
-       int i;
-       int nr_pages = 1 << order;
-       struct page *p = page + 1;
-
-       set_compound_page_dtor(page, free_compound_page);
-       set_compound_order(page, order);
-       __SetPageHead(page);
-       for (i = 1; i < nr_pages; i++, p = mem_map_next(p, page, i)) {
-               __SetPageTail(p);
-               p->first_page = page;
-       }
-}
-#endif
-
 static int destroy_compound_page(struct page *page, unsigned long order)
 {
        int i;
@@ -417,7 +409,7 @@ static inline int page_is_buddy(struct page *page, struct page *buddy,
                return 0;
 
        if (PageBuddy(buddy) && page_order(buddy) == order) {
-               BUG_ON(page_count(buddy) != 0);
+               VM_BUG_ON(page_count(buddy) != 0);
                return 1;
        }
        return 0;
@@ -448,22 +440,22 @@ static inline int page_is_buddy(struct page *page, struct page *buddy,
  */
 
 static inline void __free_one_page(struct page *page,
-               struct zone *zone, unsigned int order)
+               struct zone *zone, unsigned int order,
+               int migratetype)
 {
        unsigned long page_idx;
-       int order_size = 1 << order;
-       int migratetype = get_pageblock_migratetype(page);
 
        if (unlikely(PageCompound(page)))
                if (unlikely(destroy_compound_page(page, order)))
                        return;
 
+       VM_BUG_ON(migratetype == -1);
+
        page_idx = page_to_pfn(page) & ((1 << MAX_ORDER) - 1);
 
-       VM_BUG_ON(page_idx & (order_size - 1));
+       VM_BUG_ON(page_idx & ((1 << order) - 1));
        VM_BUG_ON(bad_range(zone, page));
 
-       __mod_zone_page_state(zone, NR_FREE_PAGES, order_size);
        while (order < MAX_ORDER-1) {
                unsigned long combined_idx;
                struct page *buddy;
@@ -487,12 +479,27 @@ static inline void __free_one_page(struct page *page,
        zone->free_area[order].nr_free++;
 }
 
+#ifdef CONFIG_HAVE_MLOCKED_PAGE_BIT
+/*
+ * free_page_mlock() -- clean up attempts to free and mlocked() page.
+ * Page should not be on lru, so no need to fix that up.
+ * free_pages_check() will verify...
+ */
+static inline void free_page_mlock(struct page *page)
+{
+       __ClearPageMlocked(page);
+       __dec_zone_page_state(page, NR_MLOCK);
+       __count_vm_event(UNEVICTABLE_MLOCKFREED);
+}
+#else
+static void free_page_mlock(struct page *page) { }
+#endif
+
 static inline int free_pages_check(struct page *page)
 {
-       free_page_mlock(page);
        if (unlikely(page_mapcount(page) |
                (page->mapping != NULL)  |
-               (page_count(page) != 0)  |
+               (atomic_read(&page->_count) != 0) |
                (page->flags & PAGE_FLAGS_CHECK_AT_FREE))) {
                bad_page(page);
                return 1;
@@ -519,6 +526,8 @@ static void free_pages_bulk(struct zone *zone, int count,
        spin_lock(&zone->lock);
        zone_clear_flag(zone, ZONE_ALL_UNRECLAIMABLE);
        zone->pages_scanned = 0;
+
+       __mod_zone_page_state(zone, NR_FREE_PAGES, count << order);
        while (count--) {
                struct page *page;
 
@@ -526,17 +535,20 @@ static void free_pages_bulk(struct zone *zone, int count,
                page = list_entry(list->prev, struct page, lru);
                /* have to delete it as __free_one_page list manipulates */
                list_del(&page->lru);
-               __free_one_page(page, zone, order);
+               __free_one_page(page, zone, order, page_private(page));
        }
        spin_unlock(&zone->lock);
 }
 
-static void free_one_page(struct zone *zone, struct page *page, int order)
+static void free_one_page(struct zone *zone, struct page *page, int order,
+                               int migratetype)
 {
        spin_lock(&zone->lock);
        zone_clear_flag(zone, ZONE_ALL_UNRECLAIMABLE);
        zone->pages_scanned = 0;
-       __free_one_page(page, zone, order);
+
+       __mod_zone_page_state(zone, NR_FREE_PAGES, 1 << order);
+       __free_one_page(page, zone, order, migratetype);
        spin_unlock(&zone->lock);
 }
 
@@ -545,6 +557,9 @@ static void __free_pages_ok(struct page *page, unsigned int order)
        unsigned long flags;
        int i;
        int bad = 0;
+       int clearMlocked = PageMlocked(page);
+
+       kmemcheck_free_shadow(page, order);
 
        for (i = 0 ; i < (1 << order) ; ++i)
                bad += free_pages_check(page + i);
@@ -560,8 +575,11 @@ static void __free_pages_ok(struct page *page, unsigned int order)
        kernel_map_pages(page, 1 << order, 0);
 
        local_irq_save(flags);
+       if (unlikely(clearMlocked))
+               free_page_mlock(page);
        __count_vm_events(PGFREE, 1 << order);
-       free_one_page(page_zone(page), page, order);
+       free_one_page(page_zone(page), page, order,
+                                       get_pageblock_migratetype(page));
        local_irq_restore(flags);
 }
 
@@ -632,7 +650,7 @@ static int prep_new_page(struct page *page, int order, gfp_t gfp_flags)
 {
        if (unlikely(page_mapcount(page) |
                (page->mapping != NULL)  |
-               (page_count(page) != 0)  |
+               (atomic_read(&page->_count) != 0)  |
                (page->flags & PAGE_FLAGS_CHECK_AT_PREP))) {
                bad_page(page);
                return 1;
@@ -657,7 +675,8 @@ static int prep_new_page(struct page *page, int order, gfp_t gfp_flags)
  * Go through the free lists for the given migratetype and remove
  * the smallest available page from the freelists
  */
-static struct page *__rmqueue_smallest(struct zone *zone, unsigned int order,
+static inline
+struct page *__rmqueue_smallest(struct zone *zone, unsigned int order,
                                                int migratetype)
 {
        unsigned int current_order;
@@ -675,7 +694,6 @@ static struct page *__rmqueue_smallest(struct zone *zone, unsigned int order,
                list_del(&page->lru);
                rmv_page_order(page);
                area->nr_free--;
-               __mod_zone_page_state(zone, NR_FREE_PAGES, - (1UL << order));
                expand(zone, page, order, current_order, area, migratetype);
                return page;
        }
@@ -766,8 +784,8 @@ static int move_freepages_block(struct zone *zone, struct page *page,
 }
 
 /* Remove an element from the buddy allocator from the fallback list */
-static struct page *__rmqueue_fallback(struct zone *zone, int order,
-                                               int start_migratetype)
+static inline struct page *
+__rmqueue_fallback(struct zone *zone, int order, int start_migratetype)
 {
        struct free_area * area;
        int current_order;
@@ -815,8 +833,6 @@ static struct page *__rmqueue_fallback(struct zone *zone, int order,
                        /* Remove the page from the freelists */
                        list_del(&page->lru);
                        rmv_page_order(page);
-                       __mod_zone_page_state(zone, NR_FREE_PAGES,
-                                                       -(1UL << order));
 
                        if (current_order == pageblock_order)
                                set_pageblock_migratetype(page,
@@ -827,8 +843,7 @@ static struct page *__rmqueue_fallback(struct zone *zone, int order,
                }
        }
 
-       /* Use MIGRATE_RESERVE rather than fail an allocation */
-       return __rmqueue_smallest(zone, order, MIGRATE_RESERVE);
+       return NULL;
 }
 
 /*
@@ -840,11 +855,23 @@ static struct page *__rmqueue(struct zone *zone, unsigned int order,
 {
        struct page *page;
 
+retry_reserve:
        page = __rmqueue_smallest(zone, order, migratetype);
 
-       if (unlikely(!page))
+       if (unlikely(!page) && migratetype != MIGRATE_RESERVE) {
                page = __rmqueue_fallback(zone, order, migratetype);
 
+               /*
+                * Use MIGRATE_RESERVE rather than fail an allocation. goto
+                * is used because __rmqueue_smallest is an inline function
+                * and we want just one call site
+                */
+               if (!page) {
+                       migratetype = MIGRATE_RESERVE;
+                       goto retry_reserve;
+               }
+       }
+
        return page;
 }
 
@@ -878,6 +905,7 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order,
                set_page_private(page, migratetype);
                list = &page->lru;
        }
+       __mod_zone_page_state(zone, NR_FREE_PAGES, -(i << order));
        spin_unlock(&zone->lock);
        return i;
 }
@@ -993,6 +1021,9 @@ static void free_hot_cold_page(struct page *page, int cold)
        struct zone *zone = page_zone(page);
        struct per_cpu_pages *pcp;
        unsigned long flags;
+       int clearMlocked = PageMlocked(page);
+
+       kmemcheck_free_shadow(page, 0);
 
        if (PageAnon(page))
                page->mapping = NULL;
@@ -1007,13 +1038,16 @@ static void free_hot_cold_page(struct page *page, int cold)
        kernel_map_pages(page, 1, 0);
 
        pcp = &zone_pcp(zone, get_cpu())->pcp;
+       set_page_private(page, get_pageblock_migratetype(page));
        local_irq_save(flags);
+       if (unlikely(clearMlocked))
+               free_page_mlock(page);
        __count_vm_event(PGFREE);
+
        if (cold)
                list_add_tail(&page->lru, &pcp->list);
        else
                list_add(&page->lru, &pcp->list);
-       set_page_private(page, get_pageblock_migratetype(page));
        pcp->count++;
        if (pcp->count >= pcp->high) {
                free_pages_bulk(zone, pcp->batch, &pcp->list, 0);
@@ -1047,6 +1081,16 @@ void split_page(struct page *page, unsigned int order)
 
        VM_BUG_ON(PageCompound(page));
        VM_BUG_ON(!page_count(page));
+
+#ifdef CONFIG_KMEMCHECK
+       /*
+        * Split shadow pages too, because free(page[0]) would
+        * otherwise free the whole shadow.
+        */
+       if (kmemcheck_page_is_tracked(page))
+               split_page(virt_to_page(page[0].shadow), order);
+#endif
+
        for (i = 1; i < (1 << order); i++)
                set_page_refcounted(page + i);
 }
@@ -1056,14 +1100,15 @@ void split_page(struct page *page, unsigned int order)
  * we cheat by calling it from here, in the order > 0 path.  Saves a branch
  * or two.
  */
-static struct page *buffered_rmqueue(struct zone *preferred_zone,
-                       struct zone *zone, int order, gfp_t gfp_flags)
+static inline
+struct page *buffered_rmqueue(struct zone *preferred_zone,
+                       struct zone *zone, int order, gfp_t gfp_flags,
+                       int migratetype)
 {
        unsigned long flags;
        struct page *page;
        int cold = !!(gfp_flags & __GFP_COLD);
        int cpu;
-       int migratetype = allocflags_to_migratetype(gfp_flags);
 
 again:
        cpu  = get_cpu();
@@ -1100,8 +1145,22 @@ again:
                list_del(&page->lru);
                pcp->count--;
        } else {
+               if (unlikely(gfp_flags & __GFP_NOFAIL)) {
+                       /*
+                        * __GFP_NOFAIL is not to be used in new code.
+                        *
+                        * All __GFP_NOFAIL callers should be fixed so that they
+                        * properly detect and handle allocation failures.
+                        *
+                        * We most definitely don't want callers attempting to
+                        * allocate greater than single-page units with
+                        * __GFP_NOFAIL.
+                        */
+                       WARN_ON_ONCE(order > 0);
+               }
                spin_lock_irqsave(&zone->lock, flags);
                page = __rmqueue(zone, order, migratetype);
+               __mod_zone_page_state(zone, NR_FREE_PAGES, -(1 << order));
                spin_unlock(&zone->lock);
                if (!page)
                        goto failed;
@@ -1123,10 +1182,15 @@ failed:
        return NULL;
 }
 
-#define ALLOC_NO_WATERMARKS    0x01 /* don't check watermarks at all */
-#define ALLOC_WMARK_MIN                0x02 /* use pages_min watermark */
-#define ALLOC_WMARK_LOW                0x04 /* use pages_low watermark */
-#define ALLOC_WMARK_HIGH       0x08 /* use pages_high watermark */
+/* The ALLOC_WMARK bits are used as an index to zone->watermark */
+#define ALLOC_WMARK_MIN                WMARK_MIN
+#define ALLOC_WMARK_LOW                WMARK_LOW
+#define ALLOC_WMARK_HIGH       WMARK_HIGH
+#define ALLOC_NO_WATERMARKS    0x04 /* don't check watermarks at all */
+
+/* Mask to get the watermark bits */
+#define ALLOC_WMARK_MASK       (ALLOC_NO_WATERMARKS-1)
+
 #define ALLOC_HARDER           0x10 /* try to alloc harder */
 #define ALLOC_HIGH             0x20 /* __GFP_HIGH set */
 #define ALLOC_CPUSET           0x40 /* check for correct cpuset */
@@ -1384,23 +1448,18 @@ static void zlc_mark_zone_full(struct zonelist *zonelist, struct zoneref *z)
  */
 static struct page *
 get_page_from_freelist(gfp_t gfp_mask, nodemask_t *nodemask, unsigned int order,
-               struct zonelist *zonelist, int high_zoneidx, int alloc_flags)
+               struct zonelist *zonelist, int high_zoneidx, int alloc_flags,
+               struct zone *preferred_zone, int migratetype)
 {
        struct zoneref *z;
        struct page *page = NULL;
        int classzone_idx;
-       struct zone *zone, *preferred_zone;
+       struct zone *zone;
        nodemask_t *allowednodes = NULL;/* zonelist_cache approximation */
        int zlc_active = 0;             /* set if using zonelist_cache */
        int did_zlc_setup = 0;          /* just call zlc_setup() one time */
 
-       (void)first_zones_zonelist(zonelist, high_zoneidx, nodemask,
-                                                       &preferred_zone);
-       if (!preferred_zone)
-               return NULL;
-
        classzone_idx = zone_idx(preferred_zone);
-
 zonelist_scan:
        /*
         * Scan zonelist, looking for a zone with enough free.
@@ -1415,31 +1474,49 @@ zonelist_scan:
                        !cpuset_zone_allowed_softwall(zone, gfp_mask))
                                goto try_next_zone;
 
+               BUILD_BUG_ON(ALLOC_NO_WATERMARKS < NR_WMARK);
                if (!(alloc_flags & ALLOC_NO_WATERMARKS)) {
                        unsigned long mark;
-                       if (alloc_flags & ALLOC_WMARK_MIN)
-                               mark = zone->pages_min;
-                       else if (alloc_flags & ALLOC_WMARK_LOW)
-                               mark = zone->pages_low;
-                       else
-                               mark = zone->pages_high;
-                       if (!zone_watermark_ok(zone, order, mark,
-                                   classzone_idx, alloc_flags)) {
-                               if (!zone_reclaim_mode ||
-                                   !zone_reclaim(zone, gfp_mask, order))
+                       int ret;
+
+                       mark = zone->watermark[alloc_flags & ALLOC_WMARK_MASK];
+                       if (zone_watermark_ok(zone, order, mark,
+                                   classzone_idx, alloc_flags))
+                               goto try_this_zone;
+
+                       if (zone_reclaim_mode == 0)
+                               goto this_zone_full;
+
+                       ret = zone_reclaim(zone, gfp_mask, order);
+                       switch (ret) {
+                       case ZONE_RECLAIM_NOSCAN:
+                               /* did not scan */
+                               goto try_next_zone;
+                       case ZONE_RECLAIM_FULL:
+                               /* scanned but unreclaimable */
+                               goto this_zone_full;
+                       default:
+                               /* did we reclaim enough */
+                               if (!zone_watermark_ok(zone, order, mark,
+                                               classzone_idx, alloc_flags))
                                        goto this_zone_full;
                        }
                }
 
-               page = buffered_rmqueue(preferred_zone, zone, order, gfp_mask);
+try_this_zone:
+               page = buffered_rmqueue(preferred_zone, zone, order,
+                                               gfp_mask, migratetype);
                if (page)
                        break;
 this_zone_full:
                if (NUMA_BUILD)
                        zlc_mark_zone_full(zonelist, z);
 try_next_zone:
-               if (NUMA_BUILD && !did_zlc_setup) {
-                       /* we do zlc_setup after the first zone is tried */
+               if (NUMA_BUILD && !did_zlc_setup && nr_online_nodes > 1) {
+                       /*
+                        * we do zlc_setup after the first zone is tried but only
+                        * if there are multiple nodes make it worthwhile
+                        */
                        allowednodes = zlc_setup(zonelist, alloc_flags);
                        zlc_active = 1;
                        did_zlc_setup = 1;
@@ -1454,47 +1531,217 @@ try_next_zone:
        return page;
 }
 
+static inline int
+should_alloc_retry(gfp_t gfp_mask, unsigned int order,
+                               unsigned long pages_reclaimed)
+{
+       /* Do not loop if specifically requested */
+       if (gfp_mask & __GFP_NORETRY)
+               return 0;
+
+       /*
+        * In this implementation, order <= PAGE_ALLOC_COSTLY_ORDER
+        * means __GFP_NOFAIL, but that may not be true in other
+        * implementations.
+        */
+       if (order <= PAGE_ALLOC_COSTLY_ORDER)
+               return 1;
+
+       /*
+        * For order > PAGE_ALLOC_COSTLY_ORDER, if __GFP_REPEAT is
+        * specified, then we retry until we no longer reclaim any pages
+        * (above), or we've reclaimed an order of pages at least as
+        * large as the allocation's order. In both cases, if the
+        * allocation still fails, we stop retrying.
+        */
+       if (gfp_mask & __GFP_REPEAT && pages_reclaimed < (1 << order))
+               return 1;
+
+       /*
+        * Don't let big-order allocations loop unless the caller
+        * explicitly requests that.
+        */
+       if (gfp_mask & __GFP_NOFAIL)
+               return 1;
+
+       return 0;
+}
+
+static inline struct page *
+__alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order,
+       struct zonelist *zonelist, enum zone_type high_zoneidx,
+       nodemask_t *nodemask, struct zone *preferred_zone,
+       int migratetype)
+{
+       struct page *page;
+
+       /* Acquire the OOM killer lock for the zones in zonelist */
+       if (!try_set_zone_oom(zonelist, gfp_mask)) {
+               schedule_timeout_uninterruptible(1);
+               return NULL;
+       }
+
+       /*
+        * Go through the zonelist yet one more time, keep very high watermark
+        * here, this is only to catch a parallel oom killing, we must fail if
+        * we're still under heavy pressure.
+        */
+       page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask,
+               order, zonelist, high_zoneidx,
+               ALLOC_WMARK_HIGH|ALLOC_CPUSET,
+               preferred_zone, migratetype);
+       if (page)
+               goto out;
+
+       /* The OOM killer will not help higher order allocs */
+       if (order > PAGE_ALLOC_COSTLY_ORDER && !(gfp_mask & __GFP_NOFAIL))
+               goto out;
+
+       /* Exhausted what can be done so it's blamo time */
+       out_of_memory(zonelist, gfp_mask, order);
+
+out:
+       clear_zonelist_oom(zonelist, gfp_mask);
+       return page;
+}
+
+/* The really slow allocator path where we enter direct reclaim */
+static inline struct page *
+__alloc_pages_direct_reclaim(gfp_t gfp_mask, unsigned int order,
+       struct zonelist *zonelist, enum zone_type high_zoneidx,
+       nodemask_t *nodemask, int alloc_flags, struct zone *preferred_zone,
+       int migratetype, unsigned long *did_some_progress)
+{
+       struct page *page = NULL;
+       struct reclaim_state reclaim_state;
+       struct task_struct *p = current;
+
+       cond_resched();
+
+       /* We now go into synchronous reclaim */
+       cpuset_memory_pressure_bump();
+
+       /*
+        * The task's cpuset might have expanded its set of allowable nodes
+        */
+       p->flags |= PF_MEMALLOC;
+       lockdep_set_current_reclaim_state(gfp_mask);
+       reclaim_state.reclaimed_slab = 0;
+       p->reclaim_state = &reclaim_state;
+
+       *did_some_progress = try_to_free_pages(zonelist, order, gfp_mask, nodemask);
+
+       p->reclaim_state = NULL;
+       lockdep_clear_current_reclaim_state();
+       p->flags &= ~PF_MEMALLOC;
+
+       cond_resched();
+
+       if (order != 0)
+               drain_all_pages();
+
+       if (likely(*did_some_progress))
+               page = get_page_from_freelist(gfp_mask, nodemask, order,
+                                       zonelist, high_zoneidx,
+                                       alloc_flags, preferred_zone,
+                                       migratetype);
+       return page;
+}
+
 /*
- * This is the 'heart' of the zoned buddy allocator.
+ * This is called in the allocator slow-path if the allocation request is of
+ * sufficient urgency to ignore watermarks and take other desperate measures
  */
-struct page *
-__alloc_pages_internal(gfp_t gfp_mask, unsigned int order,
-                       struct zonelist *zonelist, nodemask_t *nodemask)
+static inline struct page *
+__alloc_pages_high_priority(gfp_t gfp_mask, unsigned int order,
+       struct zonelist *zonelist, enum zone_type high_zoneidx,
+       nodemask_t *nodemask, struct zone *preferred_zone,
+       int migratetype)
+{
+       struct page *page;
+
+       do {
+               page = get_page_from_freelist(gfp_mask, nodemask, order,
+                       zonelist, high_zoneidx, ALLOC_NO_WATERMARKS,
+                       preferred_zone, migratetype);
+
+               if (!page && gfp_mask & __GFP_NOFAIL)
+                       congestion_wait(WRITE, HZ/50);
+       } while (!page && (gfp_mask & __GFP_NOFAIL));
+
+       return page;
+}
+
+static inline
+void wake_all_kswapd(unsigned int order, struct zonelist *zonelist,
+                                               enum zone_type high_zoneidx)
 {
-       const gfp_t wait = gfp_mask & __GFP_WAIT;
-       enum zone_type high_zoneidx = gfp_zone(gfp_mask);
        struct zoneref *z;
        struct zone *zone;
-       struct page *page;
-       struct reclaim_state reclaim_state;
-       struct task_struct *p = current;
-       int do_retry;
-       int alloc_flags;
-       unsigned long did_some_progress;
-       unsigned long pages_reclaimed = 0;
 
-       lockdep_trace_alloc(gfp_mask);
+       for_each_zone_zonelist(zone, z, zonelist, high_zoneidx)
+               wakeup_kswapd(zone, order);
+}
 
-       might_sleep_if(wait);
+static inline int
+gfp_to_alloc_flags(gfp_t gfp_mask)
+{
+       struct task_struct *p = current;
+       int alloc_flags = ALLOC_WMARK_MIN | ALLOC_CPUSET;
+       const gfp_t wait = gfp_mask & __GFP_WAIT;
 
-       if (should_fail_alloc_page(gfp_mask, order))
-               return NULL;
+       /* __GFP_HIGH is assumed to be the same as ALLOC_HIGH to save a branch. */
+       BUILD_BUG_ON(__GFP_HIGH != ALLOC_HIGH);
 
-restart:
-       z = zonelist->_zonerefs;  /* the list of zones suitable for gfp_mask */
+       /*
+        * The caller may dip into page reserves a bit more if the caller
+        * cannot run direct reclaim, or if the caller has realtime scheduling
+        * policy or is asking for __GFP_HIGH memory.  GFP_ATOMIC requests will
+        * set both ALLOC_HARDER (!wait) and ALLOC_HIGH (__GFP_HIGH).
+        */
+       alloc_flags |= (gfp_mask & __GFP_HIGH);
 
-       if (unlikely(!z->zone)) {
+       if (!wait) {
+               alloc_flags |= ALLOC_HARDER;
                /*
-                * Happens if we have an empty zonelist as a result of
-                * GFP_THISNODE being used on a memoryless node
+                * Ignore cpuset if GFP_ATOMIC (!wait) rather than fail alloc.
+                * See also cpuset_zone_allowed() comment in kernel/cpuset.c.
                 */
-               return NULL;
+               alloc_flags &= ~ALLOC_CPUSET;
+       } else if (unlikely(rt_task(p)))
+               alloc_flags |= ALLOC_HARDER;
+
+       if (likely(!(gfp_mask & __GFP_NOMEMALLOC))) {
+               if (!in_interrupt() &&
+                   ((p->flags & PF_MEMALLOC) ||
+                    unlikely(test_thread_flag(TIF_MEMDIE))))
+                       alloc_flags |= ALLOC_NO_WATERMARKS;
        }
 
-       page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask, order,
-                       zonelist, high_zoneidx, ALLOC_WMARK_LOW|ALLOC_CPUSET);
-       if (page)
-               goto got_pg;
+       return alloc_flags;
+}
+
+static inline struct page *
+__alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
+       struct zonelist *zonelist, enum zone_type high_zoneidx,
+       nodemask_t *nodemask, struct zone *preferred_zone,
+       int migratetype)
+{
+       const gfp_t wait = gfp_mask & __GFP_WAIT;
+       struct page *page = NULL;
+       int alloc_flags;
+       unsigned long pages_reclaimed = 0;
+       unsigned long did_some_progress;
+       struct task_struct *p = current;
+
+       /*
+        * In the slowpath, we sanity check order to avoid ever trying to
+        * reclaim >= MAX_ORDER areas which will never succeed. Callers may
+        * be using allocators in order of preference for an area that is
+        * too large.
+        */
+       if (WARN_ON_ONCE(order >= MAX_ORDER))
+               return NULL;
 
        /*
         * GFP_THISNODE (meaning __GFP_THISNODE, __GFP_NORETRY and
@@ -1507,154 +1754,83 @@ restart:
        if (NUMA_BUILD && (gfp_mask & GFP_THISNODE) == GFP_THISNODE)
                goto nopage;
 
-       for_each_zone_zonelist(zone, z, zonelist, high_zoneidx)
-               wakeup_kswapd(zone, order);
+       wake_all_kswapd(order, zonelist, high_zoneidx);
 
        /*
         * OK, we're below the kswapd watermark and have kicked background
         * reclaim. Now things get more complex, so set up alloc_flags according
         * to how we want to proceed.
-        *
-        * The caller may dip into page reserves a bit more if the caller
-        * cannot run direct reclaim, or if the caller has realtime scheduling
-        * policy or is asking for __GFP_HIGH memory.  GFP_ATOMIC requests will
-        * set both ALLOC_HARDER (!wait) and ALLOC_HIGH (__GFP_HIGH).
         */
-       alloc_flags = ALLOC_WMARK_MIN;
-       if ((unlikely(rt_task(p)) && !in_interrupt()) || !wait)
-               alloc_flags |= ALLOC_HARDER;
-       if (gfp_mask & __GFP_HIGH)
-               alloc_flags |= ALLOC_HIGH;
-       if (wait)
-               alloc_flags |= ALLOC_CPUSET;
+       alloc_flags = gfp_to_alloc_flags(gfp_mask);
 
-       /*
-        * Go through the zonelist again. Let __GFP_HIGH and allocations
-        * coming from realtime tasks go deeper into reserves.
-        *
-        * This is the last chance, in general, before the goto nopage.
-        * Ignore cpuset if GFP_ATOMIC (!wait) rather than fail alloc.
-        * See also cpuset_zone_allowed() comment in kernel/cpuset.c.
-        */
+restart:
+       /* This is the last chance, in general, before the goto nopage. */
        page = get_page_from_freelist(gfp_mask, nodemask, order, zonelist,
-                                               high_zoneidx, alloc_flags);
+                       high_zoneidx, alloc_flags & ~ALLOC_NO_WATERMARKS,
+                       preferred_zone, migratetype);
        if (page)
                goto got_pg;
 
-       /* This allocation should allow future memory freeing. */
-
 rebalance:
-       if (((p->flags & PF_MEMALLOC) || unlikely(test_thread_flag(TIF_MEMDIE)))
-                       && !in_interrupt()) {
-               if (!(gfp_mask & __GFP_NOMEMALLOC)) {
-nofail_alloc:
-                       /* go through the zonelist yet again, ignoring mins */
-                       page = get_page_from_freelist(gfp_mask, nodemask, order,
-                               zonelist, high_zoneidx, ALLOC_NO_WATERMARKS);
-                       if (page)
-                               goto got_pg;
-                       if (gfp_mask & __GFP_NOFAIL) {
-                               congestion_wait(WRITE, HZ/50);
-                               goto nofail_alloc;
-                       }
-               }
-               goto nopage;
+       /* Allocate without watermarks if the context allows */
+       if (alloc_flags & ALLOC_NO_WATERMARKS) {
+               page = __alloc_pages_high_priority(gfp_mask, order,
+                               zonelist, high_zoneidx, nodemask,
+                               preferred_zone, migratetype);
+               if (page)
+                       goto got_pg;
        }
 
        /* Atomic allocations - we can't balance anything */
        if (!wait)
                goto nopage;
 
-       cond_resched();
+       /* Avoid recursion of direct reclaim */
+       if (p->flags & PF_MEMALLOC)
+               goto nopage;
+
+       /* Try direct reclaim and then allocating */
+       page = __alloc_pages_direct_reclaim(gfp_mask, order,
+                                       zonelist, high_zoneidx,
+                                       nodemask,
+                                       alloc_flags, preferred_zone,
+                                       migratetype, &did_some_progress);
+       if (page)
+               goto got_pg;
 
-       /* We now go into synchronous reclaim */
-       cpuset_memory_pressure_bump();
        /*
-        * The task's cpuset might have expanded its set of allowable nodes
+        * If we failed to make any progress reclaiming, then we are
+        * running out of options and have to consider going OOM
         */
-       cpuset_update_task_memory_state();
-       p->flags |= PF_MEMALLOC;
-
-       lockdep_set_current_reclaim_state(gfp_mask);
-       reclaim_state.reclaimed_slab = 0;
-       p->reclaim_state = &reclaim_state;
-
-       did_some_progress = try_to_free_pages(zonelist, order,
-                                               gfp_mask, nodemask);
-
-       p->reclaim_state = NULL;
-       lockdep_clear_current_reclaim_state();
-       p->flags &= ~PF_MEMALLOC;
-
-       cond_resched();
+       if (!did_some_progress) {
+               if ((gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY)) {
+                       if (oom_killer_disabled)
+                               goto nopage;
+                       page = __alloc_pages_may_oom(gfp_mask, order,
+                                       zonelist, high_zoneidx,
+                                       nodemask, preferred_zone,
+                                       migratetype);
+                       if (page)
+                               goto got_pg;
 
-       if (order != 0)
-               drain_all_pages();
+                       /*
+                        * The OOM killer does not trigger for high-order
+                        * ~__GFP_NOFAIL allocations so if no progress is being
+                        * made, there are no other options and retrying is
+                        * unlikely to help.
+                        */
+                       if (order > PAGE_ALLOC_COSTLY_ORDER &&
+                                               !(gfp_mask & __GFP_NOFAIL))
+                               goto nopage;
 
-       if (likely(did_some_progress)) {
-               page = get_page_from_freelist(gfp_mask, nodemask, order,
-                                       zonelist, high_zoneidx, alloc_flags);
-               if (page)
-                       goto got_pg;
-       } else if ((gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY)) {
-               if (!try_set_zone_oom(zonelist, gfp_mask)) {
-                       schedule_timeout_uninterruptible(1);
                        goto restart;
                }
-
-               /*
-                * Go through the zonelist yet one more time, keep
-                * very high watermark here, this is only to catch
-                * a parallel oom killing, we must fail if we're still
-                * under heavy pressure.
-                */
-               page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask,
-                       order, zonelist, high_zoneidx,
-                       ALLOC_WMARK_HIGH|ALLOC_CPUSET);
-               if (page) {
-                       clear_zonelist_oom(zonelist, gfp_mask);
-                       goto got_pg;
-               }
-
-               /* The OOM killer will not help higher order allocs so fail */
-               if (order > PAGE_ALLOC_COSTLY_ORDER) {
-                       clear_zonelist_oom(zonelist, gfp_mask);
-                       goto nopage;
-               }
-
-               out_of_memory(zonelist, gfp_mask, order);
-               clear_zonelist_oom(zonelist, gfp_mask);
-               goto restart;
        }
 
-       /*
-        * Don't let big-order allocations loop unless the caller explicitly
-        * requests that.  Wait for some write requests to complete then retry.
-        *
-        * In this implementation, order <= PAGE_ALLOC_COSTLY_ORDER
-        * means __GFP_NOFAIL, but that may not be true in other
-        * implementations.
-        *
-        * For order > PAGE_ALLOC_COSTLY_ORDER, if __GFP_REPEAT is
-        * specified, then we retry until we no longer reclaim any pages
-        * (above), or we've reclaimed an order of pages at least as
-        * large as the allocation's order. In both cases, if the
-        * allocation still fails, we stop retrying.
-        */
+       /* Check if we should retry the allocation */
        pages_reclaimed += did_some_progress;
-       do_retry = 0;
-       if (!(gfp_mask & __GFP_NORETRY)) {
-               if (order <= PAGE_ALLOC_COSTLY_ORDER) {
-                       do_retry = 1;
-               } else {
-                       if (gfp_mask & __GFP_REPEAT &&
-                               pages_reclaimed < (1 << order))
-                                       do_retry = 1;
-               }
-               if (gfp_mask & __GFP_NOFAIL)
-                       do_retry = 1;
-       }
-       if (do_retry) {
+       if (should_alloc_retry(gfp_mask, order, pages_reclaimed)) {
+               /* Wait for some write requests to complete then retry */
                congestion_wait(WRITE, HZ/50);
                goto rebalance;
        }
@@ -1667,10 +1843,58 @@ nopage:
                dump_stack();
                show_mem();
        }
+       return page;
 got_pg:
+       if (kmemcheck_enabled)
+               kmemcheck_pagealloc_alloc(page, order, gfp_mask);
+       return page;
+
+}
+
+/*
+ * This is the 'heart' of the zoned buddy allocator.
+ */
+struct page *
+__alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
+                       struct zonelist *zonelist, nodemask_t *nodemask)
+{
+       enum zone_type high_zoneidx = gfp_zone(gfp_mask);
+       struct zone *preferred_zone;
+       struct page *page;
+       int migratetype = allocflags_to_migratetype(gfp_mask);
+
+       lockdep_trace_alloc(gfp_mask);
+
+       might_sleep_if(gfp_mask & __GFP_WAIT);
+
+       if (should_fail_alloc_page(gfp_mask, order))
+               return NULL;
+
+       /*
+        * Check the zones suitable for the gfp_mask contain at least one
+        * valid zone. It's possible to have an empty zonelist as a result
+        * of GFP_THISNODE and a memoryless node
+        */
+       if (unlikely(!zonelist->_zonerefs->zone))
+               return NULL;
+
+       /* The preferred zone is used for statistics later */
+       first_zones_zonelist(zonelist, high_zoneidx, nodemask, &preferred_zone);
+       if (!preferred_zone)
+               return NULL;
+
+       /* First allocation attempt */
+       page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask, order,
+                       zonelist, high_zoneidx, ALLOC_WMARK_LOW|ALLOC_CPUSET,
+                       preferred_zone, migratetype);
+       if (unlikely(!page))
+               page = __alloc_pages_slowpath(gfp_mask, order,
+                               zonelist, high_zoneidx, nodemask,
+                               preferred_zone, migratetype);
+
        return page;
 }
-EXPORT_SYMBOL(__alloc_pages_internal);
+EXPORT_SYMBOL(__alloc_pages_nodemask);
 
 /*
  * Common helper functions.
@@ -1799,7 +2023,7 @@ static unsigned int nr_free_zone_pages(int offset)
 
        for_each_zone_zonelist(zone, z, zonelist, offset) {
                unsigned long size = zone->present_pages;
-               unsigned long high = zone->pages_high;
+               unsigned long high = high_wmark_pages(zone);
                if (size > high)
                        sum += size - high;
        }
@@ -1891,19 +2115,14 @@ void show_free_areas(void)
 
        printk("Active_anon:%lu active_file:%lu inactive_anon:%lu\n"
                " inactive_file:%lu"
-//TODO:  check/adjust line lengths
-#ifdef CONFIG_UNEVICTABLE_LRU
                " unevictable:%lu"
-#endif
                " dirty:%lu writeback:%lu unstable:%lu\n"
                " free:%lu slab:%lu mapped:%lu pagetables:%lu bounce:%lu\n",
                global_page_state(NR_ACTIVE_ANON),
                global_page_state(NR_ACTIVE_FILE),
                global_page_state(NR_INACTIVE_ANON),
                global_page_state(NR_INACTIVE_FILE),
-#ifdef CONFIG_UNEVICTABLE_LRU
                global_page_state(NR_UNEVICTABLE),
-#endif
                global_page_state(NR_FILE_DIRTY),
                global_page_state(NR_WRITEBACK),
                global_page_state(NR_UNSTABLE_NFS),
@@ -1927,25 +2146,21 @@ void show_free_areas(void)
                        " inactive_anon:%lukB"
                        " active_file:%lukB"
                        " inactive_file:%lukB"
-#ifdef CONFIG_UNEVICTABLE_LRU
                        " unevictable:%lukB"
-#endif
                        " present:%lukB"
                        " pages_scanned:%lu"
                        " all_unreclaimable? %s"
                        "\n",
                        zone->name,
                        K(zone_page_state(zone, NR_FREE_PAGES)),
-                       K(zone->pages_min),
-                       K(zone->pages_low),
-                       K(zone->pages_high),
+                       K(min_wmark_pages(zone)),
+                       K(low_wmark_pages(zone)),
+                       K(high_wmark_pages(zone)),
                        K(zone_page_state(zone, NR_ACTIVE_ANON)),
                        K(zone_page_state(zone, NR_INACTIVE_ANON)),
                        K(zone_page_state(zone, NR_ACTIVE_FILE)),
                        K(zone_page_state(zone, NR_INACTIVE_FILE)),
-#ifdef CONFIG_UNEVICTABLE_LRU
                        K(zone_page_state(zone, NR_UNEVICTABLE)),
-#endif
                        K(zone->present_pages),
                        zone->pages_scanned,
                        (zone_is_all_unreclaimable(zone) ? "yes" : "no")
@@ -2103,7 +2318,7 @@ int numa_zonelist_order_handler(ctl_table *table, int write,
 }
 
 
-#define MAX_NODE_LOAD (num_online_nodes())
+#define MAX_NODE_LOAD (nr_online_nodes)
 static int node_load[MAX_NUMNODES];
 
 /**
@@ -2312,7 +2527,7 @@ static void build_zonelists(pg_data_t *pgdat)
 
        /* NUMA-aware ordering of nodes */
        local_node = pgdat->node_id;
-       load = num_online_nodes();
+       load = nr_online_nodes;
        prev_node = local_node;
        nodes_clear(used_mask);
 
@@ -2463,7 +2678,7 @@ void build_all_zonelists(void)
 
        printk("Built %i zonelists in %s order, mobility grouping %s.  "
                "Total pages: %ld\n",
-                       num_online_nodes(),
+                       nr_online_nodes,
                        zonelist_order_name[current_zonelist_order],
                        page_group_by_mobility_disabled ? "off" : "on",
                        vm_total_pages);
@@ -2542,8 +2757,8 @@ static inline unsigned long wait_table_bits(unsigned long size)
 
 /*
  * Mark a number of pageblocks as MIGRATE_RESERVE. The number
- * of blocks reserved is based on zone->pages_min. The memory within the
- * reserve will tend to store contiguous free pages. Setting min_free_kbytes
+ * of blocks reserved is based on min_wmark_pages(zone). The memory within
+ * the reserve will tend to store contiguous free pages. Setting min_free_kbytes
  * higher will lead to a bigger reserve which will get freed as contiguous
  * blocks as reclaim kicks in
  */
@@ -2556,7 +2771,7 @@ static void setup_zone_migrate_reserve(struct zone *zone)
        /* Get the start pfn, end pfn and the number of blocks to reserve */
        start_pfn = zone->zone_start_pfn;
        end_pfn = start_pfn + zone->spanned_pages;
-       reserve = roundup(zone->pages_min, pageblock_nr_pages) >>
+       reserve = roundup(min_wmark_pages(zone), pageblock_nr_pages) >>
                                                        pageblock_order;
 
        for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) {
@@ -3488,7 +3703,7 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat,
                zone_pcp_init(zone);
                for_each_lru(l) {
                        INIT_LIST_HEAD(&zone->lru[l].list);
-                       zone->lru[l].nr_scan = 0;
+                       zone->lru[l].nr_saved_scan = 0;
                }
                zone->reclaim_stat.recent_rotated[0] = 0;
                zone->reclaim_stat.recent_rotated[1] = 0;
@@ -4025,6 +4240,11 @@ void __init free_area_init_nodes(unsigned long *max_zone_pfn)
                                                early_node_map[i].start_pfn,
                                                early_node_map[i].end_pfn);
 
+       /*
+        * find_zone_movable_pfns_for_nodes/early_calculate_totalpages init
+        * that node_mask, clear it at first
+        */
+       nodes_clear(node_states[N_HIGH_MEMORY]);
        /* Initialise every node */
        mminit_verify_pageflags_layout();
        setup_nr_node_ids();
@@ -4159,8 +4379,8 @@ static void calculate_totalreserve_pages(void)
                                        max = zone->lowmem_reserve[j];
                        }
 
-                       /* we treat pages_high as reserved pages. */
-                       max += zone->pages_high;
+                       /* we treat the high watermark as reserved pages. */
+                       max += high_wmark_pages(zone);
 
                        if (max > zone->present_pages)
                                max = zone->present_pages;
@@ -4210,12 +4430,13 @@ static void setup_per_zone_lowmem_reserve(void)
 }
 
 /**
- * setup_per_zone_pages_min - called when min_free_kbytes changes.
+ * setup_per_zone_wmarks - called when min_free_kbytes changes
+ * or when memory is hot-{added|removed}
  *
- * Ensures that the pages_{min,low,high} values for each zone are set correctly
- * with respect to min_free_kbytes.
+ * Ensures that the watermark[min,low,high] values for each zone are set
+ * correctly with respect to min_free_kbytes.
  */
-void setup_per_zone_pages_min(void)
+void setup_per_zone_wmarks(void)
 {
        unsigned long pages_min = min_free_kbytes >> (PAGE_SHIFT - 10);
        unsigned long lowmem_pages = 0;
@@ -4240,7 +4461,7 @@ void setup_per_zone_pages_min(void)
                         * need highmem pages, so cap pages_min to a small
                         * value here.
                         *
-                        * The (pages_high-pages_low) and (pages_low-pages_min)
+                        * The WMARK_HIGH-WMARK_LOW and (WMARK_LOW-WMARK_MIN)
                         * deltas controls asynch page reclaim, and so should
                         * not be capped for highmem.
                         */
@@ -4251,17 +4472,17 @@ void setup_per_zone_pages_min(void)
                                min_pages = SWAP_CLUSTER_MAX;
                        if (min_pages > 128)
                                min_pages = 128;
-                       zone->pages_min = min_pages;
+                       zone->watermark[WMARK_MIN] = min_pages;
                } else {
                        /*
                         * If it's a lowmem zone, reserve a number of pages
                         * proportionate to the zone's size.
                         */
-                       zone->pages_min = tmp;
+                       zone->watermark[WMARK_MIN] = tmp;
                }
 
-               zone->pages_low   = zone->pages_min + (tmp >> 2);
-               zone->pages_high  = zone->pages_min + (tmp >> 1);
+               zone->watermark[WMARK_LOW]  = min_wmark_pages(zone) + (tmp >> 2);
+               zone->watermark[WMARK_HIGH] = min_wmark_pages(zone) + (tmp >> 1);
                setup_zone_migrate_reserve(zone);
                spin_unlock_irqrestore(&zone->lock, flags);
        }
@@ -4271,8 +4492,6 @@ void setup_per_zone_pages_min(void)
 }
 
 /**
- * setup_per_zone_inactive_ratio - called when min_free_kbytes changes.
- *
  * The inactive anon list should be small enough that the VM never has to
  * do too much work, but large enough that each inactive page has a chance
  * to be referenced again before it is swapped out.
@@ -4293,21 +4512,26 @@ void setup_per_zone_pages_min(void)
  *    1TB     101        10GB
  *   10TB     320        32GB
  */
-static void setup_per_zone_inactive_ratio(void)
+void calculate_zone_inactive_ratio(struct zone *zone)
 {
-       struct zone *zone;
-
-       for_each_zone(zone) {
-               unsigned int gb, ratio;
+       unsigned int gb, ratio;
 
-               /* Zone size in gigabytes */
-               gb = zone->present_pages >> (30 - PAGE_SHIFT);
+       /* Zone size in gigabytes */
+       gb = zone->present_pages >> (30 - PAGE_SHIFT);
+       if (gb)
                ratio = int_sqrt(10 * gb);
-               if (!ratio)
-                       ratio = 1;
+       else
+               ratio = 1;
 
-               zone->inactive_ratio = ratio;
-       }
+       zone->inactive_ratio = ratio;
+}
+
+static void __init setup_per_zone_inactive_ratio(void)
+{
+       struct zone *zone;
+
+       for_each_zone(zone)
+               calculate_zone_inactive_ratio(zone);
 }
 
 /*
@@ -4334,7 +4558,7 @@ static void setup_per_zone_inactive_ratio(void)
  * 8192MB:     11584k
  * 16384MB:    16384k
  */
-static int __init init_per_zone_pages_min(void)
+static int __init init_per_zone_wmark_min(void)
 {
        unsigned long lowmem_kbytes;
 
@@ -4345,12 +4569,12 @@ static int __init init_per_zone_pages_min(void)
                min_free_kbytes = 128;
        if (min_free_kbytes > 65536)
                min_free_kbytes = 65536;
-       setup_per_zone_pages_min();
+       setup_per_zone_wmarks();
        setup_per_zone_lowmem_reserve();
        setup_per_zone_inactive_ratio();
        return 0;
 }
-module_init(init_per_zone_pages_min)
+module_init(init_per_zone_wmark_min)
 
 /*
  * min_free_kbytes_sysctl_handler - just a wrapper around proc_dointvec() so 
@@ -4362,7 +4586,7 @@ int min_free_kbytes_sysctl_handler(ctl_table *table, int write,
 {
        proc_dointvec(table, write, file, buffer, length, ppos);
        if (write)
-               setup_per_zone_pages_min();
+               setup_per_zone_wmarks();
        return 0;
 }
 
@@ -4406,7 +4630,7 @@ int sysctl_min_slab_ratio_sysctl_handler(ctl_table *table, int write,
  *     whenever sysctl_lowmem_reserve_ratio changes.
  *
  * The reserve ratio obviously has absolutely no relation with the
- * pages_min watermarks. The lowmem reserve ratio can only make sense
+ * minimum watermarks. The lowmem reserve ratio can only make sense
  * if in function of the boot time zone sizes.
  */
 int lowmem_reserve_ratio_sysctl_handler(ctl_table *table, int write,
@@ -4513,23 +4737,13 @@ void *__init alloc_large_system_hash(const char *tablename,
                else if (hashdist)
                        table = __vmalloc(size, GFP_ATOMIC, PAGE_KERNEL);
                else {
-                       unsigned long order = get_order(size);
-                       table = (void*) __get_free_pages(GFP_ATOMIC, order);
                        /*
                         * If bucketsize is not a power-of-two, we may free
-                        * some pages at the end of hash table.
+                        * some pages at the end of hash table which
+                        * alloc_pages_exact() automatically does
                         */
-                       if (table) {
-                               unsigned long alloc_end = (unsigned long)table +
-                                               (PAGE_SIZE << order);
-                               unsigned long used = (unsigned long)table +
-                                               PAGE_ALIGN(size);
-                               split_page(virt_to_page(table), order);
-                               while (used < alloc_end) {
-                                       free_page(used);
-                                       used += PAGE_SIZE;
-                               }
-                       }
+                       if (get_order(size) < MAX_ORDER)
+                               table = alloc_pages_exact(size, GFP_ATOMIC);
                }
        } while (!table && size > PAGE_SIZE && --log2qty);
 
index 3023c475e0415fc0c6ec537a556e6d3835a2b1d9..c6f3e5071de3bb57c737cef88ab32c3cbdac4aee 100644 (file)
@@ -120,7 +120,7 @@ out:
        return ret;
 }
 
-int swap_readpage(struct file *file, struct page *page)
+int swap_readpage(struct page *page)
 {
        struct bio *bio;
        int ret = 0;
index 133b6d525513a886247ce3adc5eff41ef4e91752..aa1aa23452355067af9d62179cd41d62c64e68fc 100644 (file)
@@ -133,15 +133,12 @@ out:
 }
 
 /*
- * do_page_cache_readahead actually reads a chunk of disk.  It allocates all
+ * __do_page_cache_readahead() actually reads a chunk of disk.  It allocates all
  * the pages first, then submits them all for I/O. This avoids the very bad
  * behaviour which would occur if page allocations are causing VM writeback.
  * We really don't want to intermingle reads and writes like that.
  *
  * Returns the number of pages requested, or the maximum amount of I/O allowed.
- *
- * do_page_cache_readahead() returns -1 if it encountered request queue
- * congestion.
  */
 static int
 __do_page_cache_readahead(struct address_space *mapping, struct file *filp,
@@ -210,6 +207,7 @@ int force_page_cache_readahead(struct address_space *mapping, struct file *filp,
        if (unlikely(!mapping->a_ops->readpage && !mapping->a_ops->readpages))
                return -EINVAL;
 
+       nr_to_read = max_sane_readahead(nr_to_read);
        while (nr_to_read) {
                int err;
 
@@ -230,22 +228,6 @@ int force_page_cache_readahead(struct address_space *mapping, struct file *filp,
        return ret;
 }
 
-/*
- * This version skips the IO if the queue is read-congested, and will tell the
- * block layer to abandon the readahead if request allocation would block.
- *
- * force_page_cache_readahead() will ignore queue congestion and will block on
- * request queues.
- */
-int do_page_cache_readahead(struct address_space *mapping, struct file *filp,
-                       pgoff_t offset, unsigned long nr_to_read)
-{
-       if (bdi_read_congested(mapping->backing_dev_info))
-               return -1;
-
-       return __do_page_cache_readahead(mapping, filp, offset, nr_to_read, 0);
-}
-
 /*
  * Given a desired number of PAGE_CACHE_SIZE readahead pages, return a
  * sensible upper limit.
@@ -259,7 +241,7 @@ unsigned long max_sane_readahead(unsigned long nr)
 /*
  * Submit IO for the read-ahead request in file_ra_state.
  */
-static unsigned long ra_submit(struct file_ra_state *ra,
+unsigned long ra_submit(struct file_ra_state *ra,
                       struct address_space *mapping, struct file *filp)
 {
        int actual;
@@ -347,6 +329,59 @@ static unsigned long get_next_ra_size(struct file_ra_state *ra,
  * it approaches max_readhead.
  */
 
+/*
+ * Count contiguously cached pages from @offset-1 to @offset-@max,
+ * this count is a conservative estimation of
+ *     - length of the sequential read sequence, or
+ *     - thrashing threshold in memory tight systems
+ */
+static pgoff_t count_history_pages(struct address_space *mapping,
+                                  struct file_ra_state *ra,
+                                  pgoff_t offset, unsigned long max)
+{
+       pgoff_t head;
+
+       rcu_read_lock();
+       head = radix_tree_prev_hole(&mapping->page_tree, offset - 1, max);
+       rcu_read_unlock();
+
+       return offset - 1 - head;
+}
+
+/*
+ * page cache context based read-ahead
+ */
+static int try_context_readahead(struct address_space *mapping,
+                                struct file_ra_state *ra,
+                                pgoff_t offset,
+                                unsigned long req_size,
+                                unsigned long max)
+{
+       pgoff_t size;
+
+       size = count_history_pages(mapping, ra, offset, max);
+
+       /*
+        * no history pages:
+        * it could be a random read
+        */
+       if (!size)
+               return 0;
+
+       /*
+        * starts from beginning of file:
+        * it is a strong indication of long-run stream (or whole-file-read)
+        */
+       if (size >= offset)
+               size *= 2;
+
+       ra->start = offset;
+       ra->size = get_init_ra_size(size + req_size, max);
+       ra->async_size = ra->size;
+
+       return 1;
+}
+
 /*
  * A minimal readahead algorithm for trivial sequential/random reads.
  */
@@ -356,34 +391,26 @@ ondemand_readahead(struct address_space *mapping,
                   bool hit_readahead_marker, pgoff_t offset,
                   unsigned long req_size)
 {
-       int     max = ra->ra_pages;     /* max readahead pages */
-       pgoff_t prev_offset;
-       int     sequential;
+       unsigned long max = max_sane_readahead(ra->ra_pages);
+
+       /*
+        * start of file
+        */
+       if (!offset)
+               goto initial_readahead;
 
        /*
         * It's the expected callback offset, assume sequential access.
         * Ramp up sizes, and push forward the readahead window.
         */
-       if (offset && (offset == (ra->start + ra->size - ra->async_size) ||
-                       offset == (ra->start + ra->size))) {
+       if ((offset == (ra->start + ra->size - ra->async_size) ||
+            offset == (ra->start + ra->size))) {
                ra->start += ra->size;
                ra->size = get_next_ra_size(ra, max);
                ra->async_size = ra->size;
                goto readit;
        }
 
-       prev_offset = ra->prev_pos >> PAGE_CACHE_SHIFT;
-       sequential = offset - prev_offset <= 1UL || req_size > max;
-
-       /*
-        * Standalone, small read.
-        * Read as is, and do not pollute the readahead state.
-        */
-       if (!hit_readahead_marker && !sequential) {
-               return __do_page_cache_readahead(mapping, filp,
-                                               offset, req_size, 0);
-       }
-
        /*
         * Hit a marked page without valid readahead state.
         * E.g. interleaved reads.
@@ -394,7 +421,7 @@ ondemand_readahead(struct address_space *mapping,
                pgoff_t start;
 
                rcu_read_lock();
-               start = radix_tree_next_hole(&mapping->page_tree, offset,max+1);
+               start = radix_tree_next_hole(&mapping->page_tree, offset+1,max);
                rcu_read_unlock();
 
                if (!start || start - offset > max)
@@ -402,23 +429,53 @@ ondemand_readahead(struct address_space *mapping,
 
                ra->start = start;
                ra->size = start - offset;      /* old async_size */
+               ra->size += req_size;
                ra->size = get_next_ra_size(ra, max);
                ra->async_size = ra->size;
                goto readit;
        }
 
        /*
-        * It may be one of
-        *      - first read on start of file
-        *      - sequential cache miss
-        *      - oversize random read
-        * Start readahead for it.
+        * oversize read
+        */
+       if (req_size > max)
+               goto initial_readahead;
+
+       /*
+        * sequential cache miss
+        */
+       if (offset - (ra->prev_pos >> PAGE_CACHE_SHIFT) <= 1UL)
+               goto initial_readahead;
+
+       /*
+        * Query the page cache and look for the traces(cached history pages)
+        * that a sequential stream would leave behind.
+        */
+       if (try_context_readahead(mapping, ra, offset, req_size, max))
+               goto readit;
+
+       /*
+        * standalone, small random read
+        * Read as is, and do not pollute the readahead state.
         */
+       return __do_page_cache_readahead(mapping, filp, offset, req_size, 0);
+
+initial_readahead:
        ra->start = offset;
        ra->size = get_init_ra_size(req_size, max);
        ra->async_size = ra->size > req_size ? ra->size - req_size : ra->size;
 
 readit:
+       /*
+        * Will this read hit the readahead marker made by itself?
+        * If so, trigger the readahead marker hit now, and merge
+        * the resulted next readahead window into the current one.
+        */
+       if (offset == ra->start && ra->size == ra->async_size) {
+               ra->async_size = get_next_ra_size(ra, max);
+               ra->size += ra->async_size;
+       }
+
        return ra_submit(ra, mapping, filp);
 }
 
index 23122af3261177713b9e2640b9ef108017083457..c9ccc1a72dc32652827c0d6d81add911f59abbfb 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -333,7 +333,9 @@ static int page_mapped_in_vma(struct page *page, struct vm_area_struct *vma)
  * repeatedly from either page_referenced_anon or page_referenced_file.
  */
 static int page_referenced_one(struct page *page,
-       struct vm_area_struct *vma, unsigned int *mapcount)
+                              struct vm_area_struct *vma,
+                              unsigned int *mapcount,
+                              unsigned long *vm_flags)
 {
        struct mm_struct *mm = vma->vm_mm;
        unsigned long address;
@@ -381,11 +383,14 @@ out_unmap:
        (*mapcount)--;
        pte_unmap_unlock(pte, ptl);
 out:
+       if (referenced)
+               *vm_flags |= vma->vm_flags;
        return referenced;
 }
 
 static int page_referenced_anon(struct page *page,
-                               struct mem_cgroup *mem_cont)
+                               struct mem_cgroup *mem_cont,
+                               unsigned long *vm_flags)
 {
        unsigned int mapcount;
        struct anon_vma *anon_vma;
@@ -405,7 +410,8 @@ static int page_referenced_anon(struct page *page,
                 */
                if (mem_cont && !mm_match_cgroup(vma->vm_mm, mem_cont))
                        continue;
-               referenced += page_referenced_one(page, vma, &mapcount);
+               referenced += page_referenced_one(page, vma,
+                                                 &mapcount, vm_flags);
                if (!mapcount)
                        break;
        }
@@ -418,6 +424,7 @@ static int page_referenced_anon(struct page *page,
  * page_referenced_file - referenced check for object-based rmap
  * @page: the page we're checking references on.
  * @mem_cont: target memory controller
+ * @vm_flags: collect encountered vma->vm_flags who actually referenced the page
  *
  * For an object-based mapped page, find all the places it is mapped and
  * check/clear the referenced flag.  This is done by following the page->mapping
@@ -427,7 +434,8 @@ static int page_referenced_anon(struct page *page,
  * This function is only called from page_referenced for object-based pages.
  */
 static int page_referenced_file(struct page *page,
-                               struct mem_cgroup *mem_cont)
+                               struct mem_cgroup *mem_cont,
+                               unsigned long *vm_flags)
 {
        unsigned int mapcount;
        struct address_space *mapping = page->mapping;
@@ -467,7 +475,8 @@ static int page_referenced_file(struct page *page,
                 */
                if (mem_cont && !mm_match_cgroup(vma->vm_mm, mem_cont))
                        continue;
-               referenced += page_referenced_one(page, vma, &mapcount);
+               referenced += page_referenced_one(page, vma,
+                                                 &mapcount, vm_flags);
                if (!mapcount)
                        break;
        }
@@ -481,29 +490,35 @@ static int page_referenced_file(struct page *page,
  * @page: the page to test
  * @is_locked: caller holds lock on the page
  * @mem_cont: target memory controller
+ * @vm_flags: collect encountered vma->vm_flags who actually referenced the page
  *
  * Quick test_and_clear_referenced for all mappings to a page,
  * returns the number of ptes which referenced the page.
  */
-int page_referenced(struct page *page, int is_locked,
-                       struct mem_cgroup *mem_cont)
+int page_referenced(struct page *page,
+                   int is_locked,
+                   struct mem_cgroup *mem_cont,
+                   unsigned long *vm_flags)
 {
        int referenced = 0;
 
        if (TestClearPageReferenced(page))
                referenced++;
 
+       *vm_flags = 0;
        if (page_mapped(page) && page->mapping) {
                if (PageAnon(page))
-                       referenced += page_referenced_anon(page, mem_cont);
+                       referenced += page_referenced_anon(page, mem_cont,
+                                                               vm_flags);
                else if (is_locked)
-                       referenced += page_referenced_file(page, mem_cont);
+                       referenced += page_referenced_file(page, mem_cont,
+                                                               vm_flags);
                else if (!trylock_page(page))
                        referenced++;
                else {
                        if (page->mapping)
-                               referenced +=
-                                       page_referenced_file(page, mem_cont);
+                               referenced += page_referenced_file(page,
+                                                       mem_cont, vm_flags);
                        unlock_page(page);
                }
        }
@@ -1202,7 +1217,6 @@ int try_to_unmap(struct page *page, int migration)
        return ret;
 }
 
-#ifdef CONFIG_UNEVICTABLE_LRU
 /**
  * try_to_munlock - try to munlock a page
  * @page: the page to be munlocked
@@ -1226,4 +1240,4 @@ int try_to_munlock(struct page *page)
        else
                return try_to_unmap_file(page, 1, 0);
 }
-#endif
+
index 0132fbd45a23837d5abc3cdea527a6d3cafb53a7..e89d7ec18eda46d42abf68c3994db0e33cfded06 100644 (file)
@@ -1097,7 +1097,7 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
        shmem_swp_unmap(entry);
 unlock:
        spin_unlock(&info->lock);
-       swap_free(swap);
+       swapcache_free(swap, NULL);
 redirty:
        set_page_dirty(page);
        if (wbc->for_reclaim)
@@ -2612,7 +2612,7 @@ int shmem_unuse(swp_entry_t entry, struct page *page)
  * @size: size to be set for the file
  * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
  */
-struct file *shmem_file_setup(char *name, loff_t size, unsigned long flags)
+struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags)
 {
        int error;
        struct file *file;
index 18e3164de09a9ce3b5c69b9fd53b6533b39e9486..f257d4dd474db5f3ee0ed42016b86dd3d5b02bc4 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
 #include       <linux/rtmutex.h>
 #include       <linux/reciprocal_div.h>
 #include       <linux/debugobjects.h>
+#include       <linux/kmemcheck.h>
 
 #include       <asm/cacheflush.h>
 #include       <asm/tlbflush.h>
                         SLAB_STORE_USER | \
                         SLAB_RECLAIM_ACCOUNT | SLAB_PANIC | \
                         SLAB_DESTROY_BY_RCU | SLAB_MEM_SPREAD | \
-                        SLAB_DEBUG_OBJECTS | SLAB_NOLEAKTRACE)
+                        SLAB_DEBUG_OBJECTS | SLAB_NOLEAKTRACE | SLAB_NOTRACK)
 #else
 # define CREATE_MASK   (SLAB_HWCACHE_ALIGN | \
                         SLAB_CACHE_DMA | \
                         SLAB_RECLAIM_ACCOUNT | SLAB_PANIC | \
                         SLAB_DESTROY_BY_RCU | SLAB_MEM_SPREAD | \
-                        SLAB_DEBUG_OBJECTS | SLAB_NOLEAKTRACE)
+                        SLAB_DEBUG_OBJECTS | SLAB_NOLEAKTRACE | SLAB_NOTRACK)
 #endif
 
 /*
@@ -380,87 +381,6 @@ static void kmem_list3_init(struct kmem_list3 *parent)
        MAKE_LIST((cachep), (&(ptr)->slabs_free), slabs_free, nodeid);  \
        } while (0)
 
-/*
- * struct kmem_cache
- *
- * manages a cache.
- */
-
-struct kmem_cache {
-/* 1) per-cpu data, touched during every alloc/free */
-       struct array_cache *array[NR_CPUS];
-/* 2) Cache tunables. Protected by cache_chain_mutex */
-       unsigned int batchcount;
-       unsigned int limit;
-       unsigned int shared;
-
-       unsigned int buffer_size;
-       u32 reciprocal_buffer_size;
-/* 3) touched by every alloc & free from the backend */
-
-       unsigned int flags;             /* constant flags */
-       unsigned int num;               /* # of objs per slab */
-
-/* 4) cache_grow/shrink */
-       /* order of pgs per slab (2^n) */
-       unsigned int gfporder;
-
-       /* force GFP flags, e.g. GFP_DMA */
-       gfp_t gfpflags;
-
-       size_t colour;                  /* cache colouring range */
-       unsigned int colour_off;        /* colour offset */
-       struct kmem_cache *slabp_cache;
-       unsigned int slab_size;
-       unsigned int dflags;            /* dynamic flags */
-
-       /* constructor func */
-       void (*ctor)(void *obj);
-
-/* 5) cache creation/removal */
-       const char *name;
-       struct list_head next;
-
-/* 6) statistics */
-#if STATS
-       unsigned long num_active;
-       unsigned long num_allocations;
-       unsigned long high_mark;
-       unsigned long grown;
-       unsigned long reaped;
-       unsigned long errors;
-       unsigned long max_freeable;
-       unsigned long node_allocs;
-       unsigned long node_frees;
-       unsigned long node_overflow;
-       atomic_t allochit;
-       atomic_t allocmiss;
-       atomic_t freehit;
-       atomic_t freemiss;
-#endif
-#if DEBUG
-       /*
-        * If debugging is enabled, then the allocator can add additional
-        * fields and/or padding to every object. buffer_size contains the total
-        * object size including these internal fields, the following two
-        * variables contain the offset to the user object and its size.
-        */
-       int obj_offset;
-       int obj_size;
-#endif
-       /*
-        * We put nodelists[] at the end of kmem_cache, because we want to size
-        * this array to nr_node_ids slots instead of MAX_NUMNODES
-        * (see kmem_cache_init())
-        * We still use [MAX_NUMNODES] and not [1] or [0] because cache_cache
-        * is statically defined, so we reserve the max number of nodes.
-        */
-       struct kmem_list3 *nodelists[MAX_NUMNODES];
-       /*
-        * Do not add fields after nodelists[]
-        */
-};
-
 #define CFLGS_OFF_SLAB         (0x80000000UL)
 #define        OFF_SLAB(x)     ((x)->flags & CFLGS_OFF_SLAB)
 
@@ -898,7 +818,6 @@ static void __slab_error(const char *function, struct kmem_cache *cachep,
   */
 
 static int use_alien_caches __read_mostly = 1;
-static int numa_platform __read_mostly = 1;
 static int __init noaliencache_setup(char *s)
 {
        use_alien_caches = 0;
@@ -1457,10 +1376,8 @@ void __init kmem_cache_init(void)
        int order;
        int node;
 
-       if (num_possible_nodes() == 1) {
+       if (num_possible_nodes() == 1)
                use_alien_caches = 0;
-               numa_platform = 0;
-       }
 
        for (i = 0; i < NUM_INIT_LISTS; i++) {
                kmem_list3_init(&initkmem_list3[i]);
@@ -1707,7 +1624,7 @@ static void *kmem_getpages(struct kmem_cache *cachep, gfp_t flags, int nodeid)
        if (cachep->flags & SLAB_RECLAIM_ACCOUNT)
                flags |= __GFP_RECLAIMABLE;
 
-       page = alloc_pages_node(nodeid, flags, cachep->gfporder);
+       page = alloc_pages_exact_node(nodeid, flags | __GFP_NOTRACK, cachep->gfporder);
        if (!page)
                return NULL;
 
@@ -1720,6 +1637,16 @@ static void *kmem_getpages(struct kmem_cache *cachep, gfp_t flags, int nodeid)
                        NR_SLAB_UNRECLAIMABLE, nr_pages);
        for (i = 0; i < nr_pages; i++)
                __SetPageSlab(page + i);
+
+       if (kmemcheck_enabled && !(cachep->flags & SLAB_NOTRACK)) {
+               kmemcheck_alloc_shadow(page, cachep->gfporder, flags, nodeid);
+
+               if (cachep->ctor)
+                       kmemcheck_mark_uninitialized_pages(page, nr_pages);
+               else
+                       kmemcheck_mark_unallocated_pages(page, nr_pages);
+       }
+
        return page_address(page);
 }
 
@@ -1732,6 +1659,8 @@ static void kmem_freepages(struct kmem_cache *cachep, void *addr)
        struct page *page = virt_to_page(addr);
        const unsigned long nr_freed = i;
 
+       kmemcheck_free_shadow(page, cachep->gfporder);
+
        if (cachep->flags & SLAB_RECLAIM_ACCOUNT)
                sub_zone_page_state(page_zone(page),
                                NR_SLAB_RECLAIMABLE, nr_freed);
@@ -3261,7 +3190,7 @@ retry:
                if (local_flags & __GFP_WAIT)
                        local_irq_enable();
                kmem_flagcheck(cache, flags);
-               obj = kmem_getpages(cache, local_flags, -1);
+               obj = kmem_getpages(cache, local_flags, numa_node_id());
                if (local_flags & __GFP_WAIT)
                        local_irq_disable();
                if (obj) {
@@ -3407,6 +3336,9 @@ __cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid,
        kmemleak_alloc_recursive(ptr, obj_size(cachep), 1, cachep->flags,
                                 flags);
 
+       if (likely(ptr))
+               kmemcheck_slab_alloc(cachep, flags, ptr, obj_size(cachep));
+
        if (unlikely((flags & __GFP_ZERO) && ptr))
                memset(ptr, 0, obj_size(cachep));
 
@@ -3467,6 +3399,9 @@ __cache_alloc(struct kmem_cache *cachep, gfp_t flags, void *caller)
                                 flags);
        prefetchw(objp);
 
+       if (likely(objp))
+               kmemcheck_slab_alloc(cachep, flags, objp, obj_size(cachep));
+
        if (unlikely((flags & __GFP_ZERO) && objp))
                memset(objp, 0, obj_size(cachep));
 
@@ -3583,6 +3518,8 @@ static inline void __cache_free(struct kmem_cache *cachep, void *objp)
        kmemleak_free_recursive(objp, cachep->flags);
        objp = cache_free_debugcheck(cachep, objp, __builtin_return_address(0));
 
+       kmemcheck_slab_free(cachep, objp, obj_size(cachep));
+
        /*
         * Skip calling cache_free_alien() when the platform is not numa.
         * This will avoid cache misses that happen while accessing slabp (which
@@ -3590,7 +3527,7 @@ static inline void __cache_free(struct kmem_cache *cachep, void *objp)
         * variable to skip the call, which is mostly likely to be present in
         * the cache.
         */
-       if (numa_platform && cache_free_alien(cachep, objp))
+       if (nr_online_nodes > 1 && cache_free_alien(cachep, objp))
                return;
 
        if (likely(ac->avail < ac->limit)) {
index 12f261499925a66b2b190e4f193893e4087c6fb4..64f6db1943bfd501281c046a04f74023b198d132 100644 (file)
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -46,7 +46,7 @@
  * NUMA support in SLOB is fairly simplistic, pushing most of the real
  * logic down to the page allocator, and simply doing the node accounting
  * on the upper levels. In the event that a node id is explicitly
- * provided, alloc_pages_node() with the specified node id is used
+ * provided, alloc_pages_exact_node() with the specified node id is used
  * instead. The common case (or when the node id isn't explicitly provided)
  * will default to the current node, as per numa_node_id().
  *
@@ -244,7 +244,7 @@ static void *slob_new_pages(gfp_t gfp, int order, int node)
 
 #ifdef CONFIG_NUMA
        if (node != -1)
-               page = alloc_pages_node(node, gfp, order);
+               page = alloc_pages_exact_node(node, gfp, order);
        else
 #endif
                page = alloc_pages(gfp, order);
index 30354bfeb43d5b093669fb0ef62b213e0c3991f2..2701419b0adcab389434cb07a3f7f9af175afeca 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -18,6 +18,7 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/kmemtrace.h>
+#include <linux/kmemcheck.h>
 #include <linux/cpu.h>
 #include <linux/cpuset.h>
 #include <linux/kmemleak.h>
                SLAB_TRACE | SLAB_DESTROY_BY_RCU | SLAB_NOLEAKTRACE)
 
 #define SLUB_MERGE_SAME (SLAB_DEBUG_FREE | SLAB_RECLAIM_ACCOUNT | \
-               SLAB_CACHE_DMA)
+               SLAB_CACHE_DMA | SLAB_NOTRACK)
 
 #ifndef ARCH_KMALLOC_MINALIGN
 #define ARCH_KMALLOC_MINALIGN __alignof__(unsigned long long)
@@ -1071,6 +1072,8 @@ static inline struct page *alloc_slab_page(gfp_t flags, int node,
 {
        int order = oo_order(oo);
 
+       flags |= __GFP_NOTRACK;
+
        if (node == -1)
                return alloc_pages(flags, order);
        else
@@ -1098,6 +1101,24 @@ static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
 
                stat(get_cpu_slab(s, raw_smp_processor_id()), ORDER_FALLBACK);
        }
+
+       if (kmemcheck_enabled
+               && !(s->flags & (SLAB_NOTRACK | DEBUG_DEFAULT_FLAGS)))
+       {
+               int pages = 1 << oo_order(oo);
+
+               kmemcheck_alloc_shadow(page, oo_order(oo), flags, node);
+
+               /*
+                * Objects from caches that have a constructor don't get
+                * cleared when they're allocated, so we need to do it here.
+                */
+               if (s->ctor)
+                       kmemcheck_mark_uninitialized_pages(page, pages);
+               else
+                       kmemcheck_mark_unallocated_pages(page, pages);
+       }
+
        page->objects = oo_objects(oo);
        mod_zone_page_state(page_zone(page),
                (s->flags & SLAB_RECLAIM_ACCOUNT) ?
@@ -1171,6 +1192,8 @@ static void __free_slab(struct kmem_cache *s, struct page *page)
                __ClearPageSlubDebug(page);
        }
 
+       kmemcheck_free_shadow(page, compound_order(page));
+
        mod_zone_page_state(page_zone(page),
                (s->flags & SLAB_RECLAIM_ACCOUNT) ?
                NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE,
@@ -1626,7 +1649,9 @@ static __always_inline void *slab_alloc(struct kmem_cache *s,
        if (unlikely((gfpflags & __GFP_ZERO) && object))
                memset(object, 0, objsize);
 
+       kmemcheck_slab_alloc(s, gfpflags, object, c->objsize);
        kmemleak_alloc_recursive(object, objsize, 1, s->flags, gfpflags);
+
        return object;
 }
 
@@ -1759,6 +1784,7 @@ static __always_inline void slab_free(struct kmem_cache *s,
        kmemleak_free_recursive(x, s->flags);
        local_irq_save(flags);
        c = get_cpu_slab(s, smp_processor_id());
+       kmemcheck_slab_free(s, object, c->objsize);
        debug_check_no_locks_freed(object, c->objsize);
        if (!(s->flags & SLAB_DEBUG_OBJECTS))
                debug_check_no_obj_freed(object, c->objsize);
@@ -2633,7 +2659,8 @@ static noinline struct kmem_cache *dma_kmalloc_cache(int index, gfp_t flags)
 
        if (!s || !text || !kmem_cache_open(s, flags, text,
                        realsize, ARCH_KMALLOC_MINALIGN,
-                       SLAB_CACHE_DMA|__SYSFS_ADD_DEFERRED, NULL)) {
+                       SLAB_CACHE_DMA|SLAB_NOTRACK|__SYSFS_ADD_DEFERRED,
+                       NULL)) {
                kfree(s);
                kfree(text);
                goto unlock_out;
@@ -2727,9 +2754,10 @@ EXPORT_SYMBOL(__kmalloc);
 
 static void *kmalloc_large_node(size_t size, gfp_t flags, int node)
 {
-       struct page *page = alloc_pages_node(node, flags | __GFP_COMP,
-                                               get_order(size));
+       struct page *page;
 
+       flags |= __GFP_COMP | __GFP_NOTRACK;
+       page = alloc_pages_node(node, flags, get_order(size));
        if (page)
                return page_address(page);
        else
@@ -3737,7 +3765,7 @@ static int list_locations(struct kmem_cache *s, char *buf,
                                                 to_cpumask(l->cpus));
                }
 
-               if (num_online_nodes() > 1 && !nodes_empty(l->nodes) &&
+               if (nr_online_nodes > 1 && !nodes_empty(l->nodes) &&
                                len < PAGE_SIZE - 60) {
                        len += sprintf(buf + len, " nodes=");
                        len += nodelist_scnprintf(buf + len, PAGE_SIZE - len - 50,
@@ -4412,6 +4440,8 @@ static char *create_unique_id(struct kmem_cache *s)
                *p++ = 'a';
        if (s->flags & SLAB_DEBUG_FREE)
                *p++ = 'F';
+       if (!(s->flags & SLAB_NOTRACK))
+               *p++ = 't';
        if (p != name + 1)
                *p++ = '-';
        p += sprintf(p, "%07d", s->size);
index 1416e7e9e02db3b5da60fe3a270e98e7b84024bb..42cd38eba79f1ffb096db8683bc11dd5604fe367 100644 (file)
@@ -124,7 +124,6 @@ void __delete_from_swap_cache(struct page *page)
 /**
  * add_to_swap - allocate swap space for a page
  * @page: page we want to move to swap
- * @gfp_mask: memory allocation flags
  *
  * Allocate swap space for the page and add the page to the
  * swap cache.  Caller needs to hold the page lock. 
@@ -162,11 +161,11 @@ int add_to_swap(struct page *page)
                        return 1;
                case -EEXIST:
                        /* Raced with "speculative" read_swap_cache_async */
-                       swap_free(entry);
+                       swapcache_free(entry, NULL);
                        continue;
                default:
                        /* -ENOMEM radix-tree allocation failure */
-                       swap_free(entry);
+                       swapcache_free(entry, NULL);
                        return 0;
                }
        }
@@ -188,8 +187,7 @@ void delete_from_swap_cache(struct page *page)
        __delete_from_swap_cache(page);
        spin_unlock_irq(&swapper_space.tree_lock);
 
-       mem_cgroup_uncharge_swapcache(page, entry);
-       swap_free(entry);
+       swapcache_free(entry, page);
        page_cache_release(page);
 }
 
@@ -293,7 +291,10 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
                /*
                 * Swap entry may have been freed since our caller observed it.
                 */
-               if (!swap_duplicate(entry))
+               err = swapcache_prepare(entry);
+               if (err == -EEXIST) /* seems racy */
+                       continue;
+               if (err)           /* swp entry is obsolete ? */
                        break;
 
                /*
@@ -312,12 +313,12 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
                         * Initiate read into locked page and return.
                         */
                        lru_cache_add_anon(new_page);
-                       swap_readpage(NULL, new_page);
+                       swap_readpage(new_page);
                        return new_page;
                }
                ClearPageSwapBacked(new_page);
                __clear_page_locked(new_page);
-               swap_free(entry);
+               swapcache_free(entry, NULL);
        } while (err != -ENOMEM);
 
        if (new_page)
index 312fafe0ab6ed4815ac02da3f712aca18bacbbad..28faa01cf578bd1bc05fa20771015194fd966e4d 100644 (file)
@@ -53,6 +53,59 @@ static struct swap_info_struct swap_info[MAX_SWAPFILES];
 
 static DEFINE_MUTEX(swapon_mutex);
 
+/* For reference count accounting in swap_map */
+/* enum for swap_map[] handling. internal use only */
+enum {
+       SWAP_MAP = 0,   /* ops for reference from swap users */
+       SWAP_CACHE,     /* ops for reference from swap cache */
+};
+
+static inline int swap_count(unsigned short ent)
+{
+       return ent & SWAP_COUNT_MASK;
+}
+
+static inline bool swap_has_cache(unsigned short ent)
+{
+       return !!(ent & SWAP_HAS_CACHE);
+}
+
+static inline unsigned short encode_swapmap(int count, bool has_cache)
+{
+       unsigned short ret = count;
+
+       if (has_cache)
+               return SWAP_HAS_CACHE | ret;
+       return ret;
+}
+
+/* returnes 1 if swap entry is freed */
+static int
+__try_to_reclaim_swap(struct swap_info_struct *si, unsigned long offset)
+{
+       int type = si - swap_info;
+       swp_entry_t entry = swp_entry(type, offset);
+       struct page *page;
+       int ret = 0;
+
+       page = find_get_page(&swapper_space, entry.val);
+       if (!page)
+               return 0;
+       /*
+        * This function is called from scan_swap_map() and it's called
+        * by vmscan.c at reclaiming pages. So, we hold a lock on a page, here.
+        * We have to use trylock for avoiding deadlock. This is a special
+        * case and you should use try_to_free_swap() with explicit lock_page()
+        * in usual operations.
+        */
+       if (trylock_page(page)) {
+               ret = try_to_free_swap(page);
+               unlock_page(page);
+       }
+       page_cache_release(page);
+       return ret;
+}
+
 /*
  * We need this because the bdev->unplug_fn can sleep and we cannot
  * hold swap_lock while calling the unplug_fn. And swap_lock
@@ -167,7 +220,8 @@ static int wait_for_discard(void *word)
 #define SWAPFILE_CLUSTER       256
 #define LATENCY_LIMIT          256
 
-static inline unsigned long scan_swap_map(struct swap_info_struct *si)
+static inline unsigned long scan_swap_map(struct swap_info_struct *si,
+                                         int cache)
 {
        unsigned long offset;
        unsigned long scan_base;
@@ -273,6 +327,19 @@ checks:
                goto no_page;
        if (offset > si->highest_bit)
                scan_base = offset = si->lowest_bit;
+
+       /* reuse swap entry of cache-only swap if not busy. */
+       if (vm_swap_full() && si->swap_map[offset] == SWAP_HAS_CACHE) {
+               int swap_was_freed;
+               spin_unlock(&swap_lock);
+               swap_was_freed = __try_to_reclaim_swap(si, offset);
+               spin_lock(&swap_lock);
+               /* entry was freed successfully, try to use this again */
+               if (swap_was_freed)
+                       goto checks;
+               goto scan; /* check next one */
+       }
+
        if (si->swap_map[offset])
                goto scan;
 
@@ -285,7 +352,10 @@ checks:
                si->lowest_bit = si->max;
                si->highest_bit = 0;
        }
-       si->swap_map[offset] = 1;
+       if (cache == SWAP_CACHE) /* at usual swap-out via vmscan.c */
+               si->swap_map[offset] = encode_swapmap(0, true);
+       else /* at suspend */
+               si->swap_map[offset] = encode_swapmap(1, false);
        si->cluster_next = offset + 1;
        si->flags -= SWP_SCANNING;
 
@@ -351,6 +421,10 @@ scan:
                        spin_lock(&swap_lock);
                        goto checks;
                }
+               if (vm_swap_full() && si->swap_map[offset] == SWAP_HAS_CACHE) {
+                       spin_lock(&swap_lock);
+                       goto checks;
+               }
                if (unlikely(--latency_ration < 0)) {
                        cond_resched();
                        latency_ration = LATENCY_LIMIT;
@@ -362,6 +436,10 @@ scan:
                        spin_lock(&swap_lock);
                        goto checks;
                }
+               if (vm_swap_full() && si->swap_map[offset] == SWAP_HAS_CACHE) {
+                       spin_lock(&swap_lock);
+                       goto checks;
+               }
                if (unlikely(--latency_ration < 0)) {
                        cond_resched();
                        latency_ration = LATENCY_LIMIT;
@@ -401,7 +479,8 @@ swp_entry_t get_swap_page(void)
                        continue;
 
                swap_list.next = next;
-               offset = scan_swap_map(si);
+               /* This is called for allocating swap entry for cache */
+               offset = scan_swap_map(si, SWAP_CACHE);
                if (offset) {
                        spin_unlock(&swap_lock);
                        return swp_entry(type, offset);
@@ -415,6 +494,7 @@ noswap:
        return (swp_entry_t) {0};
 }
 
+/* The only caller of this function is now susupend routine */
 swp_entry_t get_swap_page_of_type(int type)
 {
        struct swap_info_struct *si;
@@ -424,7 +504,8 @@ swp_entry_t get_swap_page_of_type(int type)
        si = swap_info + type;
        if (si->flags & SWP_WRITEOK) {
                nr_swap_pages--;
-               offset = scan_swap_map(si);
+               /* This is called for allocating swap entry, not cache */
+               offset = scan_swap_map(si, SWAP_MAP);
                if (offset) {
                        spin_unlock(&swap_lock);
                        return swp_entry(type, offset);
@@ -471,25 +552,38 @@ out:
        return NULL;
 }
 
-static int swap_entry_free(struct swap_info_struct *p, swp_entry_t ent)
+static int swap_entry_free(struct swap_info_struct *p,
+                          swp_entry_t ent, int cache)
 {
        unsigned long offset = swp_offset(ent);
-       int count = p->swap_map[offset];
-
-       if (count < SWAP_MAP_MAX) {
-               count--;
-               p->swap_map[offset] = count;
-               if (!count) {
-                       if (offset < p->lowest_bit)
-                               p->lowest_bit = offset;
-                       if (offset > p->highest_bit)
-                               p->highest_bit = offset;
-                       if (p->prio > swap_info[swap_list.next].prio)
-                               swap_list.next = p - swap_info;
-                       nr_swap_pages++;
-                       p->inuse_pages--;
-                       mem_cgroup_uncharge_swap(ent);
+       int count = swap_count(p->swap_map[offset]);
+       bool has_cache;
+
+       has_cache = swap_has_cache(p->swap_map[offset]);
+
+       if (cache == SWAP_MAP) { /* dropping usage count of swap */
+               if (count < SWAP_MAP_MAX) {
+                       count--;
+                       p->swap_map[offset] = encode_swapmap(count, has_cache);
                }
+       } else { /* dropping swap cache flag */
+               VM_BUG_ON(!has_cache);
+               p->swap_map[offset] = encode_swapmap(count, false);
+
+       }
+       /* return code. */
+       count = p->swap_map[offset];
+       /* free if no reference */
+       if (!count) {
+               if (offset < p->lowest_bit)
+                       p->lowest_bit = offset;
+               if (offset > p->highest_bit)
+                       p->highest_bit = offset;
+               if (p->prio > swap_info[swap_list.next].prio)
+                       swap_list.next = p - swap_info;
+               nr_swap_pages++;
+               p->inuse_pages--;
+               mem_cgroup_uncharge_swap(ent);
        }
        return count;
 }
@@ -504,9 +598,26 @@ void swap_free(swp_entry_t entry)
 
        p = swap_info_get(entry);
        if (p) {
-               swap_entry_free(p, entry);
+               swap_entry_free(p, entry, SWAP_MAP);
+               spin_unlock(&swap_lock);
+       }
+}
+
+/*
+ * Called after dropping swapcache to decrease refcnt to swap entries.
+ */
+void swapcache_free(swp_entry_t entry, struct page *page)
+{
+       struct swap_info_struct *p;
+
+       if (page)
+               mem_cgroup_uncharge_swapcache(page, entry);
+       p = swap_info_get(entry);
+       if (p) {
+               swap_entry_free(p, entry, SWAP_CACHE);
                spin_unlock(&swap_lock);
        }
+       return;
 }
 
 /*
@@ -521,8 +632,7 @@ static inline int page_swapcount(struct page *page)
        entry.val = page_private(page);
        p = swap_info_get(entry);
        if (p) {
-               /* Subtract the 1 for the swap cache itself */
-               count = p->swap_map[swp_offset(entry)] - 1;
+               count = swap_count(p->swap_map[swp_offset(entry)]);
                spin_unlock(&swap_lock);
        }
        return count;
@@ -584,7 +694,7 @@ int free_swap_and_cache(swp_entry_t entry)
 
        p = swap_info_get(entry);
        if (p) {
-               if (swap_entry_free(p, entry) == 1) {
+               if (swap_entry_free(p, entry, SWAP_MAP) == SWAP_HAS_CACHE) {
                        page = find_get_page(&swapper_space, entry.val);
                        if (page && !trylock_page(page)) {
                                page_cache_release(page);
@@ -891,7 +1001,7 @@ static unsigned int find_next_to_unuse(struct swap_info_struct *si,
                        i = 1;
                }
                count = si->swap_map[i];
-               if (count && count != SWAP_MAP_BAD)
+               if (count && swap_count(count) != SWAP_MAP_BAD)
                        break;
        }
        return i;
@@ -995,13 +1105,13 @@ static int try_to_unuse(unsigned int type)
                 */
                shmem = 0;
                swcount = *swap_map;
-               if (swcount > 1) {
+               if (swap_count(swcount)) {
                        if (start_mm == &init_mm)
                                shmem = shmem_unuse(entry, page);
                        else
                                retval = unuse_mm(start_mm, entry, page);
                }
-               if (*swap_map > 1) {
+               if (swap_count(*swap_map)) {
                        int set_start_mm = (*swap_map >= swcount);
                        struct list_head *p = &start_mm->mmlist;
                        struct mm_struct *new_start_mm = start_mm;
@@ -1011,7 +1121,7 @@ static int try_to_unuse(unsigned int type)
                        atomic_inc(&new_start_mm->mm_users);
                        atomic_inc(&prev_mm->mm_users);
                        spin_lock(&mmlist_lock);
-                       while (*swap_map > 1 && !retval && !shmem &&
+                       while (swap_count(*swap_map) && !retval && !shmem &&
                                        (p = p->next) != &start_mm->mmlist) {
                                mm = list_entry(p, struct mm_struct, mmlist);
                                if (!atomic_inc_not_zero(&mm->mm_users))
@@ -1023,14 +1133,16 @@ static int try_to_unuse(unsigned int type)
                                cond_resched();
 
                                swcount = *swap_map;
-                               if (swcount <= 1)
+                               if (!swap_count(swcount)) /* any usage ? */
                                        ;
                                else if (mm == &init_mm) {
                                        set_start_mm = 1;
                                        shmem = shmem_unuse(entry, page);
                                } else
                                        retval = unuse_mm(mm, entry, page);
-                               if (set_start_mm && *swap_map < swcount) {
+
+                               if (set_start_mm &&
+                                   swap_count(*swap_map) < swcount) {
                                        mmput(new_start_mm);
                                        atomic_inc(&mm->mm_users);
                                        new_start_mm = mm;
@@ -1057,21 +1169,25 @@ static int try_to_unuse(unsigned int type)
                }
 
                /*
-                * How could swap count reach 0x7fff when the maximum
-                * pid is 0x7fff, and there's no way to repeat a swap
-                * page within an mm (except in shmem, where it's the
-                * shared object which takes the reference count)?
-                * We believe SWAP_MAP_MAX cannot occur in Linux 2.4.
-                *
+                * How could swap count reach 0x7ffe ?
+                * There's no way to repeat a swap page within an mm
+                * (except in shmem, where it's the shared object which takes
+                * the reference count)?
+                * We believe SWAP_MAP_MAX cannot occur.(if occur, unsigned
+                * short is too small....)
                 * If that's wrong, then we should worry more about
                 * exit_mmap() and do_munmap() cases described above:
                 * we might be resetting SWAP_MAP_MAX too early here.
                 * We know "Undead"s can happen, they're okay, so don't
                 * report them; but do report if we reset SWAP_MAP_MAX.
                 */
-               if (*swap_map == SWAP_MAP_MAX) {
+               /* We might release the lock_page() in unuse_mm(). */
+               if (!PageSwapCache(page) || page_private(page) != entry.val)
+                       goto retry;
+
+               if (swap_count(*swap_map) == SWAP_MAP_MAX) {
                        spin_lock(&swap_lock);
-                       *swap_map = 1;
+                       *swap_map = encode_swapmap(0, true);
                        spin_unlock(&swap_lock);
                        reset_overflow = 1;
                }
@@ -1089,7 +1205,8 @@ static int try_to_unuse(unsigned int type)
                 * pages would be incorrect if swap supported "shared
                 * private" pages, but they are handled by tmpfs files.
                 */
-               if ((*swap_map > 1) && PageDirty(page) && PageSwapCache(page)) {
+               if (swap_count(*swap_map) &&
+                    PageDirty(page) && PageSwapCache(page)) {
                        struct writeback_control wbc = {
                                .sync_mode = WB_SYNC_NONE,
                        };
@@ -1116,6 +1233,7 @@ static int try_to_unuse(unsigned int type)
                 * mark page dirty so shrink_page_list will preserve it.
                 */
                SetPageDirty(page);
+retry:
                unlock_page(page);
                page_cache_release(page);
 
@@ -1942,15 +2060,23 @@ void si_swapinfo(struct sysinfo *val)
  *
  * Note: if swap_map[] reaches SWAP_MAP_MAX the entries are treated as
  * "permanent", but will be reclaimed by the next swapoff.
+ * Returns error code in following case.
+ * - success -> 0
+ * - swp_entry is invalid -> EINVAL
+ * - swp_entry is migration entry -> EINVAL
+ * - swap-cache reference is requested but there is already one. -> EEXIST
+ * - swap-cache reference is requested but the entry is not used. -> ENOENT
  */
-int swap_duplicate(swp_entry_t entry)
+static int __swap_duplicate(swp_entry_t entry, bool cache)
 {
        struct swap_info_struct * p;
        unsigned long offset, type;
-       int result = 0;
+       int result = -EINVAL;
+       int count;
+       bool has_cache;
 
        if (is_migration_entry(entry))
-               return 1;
+               return -EINVAL;
 
        type = swp_type(entry);
        if (type >= nr_swapfiles)
@@ -1959,17 +2085,40 @@ int swap_duplicate(swp_entry_t entry)
        offset = swp_offset(entry);
 
        spin_lock(&swap_lock);
-       if (offset < p->max && p->swap_map[offset]) {
-               if (p->swap_map[offset] < SWAP_MAP_MAX - 1) {
-                       p->swap_map[offset]++;
-                       result = 1;
-               } else if (p->swap_map[offset] <= SWAP_MAP_MAX) {
+
+       if (unlikely(offset >= p->max))
+               goto unlock_out;
+
+       count = swap_count(p->swap_map[offset]);
+       has_cache = swap_has_cache(p->swap_map[offset]);
+
+       if (cache == SWAP_CACHE) { /* called for swapcache/swapin-readahead */
+
+               /* set SWAP_HAS_CACHE if there is no cache and entry is used */
+               if (!has_cache && count) {
+                       p->swap_map[offset] = encode_swapmap(count, true);
+                       result = 0;
+               } else if (has_cache) /* someone added cache */
+                       result = -EEXIST;
+               else if (!count) /* no users */
+                       result = -ENOENT;
+
+       } else if (count || has_cache) {
+               if (count < SWAP_MAP_MAX - 1) {
+                       p->swap_map[offset] = encode_swapmap(count + 1,
+                                                            has_cache);
+                       result = 0;
+               } else if (count <= SWAP_MAP_MAX) {
                        if (swap_overflow++ < 5)
-                               printk(KERN_WARNING "swap_dup: swap entry overflow\n");
-                       p->swap_map[offset] = SWAP_MAP_MAX;
-                       result = 1;
+                               printk(KERN_WARNING
+                                      "swap_dup: swap entry overflow\n");
+                       p->swap_map[offset] = encode_swapmap(SWAP_MAP_MAX,
+                                                             has_cache);
+                       result = 0;
                }
-       }
+       } else
+               result = -ENOENT; /* unused swap entry */
+unlock_out:
        spin_unlock(&swap_lock);
 out:
        return result;
@@ -1978,6 +2127,27 @@ bad_file:
        printk(KERN_ERR "swap_dup: %s%08lx\n", Bad_file, entry.val);
        goto out;
 }
+/*
+ * increase reference count of swap entry by 1.
+ */
+void swap_duplicate(swp_entry_t entry)
+{
+       __swap_duplicate(entry, SWAP_MAP);
+}
+
+/*
+ * @entry: swap entry for which we allocate swap cache.
+ *
+ * Called when allocating swap cache for exising swap entry,
+ * This can return error codes. Returns 0 at success.
+ * -EBUSY means there is a swap cache.
+ * Note: return code is different from swap_duplicate().
+ */
+int swapcache_prepare(swp_entry_t entry)
+{
+       return __swap_duplicate(entry, SWAP_CACHE);
+}
+
 
 struct swap_info_struct *
 get_swap_info_struct(unsigned type)
@@ -2016,7 +2186,7 @@ int valid_swaphandles(swp_entry_t entry, unsigned long *offset)
                /* Don't read in free or bad pages */
                if (!si->swap_map[toff])
                        break;
-               if (si->swap_map[toff] == SWAP_MAP_BAD)
+               if (swap_count(si->swap_map[toff]) == SWAP_MAP_BAD)
                        break;
        }
        /* Count contiguous allocated slots below our target */
@@ -2024,7 +2194,7 @@ int valid_swaphandles(swp_entry_t entry, unsigned long *offset)
                /* Don't read in free or bad pages */
                if (!si->swap_map[toff])
                        break;
-               if (si->swap_map[toff] == SWAP_MAP_BAD)
+               if (swap_count(si->swap_map[toff]) == SWAP_MAP_BAD)
                        break;
        }
        spin_unlock(&swap_lock);
index 12e1579f916546db1933998f4f655a8c1f8e2d34..ccc3ecf7cb9839a90eddc0086be770796e5b8884 100644 (file)
@@ -267,8 +267,21 @@ void truncate_inode_pages(struct address_space *mapping, loff_t lstart)
 }
 EXPORT_SYMBOL(truncate_inode_pages);
 
-unsigned long __invalidate_mapping_pages(struct address_space *mapping,
-                               pgoff_t start, pgoff_t end, bool be_atomic)
+/**
+ * invalidate_mapping_pages - Invalidate all the unlocked pages of one inode
+ * @mapping: the address_space which holds the pages to invalidate
+ * @start: the offset 'from' which to invalidate
+ * @end: the offset 'to' which to invalidate (inclusive)
+ *
+ * This function only removes the unlocked pages, if you want to
+ * remove all the pages of one inode, you must call truncate_inode_pages.
+ *
+ * invalidate_mapping_pages() will not block on IO activity. It will not
+ * invalidate pages which are dirty, locked, under writeback or mapped into
+ * pagetables.
+ */
+unsigned long invalidate_mapping_pages(struct address_space *mapping,
+                                      pgoff_t start, pgoff_t end)
 {
        struct pagevec pvec;
        pgoff_t next = start;
@@ -309,30 +322,10 @@ unlock:
                                break;
                }
                pagevec_release(&pvec);
-               if (likely(!be_atomic))
-                       cond_resched();
+               cond_resched();
        }
        return ret;
 }
-
-/**
- * invalidate_mapping_pages - Invalidate all the unlocked pages of one inode
- * @mapping: the address_space which holds the pages to invalidate
- * @start: the offset 'from' which to invalidate
- * @end: the offset 'to' which to invalidate (inclusive)
- *
- * This function only removes the unlocked pages, if you want to
- * remove all the pages of one inode, you must call truncate_inode_pages.
- *
- * invalidate_mapping_pages() will not block on IO activity. It will not
- * invalidate pages which are dirty, locked, under writeback or mapped into
- * pagetables.
- */
-unsigned long invalidate_mapping_pages(struct address_space *mapping,
-                               pgoff_t start, pgoff_t end)
-{
-       return __invalidate_mapping_pages(mapping, start, end, false);
-}
 EXPORT_SYMBOL(invalidate_mapping_pages);
 
 /*
index abc65aa7cdfc7bcfc76817afe2451cce7a4ece3e..d5d2213728c51725fb658b5e20225cb429d93015 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -233,13 +233,21 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
  * @pages:     array that receives pointers to the pages pinned.
  *             Should be at least nr_pages long.
  *
- * Attempt to pin user pages in memory without taking mm->mmap_sem.
- * If not successful, it will fall back to taking the lock and
- * calling get_user_pages().
- *
  * Returns number of pages pinned. This may be fewer than the number
  * requested. If nr_pages is 0 or negative, returns 0. If no pages
  * were pinned, returns -errno.
+ *
+ * get_user_pages_fast provides equivalent functionality to get_user_pages,
+ * operating on current and current->mm, with force=0 and vma=NULL. However
+ * unlike get_user_pages, it must be called without mmap_sem held.
+ *
+ * get_user_pages_fast may take mmap_sem and page table locks, so no
+ * assumptions can be made about lack of locking. get_user_pages_fast is to be
+ * implemented in a way that is advantageous (vs get_user_pages()) when the
+ * user memory area is already faulted in and present in ptes. However if the
+ * pages have to be faulted in, it may turn out to be slightly slower so
+ * callers need to carefully consider what to use. On many architectures,
+ * get_user_pages_fast simply falls back to get_user_pages.
  */
 int __attribute__((weak)) get_user_pages_fast(unsigned long start,
                                int nr_pages, int write, struct page **pages)
index 95c08a8cc2ba4fb015f71b605271f9b8804c68fb..4139aa52b941e16d95b20ae481a0775b02158518 100644 (file)
@@ -470,8 +470,7 @@ static int __remove_mapping(struct address_space *mapping, struct page *page)
                swp_entry_t swap = { .val = page_private(page) };
                __delete_from_swap_cache(page);
                spin_unlock_irq(&mapping->tree_lock);
-               mem_cgroup_uncharge_swapcache(page, swap);
-               swap_free(swap);
+               swapcache_free(swap, page);
        } else {
                __remove_from_page_cache(page);
                spin_unlock_irq(&mapping->tree_lock);
@@ -514,7 +513,6 @@ int remove_mapping(struct address_space *mapping, struct page *page)
  *
  * lru_lock must not be held, interrupts must be enabled.
  */
-#ifdef CONFIG_UNEVICTABLE_LRU
 void putback_lru_page(struct page *page)
 {
        int lru;
@@ -568,20 +566,6 @@ redo:
        put_page(page);         /* drop ref from isolate */
 }
 
-#else /* CONFIG_UNEVICTABLE_LRU */
-
-void putback_lru_page(struct page *page)
-{
-       int lru;
-       VM_BUG_ON(PageLRU(page));
-
-       lru = !!TestClearPageActive(page) + page_is_file_cache(page);
-       lru_cache_add_lru(page, lru);
-       put_page(page);
-}
-#endif /* CONFIG_UNEVICTABLE_LRU */
-
-
 /*
  * shrink_page_list() returns the number of reclaimed pages
  */
@@ -593,6 +577,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
        struct pagevec freed_pvec;
        int pgactivate = 0;
        unsigned long nr_reclaimed = 0;
+       unsigned long vm_flags;
 
        cond_resched();
 
@@ -643,7 +628,8 @@ static unsigned long shrink_page_list(struct list_head *page_list,
                                goto keep_locked;
                }
 
-               referenced = page_referenced(page, 1, sc->mem_cgroup);
+               referenced = page_referenced(page, 1,
+                                               sc->mem_cgroup, &vm_flags);
                /* In active use or really unfreeable?  Activate it. */
                if (sc->order <= PAGE_ALLOC_COSTLY_ORDER &&
                                        referenced && page_mapping_inuse(page))
@@ -943,18 +929,10 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
                        /* Check that we have not crossed a zone boundary. */
                        if (unlikely(page_zone_id(cursor_page) != zone_id))
                                continue;
-                       switch (__isolate_lru_page(cursor_page, mode, file)) {
-                       case 0:
+                       if (__isolate_lru_page(cursor_page, mode, file) == 0) {
                                list_move(&cursor_page->lru, dst);
                                nr_taken++;
                                scan++;
-                               break;
-
-                       case -EBUSY:
-                               /* else it is being freed elsewhere */
-                               list_move(&cursor_page->lru, src);
-                       default:
-                               break;  /* ! on LRU or wrong list */
                        }
                }
        }
@@ -1061,6 +1039,19 @@ static unsigned long shrink_inactive_list(unsigned long max_scan,
        unsigned long nr_scanned = 0;
        unsigned long nr_reclaimed = 0;
        struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(zone, sc);
+       int lumpy_reclaim = 0;
+
+       /*
+        * If we need a large contiguous chunk of memory, or have
+        * trouble getting a small set of contiguous pages, we
+        * will reclaim both active and inactive pages.
+        *
+        * We use the same threshold as pageout congestion_wait below.
+        */
+       if (sc->order > PAGE_ALLOC_COSTLY_ORDER)
+               lumpy_reclaim = 1;
+       else if (sc->order && priority < DEF_PRIORITY - 2)
+               lumpy_reclaim = 1;
 
        pagevec_init(&pvec, 1);
 
@@ -1073,19 +1064,7 @@ static unsigned long shrink_inactive_list(unsigned long max_scan,
                unsigned long nr_freed;
                unsigned long nr_active;
                unsigned int count[NR_LRU_LISTS] = { 0, };
-               int mode = ISOLATE_INACTIVE;
-
-               /*
-                * If we need a large contiguous chunk of memory, or have
-                * trouble getting a small set of contiguous pages, we
-                * will reclaim both active and inactive pages.
-                *
-                * We use the same threshold as pageout congestion_wait below.
-                */
-               if (sc->order > PAGE_ALLOC_COSTLY_ORDER)
-                       mode = ISOLATE_BOTH;
-               else if (sc->order && priority < DEF_PRIORITY - 2)
-                       mode = ISOLATE_BOTH;
+               int mode = lumpy_reclaim ? ISOLATE_BOTH : ISOLATE_INACTIVE;
 
                nr_taken = sc->isolate_pages(sc->swap_cluster_max,
                             &page_list, &nr_scan, sc->order, mode,
@@ -1122,7 +1101,7 @@ static unsigned long shrink_inactive_list(unsigned long max_scan,
                 * but that should be acceptable to the caller
                 */
                if (nr_freed < nr_taken && !current_is_kswapd() &&
-                                       sc->order > PAGE_ALLOC_COSTLY_ORDER) {
+                   lumpy_reclaim) {
                        congestion_wait(WRITE, HZ/10);
 
                        /*
@@ -1217,18 +1196,54 @@ static inline void note_zone_scanning_priority(struct zone *zone, int priority)
  * But we had to alter page->flags anyway.
  */
 
+static void move_active_pages_to_lru(struct zone *zone,
+                                    struct list_head *list,
+                                    enum lru_list lru)
+{
+       unsigned long pgmoved = 0;
+       struct pagevec pvec;
+       struct page *page;
+
+       pagevec_init(&pvec, 1);
+
+       while (!list_empty(list)) {
+               page = lru_to_page(list);
+               prefetchw_prev_lru_page(page, list, flags);
+
+               VM_BUG_ON(PageLRU(page));
+               SetPageLRU(page);
+
+               VM_BUG_ON(!PageActive(page));
+               if (!is_active_lru(lru))
+                       ClearPageActive(page);  /* we are de-activating */
+
+               list_move(&page->lru, &zone->lru[lru].list);
+               mem_cgroup_add_lru_list(page, lru);
+               pgmoved++;
+
+               if (!pagevec_add(&pvec, page) || list_empty(list)) {
+                       spin_unlock_irq(&zone->lru_lock);
+                       if (buffer_heads_over_limit)
+                               pagevec_strip(&pvec);
+                       __pagevec_release(&pvec);
+                       spin_lock_irq(&zone->lru_lock);
+               }
+       }
+       __mod_zone_page_state(zone, NR_LRU_BASE + lru, pgmoved);
+       if (!is_active_lru(lru))
+               __count_vm_events(PGDEACTIVATE, pgmoved);
+}
 
 static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
                        struct scan_control *sc, int priority, int file)
 {
        unsigned long pgmoved;
-       int pgdeactivate = 0;
        unsigned long pgscanned;
+       unsigned long vm_flags;
        LIST_HEAD(l_hold);      /* The pages which were snipped off */
+       LIST_HEAD(l_active);
        LIST_HEAD(l_inactive);
        struct page *page;
-       struct pagevec pvec;
-       enum lru_list lru;
        struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(zone, sc);
 
        lru_add_drain();
@@ -1245,13 +1260,14 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
        }
        reclaim_stat->recent_scanned[!!file] += pgmoved;
 
+       __count_zone_vm_events(PGREFILL, zone, pgscanned);
        if (file)
                __mod_zone_page_state(zone, NR_ACTIVE_FILE, -pgmoved);
        else
                __mod_zone_page_state(zone, NR_ACTIVE_ANON, -pgmoved);
        spin_unlock_irq(&zone->lru_lock);
 
-       pgmoved = 0;
+       pgmoved = 0;  /* count referenced (mapping) mapped pages */
        while (!list_empty(&l_hold)) {
                cond_resched();
                page = lru_to_page(&l_hold);
@@ -1264,58 +1280,44 @@ static void shrink_active_list(unsigned long nr_pages, struct zone *zone,
 
                /* page_referenced clears PageReferenced */
                if (page_mapping_inuse(page) &&
-                   page_referenced(page, 0, sc->mem_cgroup))
+                   page_referenced(page, 0, sc->mem_cgroup, &vm_flags)) {
                        pgmoved++;
+                       /*
+                        * Identify referenced, file-backed active pages and
+                        * give them one more trip around the active list. So
+                        * that executable code get better chances to stay in
+                        * memory under moderate memory pressure.  Anon pages
+                        * are not likely to be evicted by use-once streaming
+                        * IO, plus JVM can create lots of anon VM_EXEC pages,
+                        * so we ignore them here.
+                        */
+                       if ((vm_flags & VM_EXEC) && !PageAnon(page)) {
+                               list_add(&page->lru, &l_active);
+                               continue;
+                       }
+               }
 
                list_add(&page->lru, &l_inactive);
        }
 
        /*
-        * Move the pages to the [file or anon] inactive list.
+        * Move pages back to the lru list.
         */
-       pagevec_init(&pvec, 1);
-       lru = LRU_BASE + file * LRU_FILE;
-
        spin_lock_irq(&zone->lru_lock);
        /*
-        * Count referenced pages from currently used mappings as
-        * rotated, even though they are moved to the inactive list.
-        * This helps balance scan pressure between file and anonymous
-        * pages in get_scan_ratio.
+        * Count referenced pages from currently used mappings as rotated,
+        * even though only some of them are actually re-activated.  This
+        * helps balance scan pressure between file and anonymous pages in
+        * get_scan_ratio.
         */
        reclaim_stat->recent_rotated[!!file] += pgmoved;
 
-       pgmoved = 0;
-       while (!list_empty(&l_inactive)) {
-               page = lru_to_page(&l_inactive);
-               prefetchw_prev_lru_page(page, &l_inactive, flags);
-               VM_BUG_ON(PageLRU(page));
-               SetPageLRU(page);
-               VM_BUG_ON(!PageActive(page));
-               ClearPageActive(page);
+       move_active_pages_to_lru(zone, &l_active,
+                                               LRU_ACTIVE + file * LRU_FILE);
+       move_active_pages_to_lru(zone, &l_inactive,
+                                               LRU_BASE   + file * LRU_FILE);
 
-               list_move(&page->lru, &zone->lru[lru].list);
-               mem_cgroup_add_lru_list(page, lru);
-               pgmoved++;
-               if (!pagevec_add(&pvec, page)) {
-                       __mod_zone_page_state(zone, NR_LRU_BASE + lru, pgmoved);
-                       spin_unlock_irq(&zone->lru_lock);
-                       pgdeactivate += pgmoved;
-                       pgmoved = 0;
-                       if (buffer_heads_over_limit)
-                               pagevec_strip(&pvec);
-                       __pagevec_release(&pvec);
-                       spin_lock_irq(&zone->lru_lock);
-               }
-       }
-       __mod_zone_page_state(zone, NR_LRU_BASE + lru, pgmoved);
-       pgdeactivate += pgmoved;
-       __count_zone_vm_events(PGREFILL, zone, pgscanned);
-       __count_vm_events(PGDEACTIVATE, pgdeactivate);
        spin_unlock_irq(&zone->lru_lock);
-       if (buffer_heads_over_limit)
-               pagevec_strip(&pvec);
-       pagevec_release(&pvec);
 }
 
 static int inactive_anon_is_low_global(struct zone *zone)
@@ -1350,12 +1352,48 @@ static int inactive_anon_is_low(struct zone *zone, struct scan_control *sc)
        return low;
 }
 
+static int inactive_file_is_low_global(struct zone *zone)
+{
+       unsigned long active, inactive;
+
+       active = zone_page_state(zone, NR_ACTIVE_FILE);
+       inactive = zone_page_state(zone, NR_INACTIVE_FILE);
+
+       return (active > inactive);
+}
+
+/**
+ * inactive_file_is_low - check if file pages need to be deactivated
+ * @zone: zone to check
+ * @sc:   scan control of this context
+ *
+ * When the system is doing streaming IO, memory pressure here
+ * ensures that active file pages get deactivated, until more
+ * than half of the file pages are on the inactive list.
+ *
+ * Once we get to that situation, protect the system's working
+ * set from being evicted by disabling active file page aging.
+ *
+ * This uses a different ratio than the anonymous pages, because
+ * the page cache uses a use-once replacement algorithm.
+ */
+static int inactive_file_is_low(struct zone *zone, struct scan_control *sc)
+{
+       int low;
+
+       if (scanning_global_lru(sc))
+               low = inactive_file_is_low_global(zone);
+       else
+               low = mem_cgroup_inactive_file_is_low(sc->mem_cgroup);
+       return low;
+}
+
 static unsigned long shrink_list(enum lru_list lru, unsigned long nr_to_scan,
        struct zone *zone, struct scan_control *sc, int priority)
 {
        int file = is_file_lru(lru);
 
-       if (lru == LRU_ACTIVE_FILE) {
+       if (lru == LRU_ACTIVE_FILE && inactive_file_is_low(zone, sc)) {
                shrink_active_list(nr_to_scan, zone, sc, priority, file);
                return 0;
        }
@@ -1384,13 +1422,6 @@ static void get_scan_ratio(struct zone *zone, struct scan_control *sc,
        unsigned long ap, fp;
        struct zone_reclaim_stat *reclaim_stat = get_reclaim_stat(zone, sc);
 
-       /* If we have no swap space, do not bother scanning anon pages. */
-       if (!sc->may_swap || (nr_swap_pages <= 0)) {
-               percent[0] = 0;
-               percent[1] = 100;
-               return;
-       }
-
        anon  = zone_nr_pages(zone, sc, LRU_ACTIVE_ANON) +
                zone_nr_pages(zone, sc, LRU_INACTIVE_ANON);
        file  = zone_nr_pages(zone, sc, LRU_ACTIVE_FILE) +
@@ -1400,7 +1431,7 @@ static void get_scan_ratio(struct zone *zone, struct scan_control *sc,
                free  = zone_page_state(zone, NR_FREE_PAGES);
                /* If we have very few page cache pages,
                   force-scan anon pages. */
-               if (unlikely(file + free <= zone->pages_high)) {
+               if (unlikely(file + free <= high_wmark_pages(zone))) {
                        percent[0] = 100;
                        percent[1] = 0;
                        return;
@@ -1455,6 +1486,26 @@ static void get_scan_ratio(struct zone *zone, struct scan_control *sc,
        percent[1] = 100 - percent[0];
 }
 
+/*
+ * Smallish @nr_to_scan's are deposited in @nr_saved_scan,
+ * until we collected @swap_cluster_max pages to scan.
+ */
+static unsigned long nr_scan_try_batch(unsigned long nr_to_scan,
+                                      unsigned long *nr_saved_scan,
+                                      unsigned long swap_cluster_max)
+{
+       unsigned long nr;
+
+       *nr_saved_scan += nr_to_scan;
+       nr = *nr_saved_scan;
+
+       if (nr >= swap_cluster_max)
+               *nr_saved_scan = 0;
+       else
+               nr = 0;
+
+       return nr;
+}
 
 /*
  * This is a basic per-zone page freer.  Used by both kswapd and direct reclaim.
@@ -1468,26 +1519,30 @@ static void shrink_zone(int priority, struct zone *zone,
        enum lru_list l;
        unsigned long nr_reclaimed = sc->nr_reclaimed;
        unsigned long swap_cluster_max = sc->swap_cluster_max;
+       int noswap = 0;
 
-       get_scan_ratio(zone, sc, percent);
+       /* If we have no swap space, do not bother scanning anon pages. */
+       if (!sc->may_swap || (nr_swap_pages <= 0)) {
+               noswap = 1;
+               percent[0] = 0;
+               percent[1] = 100;
+       } else
+               get_scan_ratio(zone, sc, percent);
 
        for_each_evictable_lru(l) {
                int file = is_file_lru(l);
                unsigned long scan;
 
                scan = zone_nr_pages(zone, sc, l);
-               if (priority) {
+               if (priority || noswap) {
                        scan >>= priority;
                        scan = (scan * percent[file]) / 100;
                }
-               if (scanning_global_lru(sc)) {
-                       zone->lru[l].nr_scan += scan;
-                       nr[l] = zone->lru[l].nr_scan;
-                       if (nr[l] >= swap_cluster_max)
-                               zone->lru[l].nr_scan = 0;
-                       else
-                               nr[l] = 0;
-               } else
+               if (scanning_global_lru(sc))
+                       nr[l] = nr_scan_try_batch(scan,
+                                                 &zone->lru[l].nr_saved_scan,
+                                                 swap_cluster_max);
+               else
                        nr[l] = scan;
        }
 
@@ -1521,7 +1576,7 @@ static void shrink_zone(int priority, struct zone *zone,
         * Even if we did not try to evict anon pages at all, we want to
         * rebalance the anon lru active/inactive ratio.
         */
-       if (inactive_anon_is_low(zone, sc))
+       if (inactive_anon_is_low(zone, sc) && nr_swap_pages > 0)
                shrink_active_list(SWAP_CLUSTER_MAX, zone, sc, priority, 0);
 
        throttle_vm_writeout(sc->gfp_mask);
@@ -1532,11 +1587,13 @@ static void shrink_zone(int priority, struct zone *zone,
  * try to reclaim pages from zones which will satisfy the caller's allocation
  * request.
  *
- * We reclaim from a zone even if that zone is over pages_high.  Because:
+ * We reclaim from a zone even if that zone is over high_wmark_pages(zone).
+ * Because:
  * a) The caller may be trying to free *extra* pages to satisfy a higher-order
  *    allocation or
- * b) The zones may be over pages_high but they must go *over* pages_high to
- *    satisfy the `incremental min' zone defense algorithm.
+ * b) The target zone may be at high_wmark_pages(zone) but the lower zones
+ *    must go *over* high_wmark_pages(zone) to satisfy the `incremental min'
+ *    zone defense algorithm.
  *
  * If a zone is deemed to be full of pinned pages then just give it a light
  * scan then give up on it.
@@ -1742,7 +1799,7 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
 
 /*
  * For kswapd, balance_pgdat() will work across all this node's zones until
- * they are all at pages_high.
+ * they are all at high_wmark_pages(zone).
  *
  * Returns the number of pages which were actually freed.
  *
@@ -1755,11 +1812,11 @@ unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *mem_cont,
  * the zone for when the problem goes away.
  *
  * kswapd scans the zones in the highmem->normal->dma direction.  It skips
- * zones which have free_pages > pages_high, but once a zone is found to have
- * free_pages <= pages_high, we scan that zone and the lower zones regardless
- * of the number of free pages in the lower zones.  This interoperates with
- * the page allocator fallback scheme to ensure that aging of pages is balanced
- * across the zones.
+ * zones which have free_pages > high_wmark_pages(zone), but once a zone is
+ * found to have free_pages <= high_wmark_pages(zone), we scan that zone and the
+ * lower zones regardless of the number of free pages in the lower zones. This
+ * interoperates with the page allocator fallback scheme to ensure that aging
+ * of pages is balanced across the zones.
  */
 static unsigned long balance_pgdat(pg_data_t *pgdat, int order)
 {
@@ -1780,7 +1837,8 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order)
        };
        /*
         * temp_priority is used to remember the scanning priority at which
-        * this zone was successfully refilled to free_pages == pages_high.
+        * this zone was successfully refilled to
+        * free_pages == high_wmark_pages(zone).
         */
        int temp_priority[MAX_NR_ZONES];
 
@@ -1825,8 +1883,8 @@ loop_again:
                                shrink_active_list(SWAP_CLUSTER_MAX, zone,
                                                        &sc, priority, 0);
 
-                       if (!zone_watermark_ok(zone, order, zone->pages_high,
-                                              0, 0)) {
+                       if (!zone_watermark_ok(zone, order,
+                                       high_wmark_pages(zone), 0, 0)) {
                                end_zone = i;
                                break;
                        }
@@ -1860,8 +1918,8 @@ loop_again:
                                        priority != DEF_PRIORITY)
                                continue;
 
-                       if (!zone_watermark_ok(zone, order, zone->pages_high,
-                                              end_zone, 0))
+                       if (!zone_watermark_ok(zone, order,
+                                       high_wmark_pages(zone), end_zone, 0))
                                all_zones_ok = 0;
                        temp_priority[i] = priority;
                        sc.nr_scanned = 0;
@@ -1870,8 +1928,8 @@ loop_again:
                         * We put equal pressure on every zone, unless one
                         * zone has way too many pages free already.
                         */
-                       if (!zone_watermark_ok(zone, order, 8*zone->pages_high,
-                                               end_zone, 0))
+                       if (!zone_watermark_ok(zone, order,
+                                       8*high_wmark_pages(zone), end_zone, 0))
                                shrink_zone(priority, zone, &sc);
                        reclaim_state->reclaimed_slab = 0;
                        nr_slab = shrink_slab(sc.nr_scanned, GFP_KERNEL,
@@ -2037,7 +2095,7 @@ void wakeup_kswapd(struct zone *zone, int order)
                return;
 
        pgdat = zone->zone_pgdat;
-       if (zone_watermark_ok(zone, order, zone->pages_low, 0, 0))
+       if (zone_watermark_ok(zone, order, low_wmark_pages(zone), 0, 0))
                return;
        if (pgdat->kswapd_max_order < order)
                pgdat->kswapd_max_order = order;
@@ -2084,11 +2142,11 @@ static void shrink_all_zones(unsigned long nr_pages, int prio,
                                                l == LRU_ACTIVE_FILE))
                                continue;
 
-                       zone->lru[l].nr_scan += (lru_pages >> prio) + 1;
-                       if (zone->lru[l].nr_scan >= nr_pages || pass > 3) {
+                       zone->lru[l].nr_saved_scan += (lru_pages >> prio) + 1;
+                       if (zone->lru[l].nr_saved_scan >= nr_pages || pass > 3) {
                                unsigned long nr_to_scan;
 
-                               zone->lru[l].nr_scan = 0;
+                               zone->lru[l].nr_saved_scan = 0;
                                nr_to_scan = min(nr_pages, lru_pages);
                                nr_reclaimed += shrink_list(l, nr_to_scan, zone,
                                                                sc, prio);
@@ -2290,6 +2348,48 @@ int sysctl_min_unmapped_ratio = 1;
  */
 int sysctl_min_slab_ratio = 5;
 
+static inline unsigned long zone_unmapped_file_pages(struct zone *zone)
+{
+       unsigned long file_mapped = zone_page_state(zone, NR_FILE_MAPPED);
+       unsigned long file_lru = zone_page_state(zone, NR_INACTIVE_FILE) +
+               zone_page_state(zone, NR_ACTIVE_FILE);
+
+       /*
+        * It's possible for there to be more file mapped pages than
+        * accounted for by the pages on the file LRU lists because
+        * tmpfs pages accounted for as ANON can also be FILE_MAPPED
+        */
+       return (file_lru > file_mapped) ? (file_lru - file_mapped) : 0;
+}
+
+/* Work out how many page cache pages we can reclaim in this reclaim_mode */
+static long zone_pagecache_reclaimable(struct zone *zone)
+{
+       long nr_pagecache_reclaimable;
+       long delta = 0;
+
+       /*
+        * If RECLAIM_SWAP is set, then all file pages are considered
+        * potentially reclaimable. Otherwise, we have to worry about
+        * pages like swapcache and zone_unmapped_file_pages() provides
+        * a better estimate
+        */
+       if (zone_reclaim_mode & RECLAIM_SWAP)
+               nr_pagecache_reclaimable = zone_page_state(zone, NR_FILE_PAGES);
+       else
+               nr_pagecache_reclaimable = zone_unmapped_file_pages(zone);
+
+       /* If we can't clean pages, remove dirty pages from consideration */
+       if (!(zone_reclaim_mode & RECLAIM_WRITE))
+               delta += zone_page_state(zone, NR_FILE_DIRTY);
+
+       /* Watch for any possible underflows due to delta */
+       if (unlikely(delta > nr_pagecache_reclaimable))
+               delta = nr_pagecache_reclaimable;
+
+       return nr_pagecache_reclaimable - delta;
+}
+
 /*
  * Try to free up some pages from this zone through reclaim.
  */
@@ -2324,9 +2424,7 @@ static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
        reclaim_state.reclaimed_slab = 0;
        p->reclaim_state = &reclaim_state;
 
-       if (zone_page_state(zone, NR_FILE_PAGES) -
-               zone_page_state(zone, NR_FILE_MAPPED) >
-               zone->min_unmapped_pages) {
+       if (zone_pagecache_reclaimable(zone) > zone->min_unmapped_pages) {
                /*
                 * Free memory by calling shrink zone with increasing
                 * priorities until we have enough memory freed.
@@ -2384,20 +2482,18 @@ int zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
         * if less than a specified percentage of the zone is used by
         * unmapped file backed pages.
         */
-       if (zone_page_state(zone, NR_FILE_PAGES) -
-           zone_page_state(zone, NR_FILE_MAPPED) <= zone->min_unmapped_pages
-           && zone_page_state(zone, NR_SLAB_RECLAIMABLE)
-                       <= zone->min_slab_pages)
-               return 0;
+       if (zone_pagecache_reclaimable(zone) <= zone->min_unmapped_pages &&
+           zone_page_state(zone, NR_SLAB_RECLAIMABLE) <= zone->min_slab_pages)
+               return ZONE_RECLAIM_FULL;
 
        if (zone_is_all_unreclaimable(zone))
-               return 0;
+               return ZONE_RECLAIM_FULL;
 
        /*
         * Do not scan if the allocation should not be delayed.
         */
        if (!(gfp_mask & __GFP_WAIT) || (current->flags & PF_MEMALLOC))
-                       return 0;
+               return ZONE_RECLAIM_NOSCAN;
 
        /*
         * Only run zone reclaim on the local zone or on zones that do not
@@ -2407,18 +2503,21 @@ int zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
         */
        node_id = zone_to_nid(zone);
        if (node_state(node_id, N_CPU) && node_id != numa_node_id())
-               return 0;
+               return ZONE_RECLAIM_NOSCAN;
 
        if (zone_test_and_set_flag(zone, ZONE_RECLAIM_LOCKED))
-               return 0;
+               return ZONE_RECLAIM_NOSCAN;
+
        ret = __zone_reclaim(zone, gfp_mask, order);
        zone_clear_flag(zone, ZONE_RECLAIM_LOCKED);
 
+       if (!ret)
+               count_vm_event(PGSCAN_ZONE_RECLAIM_FAILED);
+
        return ret;
 }
 #endif
 
-#ifdef CONFIG_UNEVICTABLE_LRU
 /*
  * page_evictable - test whether a page is evictable
  * @page: the page to test
@@ -2665,4 +2764,3 @@ void scan_unevictable_unregister_node(struct node *node)
        sysdev_remove_file(&node->sysdev, &attr_scan_unevictable_pages);
 }
 
-#endif
index 74d66dba0cbe45429f7b663c783a6f839e2ceb3f..138bed53706ed325e2d4aac3ae0065cffccdda47 100644 (file)
@@ -629,10 +629,8 @@ static const char * const vmstat_text[] = {
        "nr_active_anon",
        "nr_inactive_file",
        "nr_active_file",
-#ifdef CONFIG_UNEVICTABLE_LRU
        "nr_unevictable",
        "nr_mlock",
-#endif
        "nr_anon_pages",
        "nr_mapped",
        "nr_file_pages",
@@ -675,6 +673,9 @@ static const char * const vmstat_text[] = {
        TEXTS_FOR_ZONES("pgscan_kswapd")
        TEXTS_FOR_ZONES("pgscan_direct")
 
+#ifdef CONFIG_NUMA
+       "zone_reclaim_failed",
+#endif
        "pginodesteal",
        "slabs_scanned",
        "kswapd_steal",
@@ -687,7 +688,6 @@ static const char * const vmstat_text[] = {
        "htlb_buddy_alloc_success",
        "htlb_buddy_alloc_fail",
 #endif
-#ifdef CONFIG_UNEVICTABLE_LRU
        "unevictable_pgs_culled",
        "unevictable_pgs_scanned",
        "unevictable_pgs_rescued",
@@ -697,7 +697,6 @@ static const char * const vmstat_text[] = {
        "unevictable_pgs_stranded",
        "unevictable_pgs_mlockfreed",
 #endif
-#endif
 };
 
 static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
@@ -710,18 +709,14 @@ static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
                   "\n        min      %lu"
                   "\n        low      %lu"
                   "\n        high     %lu"
-                  "\n        scanned  %lu (aa: %lu ia: %lu af: %lu if: %lu)"
+                  "\n        scanned  %lu"
                   "\n        spanned  %lu"
                   "\n        present  %lu",
                   zone_page_state(zone, NR_FREE_PAGES),
-                  zone->pages_min,
-                  zone->pages_low,
-                  zone->pages_high,
+                  min_wmark_pages(zone),
+                  low_wmark_pages(zone),
+                  high_wmark_pages(zone),
                   zone->pages_scanned,
-                  zone->lru[LRU_ACTIVE_ANON].nr_scan,
-                  zone->lru[LRU_INACTIVE_ANON].nr_scan,
-                  zone->lru[LRU_ACTIVE_FILE].nr_scan,
-                  zone->lru[LRU_INACTIVE_FILE].nr_scan,
                   zone->spanned_pages,
                   zone->present_pages);
 
index 1a94a3037370a4c70ee3862fb9676a4975eddeb1..5c93435b0347cc691db1ba36eeb1a23cb33809b6 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
+#include <linux/kmemcheck.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/in.h>
@@ -201,6 +202,8 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
        skb->data = data;
        skb_reset_tail_pointer(skb);
        skb->end = skb->tail + size;
+       kmemcheck_annotate_bitfield(skb, flags1);
+       kmemcheck_annotate_bitfield(skb, flags2);
        /* make sure we initialize shinfo sequentially */
        shinfo = skb_shinfo(skb);
        atomic_set(&shinfo->dataref, 1);
@@ -217,6 +220,8 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
                struct sk_buff *child = skb + 1;
                atomic_t *fclone_ref = (atomic_t *) (child + 1);
 
+               kmemcheck_annotate_bitfield(child, flags1);
+               kmemcheck_annotate_bitfield(child, flags2);
                skb->fclone = SKB_FCLONE_ORIG;
                atomic_set(fclone_ref, 1);
 
@@ -635,6 +640,9 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
                n = kmem_cache_alloc(skbuff_head_cache, gfp_mask);
                if (!n)
                        return NULL;
+
+               kmemcheck_annotate_bitfield(n, flags1);
+               kmemcheck_annotate_bitfield(n, flags2);
                n->fclone = SKB_FCLONE_UNAVAILABLE;
        }
 
index 06e26b77ad9e78437948592eb1781539b6947703..b0ba569bc97361dec5b2619a46ffbeab50331dc2 100644 (file)
@@ -945,6 +945,8 @@ static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority,
                sk = kmalloc(prot->obj_size, priority);
 
        if (sk != NULL) {
+               kmemcheck_annotate_bitfield(sk, flags);
+
                if (security_sk_alloc(sk, family, priority))
                        goto out_free;
 
index 68a8d892c711e44764e8856ef265dbb60f1f915b..61283f9288250cc6b74d440abf7621947ed91313 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/kmemcheck.h>
 #include <net/inet_hashtables.h>
 #include <net/inet_timewait_sock.h>
 #include <net/ip.h>
@@ -120,6 +121,8 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int stat
        if (tw != NULL) {
                const struct inet_sock *inet = inet_sk(sk);
 
+               kmemcheck_annotate_bitfield(tw, flags);
+
                /* Give us an identity. */
                tw->tw_daddr        = inet->daddr;
                tw->tw_rcv_saddr    = inet->rcv_saddr;
index a9b3a6f9ea95f18f2ea8325a72741fb61e0c14cf..656cbd1958250d54542c2318130dc26a81182a4a 100644 (file)
@@ -1,11 +1,12 @@
 /*
- *  linux/net/iucv/af_iucv.c
- *
  *  IUCV protocol stack for Linux on zSeries
  *
- *  Copyright 2006 IBM Corporation
+ *  Copyright IBM Corp. 2006, 2009
  *
  *  Author(s): Jennifer Hunt <jenhunt@us.ibm.com>
+ *             Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
+ *  PM functions:
+ *             Ursula Braun <ursula.braun@de.ibm.com>
  */
 
 #define KMSG_COMPONENT "af_iucv"
@@ -90,6 +91,122 @@ static inline void low_nmcpy(unsigned char *dst, char *src)
        memcpy(&dst[8], src, 8);
 }
 
+static int afiucv_pm_prepare(struct device *dev)
+{
+#ifdef CONFIG_PM_DEBUG
+       printk(KERN_WARNING "afiucv_pm_prepare\n");
+#endif
+       return 0;
+}
+
+static void afiucv_pm_complete(struct device *dev)
+{
+#ifdef CONFIG_PM_DEBUG
+       printk(KERN_WARNING "afiucv_pm_complete\n");
+#endif
+       return;
+}
+
+/**
+ * afiucv_pm_freeze() - Freeze PM callback
+ * @dev:       AFIUCV dummy device
+ *
+ * Sever all established IUCV communication pathes
+ */
+static int afiucv_pm_freeze(struct device *dev)
+{
+       struct iucv_sock *iucv;
+       struct sock *sk;
+       struct hlist_node *node;
+       int err = 0;
+
+#ifdef CONFIG_PM_DEBUG
+       printk(KERN_WARNING "afiucv_pm_freeze\n");
+#endif
+       read_lock(&iucv_sk_list.lock);
+       sk_for_each(sk, node, &iucv_sk_list.head) {
+               iucv = iucv_sk(sk);
+               skb_queue_purge(&iucv->send_skb_q);
+               skb_queue_purge(&iucv->backlog_skb_q);
+               switch (sk->sk_state) {
+               case IUCV_SEVERED:
+               case IUCV_DISCONN:
+               case IUCV_CLOSING:
+               case IUCV_CONNECTED:
+                       if (iucv->path) {
+                               err = iucv_path_sever(iucv->path, NULL);
+                               iucv_path_free(iucv->path);
+                               iucv->path = NULL;
+                       }
+                       break;
+               case IUCV_OPEN:
+               case IUCV_BOUND:
+               case IUCV_LISTEN:
+               case IUCV_CLOSED:
+               default:
+                       break;
+               }
+       }
+       read_unlock(&iucv_sk_list.lock);
+       return err;
+}
+
+/**
+ * afiucv_pm_restore_thaw() - Thaw and restore PM callback
+ * @dev:       AFIUCV dummy device
+ *
+ * socket clean up after freeze
+ */
+static int afiucv_pm_restore_thaw(struct device *dev)
+{
+       struct iucv_sock *iucv;
+       struct sock *sk;
+       struct hlist_node *node;
+
+#ifdef CONFIG_PM_DEBUG
+       printk(KERN_WARNING "afiucv_pm_restore_thaw\n");
+#endif
+       read_lock(&iucv_sk_list.lock);
+       sk_for_each(sk, node, &iucv_sk_list.head) {
+               iucv = iucv_sk(sk);
+               switch (sk->sk_state) {
+               case IUCV_CONNECTED:
+                       sk->sk_err = EPIPE;
+                       sk->sk_state = IUCV_DISCONN;
+                       sk->sk_state_change(sk);
+                       break;
+               case IUCV_DISCONN:
+               case IUCV_SEVERED:
+               case IUCV_CLOSING:
+               case IUCV_LISTEN:
+               case IUCV_BOUND:
+               case IUCV_OPEN:
+               default:
+                       break;
+               }
+       }
+       read_unlock(&iucv_sk_list.lock);
+       return 0;
+}
+
+static struct dev_pm_ops afiucv_pm_ops = {
+       .prepare = afiucv_pm_prepare,
+       .complete = afiucv_pm_complete,
+       .freeze = afiucv_pm_freeze,
+       .thaw = afiucv_pm_restore_thaw,
+       .restore = afiucv_pm_restore_thaw,
+};
+
+static struct device_driver af_iucv_driver = {
+       .owner = THIS_MODULE,
+       .name = "afiucv",
+       .bus  = &iucv_bus,
+       .pm   = &afiucv_pm_ops,
+};
+
+/* dummy device used as trigger for PM functions */
+static struct device *af_iucv_dev;
+
 /**
  * iucv_msg_length() - Returns the length of an iucv message.
  * @msg:       Pointer to struct iucv_message, MUST NOT be NULL
@@ -1556,8 +1673,30 @@ static int __init afiucv_init(void)
        err = sock_register(&iucv_sock_family_ops);
        if (err)
                goto out_proto;
+       /* establish dummy device */
+       err = driver_register(&af_iucv_driver);
+       if (err)
+               goto out_sock;
+       af_iucv_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+       if (!af_iucv_dev) {
+               err = -ENOMEM;
+               goto out_driver;
+       }
+       dev_set_name(af_iucv_dev, "af_iucv");
+       af_iucv_dev->bus = &iucv_bus;
+       af_iucv_dev->parent = iucv_root;
+       af_iucv_dev->release = (void (*)(struct device *))kfree;
+       af_iucv_dev->driver = &af_iucv_driver;
+       err = device_register(af_iucv_dev);
+       if (err)
+               goto out_driver;
+
        return 0;
 
+out_driver:
+       driver_unregister(&af_iucv_driver);
+out_sock:
+       sock_unregister(PF_IUCV);
 out_proto:
        proto_unregister(&iucv_proto);
 out_iucv:
@@ -1568,6 +1707,8 @@ out:
 
 static void __exit afiucv_exit(void)
 {
+       device_unregister(af_iucv_dev);
+       driver_unregister(&af_iucv_driver);
        sock_unregister(PF_IUCV);
        proto_unregister(&iucv_proto);
        iucv_unregister(&af_iucv_handler, 0);
index 61e8038a55ee300d3875ffcf01532624bc691dd6..c833481d32e383439b98504e84a68250d4f9c98e 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * IUCV base infrastructure.
  *
- * Copyright 2001, 2006 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright IBM Corp. 2001, 2009
+ *
  * Author(s):
  *    Original source:
  *     Alan Altmark (Alan_Altmark@us.ibm.com)  Sept. 2000
@@ -10,6 +11,8 @@
  *     Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
  *    Rewritten for af_iucv:
  *     Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *    PM functions:
+ *     Ursula Braun (ursula.braun@de.ibm.com)
  *
  * Documentation used:
  *    The original source
@@ -45,6 +48,7 @@
 #include <linux/err.h>
 #include <linux/device.h>
 #include <linux/cpu.h>
+#include <linux/reboot.h>
 #include <net/iucv/iucv.h>
 #include <asm/atomic.h>
 #include <asm/ebcdic.h>
@@ -75,9 +79,24 @@ static int iucv_bus_match(struct device *dev, struct device_driver *drv)
        return 0;
 }
 
+static int iucv_pm_prepare(struct device *);
+static void iucv_pm_complete(struct device *);
+static int iucv_pm_freeze(struct device *);
+static int iucv_pm_thaw(struct device *);
+static int iucv_pm_restore(struct device *);
+
+static struct dev_pm_ops iucv_pm_ops = {
+       .prepare = iucv_pm_prepare,
+       .complete = iucv_pm_complete,
+       .freeze = iucv_pm_freeze,
+       .thaw = iucv_pm_thaw,
+       .restore = iucv_pm_restore,
+};
+
 struct bus_type iucv_bus = {
        .name = "iucv",
        .match = iucv_bus_match,
+       .pm = &iucv_pm_ops,
 };
 EXPORT_SYMBOL(iucv_bus);
 
@@ -147,6 +166,7 @@ enum iucv_command_codes {
        IUCV_RESUME = 14,
        IUCV_SEVER = 15,
        IUCV_SETMASK = 16,
+       IUCV_SETCONTROLMASK = 17,
 };
 
 /*
@@ -364,6 +384,18 @@ static void iucv_allow_cpu(void *data)
        parm->set_mask.ipmask = 0xf8;
        iucv_call_b2f0(IUCV_SETMASK, parm);
 
+       /*
+        * Enable all iucv control interrupts.
+        * ipmask contains bits for the different interrupts
+        *      0x80 - Flag to allow pending connections interrupts
+        *      0x40 - Flag to allow connection complete interrupts
+        *      0x20 - Flag to allow connection severed interrupts
+        *      0x10 - Flag to allow connection quiesced interrupts
+        *      0x08 - Flag to allow connection resumed interrupts
+        */
+       memset(parm, 0, sizeof(union iucv_param));
+       parm->set_mask.ipmask = 0xf8;
+       iucv_call_b2f0(IUCV_SETCONTROLMASK, parm);
        /* Set indication that iucv interrupts are allowed for this cpu. */
        cpu_set(cpu, iucv_irq_cpumask);
 }
@@ -388,6 +420,31 @@ static void iucv_block_cpu(void *data)
        cpu_clear(cpu, iucv_irq_cpumask);
 }
 
+/**
+ * iucv_block_cpu_almost
+ * @data: unused
+ *
+ * Allow connection-severed interrupts only on this cpu.
+ */
+static void iucv_block_cpu_almost(void *data)
+{
+       int cpu = smp_processor_id();
+       union iucv_param *parm;
+
+       /* Allow iucv control interrupts only */
+       parm = iucv_param_irq[cpu];
+       memset(parm, 0, sizeof(union iucv_param));
+       parm->set_mask.ipmask = 0x08;
+       iucv_call_b2f0(IUCV_SETMASK, parm);
+       /* Allow iucv-severed interrupt only */
+       memset(parm, 0, sizeof(union iucv_param));
+       parm->set_mask.ipmask = 0x20;
+       iucv_call_b2f0(IUCV_SETCONTROLMASK, parm);
+
+       /* Clear indication that iucv interrupts are allowed for this cpu. */
+       cpu_clear(cpu, iucv_irq_cpumask);
+}
+
 /**
  * iucv_declare_cpu
  * @data: unused
@@ -758,6 +815,28 @@ void iucv_unregister(struct iucv_handler *handler, int smp)
 }
 EXPORT_SYMBOL(iucv_unregister);
 
+static int iucv_reboot_event(struct notifier_block *this,
+                            unsigned long event, void *ptr)
+{
+       int i, rc;
+
+       get_online_cpus();
+       on_each_cpu(iucv_block_cpu, NULL, 1);
+       preempt_disable();
+       for (i = 0; i < iucv_max_pathid; i++) {
+               if (iucv_path_table[i])
+                       rc = iucv_sever_pathid(i, NULL);
+       }
+       preempt_enable();
+       put_online_cpus();
+       iucv_disable();
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block iucv_reboot_notifier = {
+       .notifier_call = iucv_reboot_event,
+};
+
 /**
  * iucv_path_accept
  * @path: address of iucv path structure
@@ -777,6 +856,10 @@ int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler,
        int rc;
 
        local_bh_disable();
+       if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
+               rc = -EIO;
+               goto out;
+       }
        /* Prepare parameter block. */
        parm = iucv_param[smp_processor_id()];
        memset(parm, 0, sizeof(union iucv_param));
@@ -792,6 +875,7 @@ int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler,
                path->msglim = parm->ctrl.ipmsglim;
                path->flags = parm->ctrl.ipflags1;
        }
+out:
        local_bh_enable();
        return rc;
 }
@@ -821,6 +905,10 @@ int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler,
 
        spin_lock_bh(&iucv_table_lock);
        iucv_cleanup_queue();
+       if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
+               rc = -EIO;
+               goto out;
+       }
        parm = iucv_param[smp_processor_id()];
        memset(parm, 0, sizeof(union iucv_param));
        parm->ctrl.ipmsglim = path->msglim;
@@ -855,6 +943,7 @@ int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler,
                        rc = -EIO;
                }
        }
+out:
        spin_unlock_bh(&iucv_table_lock);
        return rc;
 }
@@ -876,12 +965,17 @@ int iucv_path_quiesce(struct iucv_path *path, u8 userdata[16])
        int rc;
 
        local_bh_disable();
+       if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
+               rc = -EIO;
+               goto out;
+       }
        parm = iucv_param[smp_processor_id()];
        memset(parm, 0, sizeof(union iucv_param));
        if (userdata)
                memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser));
        parm->ctrl.ippathid = path->pathid;
        rc = iucv_call_b2f0(IUCV_QUIESCE, parm);
+out:
        local_bh_enable();
        return rc;
 }
@@ -903,12 +997,17 @@ int iucv_path_resume(struct iucv_path *path, u8 userdata[16])
        int rc;
 
        local_bh_disable();
+       if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
+               rc = -EIO;
+               goto out;
+       }
        parm = iucv_param[smp_processor_id()];
        memset(parm, 0, sizeof(union iucv_param));
        if (userdata)
                memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser));
        parm->ctrl.ippathid = path->pathid;
        rc = iucv_call_b2f0(IUCV_RESUME, parm);
+out:
        local_bh_enable();
        return rc;
 }
@@ -927,6 +1026,10 @@ int iucv_path_sever(struct iucv_path *path, u8 userdata[16])
        int rc;
 
        preempt_disable();
+       if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
+               rc = -EIO;
+               goto out;
+       }
        if (iucv_active_cpu != smp_processor_id())
                spin_lock_bh(&iucv_table_lock);
        rc = iucv_sever_pathid(path->pathid, userdata);
@@ -934,6 +1037,7 @@ int iucv_path_sever(struct iucv_path *path, u8 userdata[16])
        list_del_init(&path->list);
        if (iucv_active_cpu != smp_processor_id())
                spin_unlock_bh(&iucv_table_lock);
+out:
        preempt_enable();
        return rc;
 }
@@ -956,6 +1060,10 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg,
        int rc;
 
        local_bh_disable();
+       if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
+               rc = -EIO;
+               goto out;
+       }
        parm = iucv_param[smp_processor_id()];
        memset(parm, 0, sizeof(union iucv_param));
        parm->purge.ippathid = path->pathid;
@@ -967,6 +1075,7 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg,
                msg->audit = (*(u32 *) &parm->purge.ipaudit) >> 8;
                msg->tag = parm->purge.ipmsgtag;
        }
+out:
        local_bh_enable();
        return rc;
 }
@@ -1043,6 +1152,10 @@ int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
        if (msg->flags & IUCV_IPRMDATA)
                return iucv_message_receive_iprmdata(path, msg, flags,
                                                     buffer, size, residual);
+       if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
+               rc = -EIO;
+               goto out;
+       }
        parm = iucv_param[smp_processor_id()];
        memset(parm, 0, sizeof(union iucv_param));
        parm->db.ipbfadr1 = (u32)(addr_t) buffer;
@@ -1058,6 +1171,7 @@ int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
                if (residual)
                        *residual = parm->db.ipbfln1f;
        }
+out:
        return rc;
 }
 EXPORT_SYMBOL(__iucv_message_receive);
@@ -1111,6 +1225,10 @@ int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg)
        int rc;
 
        local_bh_disable();
+       if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
+               rc = -EIO;
+               goto out;
+       }
        parm = iucv_param[smp_processor_id()];
        memset(parm, 0, sizeof(union iucv_param));
        parm->db.ippathid = path->pathid;
@@ -1118,6 +1236,7 @@ int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg)
        parm->db.iptrgcls = msg->class;
        parm->db.ipflags1 = (IUCV_IPTRGCLS | IUCV_IPFGMID | IUCV_IPFGPID);
        rc = iucv_call_b2f0(IUCV_REJECT, parm);
+out:
        local_bh_enable();
        return rc;
 }
@@ -1145,6 +1264,10 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg,
        int rc;
 
        local_bh_disable();
+       if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
+               rc = -EIO;
+               goto out;
+       }
        parm = iucv_param[smp_processor_id()];
        memset(parm, 0, sizeof(union iucv_param));
        if (flags & IUCV_IPRMDATA) {
@@ -1162,6 +1285,7 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg,
                parm->db.iptrgcls = msg->class;
        }
        rc = iucv_call_b2f0(IUCV_REPLY, parm);
+out:
        local_bh_enable();
        return rc;
 }
@@ -1190,6 +1314,10 @@ int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
        union iucv_param *parm;
        int rc;
 
+       if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
+               rc = -EIO;
+               goto out;
+       }
        parm = iucv_param[smp_processor_id()];
        memset(parm, 0, sizeof(union iucv_param));
        if (flags & IUCV_IPRMDATA) {
@@ -1212,6 +1340,7 @@ int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
        rc = iucv_call_b2f0(IUCV_SEND, parm);
        if (!rc)
                msg->id = parm->db.ipmsgid;
+out:
        return rc;
 }
 EXPORT_SYMBOL(__iucv_message_send);
@@ -1272,6 +1401,10 @@ int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg,
        int rc;
 
        local_bh_disable();
+       if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
+               rc = -EIO;
+               goto out;
+       }
        parm = iucv_param[smp_processor_id()];
        memset(parm, 0, sizeof(union iucv_param));
        if (flags & IUCV_IPRMDATA) {
@@ -1297,6 +1430,7 @@ int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg,
        rc = iucv_call_b2f0(IUCV_SEND, parm);
        if (!rc)
                msg->id = parm->db.ipmsgid;
+out:
        local_bh_enable();
        return rc;
 }
@@ -1687,6 +1821,130 @@ static void iucv_external_interrupt(u16 code)
        spin_unlock(&iucv_queue_lock);
 }
 
+static int iucv_pm_prepare(struct device *dev)
+{
+       int rc = 0;
+
+#ifdef CONFIG_PM_DEBUG
+       printk(KERN_INFO "iucv_pm_prepare\n");
+#endif
+       if (dev->driver && dev->driver->pm && dev->driver->pm->prepare)
+               rc = dev->driver->pm->prepare(dev);
+       return rc;
+}
+
+static void iucv_pm_complete(struct device *dev)
+{
+#ifdef CONFIG_PM_DEBUG
+       printk(KERN_INFO "iucv_pm_complete\n");
+#endif
+       if (dev->driver && dev->driver->pm && dev->driver->pm->complete)
+               dev->driver->pm->complete(dev);
+}
+
+/**
+ * iucv_path_table_empty() - determine if iucv path table is empty
+ *
+ * Returns 0 if there are still iucv pathes defined
+ *        1 if there are no iucv pathes defined
+ */
+int iucv_path_table_empty(void)
+{
+       int i;
+
+       for (i = 0; i < iucv_max_pathid; i++) {
+               if (iucv_path_table[i])
+                       return 0;
+       }
+       return 1;
+}
+
+/**
+ * iucv_pm_freeze() - Freeze PM callback
+ * @dev:       iucv-based device
+ *
+ * disable iucv interrupts
+ * invoke callback function of the iucv-based driver
+ * shut down iucv, if no iucv-pathes are established anymore
+ */
+static int iucv_pm_freeze(struct device *dev)
+{
+       int cpu;
+       int rc = 0;
+
+#ifdef CONFIG_PM_DEBUG
+       printk(KERN_WARNING "iucv_pm_freeze\n");
+#endif
+       for_each_cpu_mask_nr(cpu, iucv_irq_cpumask)
+               smp_call_function_single(cpu, iucv_block_cpu_almost, NULL, 1);
+       if (dev->driver && dev->driver->pm && dev->driver->pm->freeze)
+               rc = dev->driver->pm->freeze(dev);
+       if (iucv_path_table_empty())
+               iucv_disable();
+       return rc;
+}
+
+/**
+ * iucv_pm_thaw() - Thaw PM callback
+ * @dev:       iucv-based device
+ *
+ * make iucv ready for use again: allocate path table, declare interrupt buffers
+ *                               and enable iucv interrupts
+ * invoke callback function of the iucv-based driver
+ */
+static int iucv_pm_thaw(struct device *dev)
+{
+       int rc = 0;
+
+#ifdef CONFIG_PM_DEBUG
+       printk(KERN_WARNING "iucv_pm_thaw\n");
+#endif
+       if (!iucv_path_table) {
+               rc = iucv_enable();
+               if (rc)
+                       goto out;
+       }
+       if (cpus_empty(iucv_irq_cpumask)) {
+               if (iucv_nonsmp_handler)
+                       /* enable interrupts on one cpu */
+                       iucv_allow_cpu(NULL);
+               else
+                       /* enable interrupts on all cpus */
+                       iucv_setmask_mp();
+       }
+       if (dev->driver && dev->driver->pm && dev->driver->pm->thaw)
+               rc = dev->driver->pm->thaw(dev);
+out:
+       return rc;
+}
+
+/**
+ * iucv_pm_restore() - Restore PM callback
+ * @dev:       iucv-based device
+ *
+ * make iucv ready for use again: allocate path table, declare interrupt buffers
+ *                               and enable iucv interrupts
+ * invoke callback function of the iucv-based driver
+ */
+static int iucv_pm_restore(struct device *dev)
+{
+       int rc = 0;
+
+#ifdef CONFIG_PM_DEBUG
+       printk(KERN_WARNING "iucv_pm_restore %p\n", iucv_path_table);
+#endif
+       if (cpus_empty(iucv_irq_cpumask)) {
+               rc = iucv_query_maxconn();
+               rc = iucv_enable();
+               if (rc)
+                       goto out;
+       }
+       if (dev->driver && dev->driver->pm && dev->driver->pm->restore)
+               rc = dev->driver->pm->restore(dev);
+out:
+       return rc;
+}
+
 /**
  * iucv_init
  *
@@ -1740,15 +1998,20 @@ static int __init iucv_init(void)
        rc = register_hotcpu_notifier(&iucv_cpu_notifier);
        if (rc)
                goto out_free;
+       rc = register_reboot_notifier(&iucv_reboot_notifier);
+       if (rc)
+               goto out_cpu;
        ASCEBC(iucv_error_no_listener, 16);
        ASCEBC(iucv_error_no_memory, 16);
        ASCEBC(iucv_error_pathid, 16);
        iucv_available = 1;
        rc = bus_register(&iucv_bus);
        if (rc)
-               goto out_cpu;
+               goto out_reboot;
        return 0;
 
+out_reboot:
+       unregister_reboot_notifier(&iucv_reboot_notifier);
 out_cpu:
        unregister_hotcpu_notifier(&iucv_cpu_notifier);
 out_free:
@@ -1783,6 +2046,7 @@ static void __exit iucv_exit(void)
        list_for_each_entry_safe(p, n, &iucv_work_queue, list)
                kfree(p);
        spin_unlock_irq(&iucv_queue_lock);
+       unregister_reboot_notifier(&iucv_reboot_notifier);
        unregister_hotcpu_notifier(&iucv_cpu_notifier);
        for_each_possible_cpu(cpu) {
                kfree(iucv_param_irq[cpu]);
index 67e38a056240df73712c56a0ba81ddc5a645626b..9f1ce841a0bbcd348e83c7ad518649079e95c357 100644 (file)
@@ -444,6 +444,11 @@ int rxrpc_connect_call(struct rxrpc_sock *rx,
                        conn = list_entry(bundle->avail_conns.next,
                                          struct rxrpc_connection,
                                          bundle_link);
+                       if (conn->state >= RXRPC_CONN_REMOTELY_ABORTED) {
+                               list_del_init(&conn->bundle_link);
+                               bundle->num_conns--;
+                               continue;
+                       }
                        if (--conn->avail_calls == 0)
                                list_move(&conn->bundle_link,
                                          &bundle->busy_conns);
@@ -461,6 +466,11 @@ int rxrpc_connect_call(struct rxrpc_sock *rx,
                        conn = list_entry(bundle->unused_conns.next,
                                          struct rxrpc_connection,
                                          bundle_link);
+                       if (conn->state >= RXRPC_CONN_REMOTELY_ABORTED) {
+                               list_del_init(&conn->bundle_link);
+                               bundle->num_conns--;
+                               continue;
+                       }
                        ASSERTCMP(conn->avail_calls, ==, RXRPC_MAXCALLS);
                        conn->avail_calls = RXRPC_MAXCALLS - 1;
                        ASSERT(conn->channels[0] == NULL &&
index dc5cb1e19509e4d8d71bb8ad726dc493ddda3ad4..0505cdc4d6d4d5b3b299812fdc8490911a687a9d 100644 (file)
@@ -150,11 +150,15 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
        u32 serial;
        int loop, ret;
 
-       if (conn->state >= RXRPC_CONN_REMOTELY_ABORTED)
+       if (conn->state >= RXRPC_CONN_REMOTELY_ABORTED) {
+               kleave(" = -ECONNABORTED [%u]", conn->state);
                return -ECONNABORTED;
+       }
 
        serial = ntohl(sp->hdr.serial);
 
+       _enter("{%d},{%u,%%%u},", conn->debug_id, sp->hdr.type, serial);
+
        switch (sp->hdr.type) {
        case RXRPC_PACKET_TYPE_ABORT:
                if (skb_copy_bits(skb, 0, &tmp, sizeof(tmp)) < 0)
@@ -199,6 +203,7 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
                return 0;
 
        default:
+               _leave(" = -EPROTO [%u]", sp->hdr.type);
                return -EPROTO;
        }
 }
index 8847add6ca164a7aea722b96978c44abb5ba7158..5ed8931dfe98f8af810a28a046f9c6729f07e6a3 100644 (file)
@@ -124,7 +124,7 @@ svc_pool_map_choose_mode(void)
 {
        unsigned int node;
 
-       if (num_online_nodes() > 1) {
+       if (nr_online_nodes > 1) {
                /*
                 * Actually have multiple NUMA nodes,
                 * so split pools on NUMA node boundaries
index b75d28cba3f75fef74d90d01b2fb8990984a1c55..428b065ba6959791e4f7ab4c180a914c9e3ba917 100644 (file)
@@ -26,7 +26,8 @@ config SAMPLE_TRACE_EVENTS
          This build trace event example modules.
 
 config SAMPLE_KOBJECT
-       tristate "Build kobject examples"
+       tristate "Build kobject examples -- loadable modules only"
+       depends on m
        help
          This config option will allow you to build a number of
          different kobject sample modules showing how to use kobjects,
diff --git a/samples/firmware_class/firmware_sample_driver.c b/samples/firmware_class/firmware_sample_driver.c
deleted file mode 100644 (file)
index 219a298..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * firmware_sample_driver.c -
- *
- * Copyright (c) 2003 Manuel Estrada Sainz
- *
- * Sample code on how to use request_firmware() from drivers.
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/string.h>
-#include <linux/firmware.h>
-
-static struct device ghost_device = {
-       .bus_id    = "ghost0",
-};
-
-
-static void sample_firmware_load(char *firmware, int size)
-{
-       u8 buf[size+1];
-       memcpy(buf, firmware, size);
-       buf[size] = '\0';
-       printk(KERN_INFO "firmware_sample_driver: firmware: %s\n", buf);
-}
-
-static void sample_probe_default(void)
-{
-       /* uses the default method to get the firmware */
-       const struct firmware *fw_entry;
-       int retval;
-
-       printk(KERN_INFO "firmware_sample_driver: "
-               "a ghost device got inserted :)\n");
-
-       retval = request_firmware(&fw_entry, "sample_driver_fw", &ghost_device);
-       if (retval) {
-               printk(KERN_ERR
-                      "firmware_sample_driver: Firmware not available\n");
-               return;
-       }
-
-       sample_firmware_load(fw_entry->data, fw_entry->size);
-
-       release_firmware(fw_entry);
-
-       /* finish setting up the device */
-}
-
-static void sample_probe_specific(void)
-{
-       int retval;
-       /* Uses some specific hotplug support to get the firmware from
-        * userspace  directly into the hardware, or via some sysfs file */
-
-       /* NOTE: This currently doesn't work */
-
-       printk(KERN_INFO "firmware_sample_driver: "
-               "a ghost device got inserted :)\n");
-
-       retval = request_firmware(NULL, "sample_driver_fw", &ghost_device);
-       if (retval) {
-               printk(KERN_ERR
-                      "firmware_sample_driver: Firmware load failed\n");
-               return;
-       }
-
-       /* request_firmware blocks until userspace finished, so at
-        * this point the firmware should be already in the device */
-
-       /* finish setting up the device */
-}
-
-static void sample_probe_async_cont(const struct firmware *fw, void *context)
-{
-       if (!fw) {
-               printk(KERN_ERR
-                      "firmware_sample_driver: firmware load failed\n");
-               return;
-       }
-
-       printk(KERN_INFO "firmware_sample_driver: device pointer \"%s\"\n",
-              (char *)context);
-       sample_firmware_load(fw->data, fw->size);
-}
-
-static void sample_probe_async(void)
-{
-       /* Let's say that I can't sleep */
-       int error;
-       error = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG,
-                                       "sample_driver_fw", &ghost_device,
-                                       "my device pointer",
-                                       sample_probe_async_cont);
-       if (error)
-               printk(KERN_ERR "firmware_sample_driver:"
-                      " request_firmware_nowait failed\n");
-}
-
-static int __init sample_init(void)
-{
-       device_initialize(&ghost_device);
-       /* since there is no real hardware insertion I just call the
-        * sample probe functions here */
-       sample_probe_specific();
-       sample_probe_default();
-       sample_probe_async();
-       return 0;
-}
-
-static void __exit sample_exit(void)
-{
-}
-
-module_init(sample_init);
-module_exit(sample_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/samples/firmware_class/firmware_sample_firmware_class.c b/samples/firmware_class/firmware_sample_firmware_class.c
deleted file mode 100644 (file)
index e6cf7a4..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * firmware_sample_firmware_class.c -
- *
- * Copyright (c) 2003 Manuel Estrada Sainz
- *
- * NOTE: This is just a probe of concept, if you think that your driver would
- * be well served by this mechanism please contact me first.
- *
- * DON'T USE THIS CODE AS IS
- *
- */
-
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/firmware.h>
-
-
-MODULE_AUTHOR("Manuel Estrada Sainz");
-MODULE_DESCRIPTION("Hackish sample for using firmware class directly");
-MODULE_LICENSE("GPL");
-
-static inline struct class_device *to_class_dev(struct kobject *obj)
-{
-       return container_of(obj, struct class_device, kobj);
-}
-
-static inline
-struct class_device_attribute *to_class_dev_attr(struct attribute *_attr)
-{
-       return container_of(_attr, struct class_device_attribute, attr);
-}
-
-struct firmware_priv {
-       char fw_id[FIRMWARE_NAME_MAX];
-       s32 loading:2;
-       u32 abort:1;
-};
-
-static ssize_t firmware_loading_show(struct class_device *class_dev, char *buf)
-{
-       struct firmware_priv *fw_priv = class_get_devdata(class_dev);
-       return sprintf(buf, "%d\n", fw_priv->loading);
-}
-
-static ssize_t firmware_loading_store(struct class_device *class_dev,
-                                     const char *buf, size_t count)
-{
-       struct firmware_priv *fw_priv = class_get_devdata(class_dev);
-       int prev_loading = fw_priv->loading;
-
-       fw_priv->loading = simple_strtol(buf, NULL, 10);
-
-       switch (fw_priv->loading) {
-       case -1:
-               /* abort load an panic */
-               break;
-       case 1:
-               /* setup load */
-               break;
-       case 0:
-               if (prev_loading == 1) {
-                       /* finish load and get the device back to working
-                        * state */
-               }
-               break;
-       }
-
-       return count;
-}
-static CLASS_DEVICE_ATTR(loading, 0644,
-                        firmware_loading_show, firmware_loading_store);
-
-static ssize_t firmware_data_read(struct kobject *kobj,
-                                 struct bin_attribute *bin_attr,
-                                 char *buffer, loff_t offset, size_t count)
-{
-       struct class_device *class_dev = to_class_dev(kobj);
-       struct firmware_priv *fw_priv = class_get_devdata(class_dev);
-
-       /* read from the devices firmware memory */
-
-       return count;
-}
-static ssize_t firmware_data_write(struct kobject *kobj,
-                                  struct bin_attribute *bin_attr,
-                                  char *buffer, loff_t offset, size_t count)
-{
-       struct class_device *class_dev = to_class_dev(kobj);
-       struct firmware_priv *fw_priv = class_get_devdata(class_dev);
-
-       /* write to the devices firmware memory */
-
-       return count;
-}
-static struct bin_attribute firmware_attr_data = {
-       .attr = {.name = "data", .mode = 0644},
-       .size = 0,
-       .read = firmware_data_read,
-       .write = firmware_data_write,
-};
-static int fw_setup_class_device(struct class_device *class_dev,
-                                const char *fw_name,
-                                struct device *device)
-{
-       int retval;
-       struct firmware_priv *fw_priv;
-
-       fw_priv = kzalloc(sizeof(struct firmware_priv), GFP_KERNEL);
-       if (!fw_priv) {
-               retval = -ENOMEM;
-               goto out;
-       }
-
-       memset(class_dev, 0, sizeof(*class_dev));
-
-       strncpy(fw_priv->fw_id, fw_name, FIRMWARE_NAME_MAX);
-       fw_priv->fw_id[FIRMWARE_NAME_MAX-1] = '\0';
-
-       strncpy(class_dev->class_id, device->bus_id, BUS_ID_SIZE);
-       class_dev->class_id[BUS_ID_SIZE-1] = '\0';
-       class_dev->dev = device;
-
-       class_dev->class = &firmware_class;
-       class_set_devdata(class_dev, fw_priv);
-       retval = class_device_register(class_dev);
-       if (retval) {
-               printk(KERN_ERR "%s: class_device_register failed\n",
-                      __func__);
-               goto error_free_fw_priv;
-       }
-
-       retval = sysfs_create_bin_file(&class_dev->kobj, &firmware_attr_data);
-       if (retval) {
-               printk(KERN_ERR "%s: sysfs_create_bin_file failed\n",
-                      __func__);
-               goto error_unreg_class_dev;
-       }
-
-       retval = class_device_create_file(class_dev,
-                                         &class_device_attr_loading);
-       if (retval) {
-               printk(KERN_ERR "%s: class_device_create_file failed\n",
-                      __func__);
-               goto error_remove_data;
-       }
-
-       goto out;
-
-error_remove_data:
-       sysfs_remove_bin_file(&class_dev->kobj, &firmware_attr_data);
-error_unreg_class_dev:
-       class_device_unregister(class_dev);
-error_free_fw_priv:
-       kfree(fw_priv);
-out:
-       return retval;
-}
-static void fw_remove_class_device(struct class_device *class_dev)
-{
-       struct firmware_priv *fw_priv = class_get_devdata(class_dev);
-
-       class_device_remove_file(class_dev, &class_device_attr_loading);
-       sysfs_remove_bin_file(&class_dev->kobj, &firmware_attr_data);
-       class_device_unregister(class_dev);
-}
-
-static struct class_device *class_dev;
-
-static struct device my_device = {
-       .bus_id    = "my_dev0",
-};
-
-static int __init firmware_sample_init(void)
-{
-       int error;
-
-       device_initialize(&my_device);
-       class_dev = kmalloc(sizeof(struct class_device), GFP_KERNEL);
-       if (!class_dev)
-               return -ENOMEM;
-
-       error = fw_setup_class_device(class_dev, "my_firmware_image",
-                                     &my_device);
-       if (error) {
-               kfree(class_dev);
-               return error;
-       }
-       return 0;
-
-}
-static void __exit firmware_sample_exit(void)
-{
-       struct firmware_priv *fw_priv = class_get_devdata(class_dev);
-       fw_remove_class_device(class_dev);
-       kfree(fw_priv);
-       kfree(class_dev);
-}
-
-module_init(firmware_sample_init);
-module_exit(firmware_sample_exit);
index 60dc0c48c929b15953a751a1875c1aebd767e80e..3e733146cd51c01acd792503162cc43e4b7a3d74 100755 (executable)
@@ -13,7 +13,7 @@
 use strict;
 
 my $P = $0;
-my $V = '0.15';
+my $V = '0.16';
 
 use Getopt::Long qw(:config no_auto_abbrev);
 
@@ -55,6 +55,10 @@ foreach my $chief (@penguin_chief) {
 }
 my $penguin_chiefs = "\(" . join("|",@penguin_chief_names) . "\)";
 
+# rfc822 email address - preloaded methods go here.
+my $rfc822_lwsp = "(?:(?:\\r\\n)?[ \\t])";
+my $rfc822_char = '[\\000-\\377]';
+
 if (!GetOptions(
                'email!' => \$email,
                'git!' => \$email_git,
@@ -161,7 +165,7 @@ foreach my $file (@ARGV) {
        }
        close(PATCH);
        if ($file_cnt == @files) {
-           die "$P: file '${file}' doesn't appear to be a patch.  "
+           warn "$P: file '${file}' doesn't appear to be a patch.  "
                . "Add -f to options?\n";
        }
        @files = sort_and_uniq(@files);
@@ -169,6 +173,7 @@ foreach my $file (@ARGV) {
 }
 
 my @email_to = ();
+my @list_to = ();
 my @scm = ();
 my @web = ();
 my @subsystem = ();
@@ -182,7 +187,7 @@ foreach my $file (@files) {
 
     my $exclude = 0;
     foreach my $line (@typevalue) {
-       if ($line =~ m/^(\C):(.*)/) {
+       if ($line =~ m/^(\C):\s*(.*)/) {
            my $type = $1;
            my $value = $2;
            if ($type eq 'X') {
@@ -196,7 +201,7 @@ foreach my $file (@files) {
     if (!$exclude) {
        my $tvi = 0;
        foreach my $line (@typevalue) {
-           if ($line =~ m/^(\C):(.*)/) {
+           if ($line =~ m/^(\C):\s*(.*)/) {
                my $type = $1;
                my $value = $2;
                if ($type eq 'F') {
@@ -215,29 +220,33 @@ foreach my $file (@files) {
 
 }
 
-if ($email_git_penguin_chiefs) {
+if ($email) {
     foreach my $chief (@penguin_chief) {
        if ($chief =~ m/^(.*):(.*)/) {
-           my $chief_name = $1;
-           my $chief_addr = $2;
+           my $email_address;
            if ($email_usename) {
-               push(@email_to, format_email($chief_name, $chief_addr));
+               $email_address = format_email($1, $2);
+           } else {
+               $email_address = $2;
+           }
+           if ($email_git_penguin_chiefs) {
+               push(@email_to, $email_address);
            } else {
-               push(@email_to, $chief_addr);
+               @email_to = grep(!/${email_address}/, @email_to);
            }
        }
     }
 }
 
-if ($email) {
-    my $address_cnt = @email_to;
-    if ($address_cnt == 0 && $email_list) {
-       push(@email_to, "linux-kernel\@vger.kernel.org");
+if ($email || $email_list) {
+    my @to = ();
+    if ($email) {
+       @to = (@to, @email_to);
     }
-
-#Don't sort email address list, but do remove duplicates
-    @email_to = uniq(@email_to);
-    output(@email_to);
+    if ($email_list) {
+       @to = (@to, @list_to);
+    }
+    output(uniq(@to));
 }
 
 if ($scm) {
@@ -307,10 +316,10 @@ Output type options:
   --multiline => print 1 entry per line
 
 Default options:
-  [--email --git --m --l --multiline]
+  [--email --git --m --n --l --multiline]
 
 Other options:
-  --version -> show version
+  --version => show version
   --help => show this help information
 
 EOT
@@ -347,6 +356,7 @@ sub format_email {
     my ($name, $email) = @_;
 
     $name =~ s/^\s+|\s+$//g;
+    $name =~ s/^\"|\"$//g;
     $email =~ s/^\s+|\s+$//g;
 
     my $formatted_email = "";
@@ -366,36 +376,41 @@ sub add_categories {
     $index = $index - 1;
     while ($index >= 0) {
        my $tv = $typevalue[$index];
-       if ($tv =~ m/^(\C):(.*)/) {
+       if ($tv =~ m/^(\C):\s*(.*)/) {
            my $ptype = $1;
            my $pvalue = $2;
            if ($ptype eq "L") {
-               my $subscr = $pvalue;
-               if ($subscr =~ m/\s*\(subscribers-only\)/) {
+               my $list_address = $pvalue;
+               my $list_additional = "";
+               if ($list_address =~ m/([^\s]+)\s+(.*)$/) {
+                   $list_address = $1;
+                   $list_additional = $2;
+               }
+               if ($list_additional =~ m/subscribers-only/) {
                    if ($email_subscriber_list) {
-                       $subscr =~ s/\s*\(subscribers-only\)//g;
-                       push(@email_to, $subscr);
+                       push(@list_to, $list_address);
                    }
                } else {
                    if ($email_list) {
-                       push(@email_to, $pvalue);
+                       push(@list_to, $list_address);
                    }
                }
            } elsif ($ptype eq "M") {
-               if ($email_maintainer) {
-                   if ($index >= 0) {
-                       my $tv = $typevalue[$index - 1];
-                       if ($tv =~ m/^(\C):(.*)/) {
-                           if ($1 eq "P" && $email_usename) {
-                               push(@email_to, format_email($2, $pvalue));
-                           } else {
-                               push(@email_to, $pvalue);
+               my $p_used = 0;
+               if ($index >= 0) {
+                   my $tv = $typevalue[$index - 1];
+                   if ($tv =~ m/^(\C):\s*(.*)/) {
+                       if ($1 eq "P") {
+                           if ($email_usename) {
+                               push_email_address(format_email($2, $pvalue));
+                               $p_used = 1;
                            }
                        }
-                   } else {
-                       push(@email_to, $pvalue);
                    }
                }
+               if (!$p_used) {
+                   push_email_addresses($pvalue);
+               }
            } elsif ($ptype eq "T") {
                push(@scm, $pvalue);
            } elsif ($ptype eq "W") {
@@ -412,10 +427,45 @@ sub add_categories {
     }
 }
 
+sub push_email_address {
+    my ($email_address) = @_;
+
+    my $email_name = "";
+    if ($email_address =~ m/([^<]+)<(.*\@.*)>$/) {
+       $email_name = $1;
+       $email_address = $2;
+    }
+
+    if ($email_maintainer) {
+       if ($email_usename && $email_name) {
+           push(@email_to, format_email($email_name, $email_address));
+       } else {
+           push(@email_to, $email_address);
+       }
+    }
+}
+
+sub push_email_addresses {
+    my ($address) = @_;
+
+    my @address_list = ();
+
+    if (rfc822_valid($address)) {
+       push_email_address($address);
+    } elsif (@address_list = rfc822_validlist($address)) {
+       my $array_count = shift(@address_list);
+       while (my $entry = shift(@address_list)) {
+           push_email_address($entry);
+       }
+    } else {
+       warn("Invalid MAINTAINERS address: '" . $address . "'\n");
+    }
+}
+
 sub which {
     my ($bin) = @_;
 
-    foreach my $path (split /:/, $ENV{PATH}) {
+    foreach my $path (split(/:/, $ENV{PATH})) {
        if (-e "$path/$bin") {
            return "$path/$bin";
        }
@@ -434,16 +484,21 @@ sub recent_git_signoffs {
     my @lines = ();
 
     if (which("git") eq "") {
-       die("$P: git not found.  Add --nogit to options?\n");
+       warn("$P: git not found.  Add --nogit to options?\n");
+       return;
+    }
+    if (!(-d ".git")) {
+       warn("$P: .git directory not found.  Use a git repository for better results.\n");
+       warn("$P: perhaps 'git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git'\n");
+       return;
     }
 
     $cmd = "git log --since=${email_git_since} -- ${file}";
-    $cmd .= " | grep -Pi \"^[-_        a-z]+by:.*\\\@\"";
+    $cmd .= " | grep -Ei \"^[-_        a-z]+by:.*\\\@.*\$\"";
     if (!$email_git_penguin_chiefs) {
-       $cmd .= " | grep -Pv \"${penguin_chiefs}\"";
+       $cmd .= " | grep -Ev \"${penguin_chiefs}\"";
     }
     $cmd .= " | cut -f2- -d\":\"";
-    $cmd .= " | sed -e \"s/^\\s+//g\"";
     $cmd .= " | sort | uniq -c | sort -rn";
 
     $output = `${cmd}`;
@@ -465,10 +520,6 @@ sub recent_git_signoffs {
        if ($line =~ m/(.+)<(.+)>/) {
            my $git_name = $1;
            my $git_addr = $2;
-           $git_name =~ tr/^\"//;
-           $git_name =~ tr/^\\s*//;
-           $git_name =~ tr/\"$//;
-           $git_name =~ tr/\\s*$//;
            if ($email_usename) {
                push(@email_to, format_email($git_name, $git_addr));
            } else {
@@ -481,7 +532,6 @@ sub recent_git_signoffs {
            push(@email_to, $line);
        }
     }
-    return $output;
 }
 
 sub uniq {
@@ -513,3 +563,97 @@ sub output {
        print("\n");
     }
 }
+
+my $rfc822re;
+
+sub make_rfc822re {
+#   Basic lexical tokens are specials, domain_literal, quoted_string, atom, and
+#   comment.  We must allow for rfc822_lwsp (or comments) after each of these.
+#   This regexp will only work on addresses which have had comments stripped
+#   and replaced with rfc822_lwsp.
+
+    my $specials = '()<>@,;:\\\\".\\[\\]';
+    my $controls = '\\000-\\037\\177';
+
+    my $dtext = "[^\\[\\]\\r\\\\]";
+    my $domain_literal = "\\[(?:$dtext|\\\\.)*\\]$rfc822_lwsp*";
+
+    my $quoted_string = "\"(?:[^\\\"\\r\\\\]|\\\\.|$rfc822_lwsp)*\"$rfc822_lwsp*";
+
+#   Use zero-width assertion to spot the limit of an atom.  A simple
+#   $rfc822_lwsp* causes the regexp engine to hang occasionally.
+    my $atom = "[^$specials $controls]+(?:$rfc822_lwsp+|\\Z|(?=[\\[\"$specials]))";
+    my $word = "(?:$atom|$quoted_string)";
+    my $localpart = "$word(?:\\.$rfc822_lwsp*$word)*";
+
+    my $sub_domain = "(?:$atom|$domain_literal)";
+    my $domain = "$sub_domain(?:\\.$rfc822_lwsp*$sub_domain)*";
+
+    my $addr_spec = "$localpart\@$rfc822_lwsp*$domain";
+
+    my $phrase = "$word*";
+    my $route = "(?:\@$domain(?:,\@$rfc822_lwsp*$domain)*:$rfc822_lwsp*)";
+    my $route_addr = "\\<$rfc822_lwsp*$route?$addr_spec\\>$rfc822_lwsp*";
+    my $mailbox = "(?:$addr_spec|$phrase$route_addr)";
+
+    my $group = "$phrase:$rfc822_lwsp*(?:$mailbox(?:,\\s*$mailbox)*)?;\\s*";
+    my $address = "(?:$mailbox|$group)";
+
+    return "$rfc822_lwsp*$address";
+}
+
+sub rfc822_strip_comments {
+    my $s = shift;
+#   Recursively remove comments, and replace with a single space.  The simpler
+#   regexps in the Email Addressing FAQ are imperfect - they will miss escaped
+#   chars in atoms, for example.
+
+    while ($s =~ s/^((?:[^"\\]|\\.)*
+                    (?:"(?:[^"\\]|\\.)*"(?:[^"\\]|\\.)*)*)
+                    \((?:[^()\\]|\\.)*\)/$1 /osx) {}
+    return $s;
+}
+
+#   valid: returns true if the parameter is an RFC822 valid address
+#
+sub rfc822_valid ($) {
+    my $s = rfc822_strip_comments(shift);
+
+    if (!$rfc822re) {
+        $rfc822re = make_rfc822re();
+    }
+
+    return $s =~ m/^$rfc822re$/so && $s =~ m/^$rfc822_char*$/;
+}
+
+#   validlist: In scalar context, returns true if the parameter is an RFC822
+#              valid list of addresses.
+#
+#              In list context, returns an empty list on failure (an invalid
+#              address was found); otherwise a list whose first element is the
+#              number of addresses found and whose remaining elements are the
+#              addresses.  This is needed to disambiguate failure (invalid)
+#              from success with no addresses found, because an empty string is
+#              a valid list.
+
+sub rfc822_validlist ($) {
+    my $s = rfc822_strip_comments(shift);
+
+    if (!$rfc822re) {
+        $rfc822re = make_rfc822re();
+    }
+    # * null list items are valid according to the RFC
+    # * the '1' business is to aid in distinguishing failure from no results
+
+    my @r;
+    if ($s =~ m/^(?:$rfc822re)?(?:,(?:$rfc822re)?)*$/so &&
+       $s =~ m/^$rfc822_char*$/) {
+        while ($s =~ m/(?:^|,$rfc822_lwsp*)($rfc822re)/gos) {
+            push @r, $1;
+        }
+        return wantarray ? (scalar(@r), @r) : 1;
+    }
+    else {
+        return wantarray ? () : 0;
+    }
+}
diff --git a/scripts/gfp-translate b/scripts/gfp-translate
new file mode 100644 (file)
index 0000000..073cb6d
--- /dev/null
@@ -0,0 +1,81 @@
+#!/bin/bash
+# Translate the bits making up a GFP mask
+# (c) 2009, Mel Gorman <mel@csn.ul.ie>
+# Licensed under the terms of the GNU GPL License version 2
+SOURCE=
+GFPMASK=none
+
+# Helper function to report failures and exit
+die() {
+       echo ERROR: $@
+       if [ "$TMPFILE" != "" ]; then
+               rm -f $TMPFILE
+       fi
+       exit -1
+}
+
+usage() {
+       echo "usage: gfp-translate [-h] [ --source DIRECTORY ] gfpmask"
+       exit 0
+}
+
+# Parse command-line arguements
+while [ $# -gt 0 ]; do
+       case $1 in
+               --source)
+                       SOURCE=$2
+                       shift 2
+                       ;;
+               -h)
+                       usage
+                       ;;
+               --help)
+                       usage
+                       ;;
+               *)
+                       GFPMASK=$1
+                       shift
+                       ;;
+       esac
+done
+
+# Guess the kernel source directory if it's not set. Preference is in order of
+# o current directory
+# o /usr/src/linux
+if [ "$SOURCE" = "" ]; then
+       if [ -r "/usr/src/linux/Makefile" ]; then
+               SOURCE=/usr/src/linux
+       fi
+       if [ -r "`pwd`/Makefile" ]; then
+               SOURCE=`pwd`
+       fi
+fi
+
+# Confirm that a source directory exists
+if [ ! -r "$SOURCE/Makefile" ]; then
+       die "Could not locate kernel source directory or it is invalid"
+fi
+
+# Confirm that a GFP mask has been specified
+if [ "$GFPMASK" = "none" ]; then
+       usage
+fi
+
+# Extract GFP flags from the kernel source
+TMPFILE=`mktemp -t gfptranslate-XXXXXX` || exit 1
+grep "^#define __GFP" $SOURCE/include/linux/gfp.h | sed -e 's/(__force gfp_t)//' | sed -e 's/u)/)/' | grep -v GFP_BITS | sed -e 's/)\//) \//' > $TMPFILE
+
+# Parse the flags
+IFS="
+"
+echo Source: $SOURCE
+echo Parsing: $GFPMASK
+for LINE in `cat $TMPFILE`; do
+       MASK=`echo $LINE | awk '{print $3}'`
+       if [ $(($GFPMASK&$MASK)) -ne 0 ]; then
+               echo $LINE
+       fi
+done
+
+rm -f $TMPFILE
+exit 0
index 6aa2a2483f8df04abe75421f28d8deca7cff42c3..64f5ddb09ea626de131090d68aa5aeac10de060e 100644 (file)
@@ -237,22 +237,22 @@ static void write_header(void)
     fprintf(out, " *  Linux logo %s\n", logoname);
     fputs(" */\n\n", out);
     fputs("#include <linux/linux_logo.h>\n\n", out);
-    fprintf(out, "static unsigned char %s_data[] __initdata = {\n",
+    fprintf(out, "static const unsigned char %s_data[] __initconst = {\n",
            logoname);
 }
 
 static void write_footer(void)
 {
     fputs("\n};\n\n", out);
-    fprintf(out, "struct linux_logo %s __initdata = {\n", logoname);
-    fprintf(out, "    .type\t= %s,\n", logo_types[logo_type]);
-    fprintf(out, "    .width\t= %d,\n", logo_width);
-    fprintf(out, "    .height\t= %d,\n", logo_height);
+    fprintf(out, "const struct linux_logo %s __initconst = {\n", logoname);
+    fprintf(out, "\t.type\t\t= %s,\n", logo_types[logo_type]);
+    fprintf(out, "\t.width\t\t= %d,\n", logo_width);
+    fprintf(out, "\t.height\t\t= %d,\n", logo_height);
     if (logo_type == LINUX_LOGO_CLUT224) {
-       fprintf(out, "    .clutsize\t= %d,\n", logo_clutsize);
-       fprintf(out, "    .clut\t= %s_clut,\n", logoname);
+       fprintf(out, "\t.clutsize\t= %d,\n", logo_clutsize);
+       fprintf(out, "\t.clut\t\t= %s_clut,\n", logoname);
     }
-    fprintf(out, "    .data\t= %s_data\n", logoname);
+    fprintf(out, "\t.data\t\t= %s_data\n", logoname);
     fputs("};\n\n", out);
 
     /* close logo file */
@@ -374,7 +374,7 @@ static void write_logo_clut224(void)
     fputs("\n};\n\n", out);
 
     /* write logo clut */
-    fprintf(out, "static unsigned char %s_clut[] __initdata = {\n",
+    fprintf(out, "static const unsigned char %s_clut[] __initconst = {\n",
            logoname);
     write_hex_cnt = 0;
     for (i = 0; i < logo_clutsize; i++) {
index 91033e67321e84e6479816cdff61c372f3be58d1..7109e2b5bc0acf61e39c24aff4b2074016e6078c 100755 (executable)
@@ -226,6 +226,26 @@ if ($arch eq "x86_64") {
     if ($is_module eq "0") {
         $cc .= " -mconstant-gp";
     }
+} elsif ($arch eq "sparc64") {
+    # In the objdump output there are giblets like:
+    # 0000000000000000 <igmp_net_exit-0x18>:
+    # As there's some data blobs that get emitted into the
+    # text section before the first instructions and the first
+    # real symbols.  We don't want to match that, so to combat
+    # this we use '\w' so we'll match just plain symbol names,
+    # and not those that also include hex offsets inside of the
+    # '<>' brackets.  Actually the generic function_regex setting
+    # could safely use this too.
+    $function_regex = "^([0-9a-fA-F]+)\\s+<(\\w*?)>:";
+
+    # Sparc64 calls '_mcount' instead of plain 'mcount'.
+    $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$";
+
+    $alignment = 8;
+    $type = ".xword";
+    $ld .= " -m elf64_sparc";
+    $cc .= " -m64";
+    $objcopy .= " -O elf64-sparc";
 } else {
     die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD";
 }
index 902f9a992620446ed42acf46390226f71ac22fa7..db40fa04cd513f4a68d86af935fec02f27e507d2 100644 (file)
@@ -12,10 +12,9 @@ calls. Only the functions's names and the the call time are provided.
 
 Usage:
        Be sure that you have CONFIG_FUNCTION_TRACER
-       # mkdir /debugfs
-       # mount -t debug debug /debug
-       # echo function > /debug/tracing/current_tracer
-       $ cat /debug/tracing/trace_pipe > ~/raw_trace_func
+       # mount -t debugfs nodev /sys/kernel/debug
+       # echo function > /sys/kernel/debug/tracing/current_tracer
+       $ cat /sys/kernel/debug/tracing/trace_pipe > ~/raw_trace_func
        Wait some times but not too much, the script is a bit slow.
        Break the pipe (Ctrl + Z)
        $ scripts/draw_functrace.py < raw_trace_func > draw_functrace
index cdef2664218ff7c27582d49d0a987bcc2f65d030..174dd2ff0f22ceec380458349ca099681e1d35ab 100644 (file)
@@ -10,6 +10,7 @@
 #define __PCSP_H__
 
 #include <linux/hrtimer.h>
+#include <linux/timex.h>
 #if defined(CONFIG_MIPS) || defined(CONFIG_X86)
 /* Use the global PIT lock ! */
 #include <asm/i8253.h>
index 36c3ea62086be882dbba7d630643b2f6ea110978..8f7d175767a21e75b5167bf7eb117295bef3d250 100644 (file)
@@ -17,7 +17,7 @@
 
 #include <linux/init.h>
 #include <linux/spinlock.h>
-#include <asm/timex.h>
+#include <linux/timex.h>
 #include "sound_config.h"
 
 #include "pas2.h"
index 80fb2baed7a72c52ea9330336039bfe0835c621a..b0adc8094009912d00db252f7388680299475f7e 100644 (file)
@@ -259,7 +259,6 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
        int n_amixer = apcm->substream->runtime->channels, i = 0;
        int device = apcm->substream->pcm->device;
        unsigned int pitch;
-       unsigned long flags;
 
        if (NULL != apcm->src) {
                /* Prepared pcm playback */
@@ -311,10 +310,10 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
        src = apcm->src;
        for (i = 0; i < n_amixer; i++) {
                amixer = apcm->amixers[i];
-               spin_lock_irqsave(&atc->atc_lock, flags);
+               mutex_lock(&atc->atc_mutex);
                amixer->ops->setup(amixer, &src->rsc,
                                        INIT_VOL, atc->pcm[i+device*2]);
-               spin_unlock_irqrestore(&atc->atc_lock, flags);
+               mutex_unlock(&atc->atc_mutex);
                src = src->ops->next_interleave(src);
                if (NULL == src)
                        src = apcm->src;
@@ -865,7 +864,6 @@ static int
 spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm)
 {
        struct dao *dao = container_of(atc->daios[SPDIFOO], struct dao, daio);
-       unsigned long flags;
        unsigned int rate = apcm->substream->runtime->rate;
        unsigned int status;
        int err;
@@ -885,7 +883,7 @@ spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm)
                return -ENOENT;
        }
 
-       spin_lock_irqsave(&atc->atc_lock, flags);
+       mutex_lock(&atc->atc_mutex);
        dao->ops->get_spos(dao, &status);
        if (((status >> 24) & IEC958_AES3_CON_FS) != iec958_con_fs) {
                status &= ((~IEC958_AES3_CON_FS) << 24);
@@ -895,7 +893,7 @@ spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm)
        }
        if ((rate != atc->pll_rate) && (32000 != rate))
                err = atc_pll_init(atc, rate);
-       spin_unlock_irqrestore(&atc->atc_lock, flags);
+       mutex_unlock(&atc->atc_mutex);
 
        return err;
 }
@@ -908,7 +906,6 @@ spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
        struct dao *dao;
        int err;
        int i;
-       unsigned long flags;
 
        if (NULL != apcm->src)
                return 0;
@@ -934,13 +931,13 @@ spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
                        src = apcm->src;
        }
        /* Connect to SPDIFOO */
-       spin_lock_irqsave(&atc->atc_lock, flags);
+       mutex_lock(&atc->atc_mutex);
        dao = container_of(atc->daios[SPDIFOO], struct dao, daio);
        amixer = apcm->amixers[0];
        dao->ops->set_left_input(dao, &amixer->rsc);
        amixer = apcm->amixers[1];
        dao->ops->set_right_input(dao, &amixer->rsc);
-       spin_unlock_irqrestore(&atc->atc_lock, flags);
+       mutex_unlock(&atc->atc_mutex);
 
        ct_timer_prepare(apcm->timer);
 
@@ -1088,7 +1085,6 @@ static int atc_spdif_out_set_status(struct ct_atc *atc, unsigned int status)
 
 static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state)
 {
-       unsigned long flags;
        struct dao_desc da_dsc = {0};
        struct dao *dao;
        int err;
@@ -1096,7 +1092,7 @@ static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state)
        struct rsc *rscs[2] = {NULL};
        unsigned int spos = 0;
 
-       spin_lock_irqsave(&atc->atc_lock, flags);
+       mutex_lock(&atc->atc_mutex);
        dao = container_of(atc->daios[SPDIFOO], struct dao, daio);
        da_dsc.msr = state ? 1 : atc->msr;
        da_dsc.passthru = state ? 1 : 0;
@@ -1114,7 +1110,7 @@ static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state)
        }
        dao->ops->set_spos(dao, spos);
        dao->ops->commit_write(dao);
-       spin_unlock_irqrestore(&atc->atc_lock, flags);
+       mutex_unlock(&atc->atc_mutex);
 
        return err;
 }
@@ -1572,7 +1568,7 @@ int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci,
        atc->msr = msr;
        atc->chip_type = chip_type;
 
-       spin_lock_init(&atc->atc_lock);
+       mutex_init(&atc->atc_mutex);
 
        /* Find card model */
        err = atc_identify_card(atc);
index a03347232e8453bde510dbb8d23c7bf551d1b940..9fe620ea5f3f3bc1ab38125e111c46e134fd2f34 100644 (file)
@@ -19,7 +19,7 @@
 #define CTATC_H
 
 #include <linux/types.h>
-#include <linux/spinlock_types.h>
+#include <linux/mutex.h>
 #include <linux/pci.h>
 #include <linux/timer.h>
 #include <sound/core.h>
@@ -90,7 +90,7 @@ struct ct_atc {
        void (*unmap_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
        unsigned long (*get_ptp_phys)(struct ct_atc *atc, int index);
 
-       spinlock_t atc_lock;
+       struct mutex atc_mutex;
 
        int (*pcm_playback_prepare)(struct ct_atc *atc,
                                    struct ct_atc_pcm *apcm);
index 779c6c3591a5b297180eb001f85e682779cebf29..93b0aedc36d448be8ae902c6f1e2e5213934a84c 100644 (file)
@@ -180,7 +180,7 @@ static inline unsigned int ct_xfitimer_get_wc(struct ct_timer *atimer)
  *
  * call this inside the lock and irq disabled
  */
-static int ct_xfitimer_reprogram(struct ct_timer *atimer)
+static int ct_xfitimer_reprogram(struct ct_timer *atimer, int can_update)
 {
        struct ct_timer_instance *ti;
        unsigned int min_intr = (unsigned int)-1;
@@ -216,6 +216,8 @@ static int ct_xfitimer_reprogram(struct ct_timer *atimer)
                        ti->frag_count = div_u64((u64)pos * CT_TIMER_FREQ +
                                                 rate - 1, rate);
                }
+               if (ti->need_update && !can_update)
+                       min_intr = 0; /* pending to the next irq */
                if (ti->frag_count < min_intr)
                        min_intr = ti->frag_count;
        }
@@ -235,7 +237,7 @@ static void ct_xfitimer_check_period(struct ct_timer *atimer)
 
        spin_lock_irqsave(&atimer->list_lock, flags);
        list_for_each_entry(ti, &atimer->instance_head, instance_list) {
-               if (ti->need_update) {
+               if (ti->running && ti->need_update) {
                        ti->need_update = 0;
                        ti->apcm->interrupt(ti->apcm);
                }
@@ -252,7 +254,7 @@ static void ct_xfitimer_callback(struct ct_timer *atimer)
        spin_lock_irqsave(&atimer->lock, flags);
        atimer->irq_handling = 1;
        do {
-               update = ct_xfitimer_reprogram(atimer);
+               update = ct_xfitimer_reprogram(atimer, 1);
                spin_unlock(&atimer->lock);
                if (update)
                        ct_xfitimer_check_period(atimer);
@@ -265,6 +267,7 @@ static void ct_xfitimer_callback(struct ct_timer *atimer)
 static void ct_xfitimer_prepare(struct ct_timer_instance *ti)
 {
        ti->frag_count = ti->substream->runtime->period_size;
+       ti->running = 0;
        ti->need_update = 0;
 }
 
@@ -273,7 +276,6 @@ static void ct_xfitimer_prepare(struct ct_timer_instance *ti)
 static void ct_xfitimer_update(struct ct_timer *atimer)
 {
        unsigned long flags;
-       int update;
 
        spin_lock_irqsave(&atimer->lock, flags);
        if (atimer->irq_handling) {
@@ -284,10 +286,8 @@ static void ct_xfitimer_update(struct ct_timer *atimer)
        }
 
        ct_xfitimer_irq_stop(atimer);
-       update = ct_xfitimer_reprogram(atimer);
+       ct_xfitimer_reprogram(atimer, 0);
        spin_unlock_irqrestore(&atimer->lock, flags);
-       if (update)
-               ct_xfitimer_check_period(atimer);
 }
 
 static void ct_xfitimer_start(struct ct_timer_instance *ti)
@@ -298,6 +298,8 @@ static void ct_xfitimer_start(struct ct_timer_instance *ti)
        spin_lock_irqsave(&atimer->lock, flags);
        if (list_empty(&ti->running_list))
                atimer->wc = ct_xfitimer_get_wc(atimer);
+       ti->running = 1;
+       ti->need_update = 0;
        list_add(&ti->running_list, &atimer->running_head);
        spin_unlock_irqrestore(&atimer->lock, flags);
        ct_xfitimer_update(atimer);
@@ -310,7 +312,7 @@ static void ct_xfitimer_stop(struct ct_timer_instance *ti)
 
        spin_lock_irqsave(&atimer->lock, flags);
        list_del_init(&ti->running_list);
-       ti->need_update = 0;
+       ti->running = 0;
        spin_unlock_irqrestore(&atimer->lock, flags);
        ct_xfitimer_update(atimer);
 }
index 337d2a59c67e5da26127d35b82cc5ce9460d6cfc..d22b26068014a775cde4efb3b16fc6f9a3dfd3c7 100644 (file)
@@ -9014,6 +9014,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
                ALC888_ACER_ASPIRE_4930G),
        SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
                ALC888_ACER_ASPIRE_8930G),
+       SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
+               ALC888_ACER_ASPIRE_8930G),
        SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC883_AUTO),
        SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC883_AUTO),
        SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
index 173bebf9f51d0316f00a158912c2dd0eeacc9f8d..8aa5687f392a10abf1310015d8ddeb57e73d070a 100644 (file)
@@ -356,8 +356,6 @@ struct ichdev {
         unsigned int position;
        unsigned int pos_shift;
        unsigned int last_pos;
-       unsigned long last_pos_jiffies;
-       unsigned int jiffy_to_bytes;
         int frags;
         int lvi;
         int lvi_frag;
@@ -844,7 +842,6 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                val = ICH_IOCE | ICH_STARTBM;
                ichdev->last_pos = ichdev->position;
-               ichdev->last_pos_jiffies = jiffies;
                break;
        case SNDRV_PCM_TRIGGER_SUSPEND:
                ichdev->suspended = 1;
@@ -1048,7 +1045,6 @@ static int snd_intel8x0_pcm_prepare(struct snd_pcm_substream *substream)
                        ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1;
        }
        snd_intel8x0_setup_periods(chip, ichdev);
-       ichdev->jiffy_to_bytes = (runtime->rate * 4 * ichdev->pos_shift) / HZ;
        return 0;
 }
 
@@ -1073,19 +1069,23 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs
                    ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb))
                        break;
        } while (timeout--);
+       ptr = ichdev->last_pos;
        if (ptr1 != 0) {
                ptr1 <<= ichdev->pos_shift;
                ptr = ichdev->fragsize1 - ptr1;
                ptr += position;
-               ichdev->last_pos = ptr;
-               ichdev->last_pos_jiffies = jiffies;
-       } else {
-               ptr1 = jiffies - ichdev->last_pos_jiffies;
-               if (ptr1)
-                       ptr1 -= 1;
-               ptr = ichdev->last_pos + ptr1 * ichdev->jiffy_to_bytes;
-               ptr %= ichdev->size;
+               if (ptr < ichdev->last_pos) {
+                       unsigned int pos_base, last_base;
+                       pos_base = position / ichdev->fragsize1;
+                       last_base = ichdev->last_pos / ichdev->fragsize1;
+                       /* another sanity check; ptr1 can go back to full
+                        * before the base position is updated
+                        */
+                       if (pos_base == last_base)
+                               ptr = ichdev->last_pos;
+               }
        }
+       ichdev->last_pos = ptr;
        spin_unlock(&chip->reg_lock);
        if (ptr >= ichdev->size)
                return 0;
index 1fc4c8e0899c18ec1f7f12750cf80023140cd5b7..c550750c79c0654db16d480e4abee954cc71e09f 100644 (file)
@@ -375,10 +375,6 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream,
        struct snd_soc_codec *codec = socdev->card->codec;
        struct ssm2602_priv *ssm2602 = codec->private_data;
 
-       if (ssm2602->master_substream == substream)
-               ssm2602->master_substream = ssm2602->slave_substream;
-
-       ssm2602->slave_substream = NULL;
        /* deactivate */
        if (!codec->active)
                ssm2602_write(codec, SSM2602_ACTIVE, 0);
index d8a9222fbf745c53077bd3a5f12e89c3f70bded0..e8d2e3e14c45528d6dd23ba73e71bead6c8fb53b 100644 (file)
@@ -1257,22 +1257,18 @@ static struct {
        int div;
 } bclk_divs[] = {
        {  10,  0 },
-       {  15,  1 },
        {  20,  2 },
        {  30,  3 },
        {  40,  4 },
        {  50,  5 },
-       {  55,  6 },
        {  60,  7 },
        {  80,  8 },
        { 100,  9 },
-       { 110, 10 },
        { 120, 11 },
        { 160, 12 },
        { 200, 13 },
        { 220, 14 },
        { 240, 15 },
-       { 250, 16 },
        { 300, 17 },
        { 320, 18 },
        { 440, 19 },
index c89a3cdf31e4aea8ad464baf720512deb0ccd319..326955dea36cef8fb6cc3fdb05e7516e7b05e578 100644 (file)
@@ -184,7 +184,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream,
 
        /* set cpu DAI configuration */
        ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
-                       SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBS_CFS);
+                       SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_CBS_CFS);
        if (ret < 0)
                return ret;
 
index 3f44150d8e30b6a9d8f5920e497627b397c0f049..1d70829464ef3698c85df7918b9c0c4acfaf1239 100644 (file)
@@ -1389,6 +1389,9 @@ int snd_soc_init_card(struct snd_soc_device *socdev)
        snprintf(codec->card->longname, sizeof(codec->card->longname),
                 "%s (%s)", card->name, codec->name);
 
+       /* Make sure all DAPM widgets are instantiated */
+       snd_soc_dapm_new_widgets(codec);
+
        ret = snd_card_register(codec->card);
        if (ret < 0) {
                printk(KERN_ERR "asoc: failed to register soundcard for %s\n",
index 2b302bbffe7361c6faccc1eb84099f2e1c5b1baf..12522e6913d92d068676f4b3916571b03dae2d87 100644 (file)
@@ -27,6 +27,11 @@ MODULE_DESCRIPTION("Core sound module");
 MODULE_AUTHOR("Alan Cox");
 MODULE_LICENSE("GPL");
 
+static char *sound_nodename(struct device *dev)
+{
+       return kasprintf(GFP_KERNEL, "snd/%s", dev_name(dev));
+}
+
 static int __init init_soundcore(void)
 {
        int rc;
@@ -41,6 +46,8 @@ static int __init init_soundcore(void)
                return PTR_ERR(sound_class);
        }
 
+       sound_class->nodename = sound_nodename;
+
        return 0;
 }
 
index f0f7624f91781efd574a883b78da048b5f9dbafb..f6f201eb24ceeb00145b406d6fbf18bf09d08817 100644 (file)
@@ -1989,7 +1989,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
        USB_DEVICE(0x0ccd, 0x0028),
        .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
                .vendor_name = "TerraTec",
-               .product_name = "Aureon 5.1 MkII",
+               .product_name = "Aureon5.1MkII",
                .ifnum = QUIRK_NO_INTERFACE
        }
 },